Commit 4a069f4b authored by Dominik Charousset's avatar Dominik Charousset

Drastically reduce complexity of the multiplexer

When we started with caf-net in the incubator, socket managers had
minimal control flow and the read and write handlers could simply return
whether they wished to be called again later again. With SSL and its
`want_read` and `want_write` shenanigans, things got a whole lot more
complicated and the old return-next-operation model stopped being a good
fit. And finally, asynchronous events that trigger reads and writes
without prior socket events made this approach pretty much fell apart
and there were in fact two paths to influence the event mask for a
socket manager: the return value of the handlers and
`register_(reading|writing)` functions.

With this redesign, read and write handlers no longer return anything.
All bookkeeping for the event mask exclusively relies on
`register_(reading|writing)` functions. The new design also drops
`resume_reading` and simply adds more capabilities to lower layers to
(re-) start reading at any time using actions.
parent 787d4259
...@@ -21,10 +21,6 @@ public: ...@@ -21,10 +21,6 @@ public:
using factory_type = Factory; using factory_type = Factory;
using read_result = typename socket_event_layer::read_result;
using write_result = typename socket_event_layer::write_result;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
template <class... Ts> template <class... Ts>
...@@ -54,40 +50,34 @@ public: ...@@ -54,40 +50,34 @@ public:
return none; return none;
} }
read_result handle_read_event() override { void handle_read_event() override {
CAF_LOG_TRACE(""); CAF_LOG_TRACE("");
if (auto x = accept(fd_)) { if (auto x = accept(fd_)) {
socket_manager_ptr child = factory_.make(owner_->mpx_ptr(), *x); socket_manager_ptr child = factory_.make(owner_->mpx_ptr(), *x);
if (!child) { if (!child) {
CAF_LOG_ERROR("factory failed to create a new child"); CAF_LOG_ERROR("factory failed to create a new child");
return read_result::abort; owner_->deregister();
return;
} }
if (auto err = child->init(cfg_)) { if (auto err = child->init(cfg_)) {
CAF_LOG_ERROR("failed to initialize new child:" << err); CAF_LOG_ERROR("failed to initialize new child:" << err);
return read_result::abort; owner_->deregister();
return;
} }
if (limit_ == 0) { if (limit_ != 0 && ++accepted_ == limit_) {
return read_result::again; // TODO: ask owner to close socket.
} else { owner_->deregister();
return ++accepted_ < limit_ ? read_result::again : read_result::stop; return;
} }
} else { } else {
CAF_LOG_ERROR("accept failed:" << x.error()); CAF_LOG_ERROR("accept failed:" << x.error());
return read_result::stop; owner_->deregister();
}
} }
read_result handle_buffered_data() override {
return read_result::again;
}
read_result handle_continue_reading() override {
return read_result::again;
} }
write_result handle_write_event() override { void handle_write_event() override {
CAF_LOG_ERROR("connection_acceptor received write event"); CAF_LOG_ERROR("connection_acceptor received write event");
return write_result::stop; owner_->deregister_writing();
} }
void abort(const error& reason) override { void abort(const error& reason) override {
......
...@@ -5,27 +5,28 @@ ...@@ -5,27 +5,28 @@
#pragma once #pragma once
#include "caf/async/consumer.hpp" #include "caf/async/consumer.hpp"
#include "caf/detail/atomic_ref_counted.hpp"
#include "caf/net/multiplexer.hpp" #include "caf/net/multiplexer.hpp"
#include "caf/net/socket_manager.hpp" #include "caf/net/socket_manager.hpp"
#include "caf/ref_counted.hpp"
namespace caf::net { namespace caf::net {
/// Connects a socket manager to an asynchronous consumer resource. Whenever new /// Connects a socket manager to an asynchronous consumer resource. Whenever new
/// data becomes ready, the adapter registers the socket manager for writing. /// data becomes ready, the adapter registers the socket manager for writing.
template <class Buffer> template <class Buffer>
class consumer_adapter final : public ref_counted, public async::consumer { class consumer_adapter final : public detail::atomic_ref_counted,
public async::consumer {
public: public:
using buf_ptr = intrusive_ptr<Buffer>; using buf_ptr = intrusive_ptr<Buffer>;
using ptr_type = intrusive_ptr<consumer_adapter>;
void on_producer_ready() override { void on_producer_ready() override {
// nop // nop
} }
void on_producer_wakeup() override { void on_producer_wakeup() override {
mgr_->mpx().schedule_fn([adapter = strong_this()] { // mgr_->schedule(do_wakeup_);
adapter->on_wakeup();
});
} }
void ref_consumer() const noexcept override { void ref_consumer() const noexcept override {
...@@ -44,22 +45,20 @@ public: ...@@ -44,22 +45,20 @@ public:
void cancel() { void cancel() {
buf_->cancel(); buf_->cancel();
buf_ = nullptr; buf_ = nullptr;
mgr_ = nullptr;
do_wakeup_.dispose();
do_wakeup_ = nullptr;
} }
bool has_data() const noexcept { bool has_data() const noexcept {
return buf_->has_data(); return buf_->has_data();
} }
/// Tries to open the resource for reading. static ptr_type make(buf_ptr buf, socket_manager_ptr mgr, action do_wakeup) {
/// @returns a connected adapter that reads from the resource on success, if (buf) {
/// `nullptr` otherwise. auto adapter = ptr_type{new consumer_adapter(buf, mgr,
template <class Resource> std::move(do_wakeup)), //
static intrusive_ptr<consumer_adapter> false};
try_open(socket_manager* owner, Resource src) {
CAF_ASSERT(owner != nullptr);
if (auto buf = src.try_open()) {
using ptr_type = intrusive_ptr<consumer_adapter>;
auto adapter = ptr_type{new consumer_adapter(owner, buf), false};
buf->set_consumer(adapter); buf->set_consumer(adapter);
return adapter; return adapter;
} else { } else {
...@@ -67,17 +66,11 @@ public: ...@@ -67,17 +66,11 @@ public:
} }
} }
friend void intrusive_ptr_add_ref(const consumer_adapter* ptr) noexcept {
ptr->ref();
}
friend void intrusive_ptr_release(const consumer_adapter* ptr) noexcept {
ptr->deref();
}
private: private:
consumer_adapter(socket_manager* owner, buf_ptr buf) consumer_adapter(buf_ptr buf, socket_manager_ptr mgr, action do_wakeup)
: mgr_(owner), buf_(std::move(buf)) { : buf_(std::move(buf)),
mgr_(std::move(mgr)),
do_wakeup_(std::move(do_wakeup)) {
// nop // nop
} }
...@@ -91,8 +84,10 @@ private: ...@@ -91,8 +84,10 @@ private:
} }
} }
intrusive_ptr<socket_manager> mgr_;
intrusive_ptr<Buffer> buf_; intrusive_ptr<Buffer> buf_;
socket_manager_ptr mgr_;
action do_wakeup_;
action do_cancel_;
}; };
template <class T> template <class T>
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#pragma once #pragma once
#include "caf/detail/net_export.hpp" #include "caf/detail/net_export.hpp"
#include "caf/fwd.hpp"
namespace caf::net { namespace caf::net {
...@@ -17,12 +18,18 @@ public: ...@@ -17,12 +18,18 @@ public:
/// Queries whether the output device can accept more data straight away. /// Queries whether the output device can accept more data straight away.
[[nodiscard]] virtual bool can_send_more() const noexcept = 0; [[nodiscard]] virtual bool can_send_more() const noexcept = 0;
/// Halt receiving of additional bytes or messages.
virtual void suspend_reading() = 0;
/// Queries whether the lower layer is currently configured to halt receiving /// Queries whether the lower layer is currently configured to halt receiving
/// of additional bytes or messages. /// of additional bytes or messages.
[[nodiscard]] virtual bool stopped_reading() const noexcept = 0; [[nodiscard]] virtual bool is_reading() const noexcept = 0;
/// Shuts down any connection or session gracefully. Any pending data gets
/// flushed before closing the socket.
virtual void close() = 0;
/// Shuts down any connection or session du to an error. Any pending data gets
/// flushed before closing the socket. Protocols with a dedicated closing
/// handshake such as WebSocket may send the close reason to the peer.
virtual void close(const error& reason);
}; };
} // namespace caf::net } // namespace caf::net
...@@ -24,11 +24,6 @@ public: ...@@ -24,11 +24,6 @@ public:
/// function to decide whether it has to wait for write events on the socket. /// function to decide whether it has to wait for write events on the socket.
[[nodiscard]] virtual bool done_sending() = 0; [[nodiscard]] virtual bool done_sending() = 0;
/// Called by the lower layer after some event triggered re-registering the
/// socket manager for read operations after it has been stopped previously
/// by the read policy. May restart consumption of bytes or messages.
virtual void continue_reading() = 0;
/// Called by the lower layer for cleaning up any state in case of an error. /// Called by the lower layer for cleaning up any state in case of an error.
virtual void abort(const error& reason) = 0; virtual void abort(const error& reason) = 0;
}; };
......
...@@ -18,6 +18,12 @@ class CAF_NET_EXPORT lower_layer : public generic_lower_layer { ...@@ -18,6 +18,12 @@ class CAF_NET_EXPORT lower_layer : public generic_lower_layer {
public: public:
virtual ~lower_layer(); virtual ~lower_layer();
/// Start or re-start reading data from the client.
virtual void request_messages() = 0;
/// Stops reading messages until calling `request_messages`.
virtual void suspend_reading() = 0;
/// Sends the next header to the client. /// Sends the next header to the client.
virtual bool virtual bool
send_header(context ctx, status code, const header_fields_map& fields) send_header(context ctx, status code, const header_fields_map& fields)
......
...@@ -80,9 +80,13 @@ public: ...@@ -80,9 +80,13 @@ public:
bool can_send_more() const noexcept override; bool can_send_more() const noexcept override;
void suspend_reading() override; bool is_reading() const noexcept override;
void close() override;
bool stopped_reading() const noexcept override; void request_messages() override;
void suspend_reading() override;
bool send_header(context, status code, bool send_header(context, status code,
const header_fields_map& fields) override; const header_fields_map& fields) override;
...@@ -106,8 +110,6 @@ public: ...@@ -106,8 +110,6 @@ public:
bool done_sending() override; bool done_sending() override;
void continue_reading() override;
ptrdiff_t consume(byte_span input, byte_span) override; ptrdiff_t consume(byte_span input, byte_span) override;
private: private:
......
...@@ -81,8 +81,6 @@ public: ...@@ -81,8 +81,6 @@ public:
ptrdiff_t consume(byte_span buffer, byte_span delta) override; ptrdiff_t consume(byte_span buffer, byte_span delta) override;
void continue_reading() override;
bool prepare_send() override; bool prepare_send() override;
bool done_sending() override; bool done_sending() override;
...@@ -95,7 +93,7 @@ public: ...@@ -95,7 +93,7 @@ public:
void suspend_reading() override; void suspend_reading() override;
bool stopped_reading() const noexcept override; bool is_reading() const noexcept override;
void begin_message() override; void begin_message() override;
...@@ -103,9 +101,7 @@ public: ...@@ -103,9 +101,7 @@ public:
bool end_message() override; bool end_message() override;
void send_close_message() override; void close() override;
void send_close_message(const error& reason) override;
// -- utility functions ------------------------------------------------------ // -- utility functions ------------------------------------------------------
......
...@@ -116,9 +116,9 @@ public: ...@@ -116,9 +116,9 @@ public:
auto [again, consumed] = in_->pull(async::delay_errors, 1, helper); auto [again, consumed] = in_->pull(async::delay_errors, 1, helper);
if (!again) { if (!again) {
if (helper.err) { if (helper.err) {
down_->send_close_message(helper.err); down_->close(helper.err);
} else { } else {
down_->send_close_message(); down_->close();
} }
in_ = nullptr; in_ = nullptr;
} else if (helper.aborted) { } else if (helper.aborted) {
......
...@@ -47,6 +47,9 @@ public: ...@@ -47,6 +47,9 @@ public:
/// Pulls messages from the transport until calling `suspend_reading`. /// Pulls messages from the transport until calling `suspend_reading`.
virtual void request_messages() = 0; virtual void request_messages() = 0;
/// Stops reading messages until calling `request_messages`.
virtual void suspend_reading() = 0;
/// Prepares the layer for an outgoing message, e.g., by allocating an /// Prepares the layer for an outgoing message, e.g., by allocating an
/// output buffer as necessary. /// output buffer as necessary.
virtual void begin_message() = 0; virtual void begin_message() = 0;
...@@ -62,17 +65,6 @@ public: ...@@ -62,17 +65,6 @@ public:
/// @note When returning `false`, clients must also call /// @note When returning `false`, clients must also call
/// `down.set_read_error(...)` with an appropriate error code. /// `down.set_read_error(...)` with an appropriate error code.
virtual bool end_message() = 0; virtual bool end_message() = 0;
/// Inform the remote endpoint that no more messages will arrive.
/// @note Not every protocol has a dedicated close message. Some
/// implementation may simply do nothing.
virtual void send_close_message() = 0;
/// Inform the remote endpoint that no more messages will arrive because of
/// an error.
/// @note Not every protocol has a dedicated close message. Some
/// implementation may simply do nothing.
virtual void send_close_message(const error& reason) = 0;
}; };
} // namespace caf::net::message_oriented } // namespace caf::net::message_oriented
...@@ -73,10 +73,10 @@ public: ...@@ -73,10 +73,10 @@ public:
size_t num_socket_managers() const noexcept; size_t num_socket_managers() const noexcept;
/// Returns the index of `mgr` in the pollset or `-1`. /// Returns the index of `mgr` in the pollset or `-1`.
ptrdiff_t index_of(const socket_manager_ptr& mgr); ptrdiff_t index_of(const socket_manager_ptr& mgr) const noexcept;
/// Returns the index of `fd` in the pollset or `-1`. /// Returns the index of `fd` in the pollset or `-1`.
ptrdiff_t index_of(socket fd); ptrdiff_t index_of(socket fd) const noexcept;
/// Returns the owning @ref middleman instance. /// Returns the owning @ref middleman instance.
middleman& owner(); middleman& owner();
...@@ -89,22 +89,6 @@ public: ...@@ -89,22 +89,6 @@ public:
// -- thread-safe signaling -------------------------------------------------- // -- thread-safe signaling --------------------------------------------------
/// Registers `mgr` for read events.
/// @thread-safe
void register_reading(const socket_manager_ptr& mgr);
/// Registers `mgr` for write events.
/// @thread-safe
void register_writing(const socket_manager_ptr& mgr);
/// Triggers a continue reading event for `mgr`.
/// @thread-safe
void continue_reading(const socket_manager_ptr& mgr);
/// Triggers a continue writing event for `mgr`.
/// @thread-safe
void continue_writing(const socket_manager_ptr& mgr);
/// Schedules a call to `mgr->handle_error(sec::discarded)`. /// Schedules a call to `mgr->handle_error(sec::discarded)`.
/// @thread-safe /// @thread-safe
void discard(const socket_manager_ptr& mgr); void discard(const socket_manager_ptr& mgr);
...@@ -136,6 +120,29 @@ public: ...@@ -136,6 +120,29 @@ public:
/// @thread-safe /// @thread-safe
void shutdown(); void shutdown();
// -- callbacks for socket managers ------------------------------------------
/// Registers `mgr` for read events.
void register_reading(socket_manager* mgr);
/// Registers `mgr` for write events.
void register_writing(socket_manager* mgr);
/// Deregisters `mgr` from read events.
void deregister_reading(socket_manager* mgr);
/// Deregisters `mgr` from write events.
void deregister_writing(socket_manager* mgr);
/// Deregisters @p mgr from read and write events.
void deregister(socket_manager* mgr);
/// Queries whether `mgr` is currently registered for reading.
bool is_reading(const socket_manager* mgr) const noexcept;
/// Queries whether `mgr` is currently registered for writing.
bool is_writing(const socket_manager* mgr) const noexcept;
// -- control flow ----------------------------------------------------------- // -- control flow -----------------------------------------------------------
/// Polls I/O activity once and runs all socket event handlers that become /// Polls I/O activity once and runs all socket event handlers that become
...@@ -160,15 +167,12 @@ protected: ...@@ -160,15 +167,12 @@ protected:
/// Handles an I/O event on given manager. /// Handles an I/O event on given manager.
void handle(const socket_manager_ptr& mgr, short events, short revents); void handle(const socket_manager_ptr& mgr, short events, short revents);
/// Transfers socket ownership from one manager to another.
void do_handover(const socket_manager_ptr& mgr);
/// Returns a change entry for the socket at given index. Lazily creates a new /// Returns a change entry for the socket at given index. Lazily creates a new
/// entry before returning if necessary. /// entry before returning if necessary.
poll_update& update_for(ptrdiff_t index); poll_update& update_for(ptrdiff_t index);
/// Returns a change entry for the socket of the manager. /// Returns a change entry for the socket of the manager.
poll_update& update_for(const socket_manager_ptr& mgr); poll_update& update_for(socket_manager* mgr);
/// Writes `opcode` and pointer to `mgr` the the pipe for handling an event /// Writes `opcode` and pointer to `mgr` the the pipe for handling an event
/// later via the pollset updater. /// later via the pollset updater.
...@@ -182,13 +186,7 @@ protected: ...@@ -182,13 +186,7 @@ protected:
} }
/// Queries the currently active event bitmask for `mgr`. /// Queries the currently active event bitmask for `mgr`.
short active_mask_of(const socket_manager_ptr& mgr); short active_mask_of(const socket_manager* mgr) const noexcept;
/// Queries whether `mgr` is currently registered for reading.
bool is_reading(const socket_manager_ptr& mgr);
/// Queries whether `mgr` is currently registered for writing.
bool is_writing(const socket_manager_ptr& mgr);
// -- member variables ------------------------------------------------------- // -- member variables -------------------------------------------------------
...@@ -226,12 +224,6 @@ private: ...@@ -226,12 +224,6 @@ private:
void do_register_reading(const socket_manager_ptr& mgr); void do_register_reading(const socket_manager_ptr& mgr);
void do_register_writing(const socket_manager_ptr& mgr);
void do_continue_reading(const socket_manager_ptr& mgr);
void do_continue_writing(const socket_manager_ptr& mgr);
void do_discard(const socket_manager_ptr& mgr); void do_discard(const socket_manager_ptr& mgr);
void do_shutdown_reading(const socket_manager_ptr& mgr); void do_shutdown_reading(const socket_manager_ptr& mgr);
......
...@@ -25,10 +25,6 @@ public: ...@@ -25,10 +25,6 @@ public:
using msg_buf = std::array<std::byte, sizeof(intptr_t) + 1>; using msg_buf = std::array<std::byte, sizeof(intptr_t) + 1>;
enum class code : uint8_t { enum class code : uint8_t {
register_reading,
continue_reading,
register_writing,
continue_writing,
init_manager, init_manager,
discard_manager, discard_manager,
shutdown_reading, shutdown_reading,
...@@ -49,18 +45,15 @@ public: ...@@ -49,18 +45,15 @@ public:
error init(socket_manager* owner, const settings& cfg) override; error init(socket_manager* owner, const settings& cfg) override;
read_result handle_read_event() override; void handle_read_event() override;
read_result handle_buffered_data() override; void handle_write_event() override;
read_result handle_continue_reading() override;
write_result handle_write_event() override;
void abort(const error& reason) override; void abort(const error& reason) override;
private: private:
pipe_socket fd_; pipe_socket fd_;
socket_manager* owner_ = nullptr;
multiplexer* mpx_ = nullptr; multiplexer* mpx_ = nullptr;
msg_buf buf_; msg_buf buf_;
size_t buf_size_ = 0; size_t buf_size_ = 0;
......
...@@ -8,36 +8,35 @@ ...@@ -8,36 +8,35 @@
#include <new> #include <new>
#include "caf/async/producer.hpp" #include "caf/async/producer.hpp"
#include "caf/detail/atomic_ref_counted.hpp"
#include "caf/flow/observer.hpp" #include "caf/flow/observer.hpp"
#include "caf/flow/subscription.hpp" #include "caf/flow/subscription.hpp"
#include "caf/net/multiplexer.hpp" #include "caf/net/multiplexer.hpp"
#include "caf/net/socket_manager.hpp" #include "caf/net/socket_manager.hpp"
#include "caf/ref_counted.hpp"
namespace caf::net { namespace caf::net {
/// Connects a socket manager to an asynchronous producer resource. /// Connects a socket manager to an asynchronous producer resource.
template <class Buffer> template <class Buffer>
class producer_adapter final : public ref_counted, public async::producer { class producer_adapter final : public detail::atomic_ref_counted,
public async::producer {
public: public:
using atomic_count = std::atomic<size_t>;
using buf_ptr = intrusive_ptr<Buffer>; using buf_ptr = intrusive_ptr<Buffer>;
using value_type = typename Buffer::value_type; using value_type = typename Buffer::value_type;
using ptr_type = intrusive_ptr<producer_adapter>;
void on_consumer_ready() override { void on_consumer_ready() override {
// nop // nop
} }
void on_consumer_cancel() override { void on_consumer_cancel() override {
mgr_->mpx().schedule_fn([adapter = strong_this()] { // mgr_->schedule(do_cancel_);
adapter->on_cancel();
});
} }
void on_consumer_demand(size_t) override { void on_consumer_demand(size_t) override {
mgr_->continue_reading(); mgr_->schedule(do_resume_);
} }
void ref_producer() const noexcept override { void ref_producer() const noexcept override {
...@@ -48,16 +47,13 @@ public: ...@@ -48,16 +47,13 @@ public:
this->deref(); this->deref();
} }
/// Tries to open the resource for writing. static ptr_type make(buf_ptr buf, socket_manager_ptr mgr, action do_resume,
/// @returns a connected adapter that writes to the resource on success, action do_cancel) {
/// `nullptr` otherwise. if (buf) {
template <class Resource> auto adapter
static intrusive_ptr<producer_adapter> = ptr_type{new producer_adapter(buf, mgr, std::move(do_resume),
try_open(socket_manager* owner, Resource src) { std::move(do_cancel)),
CAF_ASSERT(owner != nullptr); false};
if (auto buf = src.try_open()) {
using ptr_type = intrusive_ptr<producer_adapter>;
auto adapter = ptr_type{new producer_adapter(owner, buf), false};
buf->set_producer(adapter); buf->set_producer(adapter);
return adapter; return adapter;
} else { } else {
...@@ -88,47 +84,40 @@ public: ...@@ -88,47 +84,40 @@ public:
void close() { void close() {
if (buf_) { if (buf_) {
buf_->close(); buf_->close();
buf_ = nullptr; reset();
mgr_ = nullptr;
} }
} }
void abort(error reason) { void abort(error reason) {
if (buf_) { if (buf_) {
buf_->abort(std::move(reason)); buf_->abort(std::move(reason));
buf_ = nullptr; reset();
mgr_ = nullptr;
}
} }
friend void intrusive_ptr_add_ref(const producer_adapter* ptr) noexcept {
ptr->ref();
}
friend void intrusive_ptr_release(const producer_adapter* ptr) noexcept {
ptr->deref();
} }
private: private:
producer_adapter(socket_manager* owner, buf_ptr buf) producer_adapter(buf_ptr buf, socket_manager_ptr mgr, action do_resume,
: mgr_(owner), buf_(std::move(buf)) { action do_cancel)
: buf_(std::move(buf)),
mgr_(std::move(mgr)),
do_resume_(std::move(do_resume)),
do_cancel_(std::move(do_cancel)) {
// nop // nop
} }
void on_cancel() { void reset() {
if (buf_) {
mgr_->mpx().shutdown_reading(mgr_);
buf_ = nullptr; buf_ = nullptr;
mgr_ = nullptr; mgr_ = nullptr;
} do_resume_.dispose();
do_resume_ = nullptr;
do_cancel_.dispose();
do_cancel_ = nullptr;
} }
auto strong_this() {
return intrusive_ptr{this};
}
intrusive_ptr<socket_manager> mgr_;
intrusive_ptr<Buffer> buf_; intrusive_ptr<Buffer> buf_;
intrusive_ptr<socket_manager> mgr_;
action do_resume_;
action do_cancel_;
}; };
template <class T> template <class T>
......
...@@ -16,58 +16,14 @@ class CAF_NET_EXPORT socket_event_layer { ...@@ -16,58 +16,14 @@ class CAF_NET_EXPORT socket_event_layer {
public: public:
virtual ~socket_event_layer(); virtual ~socket_event_layer();
/// Encodes how to proceed after a read operation.
enum class read_result {
/// Indicates that a manager wants to read again later.
again,
/// Indicates that a manager wants to stop reading until explicitly resumed.
stop,
/// Indicates that a manager wants to write to the socket instead of reading
/// from the socket.
want_write,
/// Indicates that the manager no longer reads from the socket.
close,
/// Indicates that the manager encountered a fatal error and stops both
/// reading and writing.
abort,
/// Indicates that a manager is done with the socket and hands ownership to
/// another manager.
handover,
};
/// Encodes how to proceed after a write operation.
enum class write_result {
/// Indicates that a manager wants to read again later.
again,
/// Indicates that a manager wants to stop reading until explicitly resumed.
stop,
/// Indicates that a manager wants to read from the socket instead of
/// writing to the socket.
want_read,
/// Indicates that the manager no longer writes to the socket.
close,
/// Indicates that the manager encountered a fatal error and stops both
/// reading and writing.
abort,
/// Indicates that a manager is done with the socket and hands ownership to
/// another manager.
handover,
};
/// Initializes the layer. /// Initializes the layer.
virtual error init(socket_manager* owner, const settings& cfg) = 0; virtual error init(socket_manager* owner, const settings& cfg) = 0;
/// Handles a read event on the managed socket. /// Handles a read event on the managed socket.
virtual read_result handle_read_event() = 0; virtual void handle_read_event() = 0;
/// Handles internally buffered data.
virtual read_result handle_buffered_data() = 0;
/// Handles a request to continue reading on the socket.
virtual read_result handle_continue_reading() = 0;
/// Handles a write event on the managed socket. /// Handles a write event on the managed socket.
virtual write_result handle_write_event() = 0; virtual void handle_write_event() = 0;
/// Called after returning `handover` from a read or write handler. /// Called after returning `handover` from a read or write handler.
virtual bool do_handover(std::unique_ptr<socket_event_layer>& next); virtual bool do_handover(std::unique_ptr<socket_event_layer>& next);
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#pragma once #pragma once
#include "caf/action.hpp"
#include "caf/actor.hpp" #include "caf/actor.hpp"
#include "caf/actor_system.hpp" #include "caf/actor_system.hpp"
#include "caf/callback.hpp" #include "caf/callback.hpp"
...@@ -28,10 +29,6 @@ class CAF_NET_EXPORT socket_manager : public ref_counted { ...@@ -28,10 +29,6 @@ class CAF_NET_EXPORT socket_manager : public ref_counted {
public: public:
// -- member types ----------------------------------------------------------- // -- member types -----------------------------------------------------------
using read_result = socket_event_layer::read_result;
using write_result = socket_event_layer::write_result;
using event_handler_ptr = std::unique_ptr<socket_event_layer>; using event_handler_ptr = std::unique_ptr<socket_event_layer>;
/// Stores manager-related flags in a single block. /// Stores manager-related flags in a single block.
...@@ -122,31 +119,54 @@ public: ...@@ -122,31 +119,54 @@ public:
return flags_.write_closed; return flags_.write_closed;
} }
/// Queries whether the manager is registered for reading.
bool is_reading() const noexcept;
/// Queries whether the manager is registered for writing.
bool is_writing() const noexcept;
// -- event loop management -------------------------------------------------- // -- event loop management --------------------------------------------------
/// Registers the manager for read operations on the @ref multiplexer. /// Registers the manager for read operations.
/// @thread-safe
void register_reading(); void register_reading();
/// Registers the manager for write operations on the @ref multiplexer. /// Registers the manager for write operations.
/// @thread-safe
void register_writing(); void register_writing();
/// Schedules a call to `handle_continue_reading` on the @ref multiplexer. /// Deregisters the manager from read operations.
/// This mechanism allows users to signal changes in the environment to the void deregister_reading();
/// manager that allow it to make progress, e.g., new demand in asynchronous
/// buffer that allow the manager to push available data downstream. The event /// Deregisters the manager from write operations.
/// is a no-op if the manager is already registered for reading. void deregister_writing();
/// @thread-safe
void continue_reading(); /// Deregisters the manager from both read and write operations.
void deregister();
/// Schedules a call to `handle_continue_reading` on the @ref multiplexer.
/// This mechanism allows users to signal changes in the environment to the /// Deregisters the manager from read operations and blocks any future
/// manager that allow it to make progress, e.g., new data for writing in an /// attempts to re-register it.
/// asynchronous buffer. The event is a no-op if the manager is already void shutdown_read();
/// registered for writing.
/// @thread-safe /// Deregisters the manager from write operations and blocks any future
void continue_writing(); /// attempts to re-register it.
void shutdown_write();
/// Deregisters the manager from both read and write operations and blocks any
/// future attempts to re-register it.
void shutdown();
// -- callbacks for the handler ----------------------------------------------
/// Schedules a call to `do_handover` on the handler.
void schedule_handover();
/// Schedules @p what to run later.
void schedule(action what);
/// Schedules @p what to run later.
template <class F>
void schedule_fn(F&& what) {
schedule(make_action(std::forward<F>(what)));
}
// -- callbacks for the multiplexer ------------------------------------------ // -- callbacks for the multiplexer ------------------------------------------
...@@ -160,30 +180,20 @@ public: ...@@ -160,30 +180,20 @@ public:
error init(const settings& cfg); error init(const settings& cfg);
/// Called whenever the socket received new data. /// Called whenever the socket received new data.
read_result handle_read_event(); void handle_read_event();
/// Called after handovers to allow the manager to process any data that is
/// already buffered at the transport policy and thus would not trigger a read
/// event on the socket.
read_result handle_buffered_data();
/// Restarts a socket manager that suspended reads. Calling this member
/// function on active managers is a no-op. This function also should read any
/// data buffered outside of the socket.
read_result handle_continue_reading();
/// Called whenever the socket is allowed to send data. /// Called whenever the socket is allowed to send data.
write_result handle_write_event(); void handle_write_event();
/// Called when the remote side becomes unreachable due to an error. /// Called when the remote side becomes unreachable due to an error.
/// @param code The error code as reported by the operating system. /// @param code The error code as reported by the operating system.
void handle_error(sec code); void handle_error(sec code);
/// Performs a handover to another transport after `handle_read_event` or
/// `handle_read_event` returned `handover`.
[[nodiscard]] bool do_handover();
private: private:
// -- utility functions ------------------------------------------------------
socket_manager_ptr strong_this();
// -- member variables ------------------------------------------------------- // -- member variables -------------------------------------------------------
/// Stores the socket file descriptor. The socket manager automatically closes /// Stores the socket file descriptor. The socket manager automatically closes
......
...@@ -45,6 +45,10 @@ class CAF_NET_EXPORT lower_layer : public generic_lower_layer { ...@@ -45,6 +45,10 @@ class CAF_NET_EXPORT lower_layer : public generic_lower_layer {
public: public:
virtual ~lower_layer(); virtual ~lower_layer();
/// Queries whether the transport is currently configured to read from its
/// socket.
virtual bool is_reading() const noexcept = 0;
/// Configures threshold for the next receive operations. Policies remain /// Configures threshold for the next receive operations. Policies remain
/// active until calling this function again. /// active until calling this function again.
/// @warning Calling this function in `consume` invalidates both byte spans. /// @warning Calling this function in `consume` invalidates both byte spans.
......
...@@ -85,6 +85,9 @@ public: ...@@ -85,6 +85,9 @@ public:
/// Stores whether we left a write handler due to want_read. /// Stores whether we left a write handler due to want_read.
bool wanted_write_from_read_event : 1; bool wanted_write_from_read_event : 1;
/// Stores whether we shutdown write on the socket after flushing.
bool shutting_down : 1;
}; };
// -- constants -------------------------------------------------------------- // -- constants --------------------------------------------------------------
...@@ -118,9 +121,9 @@ public: ...@@ -118,9 +121,9 @@ public:
bool end_output() override; bool end_output() override;
void suspend_reading() override; bool is_reading() const noexcept override;
bool stopped_reading() const noexcept override; void close() override;
// -- properties ------------------------------------------------------------- // -- properties -------------------------------------------------------------
...@@ -152,17 +155,23 @@ public: ...@@ -152,17 +155,23 @@ public:
error init(socket_manager* owner, const settings& config) override; error init(socket_manager* owner, const settings& config) override;
read_result handle_read_event() override; void handle_read_event() override;
read_result handle_buffered_data() override;
write_result handle_write_event() override; void handle_write_event() override;
read_result handle_continue_reading() override;
void abort(const error& reason) override; void abort(const error& reason) override;
protected: protected:
// -- utility functions ------------------------------------------------------
/// Consumes as much data from the buffer as possible.
void handle_buffered_data();
/// Calls abort on the upper layer and deregisters the transport from events.
void fail(const error& reason);
// -- member variables -------------------------------------------------------
/// The socket file descriptor. /// The socket file descriptor.
stream_socket fd_; stream_socket fd_;
......
...@@ -74,8 +74,6 @@ public: ...@@ -74,8 +74,6 @@ public:
ptrdiff_t consume(byte_span buffer, byte_span delta) override; ptrdiff_t consume(byte_span buffer, byte_span delta) override;
void continue_reading() override;
bool prepare_send() override; bool prepare_send() override;
bool done_sending() override; bool done_sending() override;
......
...@@ -79,6 +79,10 @@ public: ...@@ -79,6 +79,10 @@ public:
} }
}; };
bool running() const noexcept {
return in_ || out_;
}
// -- implementation of web_socket::lower_layer ------------------------------ // -- implementation of web_socket::lower_layer ------------------------------
error init(net::socket_manager* mgr, web_socket::lower_layer* down, error init(net::socket_manager* mgr, web_socket::lower_layer* down,
...@@ -86,38 +90,48 @@ public: ...@@ -86,38 +90,48 @@ public:
down_ = down; down_ = down;
auto [err, pull, push] = conn_->on_request(cfg); auto [err, pull, push] = conn_->on_request(cfg);
if (!err) { if (!err) {
in_ = consumer_type::try_open(mgr, pull); auto do_wakeup = make_action([this] {
out_ = producer_type::try_open(mgr, push); prepare_send();
CAF_ASSERT(in_ != nullptr); if (!running())
CAF_ASSERT(out_ != nullptr); down_->close();
});
auto do_resume = make_action([this] { down_->request_messages(); });
auto do_cancel = make_action([this] {
out_ = nullptr;
if (!running())
down_->close();
});
in_ = consumer_type::make(pull.try_open(), mgr, std::move(do_wakeup));
out_ = producer_type::make(push.try_open(), mgr, std::move(do_resume),
std::move(do_cancel));
conn_ = nullptr; conn_ = nullptr;
if (running())
return none; return none;
else
return make_error(sec::runtime_error,
"cannot init flow bridge: no buffers");
} else { } else {
conn_ = nullptr; conn_ = nullptr;
return err; return err;
} }
} }
void continue_reading() override {
// nop
}
bool prepare_send() override { bool prepare_send() override {
write_helper helper{this}; write_helper helper{this};
while (down_->can_send_more() && in_) { while (down_->can_send_more() && in_) {
auto [again, consumed] = in_->pull(async::delay_errors, 1, helper); auto [again, consumed] = in_->pull(async::delay_errors, 1, helper);
if (!again) { if (!again) {
if (helper.err) { if (helper.err) {
down_->send_close_message(helper.err); down_->close(helper.err);
} else { } else {
down_->send_close_message(); down_->close();
} }
in_ = nullptr; in_ = nullptr;
return false; return true;
} else if (helper.aborted) { } else if (helper.aborted) {
in_->cancel(); in_->cancel();
in_ = nullptr; in_ = nullptr;
return false; return true;
} else if (consumed == 0) { } else if (consumed == 0) {
return true; return true;
} }
......
...@@ -77,11 +77,15 @@ public: ...@@ -77,11 +77,15 @@ public:
// -- web_socket::lower_layer implementation --------------------------------- // -- web_socket::lower_layer implementation ---------------------------------
using web_socket::lower_layer::close;
bool can_send_more() const noexcept override; bool can_send_more() const noexcept override;
void suspend_reading() override; void suspend_reading() override;
bool stopped_reading() const noexcept override; bool is_reading() const noexcept override;
void close(status code, std::string_view desc) override;
void request_messages() override; void request_messages() override;
...@@ -97,17 +101,8 @@ public: ...@@ -97,17 +101,8 @@ public:
bool end_text_message() override; bool end_text_message() override;
void send_close_message() override;
void send_close_message(status code, std::string_view desc) override;
// -- interface for the lower layer ------------------------------------------ // -- interface for the lower layer ------------------------------------------
template <class LowerLayerPtr>
static void continue_reading(LowerLayerPtr down) {
down->configure_read(receive_policy::up_to(2048));
}
ptrdiff_t consume(byte_span input, byte_span); ptrdiff_t consume(byte_span input, byte_span);
private: private:
...@@ -117,10 +112,6 @@ private: ...@@ -117,10 +112,6 @@ private:
void ship_pong(byte_span payload); void ship_pong(byte_span payload);
void ship_close(uint16_t code, std::string_view msg);
void ship_close();
template <class T> template <class T>
void ship_frame(std::vector<T>& buf); void ship_frame(std::vector<T>& buf);
......
...@@ -22,6 +22,9 @@ public: ...@@ -22,6 +22,9 @@ public:
/// Pulls messages from the transport until calling `suspend_reading`. /// Pulls messages from the transport until calling `suspend_reading`.
virtual void request_messages() = 0; virtual void request_messages() = 0;
/// Stops reading messages until calling `request_messages`.
virtual void suspend_reading() = 0;
/// Begins transmission of a binary message. /// Begins transmission of a binary message.
virtual void begin_binary_message() = 0; virtual void begin_binary_message() = 0;
...@@ -42,14 +45,12 @@ public: ...@@ -42,14 +45,12 @@ public:
/// Seals the current text message buffer and ships a new WebSocket frame. /// Seals the current text message buffer and ships a new WebSocket frame.
virtual bool end_text_message() = 0; virtual bool end_text_message() = 0;
/// Sends the close message with @ref status `normal_close`. void close() override;
virtual void send_close_message() = 0;
/// Sends the close message with an custom @ref status. void close(const error& reason) override;
virtual void send_close_message(status code, std::string_view desc) = 0;
/// Sends the close message with @ref status `unexpected_condition`. /// Sends a close message with custom @ref status @p code and @p msg text.
void send_close_message(const error& reason); virtual void close(status code, std::string_view msg) = 0;
}; };
} // namespace caf::net::web_socket } // namespace caf::net::web_socket
...@@ -81,8 +81,6 @@ public: ...@@ -81,8 +81,6 @@ public:
ptrdiff_t consume(byte_span input, byte_span) override; ptrdiff_t consume(byte_span input, byte_span) override;
void continue_reading() override;
bool prepare_send() override; bool prepare_send() override;
bool done_sending() override; bool done_sending() override;
......
...@@ -10,4 +10,8 @@ generic_lower_layer::~generic_lower_layer() { ...@@ -10,4 +10,8 @@ generic_lower_layer::~generic_lower_layer() {
// nop // nop
} }
void generic_lower_layer::close(const error&) {
close();
}
} // namespace caf::net } // namespace caf::net
...@@ -14,12 +14,21 @@ bool server::can_send_more() const noexcept { ...@@ -14,12 +14,21 @@ bool server::can_send_more() const noexcept {
return down_->can_send_more(); return down_->can_send_more();
} }
void server::suspend_reading() { bool server::is_reading() const noexcept {
return down_->suspend_reading(); return down_->is_reading();
}
void server::close() {
down_->close();
}
void server::request_messages() {
if (!down_->is_reading())
down_->configure_read(receive_policy::up_to(max_request_size_));
} }
bool server::stopped_reading() const noexcept { void server::suspend_reading() {
return down_->stopped_reading(); down_->configure_read(receive_policy::stop());
} }
bool server::send_header(context, status code, bool server::send_header(context, status code,
...@@ -69,11 +78,10 @@ void server::fin(context) { ...@@ -69,11 +78,10 @@ void server::fin(context) {
error server::init(socket_manager* owner, stream_oriented::lower_layer* down, error server::init(socket_manager* owner, stream_oriented::lower_layer* down,
const settings& cfg) { const settings& cfg) {
down_ = down; down_ = down;
if (auto err = up_->init(owner, this, cfg))
return err;
if (auto max_size = get_as<uint32_t>(cfg, "http.max-request-size")) if (auto max_size = get_as<uint32_t>(cfg, "http.max-request-size"))
max_request_size_ = *max_size; max_request_size_ = *max_size;
down_->configure_read(receive_policy::up_to(max_request_size_)); if (auto err = up_->init(owner, this, cfg))
return err;
return none; return none;
} }
...@@ -89,10 +97,6 @@ bool server::done_sending() { ...@@ -89,10 +97,6 @@ bool server::done_sending() {
return up_->done_sending(); return up_->done_sending();
} }
void server::continue_reading() {
down_->configure_read(receive_policy::up_to(max_request_size_));
}
ptrdiff_t server::consume(byte_span input, byte_span) { ptrdiff_t server::consume(byte_span input, byte_span) {
using namespace literals; using namespace literals;
CAF_LOG_TRACE(CAF_ARG2("bytes", input.size())); CAF_LOG_TRACE(CAF_ARG2("bytes", input.size()));
......
...@@ -36,7 +36,7 @@ void length_prefix_framing::abort(const error& reason) { ...@@ -36,7 +36,7 @@ void length_prefix_framing::abort(const error& reason) {
} }
ptrdiff_t length_prefix_framing::consume(byte_span input, byte_span) { ptrdiff_t length_prefix_framing::consume(byte_span input, byte_span) {
CAF_LOG_TRACE("got" << input.size() << "bytes"); CAF_LOG_TRACE("got" << input.size() << "bytes\n");
if (input.size() < sizeof(uint32_t)) { if (input.size() < sizeof(uint32_t)) {
CAF_LOG_ERROR("received too few bytes from underlying transport"); CAF_LOG_ERROR("received too few bytes from underlying transport");
up_->abort(make_error(sec::logic_error, up_->abort(make_error(sec::logic_error,
...@@ -65,7 +65,7 @@ ptrdiff_t length_prefix_framing::consume(byte_span input, byte_span) { ...@@ -65,7 +65,7 @@ ptrdiff_t length_prefix_framing::consume(byte_span input, byte_span) {
if (msg_size == msg.size() && msg_size + hdr_size == input.size()) { if (msg_size == msg.size() && msg_size + hdr_size == input.size()) {
CAF_LOG_DEBUG("got message of size" << msg_size); CAF_LOG_DEBUG("got message of size" << msg_size);
if (up_->consume(msg) >= 0) { if (up_->consume(msg) >= 0) {
if (!down_->stopped_reading()) if (down_->is_reading())
down_->configure_read(receive_policy::exactly(hdr_size)); down_->configure_read(receive_policy::exactly(hdr_size));
return static_cast<ptrdiff_t>(input.size()); return static_cast<ptrdiff_t>(input.size());
} else { } else {
...@@ -79,10 +79,6 @@ ptrdiff_t length_prefix_framing::consume(byte_span input, byte_span) { ...@@ -79,10 +79,6 @@ ptrdiff_t length_prefix_framing::consume(byte_span input, byte_span) {
} }
} }
void length_prefix_framing::continue_reading() {
up_->continue_reading();
}
bool length_prefix_framing::prepare_send() { bool length_prefix_framing::prepare_send() {
return up_->prepare_send(); return up_->prepare_send();
} }
...@@ -98,15 +94,15 @@ bool length_prefix_framing::can_send_more() const noexcept { ...@@ -98,15 +94,15 @@ bool length_prefix_framing::can_send_more() const noexcept {
} }
void length_prefix_framing::suspend_reading() { void length_prefix_framing::suspend_reading() {
down_->suspend_reading(); down_->configure_read(receive_policy::stop());
} }
bool length_prefix_framing::stopped_reading() const noexcept { bool length_prefix_framing::is_reading() const noexcept {
return down_->stopped_reading(); return down_->is_reading();
} }
void length_prefix_framing::request_messages() { void length_prefix_framing::request_messages() {
if (down_->stopped_reading()) if (!down_->is_reading())
down_->configure_read(receive_policy::exactly(hdr_size)); down_->configure_read(receive_policy::exactly(hdr_size));
} }
...@@ -139,12 +135,8 @@ bool length_prefix_framing::end_message() { ...@@ -139,12 +135,8 @@ bool length_prefix_framing::end_message() {
} }
} }
void length_prefix_framing::send_close_message() { void length_prefix_framing::close() {
// nop: this layer has no close message down_->close();
}
void length_prefix_framing::send_close_message(const error&) {
// nop: this layer has no close message
} }
// -- utility functions ------------------------------------------------------ // -- utility functions ------------------------------------------------------
......
This diff is collapsed.
...@@ -31,11 +31,12 @@ std::unique_ptr<pollset_updater> pollset_updater::make(pipe_socket fd) { ...@@ -31,11 +31,12 @@ std::unique_ptr<pollset_updater> pollset_updater::make(pipe_socket fd) {
error pollset_updater::init(socket_manager* owner, const settings&) { error pollset_updater::init(socket_manager* owner, const settings&) {
CAF_LOG_TRACE(""); CAF_LOG_TRACE("");
owner_ = owner;
mpx_ = owner->mpx_ptr(); mpx_ = owner->mpx_ptr();
return nonblocking(fd_, true); return nonblocking(fd_, true);
} }
pollset_updater::read_result pollset_updater::handle_read_event() { void pollset_updater::handle_read_event() {
CAF_LOG_TRACE(""); CAF_LOG_TRACE("");
auto as_mgr = [](intptr_t ptr) { auto as_mgr = [](intptr_t ptr) {
return intrusive_ptr{reinterpret_cast<socket_manager*>(ptr), false}; return intrusive_ptr{reinterpret_cast<socket_manager*>(ptr), false};
...@@ -56,18 +57,6 @@ pollset_updater::read_result pollset_updater::handle_read_event() { ...@@ -56,18 +57,6 @@ pollset_updater::read_result pollset_updater::handle_read_event() {
intptr_t ptr; intptr_t ptr;
memcpy(&ptr, buf_.data() + 1, sizeof(intptr_t)); memcpy(&ptr, buf_.data() + 1, sizeof(intptr_t));
switch (static_cast<code>(opcode)) { switch (static_cast<code>(opcode)) {
case code::register_reading:
mpx_->do_register_reading(as_mgr(ptr));
break;
case code::continue_reading:
mpx_->do_continue_reading(as_mgr(ptr));
break;
case code::register_writing:
mpx_->do_register_writing(as_mgr(ptr));
break;
case code::continue_writing:
mpx_->do_continue_writing(as_mgr(ptr));
break;
case code::init_manager: case code::init_manager:
mpx_->do_init(as_mgr(ptr)); mpx_->do_init(as_mgr(ptr));
break; break;
...@@ -94,25 +83,20 @@ pollset_updater::read_result pollset_updater::handle_read_event() { ...@@ -94,25 +83,20 @@ pollset_updater::read_result pollset_updater::handle_read_event() {
} }
} else if (num_bytes == 0) { } else if (num_bytes == 0) {
CAF_LOG_DEBUG("pipe closed, assume shutdown"); CAF_LOG_DEBUG("pipe closed, assume shutdown");
return read_result::stop; owner_->shutdown();
return;
} else if (last_socket_error_is_temporary()) { } else if (last_socket_error_is_temporary()) {
return read_result::again; return;
} else { } else {
return read_result::stop; CAF_LOG_DEBUG("pollset updater failed to read from the pipe");
owner_->shutdown();
return;
} }
} }
} }
pollset_updater::read_result pollset_updater::handle_buffered_data() { void pollset_updater::handle_write_event() {
return read_result::again; owner_->deregister_writing();
}
pollset_updater::read_result pollset_updater::handle_continue_reading() {
return read_result::again;
}
pollset_updater::write_result pollset_updater::handle_write_event() {
return write_result::stop;
} }
void pollset_updater::abort(const error&) { void pollset_updater::abort(const error&) {
......
...@@ -40,22 +40,73 @@ actor_system& socket_manager::system() noexcept { ...@@ -40,22 +40,73 @@ actor_system& socket_manager::system() noexcept {
return mpx_->system(); return mpx_->system();
} }
bool socket_manager::is_reading() const noexcept {
return mpx_->is_reading(this);
}
bool socket_manager::is_writing() const noexcept {
return mpx_->is_writing(this);
}
// -- event loop management ---------------------------------------------------- // -- event loop management ----------------------------------------------------
void socket_manager::register_reading() { void socket_manager::register_reading() {
if (!flags_.read_closed)
mpx_->register_reading(this); mpx_->register_reading(this);
} }
void socket_manager::continue_reading() {
mpx_->continue_reading(this);
}
void socket_manager::register_writing() { void socket_manager::register_writing() {
if (!flags_.write_closed)
mpx_->register_writing(this); mpx_->register_writing(this);
} }
void socket_manager::continue_writing() { void socket_manager::deregister_reading() {
mpx_->continue_writing(this); mpx_->deregister_reading(this);
}
void socket_manager::deregister_writing() {
mpx_->deregister_writing(this);
}
void socket_manager::deregister() {
mpx_->deregister(this);
}
void socket_manager::shutdown_read() {
deregister_reading();
flags_.read_closed = true;
}
void socket_manager::shutdown_write() {
deregister_writing();
flags_.write_closed = true;
}
void socket_manager::shutdown() {
flags_.read_closed = true;
flags_.write_closed = true;
deregister();
}
// -- callbacks for the handler ------------------------------------------------
void socket_manager::schedule_handover() {
deregister();
mpx_->schedule_fn([ptr = strong_this()] { //
event_handler_ptr next;
if (ptr->handler_->do_handover(next)) {
ptr->handler_.swap(next);
}
});
}
void socket_manager::schedule(action what) {
// Wrap the action to make sure the socket manager is still alive when running
// the action later.
mpx_->schedule_fn([ptr = strong_this(), f = std::move(what)]() mutable {
CAF_IGNORE_UNUSED(ptr);
f.run();
});
} }
// -- callbacks for the multiplexer -------------------------------------------- // -- callbacks for the multiplexer --------------------------------------------
...@@ -70,16 +121,6 @@ void socket_manager::close_write() noexcept { ...@@ -70,16 +121,6 @@ void socket_manager::close_write() noexcept {
flags_.write_closed = true; flags_.write_closed = true;
} }
bool socket_manager::do_handover() {
event_handler_ptr next;
if (handler_->do_handover(next)) {
handler_.swap(next);
return true;
} else {
return false;
}
}
error socket_manager::init(const settings& cfg) { error socket_manager::init(const settings& cfg) {
CAF_LOG_TRACE(CAF_ARG(cfg)); CAF_LOG_TRACE(CAF_ARG(cfg));
if (auto err = nonblocking(fd_, true)) { if (auto err = nonblocking(fd_, true)) {
...@@ -89,32 +130,12 @@ error socket_manager::init(const settings& cfg) { ...@@ -89,32 +130,12 @@ error socket_manager::init(const settings& cfg) {
return handler_->init(this, cfg); return handler_->init(this, cfg);
} }
socket_manager::read_result socket_manager::handle_read_event() { void socket_manager::handle_read_event() {
auto result = handler_->handle_read_event(); handler_->handle_read_event();
switch (result) {
default:
break;
case read_result::close:
flags_.read_closed = true;
break;
case read_result::abort:
flags_.read_closed = true;
flags_.write_closed = true;
break;
}
return result;
}
socket_manager::read_result socket_manager::handle_buffered_data() {
return handler_->handle_buffered_data();
} }
socket_manager::read_result socket_manager::handle_continue_reading() { void socket_manager::handle_write_event() {
return handler_->handle_continue_reading(); handler_->handle_write_event();
}
socket_manager::write_result socket_manager::handle_write_event() {
return handler_->handle_write_event();
} }
void socket_manager::handle_error(sec code) { void socket_manager::handle_error(sec code) {
...@@ -124,4 +145,10 @@ void socket_manager::handle_error(sec code) { ...@@ -124,4 +145,10 @@ void socket_manager::handle_error(sec code) {
} }
} }
// -- utility functions --------------------------------------------------------
socket_manager_ptr socket_manager::strong_this() {
return socket_manager_ptr{this};
}
} // namespace caf::net } // namespace caf::net
...@@ -26,10 +26,6 @@ public: ...@@ -26,10 +26,6 @@ public:
using super = socket_event_layer; using super = socket_event_layer;
using read_result = typename super::read_result;
using write_result = typename super::write_result;
using upper_layer_ptr = transport::upper_layer_ptr; using upper_layer_ptr = transport::upper_layer_ptr;
handshake_worker(connection conn, bool is_server, upper_layer_ptr up) handshake_worker(connection conn, bool is_server, upper_layer_ptr up)
...@@ -46,55 +42,56 @@ public: ...@@ -46,55 +42,56 @@ public:
return caf::none; return caf::none;
} }
read_result handle_read_event() override { void handle_read_event() override {
if (auto res = advance_handshake(); res > 0) { if (auto res = advance_handshake(); res > 0) {
return read_result::handover; owner_->deregister();
owner_->schedule_handover();
} else if (res == 0) { } else if (res == 0) {
up_->abort(make_error(sec::connection_closed)); up_->abort(make_error(sec::connection_closed));
return read_result::stop; owner_->deregister();
} else { } else {
auto err = policy_.last_error(policy_.conn.fd(), res); auto err = policy_.last_error(policy_.conn.fd(), res);
switch (err) { switch (err) {
case stream_transport_error::want_read: case stream_transport_error::want_read:
case stream_transport_error::temporary: case stream_transport_error::temporary:
return read_result::again; break;
case stream_transport_error::want_write: case stream_transport_error::want_write:
return read_result::want_write; owner_->deregister_reading();
default: owner_->register_writing();
break;
default: {
auto err = make_error(sec::cannot_connect_to_node, auto err = make_error(sec::cannot_connect_to_node,
policy_.conn.last_error_string(res)); policy_.conn.last_error_string(res));
up_->abort(std::move(err)); up_->abort(std::move(err));
return read_result::stop; owner_->deregister();
}
} }
} }
read_result handle_buffered_data() override {
return read_result::again;
} }
read_result handle_continue_reading() override {
return read_result::again;
} }
write_result handle_write_event() override { void handle_write_event() override {
if (auto res = advance_handshake(); res > 0) { if (auto res = advance_handshake(); res > 0) {
return write_result::handover; owner_->deregister();
owner_->schedule_handover();
return;
} else if (res == 0) { } else if (res == 0) {
up_->abort(make_error(sec::connection_closed)); up_->abort(make_error(sec::connection_closed));
return write_result::stop; owner_->deregister();
} else { } else {
switch (policy_.last_error(policy_.conn.fd(), res)) { switch (policy_.last_error(policy_.conn.fd(), res)) {
case stream_transport_error::want_write: case stream_transport_error::want_write:
case stream_transport_error::temporary: case stream_transport_error::temporary:
return write_result::again; break;
case stream_transport_error::want_read: case stream_transport_error::want_read:
return write_result::want_read; owner_->deregister_writing();
default: owner_->register_reading();
break;
default: {
auto err = make_error(sec::cannot_connect_to_node, auto err = make_error(sec::cannot_connect_to_node,
policy_.conn.last_error_string(res)); policy_.conn.last_error_string(res));
up_->abort(std::move(err)); up_->abort(std::move(err));
return write_result::stop; owner_->deregister();
}
} }
} }
} }
......
This diff is collapsed.
...@@ -95,11 +95,6 @@ ptrdiff_t client::consume(byte_span buffer, byte_span delta) { ...@@ -95,11 +95,6 @@ ptrdiff_t client::consume(byte_span buffer, byte_span delta) {
} }
} }
void client::continue_reading() {
if (handshake_completed())
upper_layer().continue_reading();
}
bool client::prepare_send() { bool client::prepare_send() {
return handshake_completed() ? upper_layer().prepare_send() : true; return handshake_completed() ? upper_layer().prepare_send() : true;
} }
......
...@@ -23,15 +23,34 @@ bool framing::can_send_more() const noexcept { ...@@ -23,15 +23,34 @@ bool framing::can_send_more() const noexcept {
} }
void framing::suspend_reading() { void framing::suspend_reading() {
down_->suspend_reading(); down_->configure_read(receive_policy::stop());
} }
bool framing::stopped_reading() const noexcept { bool framing::is_reading() const noexcept {
return down_->stopped_reading(); return down_->is_reading();
}
void framing::close(status code, std::string_view msg) {
auto code_val = static_cast<uint16_t>(code);
uint32_t mask_key = 0;
byte_buffer payload;
payload.reserve(msg.size() + 2);
payload.push_back(static_cast<std::byte>((code_val & 0xFF00) >> 8));
payload.push_back(static_cast<std::byte>(code_val & 0x00FF));
for (auto c : msg)
payload.push_back(static_cast<std::byte>(c));
if (mask_outgoing_frames) {
mask_key = static_cast<uint32_t>(rng_());
detail::rfc6455::mask_data(mask_key, payload);
}
down_->begin_output();
detail::rfc6455::assemble_frame(detail::rfc6455::connection_close, mask_key,
payload, down_->output_buffer());
down_->end_output();
} }
void framing::request_messages() { void framing::request_messages() {
if (down_->stopped_reading()) if (!down_->is_reading())
down_->configure_read(receive_policy::up_to(2048)); down_->configure_read(receive_policy::up_to(2048));
} }
...@@ -61,14 +80,6 @@ bool framing::end_text_message() { ...@@ -61,14 +80,6 @@ bool framing::end_text_message() {
return true; return true;
} }
void framing::send_close_message() {
ship_close();
}
void framing::send_close_message(status code, std::string_view desc) {
ship_close(static_cast<uint16_t>(code), desc);
}
// -- interface for the lower layer -------------------------------------------- // -- interface for the lower layer --------------------------------------------
ptrdiff_t framing::consume(byte_span input, byte_span) { ptrdiff_t framing::consume(byte_span input, byte_span) {
...@@ -99,9 +110,6 @@ ptrdiff_t framing::consume(byte_span input, byte_span) { ...@@ -99,9 +110,6 @@ ptrdiff_t framing::consume(byte_span input, byte_span) {
// Wait for more data if necessary. // Wait for more data if necessary.
size_t frame_size = hdr_bytes + hdr.payload_len; size_t frame_size = hdr_bytes + hdr.payload_len;
if (buffer.size() < frame_size) { if (buffer.size() < frame_size) {
// Ask for more data unless the upper layer called suspend_reading.
if (!down_->stopped_reading())
down_->configure_read(receive_policy::up_to(2048));
down_->configure_read(receive_policy::exactly(frame_size)); down_->configure_read(receive_policy::exactly(frame_size));
return consumed; return consumed;
} }
...@@ -170,7 +178,7 @@ ptrdiff_t framing::consume(byte_span input, byte_span) { ...@@ -170,7 +178,7 @@ ptrdiff_t framing::consume(byte_span input, byte_span) {
buffer = buffer.subspan(frame_size); buffer = buffer.subspan(frame_size);
if (buffer.empty()) { if (buffer.empty()) {
// Ask for more data unless the upper layer called suspend_reading. // Ask for more data unless the upper layer called suspend_reading.
if (!down_->stopped_reading()) if (down_->is_reading())
down_->configure_read(receive_policy::up_to(2048)); down_->configure_read(receive_policy::up_to(2048));
return consumed + static_cast<ptrdiff_t>(frame_size); return consumed + static_cast<ptrdiff_t>(frame_size);
} }
...@@ -215,40 +223,6 @@ void framing::ship_pong(byte_span payload) { ...@@ -215,40 +223,6 @@ void framing::ship_pong(byte_span payload) {
down_->end_output(); down_->end_output();
} }
void framing::ship_close(uint16_t code, std::string_view msg) {
uint32_t mask_key = 0;
byte_buffer payload;
payload.reserve(msg.size() + 2);
payload.push_back(static_cast<std::byte>((code & 0xFF00) >> 8));
payload.push_back(static_cast<std::byte>(code & 0x00FF));
for (auto c : msg)
payload.push_back(static_cast<std::byte>(c));
if (mask_outgoing_frames) {
mask_key = static_cast<uint32_t>(rng_());
detail::rfc6455::mask_data(mask_key, payload);
}
down_->begin_output();
detail::rfc6455::assemble_frame(detail::rfc6455::connection_close, mask_key,
payload, down_->output_buffer());
down_->end_output();
}
void framing::ship_close() {
uint32_t mask_key = 0;
std::byte payload[] = {// Error code 1000: normal close.
std::byte{0x03}, std::byte{0xE8},
// "EOF" string as goodbye message.
std::byte{'E'}, std::byte{'O'}, std::byte{'F'}};
if (mask_outgoing_frames) {
mask_key = static_cast<uint32_t>(rng_());
detail::rfc6455::mask_data(mask_key, payload);
}
down_->begin_output();
detail::rfc6455::assemble_frame(detail::rfc6455::connection_close, mask_key,
payload, down_->output_buffer());
down_->end_output();
}
template <class T> template <class T>
void framing::ship_frame(std::vector<T>& buf) { void framing::ship_frame(std::vector<T>& buf) {
uint32_t mask_key = 0; uint32_t mask_key = 0;
......
...@@ -13,8 +13,13 @@ lower_layer::~lower_layer() { ...@@ -13,8 +13,13 @@ lower_layer::~lower_layer() {
// nop // nop
} }
void lower_layer::send_close_message(const error& reason) { void lower_layer::close() {
send_close_message(status::unexpected_condition, to_string(reason)); using namespace std::literals;
close(status::normal_close, "EOF"sv);
}
void lower_layer::close(const error& reason) {
close(status::unexpected_condition, to_string(reason));
} }
} // namespace caf::net::web_socket } // namespace caf::net::web_socket
...@@ -74,11 +74,6 @@ ptrdiff_t server::consume(byte_span input, byte_span delta) { ...@@ -74,11 +74,6 @@ ptrdiff_t server::consume(byte_span input, byte_span delta) {
} }
} }
void server::continue_reading() {
auto rp = receive_policy::up_to(handshake::max_http_size);
lower_layer().configure_read(rp);
}
bool server::prepare_send() { bool server::prepare_send() {
return handshake_complete_ ? upper_layer().prepare_send() : true; return handshake_complete_ ? upper_layer().prepare_send() : true;
} }
......
...@@ -19,8 +19,12 @@ bool mock_stream_transport::can_send_more() const noexcept { ...@@ -19,8 +19,12 @@ bool mock_stream_transport::can_send_more() const noexcept {
return true; return true;
} }
void mock_stream_transport::suspend_reading() { bool mock_stream_transport::is_reading() const noexcept {
configure_read(net::receive_policy::stop()); return max_read_size > 0;
}
void mock_stream_transport::close() {
// nop
} }
void mock_stream_transport::configure_read(net::receive_policy policy) { void mock_stream_transport::configure_read(net::receive_policy policy) {
...@@ -40,10 +44,6 @@ bool mock_stream_transport::end_output() { ...@@ -40,10 +44,6 @@ bool mock_stream_transport::end_output() {
return true; return true;
} }
bool mock_stream_transport::stopped_reading() const noexcept {
return max_read_size == 0;
}
ptrdiff_t mock_stream_transport::handle_input() { ptrdiff_t mock_stream_transport::handle_input() {
ptrdiff_t result = 0; ptrdiff_t result = 0;
while (max_read_size > 0) { while (max_read_size > 0) {
......
...@@ -32,7 +32,9 @@ public: ...@@ -32,7 +32,9 @@ public:
bool can_send_more() const noexcept override; bool can_send_more() const noexcept override;
void suspend_reading() override; bool is_reading() const noexcept override;
void close() override;
void configure_read(caf::net::receive_policy policy) override; void configure_read(caf::net::receive_policy policy) override;
...@@ -42,8 +44,6 @@ public: ...@@ -42,8 +44,6 @@ public:
bool end_output() override; bool end_output() override;
bool stopped_reading() const noexcept override;
// -- initialization --------------------------------------------------------- // -- initialization ---------------------------------------------------------
caf::error init(const caf::settings& cfg) { caf::error init(const caf::settings& cfg) {
......
...@@ -65,10 +65,6 @@ public: ...@@ -65,10 +65,6 @@ public:
return !self->terminated(); return !self->terminated();
} }
void continue_reading() override {
CAF_FAIL("continue_reading called");
}
bool done_sending() override { bool done_sending() override {
return self->try_block_mailbox(); return self->try_block_mailbox();
} }
......
...@@ -81,8 +81,9 @@ public: ...@@ -81,8 +81,9 @@ public:
net::stream_oriented::lower_layer* down_ptr, net::stream_oriented::lower_layer* down_ptr,
const settings&) override { const settings&) override {
down = down_ptr; down = down_ptr;
if (auto ptr = adapter_type::try_open(mgr, std::move(input))) { if (auto buf = input.try_open()) {
adapter = std::move(ptr); auto do_wakeup = make_action([this] { prepare_send(); });
adapter = adapter_type::make(std::move(buf), mgr, std::move(do_wakeup));
return none; return none;
} else { } else {
FAIL("unable to open the resource"); FAIL("unable to open the resource");
...@@ -137,10 +138,6 @@ public: ...@@ -137,10 +138,6 @@ public:
return done || !adapter->has_data(); return done || !adapter->has_data();
} }
void continue_reading() override {
CAF_FAIL("continue_reading called");
}
void abort(const error& reason) override { void abort(const error& reason) override {
MESSAGE("app::abort: " << reason); MESSAGE("app::abort: " << reason);
} }
......
...@@ -51,6 +51,7 @@ public: ...@@ -51,6 +51,7 @@ public:
error init(net::socket_manager*, net::http::lower_layer* down_ptr, error init(net::socket_manager*, net::http::lower_layer* down_ptr,
const settings&) override { const settings&) override {
down = down_ptr; down = down_ptr;
down->request_messages();
return none; return none;
} }
...@@ -76,10 +77,6 @@ public: ...@@ -76,10 +77,6 @@ public:
payload.assign(body.begin(), body.end()); payload.assign(body.begin(), body.end());
return static_cast<ptrdiff_t>(body.size()); return static_cast<ptrdiff_t>(body.size());
} }
void continue_reading() override {
// nop
}
}; };
} // namespace } // namespace
......
...@@ -45,10 +45,11 @@ public: ...@@ -45,10 +45,11 @@ public:
// nop // nop
} }
caf::error init(net::socket_manager*, caf::error init(net::socket_manager* mgr_ptr,
net::message_oriented::lower_layer* down_ptr, net::message_oriented::lower_layer* down_ptr,
const settings&) override { const settings&) override {
// Start reading immediately. // Start reading immediately.
mgr = mgr_ptr;
down = down_ptr; down = down_ptr;
down->request_messages(); down->request_messages();
return none; return none;
...@@ -66,23 +67,23 @@ public: ...@@ -66,23 +67,23 @@ public:
// nop // nop
} }
void continue_reading() override { void continue_reading() {
down->request_messages(); mgr->schedule_fn([this] { down->request_messages(); });
} }
ptrdiff_t consume(byte_span buf) override { ptrdiff_t consume(byte_span buf) override {
printf("app_t::consume %d\n", __LINE__);
auto printable = [](std::byte x) { auto printable = [](std::byte x) {
return ::isprint(static_cast<uint8_t>(x)); return ::isprint(static_cast<uint8_t>(x));
}; };
if (CHECK(std::all_of(buf.begin(), buf.end(), printable))) { if (CHECK(std::all_of(buf.begin(), buf.end(), printable))) {
printf("app_t::consume %d\n", __LINE__);
auto str_buf = reinterpret_cast<char*>(buf.data()); auto str_buf = reinterpret_cast<char*>(buf.data());
inputs->emplace_back(std::string{str_buf, buf.size()}); inputs->emplace_back(std::string{str_buf, buf.size()});
printf("app_t::consume %d added %s\n", __LINE__, inputs->back().c_str()); MESSAGE("app: consumed " << inputs->back());
if constexpr (EnableSuspend) if constexpr (EnableSuspend)
if (inputs->back() == "pause") if (inputs->back() == "pause") {
MESSAGE("app: suspend reading");
down->suspend_reading(); down->suspend_reading();
}
std::string response = "ok "; std::string response = "ok ";
response += std::to_string(inputs->size()); response += std::to_string(inputs->size());
auto response_bytes = as_bytes(make_span(response)); auto response_bytes = as_bytes(make_span(response));
...@@ -92,11 +93,12 @@ public: ...@@ -92,11 +93,12 @@ public:
CHECK(down->end_message()); CHECK(down->end_message());
return static_cast<ptrdiff_t>(buf.size()); return static_cast<ptrdiff_t>(buf.size());
} else { } else {
printf("app_t::consume %d\n", __LINE__);
return -1; return -1;
} }
} }
net::socket_manager* mgr = nullptr;
net::message_oriented::lower_layer* down = nullptr; net::message_oriented::lower_layer* down = nullptr;
shared_string_list inputs; shared_string_list inputs;
...@@ -157,7 +159,7 @@ SCENARIO("length-prefix framing reads data with 32-bit size headers") { ...@@ -157,7 +159,7 @@ SCENARIO("length-prefix framing reads data with 32-bit size headers") {
} }
} }
SCENARIO("calling suspend_reading removes message apps temporarily") { SCENARIO("calling suspend_reading temporarily halts receiving of messages") {
using namespace std::literals; using namespace std::literals;
GIVEN("a length_prefix_framing with an app that consumes strings") { GIVEN("a length_prefix_framing with an app that consumes strings") {
auto [fd1, fd2] = unbox(net::make_stream_socket_pair()); auto [fd1, fd2] = unbox(net::make_stream_socket_pair());
...@@ -185,6 +187,7 @@ SCENARIO("calling suspend_reading removes message apps temporarily") { ...@@ -185,6 +187,7 @@ SCENARIO("calling suspend_reading removes message apps temporarily") {
CAF_FAIL("nonblocking returned an error: " << err); CAF_FAIL("nonblocking returned an error: " << err);
auto buf = std::make_shared<string_list>(); auto buf = std::make_shared<string_list>();
auto app = app_t<true>::make(buf); auto app = app_t<true>::make(buf);
auto app_ptr = app.get();
auto framing = net::length_prefix_framing::make(std::move(app)); auto framing = net::length_prefix_framing::make(std::move(app));
auto transport = net::stream_transport::make(fd2, std::move(framing)); auto transport = net::stream_transport::make(fd2, std::move(framing));
auto mgr = net::socket_manager::make(&mpx, fd2, std::move(transport)); auto mgr = net::socket_manager::make(&mpx, fd2, std::move(transport));
...@@ -201,8 +204,8 @@ SCENARIO("calling suspend_reading removes message apps temporarily") { ...@@ -201,8 +204,8 @@ SCENARIO("calling suspend_reading removes message apps temporarily") {
CHECK_EQ(buf->at(1), "second"); CHECK_EQ(buf->at(1), "second");
CHECK_EQ(buf->at(2), "pause"); CHECK_EQ(buf->at(2), "pause");
} }
THEN("users can resume it via continue_reading ") { THEN("users can resume it manually") {
mgr->continue_reading(); app_ptr->continue_reading();
mpx.apply_updates(); mpx.apply_updates();
mpx.poll_once(true); mpx.poll_once(true);
CHECK_EQ(mpx.mask_of(mgr), net::operation::read); CHECK_EQ(mpx.mask_of(mgr), net::operation::read);
......
...@@ -63,53 +63,33 @@ public: ...@@ -63,53 +63,33 @@ public:
// -- implementation of socket_event_layer ----------------------------------- // -- implementation of socket_event_layer -----------------------------------
error init(net::socket_manager*, const settings&) override { error init(net::socket_manager* mgr, const settings&) override {
mgr_ = mgr;
return none; return none;
} }
read_result handle_read_event() override { void handle_read_event() override {
// if (trigger_handover) {
// MESSAGE(name << " triggered a handover");
// return read_result::handover;
// }
if (read_capacity() < 1024) if (read_capacity() < 1024)
rd_buf_.resize(rd_buf_.size() + 2048); rd_buf_.resize(rd_buf_.size() + 2048);
auto num_bytes = read(fd_, auto res = read(fd_, make_span(read_position_begin(), read_capacity()));
make_span(read_position_begin(), read_capacity())); if (res > 0) {
if (num_bytes > 0) { CAF_ASSERT(res > 0);
CAF_ASSERT(num_bytes > 0); rd_buf_pos_ += res;
rd_buf_pos_ += num_bytes; } else if (res == 0 || !net::last_socket_error_is_temporary()) {
return read_result::again; mgr_->deregister();
} else if (num_bytes < 0 && net::last_socket_error_is_temporary()) {
return read_result::again;
} else {
return read_result::stop;
} }
} }
read_result handle_buffered_data() override { void handle_write_event() override {
return read_result::again; if (wr_buf_.size() == 0) {
} mgr_->deregister_writing();
} else if (auto res = write(fd_, wr_buf_); res > 0) {
read_result handle_continue_reading() override { wr_buf_.erase(wr_buf_.begin(), wr_buf_.begin() + res);
return read_result::again;
}
write_result handle_write_event() override {
// if (trigger_handover) {
// MESSAGE(name << " triggered a handover");
// return write_result::handover;
// }
if (wr_buf_.size() == 0) if (wr_buf_.size() == 0)
return write_result::stop; mgr_->deregister_writing();
auto num_bytes = write(fd_, wr_buf_); } else if (res == 0 || !net::last_socket_error_is_temporary()) {
if (num_bytes > 0) { mgr_->deregister();
wr_buf_.erase(wr_buf_.begin(), wr_buf_.begin() + num_bytes);
return wr_buf_.size() > 0 ? write_result::again : write_result::stop;
} }
return num_bytes < 0 && net::last_socket_error_is_temporary()
? write_result::again
: write_result::stop;
} }
void abort(const error& reason) override { void abort(const error& reason) override {
...@@ -130,7 +110,6 @@ private: ...@@ -130,7 +110,6 @@ private:
size_t read_capacity() const { size_t read_capacity() const {
return rd_buf_.size() - rd_buf_pos_; return rd_buf_.size() - rd_buf_pos_;
} }
net::stream_socket fd_; net::stream_socket fd_;
shared_count count_; shared_count count_;
...@@ -140,6 +119,8 @@ private: ...@@ -140,6 +119,8 @@ private:
byte_buffer wr_buf_; byte_buffer wr_buf_;
byte_buffer rd_buf_; byte_buffer rd_buf_;
net::socket_manager* mgr_ = nullptr;
}; };
struct fixture { struct fixture {
...@@ -168,7 +149,9 @@ struct fixture { ...@@ -168,7 +149,9 @@ struct fixture {
make_manager(net::stream_socket fd, std::string name) { make_manager(net::stream_socket fd, std::string name) {
auto mock = mock_event_layer::make(fd, std::move(name), manager_count); auto mock = mock_event_layer::make(fd, std::move(name), manager_count);
auto mock_ptr = mock.get(); auto mock_ptr = mock.get();
return {mock_ptr, net::socket_manager::make(&mpx, fd, std::move(mock))}; auto mgr = net::socket_manager::make(&mpx, fd, std::move(mock));
std::ignore = mgr->init(settings{});
return {mock_ptr, std::move(mgr)};
} }
void init() { void init() {
......
...@@ -75,18 +75,19 @@ public: ...@@ -75,18 +75,19 @@ public:
const settings&) override { const settings&) override {
down = down_ptr; down = down_ptr;
down->request_messages(); down->request_messages();
if (auto ptr = adapter_type::try_open(mgr, std::move(output_))) { if (auto buf = output_.try_open()) {
adapter_ = std::move(ptr); // Note: the execution unit is the owner of this object. As as long as the
// execution unit lives, accessing `this` is safe.
auto do_resume = make_action([this] { down->request_messages(); });
auto do_cancel = make_action([this] { down->close(); });
adapter_ = adapter_type::make(std::move(buf), mgr, std::move(do_resume),
std::move(do_cancel));
return none; return none;
} else { } else {
FAIL("unable to open the resource"); FAIL("unable to open the resource");
} }
} }
void continue_reading() override {
down->request_messages();
}
bool prepare_send() override { bool prepare_send() override {
return true; return true;
} }
......
...@@ -80,10 +80,6 @@ public: ...@@ -80,10 +80,6 @@ public:
return true; return true;
} }
void continue_reading() override {
// nop
}
ptrdiff_t consume(byte_span data, byte_span) override { ptrdiff_t consume(byte_span data, byte_span) override {
MESSAGE("dummy app received " << data.size() << " bytes"); MESSAGE("dummy app received " << data.size() << " bytes");
// Store the received bytes. // Store the received bytes.
...@@ -193,6 +189,7 @@ SCENARIO("ssl::transport::make_client performs the client handshake") { ...@@ -193,6 +189,7 @@ SCENARIO("ssl::transport::make_client performs the client handshake") {
THEN("CAF transparently calls SSL_connect") { THEN("CAF transparently calls SSL_connect") {
net::multiplexer mpx{nullptr}; net::multiplexer mpx{nullptr};
mpx.set_thread_id(); mpx.set_thread_id();
std::ignore = mpx.init();
auto ctx = unbox(ssl::context::make_client(ssl::tls::any)); auto ctx = unbox(ssl::context::make_client(ssl::tls::any));
auto conn = unbox(ctx.new_connection(client_fd)); auto conn = unbox(ctx.new_connection(client_fd));
auto done = std::make_shared<bool>(false); auto done = std::make_shared<bool>(false);
...@@ -230,6 +227,7 @@ SCENARIO("ssl::transport::make_server performs the server handshake") { ...@@ -230,6 +227,7 @@ SCENARIO("ssl::transport::make_server performs the server handshake") {
THEN("CAF transparently calls SSL_accept") { THEN("CAF transparently calls SSL_accept") {
net::multiplexer mpx{nullptr}; net::multiplexer mpx{nullptr};
mpx.set_thread_id(); mpx.set_thread_id();
std::ignore = mpx.init();
auto ctx = unbox(ssl::context::make_server(ssl::tls::any)); auto ctx = unbox(ssl::context::make_server(ssl::tls::any));
REQUIRE(ctx.use_certificate_from_file(cert_1_pem_path, // REQUIRE(ctx.use_certificate_from_file(cert_1_pem_path, //
ssl::format::pem)); ssl::format::pem));
......
...@@ -93,10 +93,6 @@ public: ...@@ -93,10 +93,6 @@ public:
return static_cast<ptrdiff_t>(recv_buf_->size()); return static_cast<ptrdiff_t>(recv_buf_->size());
} }
void continue_reading() override {
FAIL("continue_reading called");
}
bool prepare_send() override { bool prepare_send() override {
MESSAGE("prepare_send called"); MESSAGE("prepare_send called");
auto& buf = down->output_buffer(); auto& buf = down->output_buffer();
......
...@@ -65,10 +65,6 @@ public: ...@@ -65,10 +65,6 @@ public:
return !self->terminated(); return !self->terminated();
} }
void continue_reading() override {
CAF_FAIL("continue_reading called");
}
bool done_sending() override { bool done_sending() override {
return self->try_block_mailbox(); return self->try_block_mailbox();
} }
......
...@@ -40,10 +40,6 @@ public: ...@@ -40,10 +40,6 @@ public:
return true; return true;
} }
void continue_reading() override {
// nop
}
void abort(const error& reason) override { void abort(const error& reason) override {
CAF_FAIL("app::abort called: " << reason); CAF_FAIL("app::abort called: " << reason);
} }
......
...@@ -47,10 +47,6 @@ public: ...@@ -47,10 +47,6 @@ public:
return true; return true;
} }
void continue_reading() override {
// nop
}
void abort(const error& reason) override { void abort(const error& reason) override {
CAF_FAIL("app::abort called: " << reason); CAF_FAIL("app::abort called: " << reason);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment