2019-02-25 08:48:22 -05:00
|
|
|
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
|
2014-05-03 14:02:22 -04:00
|
|
|
|
2015-06-22 05:11:21 -04:00
|
|
|
#include "remote/jsonrpcconnection.hpp"
|
2014-05-25 10:23:35 -04:00
|
|
|
#include "remote/apilistener.hpp"
|
|
|
|
|
#include "remote/apifunction.hpp"
|
|
|
|
|
#include "remote/jsonrpc.hpp"
|
2019-03-12 12:55:39 -04:00
|
|
|
#include "base/defer.hpp"
|
2015-08-15 14:28:05 -04:00
|
|
|
#include "base/configtype.hpp"
|
2019-02-19 07:57:36 -05:00
|
|
|
#include "base/io-engine.hpp"
|
2019-02-26 05:13:34 -05:00
|
|
|
#include "base/json.hpp"
|
2014-05-25 10:23:35 -04:00
|
|
|
#include "base/objectlock.hpp"
|
|
|
|
|
#include "base/utility.hpp"
|
2014-10-19 08:21:12 -04:00
|
|
|
#include "base/logger.hpp"
|
2014-05-25 10:23:35 -04:00
|
|
|
#include "base/exception.hpp"
|
2016-06-14 02:19:13 -04:00
|
|
|
#include "base/convert.hpp"
|
2019-02-19 07:57:36 -05:00
|
|
|
#include "base/tlsstream.hpp"
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <utility>
|
2019-09-09 09:11:38 -04:00
|
|
|
#include <boost/asio/io_context.hpp>
|
2019-02-19 07:57:36 -05:00
|
|
|
#include <boost/asio/spawn.hpp>
|
2019-02-20 07:49:50 -05:00
|
|
|
#include <boost/date_time/posix_time/posix_time_duration.hpp>
|
2019-06-05 04:32:20 -04:00
|
|
|
#include <boost/system/system_error.hpp>
|
2015-02-27 14:18:20 -05:00
|
|
|
#include <boost/thread/once.hpp>
|
2014-05-03 14:02:22 -04:00
|
|
|
|
|
|
|
|
using namespace icinga;
|
|
|
|
|
|
2015-08-04 08:47:44 -04:00
|
|
|
static Value SetLogPositionHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params);
|
2014-05-03 14:02:22 -04:00
|
|
|
REGISTER_APIFUNCTION(SetLogPosition, log, &SetLogPositionHandler);
|
|
|
|
|
|
2019-02-20 08:24:09 -05:00
|
|
|
static RingBuffer l_TaskStats (15 * 60);
|
|
|
|
|
|
2025-06-06 03:53:03 -04:00
|
|
|
JsonRpcConnection::JsonRpcConnection(const WaitGroup::Ptr& waitGroup, const String& identity, bool authenticated,
|
2019-07-25 08:34:29 -04:00
|
|
|
const Shared<AsioTlsStream>::Ptr& stream, ConnectionRole role)
|
2025-06-06 03:53:03 -04:00
|
|
|
: JsonRpcConnection(waitGroup, identity, authenticated, stream, role, IoEngine::Get().GetIoContext())
|
2019-06-07 10:30:34 -04:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-06 03:53:03 -04:00
|
|
|
JsonRpcConnection::JsonRpcConnection(const WaitGroup::Ptr& waitGroup, const String& identity, bool authenticated,
|
2019-07-25 08:34:29 -04:00
|
|
|
const Shared<AsioTlsStream>::Ptr& stream, ConnectionRole role, boost::asio::io_context& io)
|
2019-06-07 10:30:34 -04:00
|
|
|
: m_Identity(identity), m_Authenticated(authenticated), m_Stream(stream), m_Role(role),
|
2024-10-30 09:31:48 -04:00
|
|
|
m_Timestamp(Utility::GetTime()), m_Seen(Utility::GetTime()), m_IoStrand(io),
|
2025-06-06 03:53:03 -04:00
|
|
|
m_OutgoingMessagesQueued(io), m_WriterDone(io), m_ShuttingDown(false), m_WaitGroup(waitGroup),
|
2019-06-07 10:30:34 -04:00
|
|
|
m_CheckLivenessTimer(io), m_HeartbeatTimer(io)
|
2014-05-08 09:00:09 -04:00
|
|
|
{
|
2014-10-16 03:01:18 -04:00
|
|
|
if (authenticated)
|
|
|
|
|
m_Endpoint = Endpoint::GetByName(identity);
|
2019-02-19 07:57:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void JsonRpcConnection::Start()
|
|
|
|
|
{
|
|
|
|
|
namespace asio = boost::asio;
|
|
|
|
|
|
2019-03-11 05:12:05 -04:00
|
|
|
JsonRpcConnection::Ptr keepAlive (this);
|
2019-02-19 07:57:36 -05:00
|
|
|
|
2019-09-06 09:11:55 -04:00
|
|
|
IoEngine::SpawnCoroutine(m_IoStrand, [this, keepAlive](asio::yield_context yc) { HandleIncomingMessages(yc); });
|
|
|
|
|
IoEngine::SpawnCoroutine(m_IoStrand, [this, keepAlive](asio::yield_context yc) { WriteOutgoingMessages(yc); });
|
|
|
|
|
IoEngine::SpawnCoroutine(m_IoStrand, [this, keepAlive](asio::yield_context yc) { HandleAndWriteHeartbeats(yc); });
|
|
|
|
|
IoEngine::SpawnCoroutine(m_IoStrand, [this, keepAlive](asio::yield_context yc) { CheckLiveness(yc); });
|
2014-05-08 09:00:09 -04:00
|
|
|
}
|
2014-05-03 14:02:22 -04:00
|
|
|
|
2019-02-19 07:57:36 -05:00
|
|
|
void JsonRpcConnection::HandleIncomingMessages(boost::asio::yield_context yc)
|
2015-02-27 14:18:20 -05:00
|
|
|
{
|
2024-08-29 08:14:20 -04:00
|
|
|
namespace ch = std::chrono;
|
|
|
|
|
|
|
|
|
|
auto toMilliseconds ([](ch::steady_clock::duration d) {
|
|
|
|
|
return ch::duration_cast<ch::milliseconds>(d).count();
|
|
|
|
|
});
|
|
|
|
|
|
2020-02-13 12:18:58 -05:00
|
|
|
m_Stream->next_layer().SetSeen(&m_Seen);
|
|
|
|
|
|
2024-10-31 09:19:05 -04:00
|
|
|
while (!m_ShuttingDown) {
|
2024-08-29 08:14:20 -04:00
|
|
|
String jsonString;
|
2019-02-19 07:57:36 -05:00
|
|
|
|
|
|
|
|
try {
|
2024-08-29 08:14:20 -04:00
|
|
|
jsonString = JsonRpc::ReadMessage(m_Stream, yc, m_Endpoint ? -1 : 1024 * 1024);
|
2019-02-19 07:57:36 -05:00
|
|
|
} catch (const std::exception& ex) {
|
2021-03-04 10:23:03 -05:00
|
|
|
Log(m_ShuttingDown ? LogDebug : LogNotice, "JsonRpcConnection")
|
|
|
|
|
<< "Error while reading JSON-RPC message for identity '" << m_Identity
|
|
|
|
|
<< "': " << DiagnosticInformation(ex);
|
2019-02-19 07:57:36 -05:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-20 07:49:50 -05:00
|
|
|
m_Seen = Utility::GetTime();
|
2024-08-29 08:14:20 -04:00
|
|
|
if (m_Endpoint) {
|
|
|
|
|
m_Endpoint->AddMessageReceived(jsonString.GetLength());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String rpcMethod("UNKNOWN");
|
|
|
|
|
ch::steady_clock::duration cpuBoundDuration(0);
|
|
|
|
|
auto start (ch::steady_clock::now());
|
2019-02-20 07:49:50 -05:00
|
|
|
|
2019-02-19 07:57:36 -05:00
|
|
|
try {
|
|
|
|
|
CpuBoundWork handleMessage (yc);
|
|
|
|
|
|
2024-08-29 08:14:20 -04:00
|
|
|
// Cache the elapsed time to acquire a CPU semaphore used to detect extremely heavy workloads.
|
|
|
|
|
cpuBoundDuration = ch::steady_clock::now() - start;
|
|
|
|
|
|
|
|
|
|
Dictionary::Ptr message = JsonRpc::DecodeMessage(jsonString);
|
|
|
|
|
if (String method = message->Get("method"); !method.IsEmpty()) {
|
|
|
|
|
rpcMethod = std::move(method);
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-19 07:57:36 -05:00
|
|
|
MessageHandler(message);
|
2024-02-08 05:30:23 -05:00
|
|
|
|
|
|
|
|
l_TaskStats.InsertValue(Utility::GetTime(), 1);
|
2024-08-29 08:14:20 -04:00
|
|
|
|
|
|
|
|
auto total = ch::steady_clock::now() - start;
|
2025-09-08 11:52:18 -04:00
|
|
|
if (m_Endpoint) {
|
|
|
|
|
m_Endpoint->AddMessageProcessed(total);
|
|
|
|
|
}
|
2024-08-29 08:14:20 -04:00
|
|
|
|
|
|
|
|
Log msg(total >= ch::seconds(5) ? LogWarning : LogDebug, "JsonRpcConnection");
|
|
|
|
|
msg << "Processed JSON-RPC '" << rpcMethod << "' message for identity '" << m_Identity
|
|
|
|
|
<< "' (took total " << toMilliseconds(total) << "ms";
|
|
|
|
|
|
|
|
|
|
if (cpuBoundDuration >= ch::seconds(1)) {
|
|
|
|
|
msg << ", waited " << toMilliseconds(cpuBoundDuration) << "ms on semaphore";
|
|
|
|
|
}
|
|
|
|
|
msg << ").";
|
2019-02-19 07:57:36 -05:00
|
|
|
} catch (const std::exception& ex) {
|
2024-08-29 08:14:20 -04:00
|
|
|
auto total = ch::steady_clock::now() - start;
|
|
|
|
|
|
|
|
|
|
Log msg(m_ShuttingDown ? LogDebug : LogWarning, "JsonRpcConnection");
|
|
|
|
|
msg << "Error while processing JSON-RPC '" << rpcMethod << "' message for identity '"
|
|
|
|
|
<< m_Identity << "' (took total " << toMilliseconds(total) << "ms";
|
|
|
|
|
|
|
|
|
|
if (cpuBoundDuration >= ch::seconds(1)) {
|
|
|
|
|
msg << ", waited " << toMilliseconds(cpuBoundDuration) << "ms on semaphore";
|
|
|
|
|
}
|
|
|
|
|
msg << "): " << DiagnosticInformation(ex);
|
2019-02-19 07:57:36 -05:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-06-14 02:19:13 -04:00
|
|
|
}
|
2019-09-09 04:53:37 -04:00
|
|
|
|
|
|
|
|
Disconnect();
|
2019-02-19 07:57:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void JsonRpcConnection::WriteOutgoingMessages(boost::asio::yield_context yc)
|
|
|
|
|
{
|
2019-02-22 10:13:28 -05:00
|
|
|
Defer signalWriterDone ([this]() { m_WriterDone.Set(); });
|
2019-02-19 07:57:36 -05:00
|
|
|
|
|
|
|
|
do {
|
2019-02-22 10:13:28 -05:00
|
|
|
m_OutgoingMessagesQueued.Wait(yc);
|
2019-02-19 07:57:36 -05:00
|
|
|
|
|
|
|
|
auto queue (std::move(m_OutgoingMessagesQueue));
|
|
|
|
|
|
|
|
|
|
m_OutgoingMessagesQueue.clear();
|
2019-02-22 10:13:28 -05:00
|
|
|
m_OutgoingMessagesQueued.Clear();
|
2017-11-21 08:07:44 -05:00
|
|
|
|
2019-02-19 07:57:36 -05:00
|
|
|
if (!queue.empty()) {
|
|
|
|
|
try {
|
|
|
|
|
for (auto& message : queue) {
|
2024-11-07 11:32:12 -05:00
|
|
|
if (m_ShuttingDown) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-26 05:13:34 -05:00
|
|
|
size_t bytesSent = JsonRpc::SendRawMessage(m_Stream, message, yc);
|
2019-02-19 07:57:36 -05:00
|
|
|
|
|
|
|
|
if (m_Endpoint) {
|
|
|
|
|
m_Endpoint->AddMessageSent(bytesSent);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_Stream->async_flush(yc);
|
|
|
|
|
} catch (const std::exception& ex) {
|
2021-03-04 10:23:03 -05:00
|
|
|
Log(m_ShuttingDown ? LogDebug : LogWarning, "JsonRpcConnection")
|
|
|
|
|
<< "Error while sending JSON-RPC message for identity '"
|
|
|
|
|
<< m_Identity << "'\n" << DiagnosticInformation(ex);
|
2019-02-19 07:57:36 -05:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-02-20 06:00:11 -05:00
|
|
|
} while (!m_ShuttingDown);
|
2019-09-09 04:53:37 -04:00
|
|
|
|
|
|
|
|
Disconnect();
|
2014-05-03 14:02:22 -04:00
|
|
|
}
|
|
|
|
|
|
2018-01-03 22:25:35 -05:00
|
|
|
double JsonRpcConnection::GetTimestamp() const
|
2016-01-25 04:57:06 -05:00
|
|
|
{
|
|
|
|
|
return m_Timestamp;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-03 22:25:35 -05:00
|
|
|
String JsonRpcConnection::GetIdentity() const
|
2014-05-08 09:00:09 -04:00
|
|
|
{
|
|
|
|
|
return m_Identity;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-03 22:25:35 -05:00
|
|
|
bool JsonRpcConnection::IsAuthenticated() const
|
2014-10-16 03:01:18 -04:00
|
|
|
{
|
|
|
|
|
return m_Authenticated;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-03 22:25:35 -05:00
|
|
|
Endpoint::Ptr JsonRpcConnection::GetEndpoint() const
|
2014-05-03 14:02:22 -04:00
|
|
|
{
|
|
|
|
|
return m_Endpoint;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-25 08:34:29 -04:00
|
|
|
Shared<AsioTlsStream>::Ptr JsonRpcConnection::GetStream() const
|
2014-05-03 14:02:22 -04:00
|
|
|
{
|
|
|
|
|
return m_Stream;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-03 22:25:35 -05:00
|
|
|
ConnectionRole JsonRpcConnection::GetRole() const
|
2014-05-03 14:02:22 -04:00
|
|
|
{
|
|
|
|
|
return m_Role;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-22 05:11:21 -04:00
|
|
|
void JsonRpcConnection::SendMessage(const Dictionary::Ptr& message)
|
2014-05-03 14:02:22 -04:00
|
|
|
{
|
2024-02-07 07:56:31 -05:00
|
|
|
if (m_ShuttingDown) {
|
2024-02-21 06:04:40 -05:00
|
|
|
BOOST_THROW_EXCEPTION(std::runtime_error("Cannot send message to already disconnected API client '" + GetIdentity() + "'!"));
|
2024-02-07 07:56:31 -05:00
|
|
|
}
|
|
|
|
|
|
2020-02-17 10:12:07 -05:00
|
|
|
Ptr keepAlive (this);
|
|
|
|
|
|
2025-01-07 11:53:42 -05:00
|
|
|
boost::asio::post(m_IoStrand, [this, keepAlive, message] { SendMessageInternal(message); });
|
2019-02-26 04:17:10 -05:00
|
|
|
}
|
|
|
|
|
|
2019-02-26 05:13:34 -05:00
|
|
|
void JsonRpcConnection::SendRawMessage(const String& message)
|
|
|
|
|
{
|
2024-02-07 07:56:31 -05:00
|
|
|
if (m_ShuttingDown) {
|
2024-02-21 06:04:40 -05:00
|
|
|
BOOST_THROW_EXCEPTION(std::runtime_error("Cannot send message to already disconnected API client '" + GetIdentity() + "'!"));
|
2024-02-07 07:56:31 -05:00
|
|
|
}
|
|
|
|
|
|
2020-02-17 10:12:07 -05:00
|
|
|
Ptr keepAlive (this);
|
|
|
|
|
|
2025-01-07 11:53:42 -05:00
|
|
|
boost::asio::post(m_IoStrand, [this, keepAlive, message] {
|
2024-02-07 07:56:31 -05:00
|
|
|
if (m_ShuttingDown) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-26 05:13:34 -05:00
|
|
|
m_OutgoingMessagesQueue.emplace_back(message);
|
|
|
|
|
m_OutgoingMessagesQueued.Set();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-26 04:17:10 -05:00
|
|
|
void JsonRpcConnection::SendMessageInternal(const Dictionary::Ptr& message)
|
|
|
|
|
{
|
2024-02-07 07:56:31 -05:00
|
|
|
if (m_ShuttingDown) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-26 05:13:34 -05:00
|
|
|
m_OutgoingMessagesQueue.emplace_back(JsonEncode(message));
|
2019-02-26 04:17:10 -05:00
|
|
|
m_OutgoingMessagesQueued.Set();
|
2016-01-27 10:43:23 -05:00
|
|
|
}
|
|
|
|
|
|
2019-02-20 06:00:11 -05:00
|
|
|
void JsonRpcConnection::Disconnect()
|
|
|
|
|
{
|
|
|
|
|
namespace asio = boost::asio;
|
|
|
|
|
|
2024-02-07 07:46:13 -05:00
|
|
|
if (!m_ShuttingDown.exchange(true)) {
|
|
|
|
|
JsonRpcConnection::Ptr keepAlive (this);
|
2019-02-20 06:00:11 -05:00
|
|
|
|
2024-11-25 05:30:10 -05:00
|
|
|
Log(LogNotice, "JsonRpcConnection")
|
|
|
|
|
<< "Disconnecting API client for identity '" << m_Identity << "'";
|
2019-02-20 06:00:11 -05:00
|
|
|
|
2024-11-25 05:30:10 -05:00
|
|
|
IoEngine::SpawnCoroutine(m_IoStrand, [this, keepAlive](asio::yield_context yc) {
|
2019-02-22 10:13:28 -05:00
|
|
|
m_OutgoingMessagesQueued.Set();
|
2019-02-20 06:00:11 -05:00
|
|
|
|
2024-11-28 05:06:44 -05:00
|
|
|
{
|
|
|
|
|
Timeout writerTimeout(
|
|
|
|
|
m_IoStrand,
|
|
|
|
|
boost::posix_time::seconds(5),
|
|
|
|
|
[this]() {
|
|
|
|
|
// The writer coroutine could not finish soon enough to unblock the waiter down blow,
|
|
|
|
|
// so we have to do this on our own, and the coroutine will be terminated forcibly when
|
|
|
|
|
// the ops on the underlying socket are cancelled.
|
|
|
|
|
boost::system::error_code ec;
|
|
|
|
|
m_Stream->lowest_layer().cancel(ec);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
m_WriterDone.Wait(yc);
|
|
|
|
|
// We don't need to explicitly cancel the timer here; its destructor will handle it for us.
|
|
|
|
|
}
|
2019-02-20 06:00:11 -05:00
|
|
|
|
2019-09-09 07:10:12 -04:00
|
|
|
m_CheckLivenessTimer.cancel();
|
|
|
|
|
m_HeartbeatTimer.cancel();
|
2019-09-09 03:26:12 -04:00
|
|
|
|
2024-02-12 11:02:35 -05:00
|
|
|
m_Stream->GracefulDisconnect(m_IoStrand, yc);
|
2024-10-31 05:19:40 -04:00
|
|
|
|
|
|
|
|
if (m_Endpoint) {
|
|
|
|
|
m_Endpoint->RemoveClient(this);
|
|
|
|
|
} else {
|
|
|
|
|
ApiListener::GetInstance()->RemoveAnonymousClient(this);
|
|
|
|
|
}
|
2024-11-25 05:30:10 -05:00
|
|
|
|
2025-06-06 03:53:03 -04:00
|
|
|
Log(LogInformation, "JsonRpcConnection")
|
2024-11-25 05:30:10 -05:00
|
|
|
<< "API client disconnected for identity '" << m_Identity << "'";
|
2024-02-07 07:46:13 -05:00
|
|
|
});
|
|
|
|
|
}
|
2019-02-20 06:00:11 -05:00
|
|
|
}
|
|
|
|
|
|
2024-08-29 08:14:20 -04:00
|
|
|
/**
|
|
|
|
|
* Route the provided message to its corresponding handler (if any).
|
|
|
|
|
*
|
|
|
|
|
* This will first verify the timestamp of that RPC message (if any) and subsequently, rejects any message whose
|
|
|
|
|
* timestamp is less than the remote log position of the client Endpoint; otherwise, the endpoint's remote log
|
|
|
|
|
* position is updated to that timestamp. It is not expected to happen, but any message lacking an RPC method or
|
|
|
|
|
* referring to a non-existent one is also discarded. Afterward, the RPC handler is then called for that message
|
|
|
|
|
* and sends it's result back to the sender if the message contains an ID.
|
|
|
|
|
*
|
|
|
|
|
* @param message The RPC message you want to process.
|
|
|
|
|
*/
|
|
|
|
|
void JsonRpcConnection::MessageHandler(const Dictionary::Ptr& message)
|
2016-01-27 10:43:23 -05:00
|
|
|
{
|
2025-06-06 03:53:03 -04:00
|
|
|
std::shared_lock wgLock(*m_WaitGroup, std::try_to_lock);
|
|
|
|
|
if (!wgLock) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-08 09:00:09 -04:00
|
|
|
if (m_Endpoint && message->Contains("ts")) {
|
2014-05-03 14:02:22 -04:00
|
|
|
double ts = message->Get("ts");
|
|
|
|
|
|
|
|
|
|
/* ignore old messages */
|
|
|
|
|
if (ts < m_Endpoint->GetRemoteLogPosition())
|
2016-01-27 09:45:58 -05:00
|
|
|
return;
|
2014-05-03 14:02:22 -04:00
|
|
|
|
|
|
|
|
m_Endpoint->SetRemoteLogPosition(ts);
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-04 08:47:44 -04:00
|
|
|
MessageOrigin::Ptr origin = new MessageOrigin();
|
|
|
|
|
origin->FromClient = this;
|
2014-05-03 14:02:22 -04:00
|
|
|
|
2014-05-08 09:00:09 -04:00
|
|
|
if (m_Endpoint) {
|
|
|
|
|
if (m_Endpoint->GetZone() != Zone::GetLocalZone())
|
2015-08-04 08:47:44 -04:00
|
|
|
origin->FromZone = m_Endpoint->GetZone();
|
2014-05-08 09:00:09 -04:00
|
|
|
else
|
2015-08-04 08:47:44 -04:00
|
|
|
origin->FromZone = Zone::GetByName(message->Get("originZone"));
|
2014-05-08 09:00:09 -04:00
|
|
|
}
|
2014-05-03 14:02:22 -04:00
|
|
|
|
2017-08-29 08:37:13 -04:00
|
|
|
Value vmethod;
|
|
|
|
|
|
|
|
|
|
if (!message->Get("method", &vmethod)) {
|
|
|
|
|
Value vid;
|
|
|
|
|
|
|
|
|
|
if (!message->Get("id", &vid))
|
|
|
|
|
return;
|
|
|
|
|
|
2017-09-07 04:39:00 -04:00
|
|
|
Log(LogWarning, "JsonRpcConnection",
|
2017-12-19 09:50:05 -05:00
|
|
|
"We received a JSON-RPC response message. This should never happen because we're only ever sending notifications.");
|
2017-08-29 08:37:13 -04:00
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String method = vmethod;
|
2014-05-03 14:02:22 -04:00
|
|
|
|
2015-06-22 05:11:21 -04:00
|
|
|
Log(LogNotice, "JsonRpcConnection")
|
2019-08-15 03:29:05 -04:00
|
|
|
<< "Received '" << method << "' message from identity '" << m_Identity << "'.";
|
2014-05-03 14:02:22 -04:00
|
|
|
|
2014-11-08 15:17:16 -05:00
|
|
|
Dictionary::Ptr resultMessage = new Dictionary();
|
2014-05-03 14:02:22 -04:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
ApiFunction::Ptr afunc = ApiFunction::GetByName(method);
|
|
|
|
|
|
2017-11-27 06:09:42 -05:00
|
|
|
if (!afunc) {
|
|
|
|
|
Log(LogNotice, "JsonRpcConnection")
|
2017-12-19 09:50:05 -05:00
|
|
|
<< "Call to non-existent function '" << method << "' from endpoint '" << m_Identity << "'.";
|
2017-11-27 06:09:42 -05:00
|
|
|
} else {
|
2025-04-01 09:38:38 -04:00
|
|
|
if (m_Endpoint) {
|
|
|
|
|
m_Endpoint->AddMessageReceived(afunc);
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-31 04:17:49 -05:00
|
|
|
Dictionary::Ptr params = message->Get("params");
|
|
|
|
|
if (params)
|
|
|
|
|
resultMessage->Set("result", afunc->Invoke(origin, params));
|
|
|
|
|
else
|
|
|
|
|
resultMessage->Set("result", Empty);
|
2017-11-27 06:09:42 -05:00
|
|
|
}
|
2014-08-25 02:35:35 -04:00
|
|
|
} catch (const std::exception& ex) {
|
2015-09-22 11:58:12 -04:00
|
|
|
/* TODO: Add a user readable error message for the remote caller */
|
2017-08-30 09:12:24 -04:00
|
|
|
String diagInfo = DiagnosticInformation(ex);
|
|
|
|
|
resultMessage->Set("error", diagInfo);
|
2015-06-22 05:11:21 -04:00
|
|
|
Log(LogWarning, "JsonRpcConnection")
|
2017-12-19 09:50:05 -05:00
|
|
|
<< "Error while processing message for identity '" << m_Identity << "'\n" << diagInfo;
|
2014-05-03 14:02:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (message->Contains("id")) {
|
|
|
|
|
resultMessage->Set("jsonrpc", "2.0");
|
|
|
|
|
resultMessage->Set("id", message->Get("id"));
|
2016-02-01 02:35:55 -05:00
|
|
|
|
2019-02-26 04:17:10 -05:00
|
|
|
SendMessageInternal(resultMessage);
|
2019-02-19 07:57:36 -05:00
|
|
|
}
|
2014-05-03 14:02:22 -04:00
|
|
|
}
|
|
|
|
|
|
2015-08-04 08:47:44 -04:00
|
|
|
Value SetLogPositionHandler(const MessageOrigin::Ptr& origin, const Dictionary::Ptr& params)
|
2014-05-03 14:02:22 -04:00
|
|
|
{
|
|
|
|
|
double log_position = params->Get("log_position");
|
2015-08-04 08:47:44 -04:00
|
|
|
Endpoint::Ptr endpoint = origin->FromClient->GetEndpoint();
|
2014-05-03 14:02:22 -04:00
|
|
|
|
2014-05-08 09:00:09 -04:00
|
|
|
if (!endpoint)
|
|
|
|
|
return Empty;
|
|
|
|
|
|
2014-05-03 14:02:22 -04:00
|
|
|
if (log_position > endpoint->GetLocalLogPosition())
|
|
|
|
|
endpoint->SetLocalLogPosition(log_position);
|
|
|
|
|
|
|
|
|
|
return Empty;
|
|
|
|
|
}
|
2014-10-16 06:27:09 -04:00
|
|
|
|
2019-02-20 07:49:50 -05:00
|
|
|
void JsonRpcConnection::CheckLiveness(boost::asio::yield_context yc)
|
|
|
|
|
{
|
2019-06-05 04:32:20 -04:00
|
|
|
boost::system::error_code ec;
|
2019-02-20 07:49:50 -05:00
|
|
|
|
2020-11-12 11:32:07 -05:00
|
|
|
if (!m_Authenticated) {
|
|
|
|
|
/* Anonymous connections are normally only used for requesting a certificate and are closed after this request
|
|
|
|
|
* is received. However, the request is only sent if the child has successfully verified the certificate of its
|
|
|
|
|
* parent so that it is an authenticated connection from its perspective. In case this verification fails, both
|
|
|
|
|
* ends view it as an anonymous connection and never actually use it but attempt a reconnect after 10 seconds
|
|
|
|
|
* leaking the connection. Therefore close it after a timeout.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
m_CheckLivenessTimer.expires_from_now(boost::posix_time::seconds(10));
|
2019-06-05 04:32:20 -04:00
|
|
|
m_CheckLivenessTimer.async_wait(yc[ec]);
|
2019-02-20 07:49:50 -05:00
|
|
|
|
|
|
|
|
if (m_ShuttingDown) {
|
2020-11-12 11:32:07 -05:00
|
|
|
return;
|
2019-02-20 07:49:50 -05:00
|
|
|
}
|
|
|
|
|
|
2020-11-12 11:32:07 -05:00
|
|
|
auto remote (m_Stream->lowest_layer().remote_endpoint());
|
2019-02-20 07:49:50 -05:00
|
|
|
|
2020-11-12 11:32:07 -05:00
|
|
|
Log(LogInformation, "JsonRpcConnection")
|
|
|
|
|
<< "Closing anonymous connection [" << remote.address() << "]:" << remote.port() << " after 10 seconds.";
|
|
|
|
|
|
|
|
|
|
Disconnect();
|
|
|
|
|
} else {
|
|
|
|
|
for (;;) {
|
|
|
|
|
m_CheckLivenessTimer.expires_from_now(boost::posix_time::seconds(30));
|
|
|
|
|
m_CheckLivenessTimer.async_wait(yc[ec]);
|
|
|
|
|
|
|
|
|
|
if (m_ShuttingDown) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_Seen < Utility::GetTime() - 60 && (!m_Endpoint || !m_Endpoint->GetSyncing())) {
|
|
|
|
|
Log(LogInformation, "JsonRpcConnection")
|
|
|
|
|
<< "No messages for identity '" << m_Identity << "' have been received in the last 60 seconds.";
|
|
|
|
|
|
|
|
|
|
Disconnect();
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-02-20 07:49:50 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-02-20 08:24:09 -05:00
|
|
|
|
|
|
|
|
double JsonRpcConnection::GetWorkQueueRate()
|
|
|
|
|
{
|
|
|
|
|
return l_TaskStats.UpdateAndGetValues(Utility::GetTime(), 60) / 60.0;
|
|
|
|
|
}
|