2016-08-16 16:51:22 +02:00
|
|
|
/*
|
2017-11-09 19:34:51 +01:00
|
|
|
* This file is part of the Flowee project
|
2019-03-09 16:36:13 +01:00
|
|
|
* Copyright (C) 2016, 2019 Tom Zander <tomz@freedommail.ch>
|
2016-08-16 16:51:22 +02:00
|
|
|
*
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
2018-02-15 19:50:12 +01:00
|
|
|
#include "APIServer.h"
|
|
|
|
|
#include "APIRPCBinding.h"
|
|
|
|
|
#include "APIProtocol.h"
|
2016-08-16 16:51:22 +02:00
|
|
|
|
|
|
|
|
#include "streaming/MessageBuilder.h"
|
|
|
|
|
#include "streaming/MessageParser.h"
|
|
|
|
|
|
2017-03-08 15:31:28 -08:00
|
|
|
#include "chainparamsbase.h"
|
|
|
|
|
#include "netbase.h"
|
2016-08-16 16:51:22 +02:00
|
|
|
#include "util.h"
|
|
|
|
|
#include "utilstrencodings.h"
|
|
|
|
|
#include "random.h"
|
|
|
|
|
#include "rpcserver.h"
|
|
|
|
|
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <functional>
|
|
|
|
|
|
2019-03-26 19:37:33 +01:00
|
|
|
// the amount of seconds after which we disconnect incoming connections that have done anything yet.
|
|
|
|
|
#define INTRODUCTION_TIMEOUT 4
|
2016-08-16 16:51:22 +02:00
|
|
|
|
2019-08-12 23:48:46 +02:00
|
|
|
#ifdef __linux__
|
|
|
|
|
#ifndef _GNU_SOURCE
|
|
|
|
|
# define _GNU_SOURCE /* To get defns of NI_MAXSERV and NI_MAXHOST */
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
std::deque<std::string> allInterfaces() {
|
|
|
|
|
std::deque<std::string> answer;
|
|
|
|
|
|
|
|
|
|
struct ifaddrs *ifaddr;
|
|
|
|
|
if (getifaddrs(&ifaddr) == -1)
|
|
|
|
|
return answer;
|
|
|
|
|
|
|
|
|
|
for (struct ifaddrs *ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
|
|
|
|
|
if (ifa->ifa_addr == nullptr)
|
|
|
|
|
continue;
|
|
|
|
|
int family = ifa->ifa_addr->sa_family;
|
|
|
|
|
if (family != AF_INET && family != AF_INET6)
|
|
|
|
|
continue;
|
|
|
|
|
char host[NI_MAXHOST];
|
|
|
|
|
int s = getnameinfo(ifa->ifa_addr,
|
|
|
|
|
(family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
|
|
|
|
|
host, NI_MAXHOST,
|
|
|
|
|
nullptr, 0, NI_NUMERICHOST);
|
|
|
|
|
if (s == 0)
|
|
|
|
|
answer.push_back(std::string(host));
|
|
|
|
|
}
|
|
|
|
|
freeifaddrs(ifaddr);
|
|
|
|
|
return answer;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2018-02-15 19:50:12 +01:00
|
|
|
Api::Server::Server(boost::asio::io_service &service)
|
2016-08-16 16:51:22 +02:00
|
|
|
: m_networkManager(service),
|
|
|
|
|
m_timerRunning(false),
|
|
|
|
|
m_newConnectionTimeout(service)
|
|
|
|
|
{
|
2019-12-12 17:48:48 +01:00
|
|
|
uint16_t defaultPort = BaseParams().ApiServerPort();
|
2019-05-24 23:14:15 +02:00
|
|
|
using boost::asio::ip::tcp;
|
|
|
|
|
std::list<tcp::endpoint> endpoints;
|
2017-03-08 15:31:28 -08:00
|
|
|
|
2018-02-15 19:50:12 +01:00
|
|
|
if (mapArgs.count("-apilisten")) {
|
|
|
|
|
for (auto strAddress : mapMultiArgs["-apilisten"]) {
|
2019-06-02 20:16:49 +02:00
|
|
|
uint16_t port = defaultPort;
|
2017-03-08 15:31:28 -08:00
|
|
|
std::string host;
|
|
|
|
|
SplitHostPort(strAddress, port, host);
|
2019-05-24 23:14:15 +02:00
|
|
|
if (host.empty()) {
|
2017-03-08 15:31:28 -08:00
|
|
|
host = "127.0.0.1";
|
2019-05-24 23:14:15 +02:00
|
|
|
} else if (host == "localhost") {
|
|
|
|
|
endpoints.push_back(tcp::endpoint(boost::asio::ip::address_v4::loopback(), port));
|
|
|
|
|
endpoints.push_back(tcp::endpoint(boost::asio::ip::address_v6::loopback(), port));
|
|
|
|
|
continue;
|
2019-08-12 23:48:46 +02:00
|
|
|
#ifdef __linux__
|
|
|
|
|
} else if (host == "0.0.0.0") {
|
|
|
|
|
for (auto iface : allInterfaces()) {
|
|
|
|
|
endpoints.push_back(tcp::endpoint(boost::asio::ip::address::from_string(iface), port));
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
#endif
|
2019-05-24 23:14:15 +02:00
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
endpoints.push_back(tcp::endpoint(boost::asio::ip::address::from_string(host), port));
|
|
|
|
|
} catch (std::runtime_error &e) {
|
|
|
|
|
logCritical(Log::ApiServer) << "Bind port needs to be an API address. Parsing failed with" << e;
|
|
|
|
|
}
|
2017-03-08 15:31:28 -08:00
|
|
|
}
|
|
|
|
|
} else {
|
2019-05-24 23:14:15 +02:00
|
|
|
endpoints.push_back(tcp::endpoint(boost::asio::ip::address_v4::loopback(), defaultPort));
|
|
|
|
|
endpoints.push_back(tcp::endpoint(boost::asio::ip::address_v6::loopback(), defaultPort));
|
2017-03-08 15:31:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto endpoint : endpoints) {
|
|
|
|
|
try {
|
2018-02-15 19:50:12 +01:00
|
|
|
m_networkManager.bind(endpoint, std::bind(&Api::Server::newConnection, this, std::placeholders::_1));
|
2019-05-24 23:14:15 +02:00
|
|
|
logInfo(Log::ApiServer) << "Api Server listening on" << endpoint;
|
2017-03-08 15:31:28 -08:00
|
|
|
} catch (const std::exception &e) {
|
2019-05-24 23:14:15 +02:00
|
|
|
logCritical(Log::ApiServer) << "Api Server failed to listen on" << endpoint << "due to:" << e;
|
2017-03-08 15:31:28 -08:00
|
|
|
}
|
|
|
|
|
}
|
2016-08-16 16:51:22 +02:00
|
|
|
}
|
|
|
|
|
|
2018-02-17 14:27:49 +01:00
|
|
|
void Api::Server::addService(NetworkService *service)
|
|
|
|
|
{
|
|
|
|
|
m_networkManager.addService(service);
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-15 19:50:12 +01:00
|
|
|
void Api::Server::newConnection(NetworkConnection &connection)
|
2016-08-16 16:51:22 +02:00
|
|
|
{
|
2019-06-10 17:06:27 +02:00
|
|
|
boost::mutex::scoped_lock lock(m_mutex);
|
|
|
|
|
logDebug() << "server newConnection";
|
|
|
|
|
NewConnection con;
|
2019-03-26 19:37:33 +01:00
|
|
|
connection.setOnIncomingMessage(std::bind(&Api::Server::incomingMessage, this, std::placeholders::_1));
|
2018-02-15 19:50:12 +01:00
|
|
|
connection.setOnDisconnected(std::bind(&Api::Server::connectionRemoved, this, std::placeholders::_1));
|
2016-08-16 16:51:22 +02:00
|
|
|
connection.accept();
|
|
|
|
|
con.connection = std::move(connection);
|
2019-03-26 19:37:33 +01:00
|
|
|
con.initialConnectionTime = boost::posix_time::second_clock::universal_time();
|
2016-08-16 16:51:22 +02:00
|
|
|
|
|
|
|
|
m_newConnections.push_back(std::move(con));
|
|
|
|
|
|
|
|
|
|
if (!m_timerRunning) {
|
|
|
|
|
m_timerRunning = true;
|
2019-03-26 19:37:33 +01:00
|
|
|
m_newConnectionTimeout.expires_from_now(boost::posix_time::seconds(INTRODUCTION_TIMEOUT));
|
2018-02-15 19:50:12 +01:00
|
|
|
m_newConnectionTimeout.async_wait(std::bind(&Api::Server::checkConnections, this, std::placeholders::_1));
|
2016-08-16 16:51:22 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-15 19:50:12 +01:00
|
|
|
void Api::Server::connectionRemoved(const EndPoint &endPoint)
|
2016-08-16 16:51:22 +02:00
|
|
|
{
|
|
|
|
|
boost::mutex::scoped_lock lock(m_mutex);
|
|
|
|
|
auto iter = m_newConnections.begin();
|
|
|
|
|
while (iter != m_newConnections.end()) {
|
|
|
|
|
if (iter->connection.connectionId() == endPoint.connectionId) {
|
|
|
|
|
m_newConnections.erase(iter);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
++iter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto conIter = m_connections.begin();
|
|
|
|
|
while (conIter != m_connections.end()) {
|
|
|
|
|
if ((*conIter)->m_connection.connectionId() == endPoint.connectionId) {
|
|
|
|
|
m_connections.erase(conIter);
|
|
|
|
|
delete *conIter;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
++conIter;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-26 19:37:33 +01:00
|
|
|
void Api::Server::incomingMessage(const Message &message)
|
2016-08-16 16:51:22 +02:00
|
|
|
{
|
2019-06-10 17:06:27 +02:00
|
|
|
logDebug() << "incomingMessage";
|
|
|
|
|
Connection *handler;
|
2019-04-10 17:55:08 +02:00
|
|
|
{
|
|
|
|
|
boost::mutex::scoped_lock lock(m_mutex);
|
2019-06-10 17:06:27 +02:00
|
|
|
bool found = false;
|
2019-04-10 17:55:08 +02:00
|
|
|
auto iter = m_newConnections.begin();
|
|
|
|
|
while (iter != m_newConnections.end()) {
|
|
|
|
|
if (iter->connection.connectionId() == message.remote) {
|
|
|
|
|
m_newConnections.erase(iter);
|
2019-06-10 17:06:27 +02:00
|
|
|
found = true;
|
2019-04-10 17:55:08 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
++iter;
|
2016-08-16 16:51:22 +02:00
|
|
|
}
|
2019-06-10 17:06:27 +02:00
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
|
return;
|
|
|
|
|
NetworkConnection con(&m_networkManager, message.remote);
|
|
|
|
|
assert(con.isValid());
|
|
|
|
|
con.setOnDisconnected(std::bind(&Api::Server::connectionRemoved, this, std::placeholders::_1));
|
|
|
|
|
|
|
|
|
|
handler = new Connection(std::move(con));
|
|
|
|
|
m_connections.push_back(handler);
|
2016-08-16 16:51:22 +02:00
|
|
|
}
|
2019-03-26 19:37:33 +01:00
|
|
|
handler->incomingMessage(message);
|
2016-08-16 16:51:22 +02:00
|
|
|
}
|
|
|
|
|
|
2018-02-15 19:50:12 +01:00
|
|
|
void Api::Server::checkConnections(boost::system::error_code error)
|
2016-08-16 16:51:22 +02:00
|
|
|
{
|
|
|
|
|
if (error.value() == boost::asio::error::operation_aborted)
|
|
|
|
|
return;
|
|
|
|
|
boost::mutex::scoped_lock lock(m_mutex);
|
2019-03-26 19:37:33 +01:00
|
|
|
const auto disconnectTime = boost::posix_time::second_clock::universal_time()
|
|
|
|
|
- boost::posix_time::seconds(INTRODUCTION_TIMEOUT);
|
2016-08-16 16:51:22 +02:00
|
|
|
auto iter = m_newConnections.begin();
|
|
|
|
|
while (iter != m_newConnections.end()) {
|
2019-03-26 19:37:33 +01:00
|
|
|
if (iter->initialConnectionTime <= disconnectTime) {
|
|
|
|
|
logDebug() << "Calling disconnect on connection" << iter->connection.connectionId() << "now";
|
2016-08-16 16:51:22 +02:00
|
|
|
iter->connection.disconnect();
|
|
|
|
|
iter = m_newConnections.erase(iter);
|
|
|
|
|
} else {
|
|
|
|
|
++iter;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// restart timer if there is still something left.
|
|
|
|
|
if (!m_newConnections.empty()) {
|
|
|
|
|
m_timerRunning = true;
|
|
|
|
|
m_newConnectionTimeout.expires_from_now(boost::posix_time::seconds(1));
|
2018-02-15 19:50:12 +01:00
|
|
|
m_newConnectionTimeout.async_wait(std::bind(&Api::Server::checkConnections, this, std::placeholders::_1));
|
2016-08-16 16:51:22 +02:00
|
|
|
} else {
|
|
|
|
|
m_timerRunning = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-02-15 19:50:12 +01:00
|
|
|
Api::Server::Connection::Connection(NetworkConnection && connection)
|
2019-06-13 13:14:26 +02:00
|
|
|
: m_connection(std::move(connection)),
|
|
|
|
|
m_bufferPool(4000000) // default size is 4MB
|
2016-08-16 16:51:22 +02:00
|
|
|
{
|
2018-02-15 19:50:12 +01:00
|
|
|
m_connection.setOnIncomingMessage(std::bind(&Api::Server::Connection::incomingMessage, this, std::placeholders::_1));
|
2016-08-16 16:51:22 +02:00
|
|
|
}
|
|
|
|
|
|
2019-03-09 16:36:13 +01:00
|
|
|
Api::Server::Connection::~Connection()
|
|
|
|
|
{
|
|
|
|
|
for (auto iter = m_properties.begin(); iter != m_properties.end(); ++iter) {
|
|
|
|
|
delete iter->second;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-15 19:50:12 +01:00
|
|
|
void Api::Server::Connection::incomingMessage(const Message &message)
|
2016-08-16 16:51:22 +02:00
|
|
|
{
|
2019-03-27 18:44:26 +01:00
|
|
|
if (message.serviceId() >= 16) // not a service we handle
|
2018-03-26 17:07:10 +02:00
|
|
|
return;
|
2019-04-10 17:55:08 +02:00
|
|
|
if (message.serviceId() == APIService && message.messageId() == Meta::Version) {
|
|
|
|
|
Streaming::MessageBuilder builder(m_bufferPool);
|
|
|
|
|
std::ostringstream ss;
|
2019-12-12 17:48:48 +01:00
|
|
|
ss << "Flowee:" << HUB_SERIES << " (" << CLIENT_VERSION_MAJOR << "-";
|
2019-12-31 18:05:24 +01:00
|
|
|
ss.width(2);
|
|
|
|
|
ss.fill('0');
|
|
|
|
|
ss << CLIENT_VERSION_MINOR << ")";
|
2019-04-10 17:55:08 +02:00
|
|
|
builder.add(Meta::GenericByteData, ss.str());
|
2019-06-22 23:24:00 +02:00
|
|
|
m_connection.send(builder.reply(message));
|
2019-04-10 17:55:08 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-07 18:38:03 +01:00
|
|
|
std::unique_ptr<Api::Parser> parser;
|
2016-08-16 16:51:22 +02:00
|
|
|
try {
|
2019-03-07 18:38:03 +01:00
|
|
|
parser.reset(Api::createParser(message));
|
2016-08-16 16:51:22 +02:00
|
|
|
assert(parser.get()); // createParser should never return a nullptr
|
|
|
|
|
} catch (const std::exception &e) {
|
2018-03-19 22:40:50 +01:00
|
|
|
logWarning(Log::ApiServer) << e;
|
2016-08-16 16:51:22 +02:00
|
|
|
sendFailedMessage(message, e.what());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(parser.get());
|
2019-03-09 16:36:13 +01:00
|
|
|
assert(message.serviceId() < 0xFFFF);
|
|
|
|
|
assert(message.messageId() < 0xFFFF);
|
2019-12-12 17:48:48 +01:00
|
|
|
const uint32_t sessionDataId = (static_cast<uint32_t>(message.serviceId()) << 16) + static_cast<uint32_t>(message.messageId());
|
2019-03-09 16:36:13 +01:00
|
|
|
parser.get()->setSessionData(&m_properties[sessionDataId]);
|
2016-08-16 16:51:22 +02:00
|
|
|
|
2019-03-07 18:38:03 +01:00
|
|
|
auto *rpcParser = dynamic_cast<Api::RpcParser*>(parser.get());
|
2017-10-06 20:18:09 +02:00
|
|
|
if (rpcParser) {
|
|
|
|
|
assert(!rpcParser->method().empty());
|
2016-08-16 16:51:22 +02:00
|
|
|
try {
|
2017-10-06 20:18:09 +02:00
|
|
|
UniValue request(UniValue::VOBJ);
|
|
|
|
|
rpcParser->createRequest(message, request);
|
|
|
|
|
UniValue result;
|
|
|
|
|
try {
|
2018-03-19 22:40:50 +01:00
|
|
|
logInfo(Log::ApiServer) << rpcParser->method() << message.serviceId() << '/' << message.messageId();
|
2017-10-06 20:18:09 +02:00
|
|
|
result = tableRPC.execute(rpcParser->method(), request);
|
|
|
|
|
} catch (UniValue& objError) {
|
2018-03-19 22:40:50 +01:00
|
|
|
const std::string error = find_value(objError, "message").get_str();
|
|
|
|
|
logWarning(Log::ApiServer) << error;
|
|
|
|
|
sendFailedMessage(message, error);
|
2017-10-06 20:18:09 +02:00
|
|
|
return;
|
|
|
|
|
} catch(const std::exception &e) {
|
2018-03-19 22:40:50 +01:00
|
|
|
logWarning(Log::ApiServer) << e;
|
2017-10-06 20:18:09 +02:00
|
|
|
sendFailedMessage(message, std::string(e.what()));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-06-16 00:23:09 +02:00
|
|
|
int reserveSize = rpcParser->messageSize(result);
|
|
|
|
|
m_bufferPool.reserve(reserveSize);
|
2017-10-06 20:18:09 +02:00
|
|
|
Streaming::MessageBuilder builder(m_bufferPool);
|
|
|
|
|
rpcParser->buildReply(builder, result);
|
2019-06-22 23:24:00 +02:00
|
|
|
Message reply = builder.reply(message, rpcParser->replyMessageId());
|
2019-06-16 00:23:09 +02:00
|
|
|
if (reserveSize < reply.body().size())
|
|
|
|
|
logDebug(Log::ApiServer) << "Generated message larger than space reserved."
|
|
|
|
|
<< message.serviceId() << message.messageId()
|
|
|
|
|
<< "reserved:" << reserveSize << "built:" << reply.body().size();
|
|
|
|
|
assert(reply.body().size() <= reserveSize); // fail fast.
|
2017-10-06 20:18:09 +02:00
|
|
|
m_connection.send(reply);
|
2019-03-09 16:36:13 +01:00
|
|
|
} catch (const ParserException &e) {
|
|
|
|
|
logWarning(Log::ApiServer) << e;
|
|
|
|
|
sendFailedMessage(message, e.what());
|
|
|
|
|
return;
|
2017-10-06 20:18:09 +02:00
|
|
|
} catch (const std::exception &e) {
|
|
|
|
|
std::string error = "Interal Error " + std::string(e.what());
|
2018-02-15 19:50:12 +01:00
|
|
|
logCritical(Log::ApiServer) << "ApiServer internal error in parsing" << rpcParser->method() << e;
|
2017-10-06 20:18:09 +02:00
|
|
|
(void) m_bufferPool.commit(); // make sure the partial message is discarded
|
|
|
|
|
sendFailedMessage(message, error);
|
2016-08-16 16:51:22 +02:00
|
|
|
}
|
2017-10-06 20:18:09 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2019-03-07 18:38:03 +01:00
|
|
|
auto *directParser = dynamic_cast<Api::DirectParser*>(parser.get());
|
2019-03-08 17:59:17 +01:00
|
|
|
assert(directParser);
|
2017-10-06 20:18:09 +02:00
|
|
|
if (directParser) {
|
2019-06-16 00:23:09 +02:00
|
|
|
int reserveSize = 0;
|
2019-04-03 15:36:50 +02:00
|
|
|
try {
|
2019-06-16 00:23:09 +02:00
|
|
|
reserveSize = directParser->calculateMessageSize(message);
|
|
|
|
|
m_bufferPool.reserve(reserveSize);
|
2019-04-03 15:36:50 +02:00
|
|
|
} catch (const ParserException &e) {
|
|
|
|
|
logWarning(Log::ApiServer) << "calculateMessageSize() threw:" << e;
|
|
|
|
|
sendFailedMessage(message, e.what());
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-03-08 17:59:17 +01:00
|
|
|
logInfo(Log::ApiServer) << message.serviceId() << '/' << message.messageId();
|
2016-08-16 16:51:22 +02:00
|
|
|
Streaming::MessageBuilder builder(m_bufferPool);
|
2019-03-09 16:36:13 +01:00
|
|
|
try {
|
|
|
|
|
directParser->buildReply(message, builder);
|
2019-06-22 23:24:00 +02:00
|
|
|
Message reply = builder.reply(message, directParser->replyMessageId());
|
2019-06-16 00:23:09 +02:00
|
|
|
if (reserveSize < reply.body().size())
|
2019-06-13 12:30:20 +02:00
|
|
|
logDebug(Log::ApiServer) << "Generated message larger than space reserved."
|
|
|
|
|
<< message.serviceId() << message.messageId()
|
2019-06-16 00:23:09 +02:00
|
|
|
<< "reserved:" << reserveSize << "built:" << reply.body().size();
|
|
|
|
|
assert(reply.body().size() <= reserveSize); // fail fast.
|
2019-03-09 16:36:13 +01:00
|
|
|
m_connection.send(reply);
|
|
|
|
|
} catch (const ParserException &e) {
|
|
|
|
|
logWarning(Log::ApiServer) << e;
|
|
|
|
|
sendFailedMessage(message, e.what());
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-08-16 16:51:22 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-15 19:50:12 +01:00
|
|
|
void Api::Server::Connection::sendFailedMessage(const Message &origin, const std::string &failReason)
|
2016-08-16 16:51:22 +02:00
|
|
|
{
|
2018-03-26 17:07:10 +02:00
|
|
|
m_bufferPool.reserve(failReason.size() + 40);
|
2016-08-16 16:51:22 +02:00
|
|
|
Streaming::MessageBuilder builder(m_bufferPool);
|
2019-04-10 17:55:08 +02:00
|
|
|
builder.add(Meta::FailedReason, failReason);
|
|
|
|
|
builder.add(Meta::FailedCommandServiceId, origin.serviceId());
|
|
|
|
|
builder.add(Meta::FailedCommandId, origin.messageId());
|
|
|
|
|
Message answer = builder.message(APIService, Meta::CommandFailed);
|
|
|
|
|
const int requestId = origin.headerInt(RequestId);
|
2016-08-16 16:51:22 +02:00
|
|
|
if (requestId != -1)
|
2019-04-10 17:55:08 +02:00
|
|
|
answer.setHeaderInt(RequestId, requestId);
|
2016-08-16 16:51:22 +02:00
|
|
|
m_connection.send(answer);
|
|
|
|
|
}
|
2019-03-09 16:36:13 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Api::SessionData::~SessionData()
|
|
|
|
|
{
|
|
|
|
|
}
|