#include "secsgem/endpoint.hpp" namespace secsgem { using asio::ip::tcp; // --- Server --------------------------------------------------------------- Server::Server(asio::io_context& io, Config cfg) : io_(io), acceptor_(io, tcp::endpoint(tcp::v4(), cfg.port)), cfg_(std::move(cfg)) {} void Server::start() { log("listening on port " + std::to_string(cfg_.port) + " (device " + std::to_string(cfg_.device_id) + ")"); do_accept(); } void Server::do_accept() { acceptor_.async_accept([this](std::error_code ec, tcp::socket socket) { if (ec) { log("accept error: " + ec.message()); return; } std::error_code rec; auto remote = socket.remote_endpoint(rec); log("accepted connection from " + (rec ? std::string("?") : remote.address().to_string() + ":" + std::to_string(remote.port()))); auto conn = std::make_shared(std::move(socket), Connection::Mode::Passive, cfg_.device_id, cfg_.timers); if (on_log_) conn->set_log_handler(on_log_); if (on_connection_) on_connection_(conn); conn->start(); do_accept(); }); } void Server::log(const std::string& msg) { if (on_log_) on_log_(msg); } // --- Client --------------------------------------------------------------- Client::Client(asio::io_context& io, Config cfg) : io_(io), resolver_(io), retry_timer_(io), cfg_(std::move(cfg)) {} void Client::start() { do_connect(); } void Client::do_connect() { log("connecting to " + cfg_.host + ":" + std::to_string(cfg_.port)); resolver_.async_resolve( cfg_.host, std::to_string(cfg_.port), [this](std::error_code ec, tcp::resolver::results_type results) { if (ec) { log("resolve failed: " + ec.message()); schedule_retry(); return; } auto socket = std::make_shared(io_); asio::async_connect( *socket, results, [this, socket](std::error_code cec, const tcp::endpoint& ep) { if (cec) { log("connect failed: " + cec.message()); schedule_retry(); return; } log("connected to " + ep.address().to_string() + ":" + std::to_string(ep.port())); auto conn = std::make_shared( std::move(*socket), Connection::Mode::Active, cfg_.device_id, cfg_.timers); if (on_log_) conn->set_log_handler(on_log_); if (on_connection_) on_connection_(conn); conn->start(); }); }); } void Client::schedule_retry() { log("retrying in " + std::to_string(cfg_.timers.t5.count()) + " ms (T5)"); retry_timer_.expires_after(cfg_.timers.t5); retry_timer_.async_wait([this](std::error_code ec) { if (!ec) do_connect(); }); } void Client::log(const std::string& msg) { if (on_log_) on_log_(msg); } } // namespace secsgem