Commit c2e3d0e4 authored by Dominik Charousset's avatar Dominik Charousset

Fix shutdown behavior of socket managers

parent 599aafbb
...@@ -40,17 +40,17 @@ int caf_main(caf::actor_system& sys, const config& cfg) { ...@@ -40,17 +40,17 @@ int caf_main(caf::actor_system& sys, const config& cfg) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// Create buffers to signal events from the WebSocket server to the worker. // Create buffers to signal events from the WebSocket server to the worker.
auto [worker_res, server_res] = net::http::make_request_resource(); auto [worker_pull, server_push] = net::http::make_request_resource();
// Spin up the HTTP server. // Spin up the HTTP server.
net::http::serve(sys, fd, std::move(server_res)); net::http::serve(sys, fd, std::move(server_push));
// Spin up a worker to handle the HTTP requests. // Spin up a worker to handle the HTTP requests.
auto worker = sys.spawn([wres = worker_res](event_based_actor* self) { auto worker = sys.spawn([wres = worker_pull](event_based_actor* self) {
// For each incoming request ... // For each incoming request ...
wres wres
.observe_on(self) // .observe_on(self) //
.for_each([](const net::http::request& req) { .for_each([](const net::http::request& req) {
// ... we simply return the current time as string. // ... we simply return the current time as string.
// Note: we may not respond more than once to a single request. // Note: we cannot respond more than once to a request.
auto str = caf::deep_to_string(make_timestamp()); auto str = caf::deep_to_string(make_timestamp());
req.respond(net::http::status::ok, "text/plain", str); req.respond(net::http::status::ok, "text/plain", str);
}); });
......
...@@ -50,8 +50,7 @@ int caf_main(caf::actor_system& sys, const config& cfg) { ...@@ -50,8 +50,7 @@ int caf_main(caf::actor_system& sys, const config& cfg) {
.for_each([self](const event_t& event) { .for_each([self](const event_t& event) {
// ... that simply pushes data back to the sender. // ... that simply pushes data back to the sender.
auto [pull, push] = event.data(); auto [pull, push] = event.data();
self->make_observable() pull.observe_on(self)
.from_resource(pull)
.do_on_next([](const ws::frame& x) { .do_on_next([](const ws::frame& x) {
if (x.is_binary()) { if (x.is_binary()) {
std::cout << "*** received a binary WebSocket frame of size " std::cout << "*** received a binary WebSocket frame of size "
......
...@@ -60,8 +60,7 @@ int caf_main(caf::actor_system& sys, const config& cfg) { ...@@ -60,8 +60,7 @@ int caf_main(caf::actor_system& sys, const config& cfg) {
sys.spawn([conn, hello](caf::event_based_actor* self) { sys.spawn([conn, hello](caf::event_based_actor* self) {
auto [pull, push] = conn.data(); auto [pull, push] = conn.data();
// Print everything from the server to stdout. // Print everything from the server to stdout.
self->make_observable() pull.observe_on(self)
.from_resource(pull)
.do_on_error([](const caf::error& what) { .do_on_error([](const caf::error& what) {
std::cerr << "*** error while reading from the WebSocket: " std::cerr << "*** error while reading from the WebSocket: "
<< to_string(what) << '\n'; << to_string(what) << '\n';
......
...@@ -128,7 +128,8 @@ int caf_main(caf::actor_system& sys, const config& cfg) { ...@@ -128,7 +128,8 @@ int caf_main(caf::actor_system& sys, const config& cfg) {
auto quote = quotes.empty() ? "Try /epictetus, /seneca or /plato." auto quote = quotes.empty() ? "Try /epictetus, /seneca or /plato."
: f(quotes); : f(quotes);
self->make_observable().just(ws::frame{quote}).subscribe(push); self->make_observable().just(ws::frame{quote}).subscribe(push);
// Note: we simply drop `pull` here, which will close the buffer. // We ignore whatever the client may send to us.
pull.observe_on(self).subscribe(std::ignore);
}); });
}); });
// Callback for incoming WebSocket requests. // Callback for incoming WebSocket requests.
......
...@@ -470,6 +470,11 @@ disposable observable<T>::subscribe(async::producer_resource<T> resource) { ...@@ -470,6 +470,11 @@ disposable observable<T>::subscribe(async::producer_resource<T> resource) {
} }
} }
template <class T>
disposable observable<T>::subscribe(ignore_t) {
return subscribe(observer<T>::ignore());
}
template <class T> template <class T>
template <class OnNext> template <class OnNext>
disposable observable<T>::for_each(OnNext on_next) { disposable observable<T>::for_each(OnNext on_next) {
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "caf/intrusive_ptr.hpp" #include "caf/intrusive_ptr.hpp"
#include <cstddef> #include <cstddef>
#include <tuple>
#include <utility> #include <utility>
#include <vector> #include <vector>
...@@ -32,6 +33,9 @@ public: ...@@ -32,6 +33,9 @@ public:
/// The pointer-to-implementation type. /// The pointer-to-implementation type.
using pimpl_type = intrusive_ptr<op::base<T>>; using pimpl_type = intrusive_ptr<op::base<T>>;
/// Type for drop-all subscribers.
using ignore_t = decltype(std::ignore);
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
explicit observable(pimpl_type pimpl) noexcept : pimpl_(std::move(pimpl)) { explicit observable(pimpl_type pimpl) noexcept : pimpl_(std::move(pimpl)) {
...@@ -57,6 +61,9 @@ public: ...@@ -57,6 +61,9 @@ public:
/// Creates a new observer that pushes all observed items to the resource. /// Creates a new observer that pushes all observed items to the resource.
disposable subscribe(async::producer_resource<T> resource); disposable subscribe(async::producer_resource<T> resource);
/// Subscribes a new observer to the items emitted by this observable.
disposable subscribe(ignore_t);
/// Calls `on_next` for each item emitted by this observable. /// Calls `on_next` for each item emitted by this observable.
template <class OnNext> template <class OnNext>
disposable for_each(OnNext on_next); disposable for_each(OnNext on_next);
......
...@@ -24,12 +24,12 @@ public: ...@@ -24,12 +24,12 @@ public:
/// Shuts down any connection or session gracefully. Any pending data gets /// Shuts down any connection or session gracefully. Any pending data gets
/// flushed before closing the socket. /// flushed before closing the socket.
virtual void close() = 0; virtual void shutdown() = 0;
/// Shuts down any connection or session du to an error. Any pending data gets /// Shuts down any connection or session du to an error. Any pending data gets
/// flushed before closing the socket. Protocols with a dedicated closing /// flushed before closing the socket. Protocols with a dedicated closing
/// handshake such as WebSocket may send the close reason to the peer. /// handshake such as WebSocket may send the close reason to the peer.
virtual void close(const error& reason); virtual void shutdown(const error& reason);
}; };
} // namespace caf::net } // namespace caf::net
...@@ -15,16 +15,16 @@ class CAF_NET_EXPORT generic_upper_layer { ...@@ -15,16 +15,16 @@ class CAF_NET_EXPORT generic_upper_layer {
public: public:
virtual ~generic_upper_layer(); virtual ~generic_upper_layer();
/// Prepares any pending data for sending. /// Gives the upper layer an opportunity to add additional data to the output
/// @returns `false` in case of an error to cause the lower layer to stop, /// buffer.
/// `true` otherwise. virtual void prepare_send() = 0;
[[nodiscard]] virtual bool prepare_send() = 0;
/// Queries whether all pending data has been sent. The lower calls this /// Queries whether all pending data has been sent. The lower calls this
/// 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 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 or
/// when disposed.
virtual void abort(const error& reason) = 0; virtual void abort(const error& reason) = 0;
}; };
......
...@@ -57,7 +57,7 @@ public: ...@@ -57,7 +57,7 @@ public:
// nop // nop
} }
bool prepare_send() override; void prepare_send() override;
bool done_sending() override; bool done_sending() override;
...@@ -144,7 +144,6 @@ disposable serve(actor_system& sys, Socket fd, ...@@ -144,7 +144,6 @@ disposable serve(actor_system& sys, Socket fd,
} else { } else {
return disposable{}; return disposable{};
} }
// TODO: serve() should return a disposable to stop the HTTP server.
} }
} // namespace caf::net::http } // namespace caf::net::http
...@@ -81,7 +81,7 @@ public: ...@@ -81,7 +81,7 @@ public:
bool is_reading() const noexcept override; bool is_reading() const noexcept override;
void close() override; void shutdown() override;
void request_messages() override; void request_messages() override;
...@@ -106,7 +106,7 @@ public: ...@@ -106,7 +106,7 @@ public:
void abort(const error& reason) override; void abort(const error& reason) override;
bool prepare_send() override; void prepare_send() override;
bool done_sending() override; bool done_sending() override;
......
...@@ -81,7 +81,7 @@ public: ...@@ -81,7 +81,7 @@ public:
ptrdiff_t consume(byte_span buffer, byte_span delta) override; ptrdiff_t consume(byte_span buffer, byte_span delta) override;
bool prepare_send() override; void prepare_send() override;
bool done_sending() override; bool done_sending() override;
...@@ -101,7 +101,7 @@ public: ...@@ -101,7 +101,7 @@ public:
bool end_message() override; bool end_message() override;
void close() override; void shutdown() override;
// -- utility functions ------------------------------------------------------ // -- utility functions ------------------------------------------------------
......
...@@ -110,26 +110,23 @@ public: ...@@ -110,26 +110,23 @@ public:
} }
}; };
bool prepare_send() override { void 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_->close(helper.err); down_->shutdown(helper.err);
} else { } else {
down_->close(); down_->shutdown();
} }
in_ = nullptr; in_ = nullptr;
} else if (helper.aborted) { } else if (helper.aborted) {
in_->cancel(); in_->cancel();
in_ = nullptr; in_ = nullptr;
return false; down_->shutdown(trait_.last_error());
} else if (consumed == 0) {
return true;
} }
} }
return true;
} }
bool done_sending() override { bool done_sending() override {
......
...@@ -107,18 +107,6 @@ public: ...@@ -107,18 +107,6 @@ public:
// -- thread-safe signaling -------------------------------------------------- // -- thread-safe signaling --------------------------------------------------
/// Schedules a call to `mgr->handle_error(sec::disposed)`.
/// @thread-safe
void dispose(socket_manager_ptr mgr);
/// Stops further reading by `mgr`.
/// @thread-safe
void shutdown_reading(socket_manager_ptr mgr);
/// Stops further writing by `mgr`.
/// @thread-safe
void shutdown_writing(socket_manager_ptr mgr);
/// Registers `mgr` for initialization in the multiplexer's thread. /// Registers `mgr` for initialization in the multiplexer's thread.
/// @thread-safe /// @thread-safe
void init(socket_manager_ptr mgr); void init(socket_manager_ptr mgr);
...@@ -239,12 +227,6 @@ private: ...@@ -239,12 +227,6 @@ private:
void do_register_reading(const socket_manager_ptr& mgr); void do_register_reading(const socket_manager_ptr& mgr);
void do_dispose(const socket_manager_ptr& mgr);
void do_shutdown_reading(const socket_manager_ptr& mgr);
void do_shutdown_writing(const socket_manager_ptr& mgr);
void do_init(const socket_manager_ptr& mgr); void do_init(const socket_manager_ptr& mgr);
}; };
......
...@@ -26,7 +26,6 @@ public: ...@@ -26,7 +26,6 @@ public:
enum class code : uint8_t { enum class code : uint8_t {
init_manager, init_manager,
dispose_manager,
shutdown_reading, shutdown_reading,
shutdown_writing, shutdown_writing,
run_action, run_action,
......
...@@ -55,7 +55,7 @@ public: ...@@ -55,7 +55,7 @@ public:
// -- implementation of http::upper_layer ------------------------------------ // -- implementation of http::upper_layer ------------------------------------
bool prepare_send() override; void prepare_send() override;
bool done_sending() override; bool done_sending() override;
......
...@@ -37,6 +37,14 @@ struct CAF_NET_EXPORT socket : detail::comparable<socket> { ...@@ -37,6 +37,14 @@ struct CAF_NET_EXPORT socket : detail::comparable<socket> {
return static_cast<signed_socket_id>(id) return static_cast<signed_socket_id>(id)
- static_cast<signed_socket_id>(other.id); - static_cast<signed_socket_id>(other.id);
} }
constexpr explicit operator bool() const noexcept {
return id != invalid_socket_id;
}
constexpr bool operator!() const noexcept {
return id == invalid_socket_id;
}
}; };
/// @relates socket /// @relates socket
......
...@@ -28,8 +28,12 @@ public: ...@@ -28,8 +28,12 @@ public:
/// 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);
/// Called on hard errors on the managed socket. /// Called on socket errors or when the manager gets disposed.
virtual void abort(const error& reason) = 0; virtual void abort(const error& reason) = 0;
/// Queries whether the object can be safely discarded after calling
/// @ref abort on it, e.g., that pending data has been written.
virtual bool finalized() const noexcept;
}; };
} // namespace caf::net } // namespace caf::net
...@@ -33,12 +33,6 @@ public: ...@@ -33,12 +33,6 @@ public:
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.
struct flags_t {
bool read_closed : 1;
bool write_closed : 1;
};
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
/// @pre `handle != invalid_socket` /// @pre `handle != invalid_socket`
...@@ -111,16 +105,6 @@ public: ...@@ -111,16 +105,6 @@ public:
return mpx_; return mpx_;
} }
/// Returns whether the manager closed read operations on the socket.
[[nodiscard]] bool read_closed() const noexcept {
return flags_.read_closed;
}
/// Returns whether the manager closed write operations on the socket.
[[nodiscard]] bool write_closed() const noexcept {
return flags_.write_closed;
}
/// Queries whether the manager is registered for reading. /// Queries whether the manager is registered for reading.
bool is_reading() const noexcept; bool is_reading() const noexcept;
...@@ -144,18 +128,6 @@ public: ...@@ -144,18 +128,6 @@ public:
/// Deregisters the manager from both read and write operations. /// Deregisters the manager from both read and write operations.
void deregister(); void deregister();
/// Deregisters the manager from read operations and blocks any future
/// attempts to re-register it.
void shutdown_read();
/// Deregisters the manager from write operations and blocks any future
/// 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 ---------------------------------------------- // -- callbacks for the handler ----------------------------------------------
/// Schedules a call to `do_handover` on the handler. /// Schedules a call to `do_handover` on the handler.
...@@ -170,13 +142,10 @@ public: ...@@ -170,13 +142,10 @@ public:
schedule(make_action(std::forward<F>(what))); schedule(make_action(std::forward<F>(what)));
} }
// -- callbacks for the multiplexer ------------------------------------------ /// Shuts down this socket manager.
void shutdown();
/// Closes the read channel of the socket.
void close_read() noexcept;
/// Closes the write channel of the socket. // -- callbacks for the multiplexer ------------------------------------------
void close_write() noexcept;
/// Initializes the manager and its all of its sub-components. /// Initializes the manager and its all of its sub-components.
error init(const settings& cfg); error init(const settings& cfg);
...@@ -187,8 +156,10 @@ public: ...@@ -187,8 +156,10 @@ public:
/// Called whenever the socket is allowed to send data. /// Called whenever the socket is allowed to send data.
void 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 or after
/// @param code The error code as reported by the operating system. /// calling @ref dispose.
/// @param code The error code as reported by the operating system or
/// @ref sec::disposed.
void handle_error(sec code); void handle_error(sec code);
// -- implementation of disposable_impl -------------------------------------- // -- implementation of disposable_impl --------------------------------------
...@@ -204,6 +175,8 @@ public: ...@@ -204,6 +175,8 @@ public:
private: private:
// -- utility functions ------------------------------------------------------ // -- utility functions ------------------------------------------------------
void cleanup();
socket_manager_ptr strong_this(); socket_manager_ptr strong_this();
// -- member variables ------------------------------------------------------- // -- member variables -------------------------------------------------------
...@@ -219,12 +192,14 @@ private: ...@@ -219,12 +192,14 @@ private:
/// down (and the multiplexer is part of the actor system). /// down (and the multiplexer is part of the actor system).
multiplexer* mpx_; multiplexer* mpx_;
/// Stores flags for the socket file descriptor.
flags_t flags_;
/// Stores the event handler that operators on the socket file descriptor. /// Stores the event handler that operators on the socket file descriptor.
event_handler_ptr handler_; event_handler_ptr handler_;
/// Stores whether `shutdown` has been called.
bool shutting_down_ = false;
/// Stores whether the manager has been either explicitly disposed or shut
/// down by demand of the application.
std::atomic<bool> disposed_; std::atomic<bool> disposed_;
}; };
......
...@@ -86,7 +86,7 @@ public: ...@@ -86,7 +86,7 @@ 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. /// Stores whether the application has asked to shut down.
bool shutting_down : 1; bool shutting_down : 1;
}; };
...@@ -123,7 +123,7 @@ public: ...@@ -123,7 +123,7 @@ public:
bool is_reading() const noexcept override; bool is_reading() const noexcept override;
void close() override; void shutdown() override;
// -- properties ------------------------------------------------------------- // -- properties -------------------------------------------------------------
...@@ -161,6 +161,8 @@ public: ...@@ -161,6 +161,8 @@ public:
void abort(const error& reason) override; void abort(const error& reason) override;
bool finalized() const noexcept override;
protected: protected:
// -- utility functions ------------------------------------------------------ // -- utility functions ------------------------------------------------------
......
...@@ -78,7 +78,7 @@ public: ...@@ -78,7 +78,7 @@ public:
ptrdiff_t consume(byte_span buffer, byte_span delta) override; ptrdiff_t consume(byte_span buffer, byte_span delta) override;
bool prepare_send() override; void prepare_send() override;
bool done_sending() override; bool done_sending() override;
......
...@@ -32,6 +32,8 @@ public: ...@@ -32,6 +32,8 @@ public:
bool convert(const_byte_span bytes, input_type& x); bool convert(const_byte_span bytes, input_type& x);
bool convert(std::string_view text, input_type& x); bool convert(std::string_view text, input_type& x);
error last_error();
}; };
} // namespace caf::net::web_socket } // namespace caf::net::web_socket
...@@ -40,6 +40,13 @@ public: ...@@ -40,6 +40,13 @@ public:
// nop // nop
} }
~flow_bridge() {
if (in_)
in_->cancel();
if (out_)
out_->close();
}
static std::unique_ptr<flow_bridge> make(connector_pointer conn) { static std::unique_ptr<flow_bridge> make(connector_pointer conn) {
return std::make_unique<flow_bridge>(std::move(conn)); return std::make_unique<flow_bridge>(std::move(conn));
} }
...@@ -94,13 +101,13 @@ public: ...@@ -94,13 +101,13 @@ public:
auto do_wakeup = make_action([this] { auto do_wakeup = make_action([this] {
prepare_send(); prepare_send();
if (!running()) if (!running())
down_->close(); down_->shutdown();
}); });
auto do_resume = make_action([this] { down_->request_messages(); }); auto do_resume = make_action([this] { down_->request_messages(); });
auto do_cancel = make_action([this] { auto do_cancel = make_action([this] {
out_ = nullptr; out_ = nullptr;
if (!running()) if (!running())
down_->close(); down_->shutdown();
}); });
in_ = consumer_type::make(pull.try_open(), mgr, std::move(do_wakeup)); in_ = consumer_type::make(pull.try_open(), mgr, std::move(do_wakeup));
out_ = producer_type::make(push.try_open(), mgr, std::move(do_resume), out_ = producer_type::make(push.try_open(), mgr, std::move(do_resume),
...@@ -117,27 +124,25 @@ public: ...@@ -117,27 +124,25 @@ public:
} }
} }
bool prepare_send() override { void 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_->close(helper.err); down_->shutdown(helper.err);
} else { } else {
down_->close(); down_->shutdown();
} }
in_ = nullptr; in_ = nullptr;
return true;
} else if (helper.aborted) { } else if (helper.aborted) {
in_->cancel(); in_->cancel();
in_ = nullptr; in_ = nullptr;
return true; down_->shutdown(trait_.last_error());
} else if (consumed == 0) { } else if (consumed == 0) {
return true; return;
} }
} }
return true;
} }
bool done_sending() override { bool done_sending() override {
......
...@@ -77,7 +77,7 @@ public: ...@@ -77,7 +77,7 @@ public:
// -- web_socket::lower_layer implementation --------------------------------- // -- web_socket::lower_layer implementation ---------------------------------
using web_socket::lower_layer::close; using web_socket::lower_layer::shutdown;
bool can_send_more() const noexcept override; bool can_send_more() const noexcept override;
...@@ -85,7 +85,7 @@ public: ...@@ -85,7 +85,7 @@ public:
bool is_reading() const noexcept override; bool is_reading() const noexcept override;
void close(status code, std::string_view desc) override; void shutdown(status code, std::string_view desc) override;
void request_messages() override; void request_messages() override;
......
...@@ -45,12 +45,12 @@ public: ...@@ -45,12 +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;
void close() override; void shutdown() override;
void close(const error& reason) override; void shutdown(const error& reason) override;
/// Sends a close message with custom @ref status @p code and @p msg text. /// Sends a shutdown message with custom @ref status @p code and @p msg text.
virtual void close(status code, std::string_view msg) = 0; virtual void shutdown(status code, std::string_view msg) = 0;
}; };
} // namespace caf::net::web_socket } // namespace caf::net::web_socket
...@@ -81,7 +81,7 @@ public: ...@@ -81,7 +81,7 @@ public:
ptrdiff_t consume(byte_span input, byte_span) override; ptrdiff_t consume(byte_span input, byte_span) override;
bool prepare_send() override; void prepare_send() override;
bool done_sending() override; bool done_sending() override;
......
...@@ -10,8 +10,8 @@ generic_lower_layer::~generic_lower_layer() { ...@@ -10,8 +10,8 @@ generic_lower_layer::~generic_lower_layer() {
// nop // nop
} }
void generic_lower_layer::close(const error&) { void generic_lower_layer::shutdown(const error&) {
close(); shutdown();
} }
} // namespace caf::net } // namespace caf::net
...@@ -35,8 +35,8 @@ bool http_request_producer::push(const net::http::request& item) { ...@@ -35,8 +35,8 @@ bool http_request_producer::push(const net::http::request& item) {
// -- http_flow_adapter -------------------------------------------------------- // -- http_flow_adapter --------------------------------------------------------
bool http_flow_adapter::prepare_send() { void http_flow_adapter::prepare_send() {
return true; // nop
} }
bool http_flow_adapter::done_sending() { bool http_flow_adapter::done_sending() {
...@@ -59,6 +59,11 @@ error http_flow_adapter::init(net::socket_manager* owner, ...@@ -59,6 +59,11 @@ error http_flow_adapter::init(net::socket_manager* owner,
ptrdiff_t http_flow_adapter::consume(const net::http::header& hdr, ptrdiff_t http_flow_adapter::consume(const net::http::header& hdr,
const_byte_span payload) { const_byte_span payload) {
using namespace net::http; using namespace net::http;
if (!pending_.empty()) {
CAF_LOG_WARNING("received multiple requests from the same HTTP client: "
"not implemented yet (drop request)");
return static_cast<ptrdiff_t>(payload.size());
}
auto prom = async::promise<response>(); auto prom = async::promise<response>();
auto fut = prom.get_future(); auto fut = prom.get_future();
auto buf = std::vector<std::byte>{payload.begin(), payload.end()}; auto buf = std::vector<std::byte>{payload.begin(), payload.end()};
...@@ -71,14 +76,13 @@ ptrdiff_t http_flow_adapter::consume(const net::http::header& hdr, ...@@ -71,14 +76,13 @@ ptrdiff_t http_flow_adapter::consume(const net::http::header& hdr,
down_->add_header_field(key, val); down_->add_header_field(key, val);
std::ignore = down_->end_header(); std::ignore = down_->end_header();
down_->send_payload(res.body()); down_->send_payload(res.body());
// TODO: we should close the connection unless indicated otherwise down_->shutdown();
// (keepalive flag?). Also, we should clean up pending_.
}, },
[this](const error& err) { [this](const error& err) {
auto description = to_string(err); auto description = to_string(err);
down_->send_response(status::internal_server_error, "text/plain", down_->send_response(status::internal_server_error, "text/plain",
description); description);
// TODO: see above. down_->shutdown();
}); });
pending_.emplace_back(std::move(hdl)); pending_.emplace_back(std::move(hdl));
return static_cast<ptrdiff_t>(payload.size()); return static_cast<ptrdiff_t>(payload.size());
......
...@@ -18,8 +18,8 @@ bool server::is_reading() const noexcept { ...@@ -18,8 +18,8 @@ bool server::is_reading() const noexcept {
return down_->is_reading(); return down_->is_reading();
} }
void server::close() { void server::shutdown() {
down_->close(); down_->shutdown();
} }
void server::request_messages() { void server::request_messages() {
...@@ -90,8 +90,8 @@ void server::abort(const error& reason) { ...@@ -90,8 +90,8 @@ void server::abort(const error& reason) {
up_->abort(reason); up_->abort(reason);
} }
bool server::prepare_send() { void server::prepare_send() {
return up_->prepare_send(); up_->prepare_send();
} }
bool server::done_sending() { bool server::done_sending() {
......
...@@ -79,8 +79,8 @@ ptrdiff_t length_prefix_framing::consume(byte_span input, byte_span) { ...@@ -79,8 +79,8 @@ ptrdiff_t length_prefix_framing::consume(byte_span input, byte_span) {
} }
} }
bool length_prefix_framing::prepare_send() { void length_prefix_framing::prepare_send() {
return up_->prepare_send(); up_->prepare_send();
} }
bool length_prefix_framing::done_sending() { bool length_prefix_framing::done_sending() {
...@@ -135,8 +135,8 @@ bool length_prefix_framing::end_message() { ...@@ -135,8 +135,8 @@ bool length_prefix_framing::end_message() {
} }
} }
void length_prefix_framing::close() { void length_prefix_framing::shutdown() {
down_->close(); down_->shutdown();
} }
// -- utility functions ------------------------------------------------------ // -- utility functions ------------------------------------------------------
......
...@@ -57,13 +57,8 @@ const short output_mask = POLLOUT; ...@@ -57,13 +57,8 @@ const short output_mask = POLLOUT;
// | (is_writing(mask) ? output_mask : 0)); // | (is_writing(mask) ? output_mask : 0));
// } // }
operation to_operation(const socket_manager_ptr& mgr, operation to_operation(const socket_manager_ptr&, std::optional<short> mask) {
std::optional<short> mask) {
operation res = operation::none; operation res = operation::none;
if (mgr->read_closed())
res = block_reads(res);
if (mgr->write_closed())
res = block_writes(res);
if (mask) { if (mask) {
if ((*mask & input_mask) != 0) if ((*mask & input_mask) != 0)
res = add_read_flag(res); res = add_read_flag(res);
...@@ -187,33 +182,6 @@ void multiplexer::watch(disposable what) { ...@@ -187,33 +182,6 @@ void multiplexer::watch(disposable what) {
// -- thread-safe signaling ---------------------------------------------------- // -- thread-safe signaling ----------------------------------------------------
void multiplexer::dispose(socket_manager_ptr mgr) {
CAF_LOG_TRACE(CAF_ARG2("socket", mgr->handle().id));
if (std::this_thread::get_id() == tid_) {
do_dispose(mgr);
} else {
write_to_pipe(pollset_updater::code::dispose_manager, mgr.release());
}
}
void multiplexer::shutdown_reading(socket_manager_ptr mgr) {
CAF_LOG_TRACE(CAF_ARG2("socket", mgr->handle().id));
if (std::this_thread::get_id() == tid_) {
do_shutdown_reading(mgr);
} else {
write_to_pipe(pollset_updater::code::shutdown_reading, mgr.release());
}
}
void multiplexer::shutdown_writing(socket_manager_ptr mgr) {
CAF_LOG_TRACE(CAF_ARG2("socket", mgr->handle().id));
if (std::this_thread::get_id() == tid_) {
do_shutdown_writing(mgr);
} else {
write_to_pipe(pollset_updater::code::shutdown_writing, mgr.release());
}
}
void multiplexer::init(socket_manager_ptr mgr) { void multiplexer::init(socket_manager_ptr mgr) {
CAF_LOG_TRACE(CAF_ARG2("socket", mgr->handle().id)); CAF_LOG_TRACE(CAF_ARG2("socket", mgr->handle().id));
if (std::this_thread::get_id() == tid_) { if (std::this_thread::get_id() == tid_) {
...@@ -288,7 +256,6 @@ bool multiplexer::poll_once(bool blocking) { ...@@ -288,7 +256,6 @@ bool multiplexer::poll_once(bool blocking) {
CAF_LOG_DEBUG("poll() on" << pollset_.size() << "sockets reported" CAF_LOG_DEBUG("poll() on" << pollset_.size() << "sockets reported"
<< presult << "event(s)"); << presult << "event(s)");
// Scan pollset for events. // Scan pollset for events.
CAF_LOG_DEBUG("scan pollset for socket events");
if (auto revents = pollset_[0].revents; revents != 0) { if (auto revents = pollset_[0].revents; revents != 0) {
// Index 0 is always the pollset updater. This is the only handler that // Index 0 is always the pollset updater. This is the only handler that
// is allowed to modify pollset_ and managers_. Since this may very well // is allowed to modify pollset_ and managers_. Since this may very well
...@@ -297,6 +264,7 @@ bool multiplexer::poll_once(bool blocking) { ...@@ -297,6 +264,7 @@ bool multiplexer::poll_once(bool blocking) {
handle(mgr, pollset_[0].events, revents); handle(mgr, pollset_[0].events, revents);
--presult; --presult;
} }
apply_updates();
for (size_t i = 1; i < pollset_.size() && presult > 0; ++i) { for (size_t i = 1; i < pollset_.size() && presult > 0; ++i) {
if (auto revents = pollset_[i].revents; revents != 0) { if (auto revents = pollset_[i].revents; revents != 0) {
handle(managers_[i], pollset_[i].events, revents); handle(managers_[i], pollset_[i].events, revents);
...@@ -369,6 +337,8 @@ void multiplexer::set_thread_id() { ...@@ -369,6 +337,8 @@ void multiplexer::set_thread_id() {
void multiplexer::run() { void multiplexer::run() {
CAF_LOG_TRACE(""); CAF_LOG_TRACE("");
CAF_LOG_DEBUG("run multiplexer" << CAF_ARG(input_mask) << CAF_ARG(error_mask)
<< CAF_ARG(output_mask));
// On systems like Linux, we cannot disable sigpipe on the socket alone. We // On systems like Linux, we cannot disable sigpipe on the socket alone. We
// need to block the signal at thread level since some APIs (such as OpenSSL) // need to block the signal at thread level since some APIs (such as OpenSSL)
// are unsafe to call otherwise. // are unsafe to call otherwise.
...@@ -393,6 +363,8 @@ void multiplexer::handle(const socket_manager_ptr& mgr, ...@@ -393,6 +363,8 @@ void multiplexer::handle(const socket_manager_ptr& mgr,
<< CAF_ARG(events) << CAF_ARG(revents)); << CAF_ARG(events) << CAF_ARG(revents));
CAF_ASSERT(mgr != nullptr); CAF_ASSERT(mgr != nullptr);
bool checkerror = true; bool checkerror = true;
CAF_LOG_DEBUG("handle event on socket" << mgr->handle().id << CAF_ARG(events)
<< CAF_ARG(revents));
// Note: we double-check whether the manager is actually reading because a // Note: we double-check whether the manager is actually reading because a
// previous action from the pipe may have disabled reading. // previous action from the pipe may have disabled reading.
if ((revents & input_mask) != 0 && is_reading(mgr.get())) { if ((revents & input_mask) != 0 && is_reading(mgr.get())) {
...@@ -478,36 +450,11 @@ void multiplexer::do_shutdown() { ...@@ -478,36 +450,11 @@ void multiplexer::do_shutdown() {
shutting_down_ = true; shutting_down_ = true;
apply_updates(); apply_updates();
// Skip the first manager (the pollset updater). // Skip the first manager (the pollset updater).
for (size_t i = 1; i < managers_.size(); ++i) { for (size_t i = 1; i < managers_.size(); ++i)
auto& mgr = managers_[i]; managers_[i]->dispose();
mgr->close_read();
update_for(static_cast<ptrdiff_t>(i)).events &= ~input_mask;
}
apply_updates(); apply_updates();
} }
void multiplexer::do_dispose(const socket_manager_ptr& mgr) {
CAF_LOG_TRACE(CAF_ARG2("socket", mgr->handle().id));
mgr->handle_error(sec::disposed);
update_for(mgr.get()).events = 0;
}
void multiplexer::do_shutdown_reading(const socket_manager_ptr& mgr) {
CAF_LOG_TRACE(CAF_ARG2("socket", mgr->handle().id));
if (!shutting_down_ && !mgr->read_closed()) {
mgr->close_read();
update_for(mgr.get()).events &= ~input_mask;
}
}
void multiplexer::do_shutdown_writing(const socket_manager_ptr& mgr) {
CAF_LOG_TRACE(CAF_ARG2("socket", mgr->handle().id));
if (!shutting_down_ && !mgr->write_closed()) {
mgr->close_write();
update_for(mgr.get()).events &= ~output_mask;
}
}
void multiplexer::do_init(const socket_manager_ptr& mgr) { void multiplexer::do_init(const socket_manager_ptr& mgr) {
CAF_LOG_TRACE(CAF_ARG2("socket", mgr->handle().id)); CAF_LOG_TRACE(CAF_ARG2("socket", mgr->handle().id));
if (!shutting_down_) { if (!shutting_down_) {
......
...@@ -60,15 +60,6 @@ void pollset_updater::handle_read_event() { ...@@ -60,15 +60,6 @@ void pollset_updater::handle_read_event() {
case code::init_manager: case code::init_manager:
mpx_->do_init(as_mgr(ptr)); mpx_->do_init(as_mgr(ptr));
break; break;
case code::dispose_manager:
mpx_->do_dispose(as_mgr(ptr));
break;
case code::shutdown_reading:
mpx_->do_shutdown_reading(as_mgr(ptr));
break;
case code::shutdown_writing:
mpx_->do_shutdown_writing(as_mgr(ptr));
break;
case code::run_action: case code::run_action:
run_action(ptr); run_action(ptr);
break; break;
...@@ -83,13 +74,13 @@ void pollset_updater::handle_read_event() { ...@@ -83,13 +74,13 @@ void 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");
owner_->shutdown(); owner_->deregister();
return; return;
} else if (last_socket_error_is_temporary()) { } else if (last_socket_error_is_temporary()) {
return; return;
} else { } else {
CAF_LOG_DEBUG("pollset updater failed to read from the pipe"); CAF_LOG_ERROR("pollset updater failed to read from the pipe");
owner_->shutdown(); owner_->deregister();
return; return;
} }
} }
......
...@@ -24,8 +24,8 @@ std::string_view server::scrape_state::scrape() { ...@@ -24,8 +24,8 @@ std::string_view server::scrape_state::scrape() {
// -- implementation of http::upper_layer -------------------------------------- // -- implementation of http::upper_layer --------------------------------------
bool server::prepare_send() { void server::prepare_send() {
return true; // nop
} }
bool server::done_sending() { bool server::done_sending() {
...@@ -45,19 +45,19 @@ error server::init(socket_manager*, http::lower_layer* down, const settings&) { ...@@ -45,19 +45,19 @@ error server::init(socket_manager*, http::lower_layer* down, const settings&) {
ptrdiff_t server::consume(const http::header& hdr, const_byte_span payload) { ptrdiff_t server::consume(const http::header& hdr, const_byte_span payload) {
if (hdr.path() != "/metrics") { if (hdr.path() != "/metrics") {
down_->send_response(http::status::not_found, "text/plain", "Not found."); down_->send_response(http::status::not_found, "text/plain", "Not found.");
down_->close(); down_->shutdown();
} else if (hdr.method() != http::method::get) { } else if (hdr.method() != http::method::get) {
down_->send_response(http::status::method_not_allowed, "text/plain", down_->send_response(http::status::method_not_allowed, "text/plain",
"Method not allowed."); "Method not allowed.");
down_->close(); down_->shutdown();
} else if (!hdr.query().empty() || !hdr.fragment().empty()) { } else if (!hdr.query().empty() || !hdr.fragment().empty()) {
down_->send_response(http::status::bad_request, "text/plain", down_->send_response(http::status::bad_request, "text/plain",
"No fragment or query allowed."); "No fragment or query allowed.");
down_->close(); down_->shutdown();
} else { } else {
auto str = state_->scrape(); auto str = state_->scrape();
down_->send_response(http::status::ok, "text/plain;version=0.0.4", str); down_->send_response(http::status::ok, "text/plain;version=0.0.4", str);
down_->close(); down_->shutdown();
} }
return static_cast<ptrdiff_t>(payload.size()); return static_cast<ptrdiff_t>(payload.size());
} }
......
...@@ -14,4 +14,8 @@ bool socket_event_layer::do_handover(std::unique_ptr<socket_event_layer>&) { ...@@ -14,4 +14,8 @@ bool socket_event_layer::do_handover(std::unique_ptr<socket_event_layer>&) {
return false; return false;
} }
bool socket_event_layer::finalized() const noexcept {
return true;
}
} // namespace caf::net } // namespace caf::net
...@@ -19,11 +19,11 @@ socket_manager::socket_manager(multiplexer* mpx, socket fd, ...@@ -19,11 +19,11 @@ socket_manager::socket_manager(multiplexer* mpx, socket fd,
CAF_ASSERT(fd_ != invalid_socket); CAF_ASSERT(fd_ != invalid_socket);
CAF_ASSERT(mpx_ != nullptr); CAF_ASSERT(mpx_ != nullptr);
CAF_ASSERT(handler_ != nullptr); CAF_ASSERT(handler_ != nullptr);
memset(&flags_, 0, sizeof(flags_t));
} }
socket_manager::~socket_manager() { socket_manager::~socket_manager() {
close(fd_); if (fd_)
close(fd_);
} }
// -- factories ---------------------------------------------------------------- // -- factories ----------------------------------------------------------------
...@@ -53,13 +53,11 @@ bool socket_manager::is_writing() const noexcept { ...@@ -53,13 +53,11 @@ bool socket_manager::is_writing() const noexcept {
// -- 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::register_writing() { void socket_manager::register_writing() {
if (!flags_.write_closed) mpx_->register_writing(this);
mpx_->register_writing(this);
} }
void socket_manager::deregister_reading() { void socket_manager::deregister_reading() {
...@@ -74,23 +72,6 @@ void socket_manager::deregister() { ...@@ -74,23 +72,6 @@ void socket_manager::deregister() {
mpx_->deregister(this); 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;
disposed_ = true;
deregister();
}
// -- callbacks for the handler ------------------------------------------------ // -- callbacks for the handler ------------------------------------------------
void socket_manager::schedule_handover() { void socket_manager::schedule_handover() {
...@@ -112,21 +93,20 @@ void socket_manager::schedule(action what) { ...@@ -112,21 +93,20 @@ void socket_manager::schedule(action what) {
}); });
} }
// -- callbacks for the multiplexer -------------------------------------------- void socket_manager::shutdown() {
if (!shutting_down_) {
void socket_manager::close_read() noexcept { shutting_down_ = true;
// TODO: extend transport API for closing read operations. dispose();
flags_.read_closed = true; } else {
if (flags_.write_closed) // This usually only happens after disposing the manager if the handler
disposed_ = true; // still had data to send.
mpx_->schedule_fn([ptr = strong_this()] { //
ptr->cleanup();
});
}
} }
void socket_manager::close_write() noexcept { // -- callbacks for the multiplexer --------------------------------------------
// TODO: extend transport API for closing write operations.
flags_.write_closed = true;
if (flags_.read_closed)
disposed_ = true;
}
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));
...@@ -138,26 +118,46 @@ error socket_manager::init(const settings& cfg) { ...@@ -138,26 +118,46 @@ error socket_manager::init(const settings& cfg) {
} }
void socket_manager::handle_read_event() { void socket_manager::handle_read_event() {
handler_->handle_read_event(); if (handler_)
handler_->handle_read_event();
else
deregister();
} }
void socket_manager::handle_write_event() { void socket_manager::handle_write_event() {
handler_->handle_write_event(); if (handler_)
handler_->handle_write_event();
else
deregister();
} }
void socket_manager::handle_error(sec code) { void socket_manager::handle_error(sec code) {
if (handler_) { if (!disposed_)
handler_->abort(make_error(code));
handler_ = nullptr;
disposed_ = true; disposed_ = true;
if (handler_) {
if (!shutting_down_) {
handler_->abort(make_error(code));
shutting_down_ = true;
}
if (code == sec::disposed && !handler_->finalized()) {
// When disposing the manger, the transport is still allowed to send any
// pending data and it will call shutdown() later to trigger cleanup().
deregister_reading();
} else {
cleanup();
}
} }
} }
// -- implementation of disposable_impl ---------------------------------------- // -- implementation of disposable_impl ----------------------------------------
void socket_manager::dispose() { void socket_manager::dispose() {
if (!disposed()) bool expected = false;
mpx_->dispose(this); if (disposed_.compare_exchange_strong(expected, true)) {
mpx_->schedule_fn([ptr = strong_this()] { //
ptr->handle_error(sec::disposed);
});
}
} }
bool socket_manager::disposed() const noexcept { bool socket_manager::disposed() const noexcept {
...@@ -174,6 +174,15 @@ void socket_manager::deref_disposable() const noexcept { ...@@ -174,6 +174,15 @@ void socket_manager::deref_disposable() const noexcept {
// -- utility functions -------------------------------------------------------- // -- utility functions --------------------------------------------------------
void socket_manager::cleanup() {
deregister();
handler_.reset();
if (fd_) {
close(fd_);
fd_ = invalid_socket;
}
}
socket_manager_ptr socket_manager::strong_this() { socket_manager_ptr socket_manager::strong_this() {
return socket_manager_ptr{this}; return socket_manager_ptr{this};
} }
......
...@@ -111,12 +111,14 @@ bool stream_transport::is_reading() const noexcept { ...@@ -111,12 +111,14 @@ bool stream_transport::is_reading() const noexcept {
return max_read_size_ > 0; return max_read_size_ > 0;
} }
void stream_transport::close() { void stream_transport::shutdown() {
parent_->shutdown_read(); if (write_buf_.empty()) {
if (write_buf_.empty()) parent_->shutdown();
parent_->shutdown_write(); } else {
else configure_read(receive_policy::stop());
parent_->deregister_reading();
flags_.shutting_down = true; flags_.shutting_down = true;
}
} }
// -- implementation of transport ---------------------------------------------- // -- implementation of transport ----------------------------------------------
...@@ -283,29 +285,25 @@ void stream_transport::handle_write_event() { ...@@ -283,29 +285,25 @@ void stream_transport::handle_write_event() {
return; return;
} }
} }
// Allow the upper layer to add extra data to the write buffer. // When shutting down, we flush our buffer and then shut down the manager.
if (!up_->prepare_send()) { if (flags_.shutting_down) {
CAF_LOG_DEBUG("prepare_send failed"); if (write_buf_.empty()) {
parent_->deregister(); parent_->shutdown();
return; return;
}
if (write_buf_.empty()) {
if (up_->done_sending()) {
if (!flags_.shutting_down)
parent_->deregister_writing();
else
parent_->shutdown_write();
} }
return; } else if (can_send_more()) {
// Allow the upper layer to add extra data to the write buffer.
up_->prepare_send();
} }
auto write_res = policy_->write(fd_, write_buf_); auto write_res = policy_->write(fd_, write_buf_);
if (write_res > 0) { if (write_res > 0) {
write_buf_.erase(write_buf_.begin(), write_buf_.begin() + write_res); write_buf_.erase(write_buf_.begin(), write_buf_.begin() + write_res);
if (write_buf_.empty() && up_->done_sending()) { if (write_buf_.empty() && up_->done_sending()) {
if (!flags_.shutting_down) if (!flags_.shutting_down) {
parent_->deregister_writing(); parent_->deregister_writing();
else } else {
parent_->shutdown_write(); parent_->shutdown();
}
} }
return; return;
} else if (write_res < 0) { } else if (write_res < 0) {
...@@ -331,6 +329,11 @@ void stream_transport::handle_write_event() { ...@@ -331,6 +329,11 @@ void stream_transport::handle_write_event() {
void stream_transport::abort(const error& reason) { void stream_transport::abort(const error& reason) {
up_->abort(reason); up_->abort(reason);
flags_.shutting_down = true;
}
bool stream_transport::finalized() const noexcept {
return write_buf_.empty();
} }
// -- free functions ----------------------------------------------------------- // -- free functions -----------------------------------------------------------
......
...@@ -75,6 +75,7 @@ expected<tcp_accept_socket> new_tcp_acceptor_impl(uint16_t port, ...@@ -75,6 +75,7 @@ expected<tcp_accept_socket> new_tcp_acceptor_impl(uint16_t port,
CAF_NET_SYSCALL("bind", res, !=, 0, CAF_NET_SYSCALL("bind", res, !=, 0,
bind(fd, reinterpret_cast<sockaddr*>(&sa), bind(fd, reinterpret_cast<sockaddr*>(&sa),
static_cast<socket_size_type>(sizeof(sa)))); static_cast<socket_size_type>(sizeof(sa))));
CAF_LOG_DEBUG("bound socket" << fd << "to listen on port" << port);
return sguard.release(); return sguard.release();
} }
...@@ -130,6 +131,7 @@ make_tcp_accept_socket(uint16_t port, std::string addr, bool reuse_addr) { ...@@ -130,6 +131,7 @@ make_tcp_accept_socket(uint16_t port, std::string addr, bool reuse_addr) {
} }
expected<tcp_stream_socket> accept(tcp_accept_socket x) { expected<tcp_stream_socket> accept(tcp_accept_socket x) {
CAF_LOG_TRACE(CAF_ARG(x));
auto sock = ::accept(x.id, nullptr, nullptr); auto sock = ::accept(x.id, nullptr, nullptr);
if (sock == net::invalid_socket_id) { if (sock == net::invalid_socket_id) {
auto err = net::last_socket_error(); auto err = net::last_socket_error();
...@@ -139,6 +141,7 @@ expected<tcp_stream_socket> accept(tcp_accept_socket x) { ...@@ -139,6 +141,7 @@ expected<tcp_stream_socket> accept(tcp_accept_socket x) {
} }
return caf::make_error(sec::socket_operation_failed, "tcp accept failed"); return caf::make_error(sec::socket_operation_failed, "tcp accept failed");
} }
CAF_LOG_DEBUG("accepted TCP socket" << sock << "on accept socket" << x.id);
return tcp_stream_socket{sock}; return tcp_stream_socket{sock};
} }
......
...@@ -96,8 +96,9 @@ ptrdiff_t client::consume(byte_span buffer, byte_span delta) { ...@@ -96,8 +96,9 @@ ptrdiff_t client::consume(byte_span buffer, byte_span delta) {
} }
} }
bool client::prepare_send() { void client::prepare_send() {
return handshake_completed() ? upper_layer().prepare_send() : true; if (handshake_completed())
upper_layer().prepare_send();
} }
bool client::done_sending() { bool client::done_sending() {
......
...@@ -4,7 +4,10 @@ ...@@ -4,7 +4,10 @@
#include "caf/net/web_socket/default_trait.hpp" #include "caf/net/web_socket/default_trait.hpp"
#include "caf/error.hpp"
#include "caf/logger.hpp"
#include "caf/net/web_socket/frame.hpp" #include "caf/net/web_socket/frame.hpp"
#include "caf/sec.hpp"
namespace caf::net::web_socket { namespace caf::net::web_socket {
...@@ -34,4 +37,9 @@ bool default_trait::convert(std::string_view text, input_type& x) { ...@@ -34,4 +37,9 @@ bool default_trait::convert(std::string_view text, input_type& x) {
return true; return true;
} }
error default_trait::last_error() {
CAF_LOG_ERROR("default_trait::last_error called");
return {sec::logic_error};
}
} // namespace caf::net::web_socket } // namespace caf::net::web_socket
...@@ -30,7 +30,7 @@ bool framing::is_reading() const noexcept { ...@@ -30,7 +30,7 @@ bool framing::is_reading() const noexcept {
return down_->is_reading(); return down_->is_reading();
} }
void framing::close(status code, std::string_view msg) { void framing::shutdown(status code, std::string_view msg) {
auto code_val = static_cast<uint16_t>(code); auto code_val = static_cast<uint16_t>(code);
uint32_t mask_key = 0; uint32_t mask_key = 0;
byte_buffer payload; byte_buffer payload;
...@@ -47,6 +47,7 @@ void framing::close(status code, std::string_view msg) { ...@@ -47,6 +47,7 @@ void framing::close(status code, std::string_view msg) {
detail::rfc6455::assemble_frame(detail::rfc6455::connection_close, mask_key, detail::rfc6455::assemble_frame(detail::rfc6455::connection_close, mask_key,
payload, down_->output_buffer()); payload, down_->output_buffer());
down_->end_output(); down_->end_output();
down_->shutdown();
} }
void framing::request_messages() { void framing::request_messages() {
......
...@@ -13,13 +13,13 @@ lower_layer::~lower_layer() { ...@@ -13,13 +13,13 @@ lower_layer::~lower_layer() {
// nop // nop
} }
void lower_layer::close() { void lower_layer::shutdown() {
using namespace std::literals; using namespace std::literals;
close(status::normal_close, "EOF"sv); shutdown(status::normal_close, "EOF"sv);
} }
void lower_layer::close(const error& reason) { void lower_layer::shutdown(const error& reason) {
close(status::unexpected_condition, to_string(reason)); shutdown(status::unexpected_condition, to_string(reason));
} }
} // namespace caf::net::web_socket } // namespace caf::net::web_socket
...@@ -75,8 +75,9 @@ ptrdiff_t server::consume(byte_span input, byte_span delta) { ...@@ -75,8 +75,9 @@ ptrdiff_t server::consume(byte_span input, byte_span delta) {
} }
} }
bool server::prepare_send() { void server::prepare_send() {
return handshake_complete_ ? upper_layer().prepare_send() : true; if (handshake_complete_)
upper_layer().prepare_send();
} }
bool server::done_sending() { bool server::done_sending() {
......
...@@ -23,7 +23,7 @@ bool mock_stream_transport::is_reading() const noexcept { ...@@ -23,7 +23,7 @@ bool mock_stream_transport::is_reading() const noexcept {
return max_read_size > 0; return max_read_size > 0;
} }
void mock_stream_transport::close() { void mock_stream_transport::shutdown() {
// nop // nop
} }
......
...@@ -34,7 +34,7 @@ public: ...@@ -34,7 +34,7 @@ public:
bool is_reading() const noexcept override; bool is_reading() const noexcept override;
void close() override; void shutdown() override;
void configure_read(caf::net::receive_policy policy) override; void configure_read(caf::net::receive_policy policy) override;
......
...@@ -59,18 +59,17 @@ public: ...@@ -59,18 +59,17 @@ public:
return none; return none;
} }
bool prepare_send() override { void prepare_send() override {
while (self->consume_message()) while (!self->terminated() && self->consume_message())
; // repeat ; // repeat
return !self->terminated();
} }
bool done_sending() override { bool done_sending() override {
return self->try_block_mailbox(); return self->try_block_mailbox();
} }
void abort(const error& reason) override { void abort(const error&) override {
CAF_FAIL("app::abort called: " << reason); // nop
} }
ptrdiff_t consume(byte_span buf, byte_span) override { ptrdiff_t consume(byte_span buf, byte_span) override {
......
...@@ -115,23 +115,22 @@ public: ...@@ -115,23 +115,22 @@ public:
} }
}; };
bool prepare_send() override { void prepare_send() override {
if (done || !adapter) if (!done && adapter) {
return true; auto helper = send_helper{this};
auto helper = send_helper{this}; while (down->can_send_more()) {
while (down->can_send_more()) { auto [again, consumed] = adapter->pull(async::delay_errors, 1, helper);
auto [again, consumed] = adapter->pull(async::delay_errors, 1, helper); if (!again) {
if (!again) { MESSAGE("adapter signaled end-of-buffer");
MESSAGE("adapter signaled end-of-buffer"); adapter = nullptr;
adapter = nullptr; done = true;
done = true; break;
break; } else if (consumed == 0) {
} else if (consumed == 0) { break;
break; }
} }
MESSAGE(written_bytes.size() << " bytes written");
} }
MESSAGE(written_bytes.size() << " bytes written");
return true;
} }
bool done_sending() override { bool done_sending() override {
......
...@@ -59,8 +59,8 @@ public: ...@@ -59,8 +59,8 @@ public:
CAF_FAIL("app::abort called: " << reason); CAF_FAIL("app::abort called: " << reason);
} }
bool prepare_send() override { void prepare_send() override {
return true; // nop
} }
bool done_sending() override { bool done_sending() override {
......
...@@ -55,8 +55,8 @@ public: ...@@ -55,8 +55,8 @@ public:
return none; return none;
} }
bool prepare_send() override { void prepare_send() override {
return true; // nop
} }
bool done_sending() override { bool done_sending() override {
......
...@@ -93,11 +93,13 @@ public: ...@@ -93,11 +93,13 @@ public:
} }
void abort(const error& reason) override { void abort(const error& reason) override {
FAIL("abort called: " << reason); abort_reason = reason;
} }
std::string name; std::string name;
error abort_reason;
private: private:
std::byte* read_position_begin() { std::byte* read_position_begin() {
return rd_buf_.data() + rd_buf_pos_; return rd_buf_.data() + rd_buf_pos_;
...@@ -232,8 +234,8 @@ SCENARIO("a multiplexer terminates its thread after shutting down") { ...@@ -232,8 +234,8 @@ SCENARIO("a multiplexer terminates its thread after shutting down") {
mpx->shutdown(); mpx->shutdown();
THEN("the thread terminates and all socket managers get shut down") { THEN("the thread terminates and all socket managers get shut down") {
mpx_thread.join(); mpx_thread.join();
CHECK(alice_mgr->read_closed()); CHECK(alice_mgr->disposed());
CHECK(bob_mgr->read_closed()); CHECK(bob_mgr->disposed());
} }
} }
} }
......
...@@ -79,7 +79,7 @@ public: ...@@ -79,7 +79,7 @@ public:
// Note: the execution unit is the owner of this object. As as long as the // Note: the execution unit is the owner of this object. As as long as the
// execution unit lives, accessing `this` is safe. // execution unit lives, accessing `this` is safe.
auto do_resume = make_action([this] { down->request_messages(); }); auto do_resume = make_action([this] { down->request_messages(); });
auto do_cancel = make_action([this] { down->close(); }); auto do_cancel = make_action([this] { down->shutdown(); });
adapter_ = adapter_type::make(std::move(buf), mgr, std::move(do_resume), adapter_ = adapter_type::make(std::move(buf), mgr, std::move(do_resume),
std::move(do_cancel)); std::move(do_cancel));
return none; return none;
...@@ -88,8 +88,8 @@ public: ...@@ -88,8 +88,8 @@ public:
} }
} }
bool prepare_send() override { void prepare_send() override {
return true; // nop
} }
bool done_sending() override { bool done_sending() override {
......
...@@ -72,8 +72,8 @@ public: ...@@ -72,8 +72,8 @@ public:
return none; return none;
} }
bool prepare_send() override { void prepare_send() override {
return true; // nop
} }
bool done_sending() override { bool done_sending() override {
......
...@@ -93,12 +93,11 @@ public: ...@@ -93,12 +93,11 @@ public:
return static_cast<ptrdiff_t>(recv_buf_->size()); return static_cast<ptrdiff_t>(recv_buf_->size());
} }
bool prepare_send() override { void prepare_send() override {
MESSAGE("prepare_send called"); MESSAGE("prepare_send called");
auto& buf = down->output_buffer(); auto& buf = down->output_buffer();
auto data = as_bytes(make_span(hello_manager)); auto data = as_bytes(make_span(hello_manager));
buf.insert(buf.end(), data.begin(), data.end()); buf.insert(buf.end(), data.begin(), data.end());
return true;
} }
bool done_sending() override { bool done_sending() override {
......
...@@ -59,18 +59,17 @@ public: ...@@ -59,18 +59,17 @@ public:
return none; return none;
} }
bool prepare_send() override { void prepare_send() override {
while (self->consume_message()) while (!self->terminated() && self->consume_message())
; // repeat ; // repeat
return !self->terminated();
} }
bool done_sending() override { bool done_sending() override {
return self->try_block_mailbox(); return self->try_block_mailbox();
} }
void abort(const error& reason) override { void abort(const error&) override {
CAF_FAIL("app::abort called: " << reason); // nop
} }
ptrdiff_t consume(byte_span buf, byte_span) override { ptrdiff_t consume(byte_span buf, byte_span) override {
......
...@@ -32,8 +32,8 @@ public: ...@@ -32,8 +32,8 @@ public:
return none; return none;
} }
bool prepare_send() override { void prepare_send() override {
return true; // nop
} }
bool done_sending() override { bool done_sending() override {
......
...@@ -39,8 +39,8 @@ public: ...@@ -39,8 +39,8 @@ public:
return none; return none;
} }
bool prepare_send() override { void prepare_send() override {
return true; // nop
} }
bool done_sending() override { bool done_sending() override {
......
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