Mercurial > irccd
view libirccd/irccd/transport_client.cpp @ 534:2326a4dc39e6
Irccd: rewrite transports in Boost.Asio, closes #681
author | David Demelier <markand@malikania.fr> |
---|---|
date | Fri, 17 Nov 2017 20:56:10 +0100 |
parents | |
children | 5c92ebd4423c |
line wrap: on
line source
/* * transport_client.cpp -- server side transport clients * * Copyright (c) 2013-2017 David Demelier <markand@malikania.fr> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <cassert> #include "transport_client.hpp" #include "transport_server.hpp" namespace irccd { /* * transport_client::close * ------------------------------------------------------------------ */ void transport_client::close() { state_ = state_t::closing; output_.clear(); parent_.clients().erase(shared_from_this()); } /* * transport_client::flush * ------------------------------------------------------------------ */ void transport_client::flush() { if (output_.empty()) return; auto self = shared_from_this(); auto size = output_[0].first.size(); do_send(output_[0].first, [this, self, size] (auto code, auto xfer) { if (output_[0].second) output_[0].second(code); output_.pop_front(); if (code || xfer != size || (output_.empty() && state_ == state_t::closing)) close(); else if (!output_.empty()) flush(); }); } /* * transport_client::recv * ------------------------------------------------------------------ */ void transport_client::recv(recv_t handler) { assert(handler); auto self = shared_from_this(); do_recv(input_, [this, self, handler] (auto code, auto xfer) { if (code || xfer == 0) { handler("", code); close(); return; } std::string message( boost::asio::buffers_begin(input_.data()), boost::asio::buffers_begin(input_.data()) + xfer - 4 ); // Remove early in case of errors. input_.consume(xfer); try { auto json = nlohmann::json::parse(message); if (!json.is_object()) handler(nullptr, transport_error::invalid_message); else handler(json, code); } catch (...) { handler(nullptr, transport_error::invalid_message); } }); } /* * transport_client::send * ------------------------------------------------------------------ */ void transport_client::send(const nlohmann::json& data, send_t handler) { assert(data.is_object()); if (state_ == state_t::closing) return; auto in_progress = !output_.empty(); output_.emplace_back(data.dump() + "\r\n\r\n", std::move(handler)); if (!in_progress) flush(); } /* * transport_client::error * ------------------------------------------------------------------ */ void transport_client::error(const nlohmann::json& data, send_t handler) { send(std::move(data), std::move(handler)); set_state(state_t::closing); } /* * transport_category * ------------------------------------------------------------------ */ const boost::system::error_category& transport_category() noexcept { static const class category : public boost::system::error_category { public: const char* name() const noexcept override { return "transport"; } std::string message(int e) const override { switch (static_cast<transport_error>(e)) { case transport_error::invalid_auth: return "invalid authentication"; case transport_error::invalid_message: return "invalid message"; case transport_error::incomplete_message: return "incomplete message"; } return "unknown error"; } } cat; return cat; } /* * make_error_code * ------------------------------------------------------------------ */ boost::system::error_code make_error_code(transport_error e) noexcept { return {static_cast<int>(e), transport_category()}; } } // !irccd