Mercurial > malikania
view libmlk/malikania/socket.cpp @ 189:f28cb6d04731
Misc: extreme refactoring
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 25 Oct 2018 21:36:14 +0200 |
parents | libcommon/malikania/socket.cpp@fbfc2555bda5 |
children | 74afc5a41c83 |
line wrap: on
line source
/* * socket.cpp -- SSL socket using JSON messages * * Copyright (c) 2013-2018 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 "socket.hpp" namespace mlk { void socket::do_recv(recv_handler handler) { boost::asio::async_read_until(socket_, rbuffer_, "\r\n\r\n", [this, handler] (auto code, auto xfer) { if (code) handler(std::move(code), nullptr); else if (xfer == 0U) handler(make_error_code(boost::system::errc::network_down), nullptr); else { std::string str( boost::asio::buffers_begin(rbuffer_.data()), boost::asio::buffers_begin(rbuffer_.data()) + xfer - 4 ); // Remove early in case of errors. rbuffer_.consume(xfer); // TODO: catch nlohmann::json::parse_error when 3.0.0 is released. nlohmann::json message; try { message = nlohmann::json::parse(str); } catch (...) {} if (!message.is_object()) handler(make_error_code(boost::system::errc::invalid_argument), nullptr); else handler(code, std::move(message)); } }); } void socket::do_send(const std::string& str, send_handler handler) { boost::asio::async_write(socket_, boost::asio::buffer(str), [handler] (auto code, auto xfer) { if (xfer == 0U) handler(make_error_code(boost::system::errc::network_down)); else handler(code); }); } socket::socket(boost::asio::io_service& service, boost::asio::ssl::context& ctx) : socket_(service, ctx) { } auto socket::get_socket() const noexcept -> const socket_t& { return socket_; } auto socket::get_socket() noexcept -> socket_t& { return socket_; } auto socket::is_receiving() const noexcept -> bool { return !rqueue_.empty(); } auto socket::is_sending() const noexcept -> bool { return !squeue_.empty(); } auto socket::is_active() const noexcept -> bool { return is_receiving() || is_sending(); } void socket::rflush() { if (rqueue_.empty()) return; do_recv([this] (auto code, auto json) { auto handler = rqueue_.front(); rqueue_.pop_front(); handler(code, std::move(json)); if (!code) rflush(); }); } void socket::sflush() { if (squeue_.empty()) return; do_send(squeue_.front().first, [this] (auto code) { auto handler = squeue_.front().second; squeue_.pop_front(); if (handler) handler(code); if (!code) sflush(); }); } void socket::recv(recv_handler handler) { assert(handler); auto in_progress = !rqueue_.empty(); rqueue_.push_back(std::move(handler)); if (!in_progress) rflush(); } void socket::send(nlohmann::json json, send_handler handler) { assert(json.is_object()); auto in_progress = !squeue_.empty(); squeue_.emplace_back(json.dump(0) + "\r\n\r\n", std::move(handler)); if (!in_progress) sflush(); } } // !mlk