mirror of
https://github.com/binary-kitchen/doorlockd
synced 2024-12-22 18:34:25 +01:00
Big rewrite of several things
- Data type Token changed from uint64_t to std::string - Added new class "Request" that describes a JSON TCP request - Classes may now throw Responses for proper error handling - Removed JSON parsing from Logic - proper Error handling everywhere - Many small fixes - removed unnecessary includes - removed using namespace std everywhere
This commit is contained in:
parent
abf69d70fa
commit
49a5b88f6c
@ -67,6 +67,8 @@ set(LIBDOORLOCK_SRCS
|
|||||||
lib/logger.h
|
lib/logger.h
|
||||||
lib/logic.cpp
|
lib/logic.cpp
|
||||||
lib/logic.h
|
lib/logic.h
|
||||||
|
lib/request.cpp
|
||||||
|
lib/request.h
|
||||||
lib/response.cpp
|
lib/response.cpp
|
||||||
lib/response.h
|
lib/response.h
|
||||||
lib/util.cpp
|
lib/util.cpp
|
||||||
|
@ -71,7 +71,6 @@ static int doorlock_client(const std::string &hostname,
|
|||||||
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
|
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
|
||||||
tcp::resolver::iterator end;
|
tcp::resolver::iterator end;
|
||||||
boost::system::error_code error = ba::error::host_not_found;
|
boost::system::error_code error = ba::error::host_not_found;
|
||||||
size_t length;
|
|
||||||
std::vector<char> data;
|
std::vector<char> data;
|
||||||
|
|
||||||
while (error && endpoint_iterator != end) {
|
while (error && endpoint_iterator != end) {
|
||||||
@ -97,7 +96,8 @@ static int doorlock_client(const std::string &hostname,
|
|||||||
throw boost::system::system_error(ec);
|
throw boost::system::system_error(ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto message = Clientmessage::fromJson(std::string(data.begin(), data.begin()+length));
|
const auto message = Clientmessage::fromString(
|
||||||
|
std::string(data.begin(), data.begin()+length));
|
||||||
onDoorlockUpdate(message);
|
onDoorlockUpdate(message);
|
||||||
|
|
||||||
receiveMessage();
|
receiveMessage();
|
||||||
@ -107,13 +107,15 @@ static int doorlock_client(const std::string &hostname,
|
|||||||
receiveMessage();
|
receiveMessage();
|
||||||
io_service.run();
|
io_service.run();
|
||||||
}
|
}
|
||||||
catch(const std::exception &e)
|
catch(const Response &err) {
|
||||||
{
|
l(err.message, LogLevel::error);
|
||||||
l(LogLevel::error, e.what());
|
retval = -1;
|
||||||
goto out;
|
}
|
||||||
|
catch(const std::exception &err) {
|
||||||
|
l(LogLevel::error, err.what());
|
||||||
|
retval = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,24 +9,22 @@
|
|||||||
|
|
||||||
#include "daemon.h"
|
#include "daemon.h"
|
||||||
|
|
||||||
using namespace std;
|
void daemonize(const std::string &dir,
|
||||||
|
const std::string &stdinfile,
|
||||||
void daemonize(const string &dir,
|
const std::string &stdoutfile,
|
||||||
const string &stdinfile,
|
const std::string &stderrfile)
|
||||||
const string &stdoutfile,
|
|
||||||
const string &stderrfile)
|
|
||||||
{
|
{
|
||||||
umask(0);
|
umask(0);
|
||||||
|
|
||||||
rlimit rl;
|
rlimit rl;
|
||||||
if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
|
if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
|
||||||
{
|
{
|
||||||
throw runtime_error(strerror(errno));
|
throw std::runtime_error(strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dir.empty() && chdir(dir.c_str()) < 0)
|
if (!dir.empty() && chdir(dir.c_str()) < 0)
|
||||||
{
|
{
|
||||||
throw runtime_error(strerror(errno));
|
throw std::runtime_error(strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rl.rlim_max == RLIM_INFINITY)
|
if (rl.rlim_max == RLIM_INFINITY)
|
||||||
@ -47,6 +45,6 @@ void daemonize(const string &dir,
|
|||||||
|
|
||||||
if (fd0 != STDIN_FILENO || fd1 != STDOUT_FILENO || fd2 != STDERR_FILENO)
|
if (fd0 != STDIN_FILENO || fd1 != STDOUT_FILENO || fd2 != STDERR_FILENO)
|
||||||
{
|
{
|
||||||
throw runtime_error("new standard file descriptors were not opened as expected");
|
throw std::runtime_error("new standard file descriptors were not opened as expected");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <memory>
|
|
||||||
#include <utility>
|
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
@ -11,13 +7,13 @@
|
|||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
|
||||||
#include "../lib/logic.h"
|
#include "../lib/logic.h"
|
||||||
#include "../lib/util.h"
|
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "daemon.h"
|
#include "daemon.h"
|
||||||
|
|
||||||
namespace po = boost::program_options;
|
namespace po = boost::program_options;
|
||||||
using boost::asio::ip::tcp;
|
namespace ba = boost::asio;
|
||||||
|
using ba::ip::tcp;
|
||||||
|
|
||||||
// Info about doorlockd version
|
// Info about doorlockd version
|
||||||
const static std::string version =
|
const static std::string version =
|
||||||
@ -31,7 +27,7 @@ const int constexpr SOCKET_BUFFERLENGTH = 2048;
|
|||||||
const static Logger &l = Logger::get();
|
const static Logger &l = Logger::get();
|
||||||
|
|
||||||
static std::unique_ptr<Logic> logic = nullptr;
|
static std::unique_ptr<Logic> logic = nullptr;
|
||||||
static boost::asio::io_service io_service;
|
static ba::io_service io_service;
|
||||||
|
|
||||||
static std::mutex mutex;
|
static std::mutex mutex;
|
||||||
static std::condition_variable onClientMessage;
|
static std::condition_variable onClientMessage;
|
||||||
@ -46,13 +42,26 @@ static void signal_handler(int signum)
|
|||||||
onClientMessage.notify_all();
|
onClientMessage.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Response subscribe(tcp::socket &sock)
|
||||||
|
{
|
||||||
|
sock.write_some(ba::buffer(logic->getClientMessage().toJson()));
|
||||||
|
while (run) {
|
||||||
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
|
onClientMessage.wait(lock);
|
||||||
|
if (run) {
|
||||||
|
sock.write_some(ba::buffer(logic->getClientMessage().toJson()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Response(Response::Code::Success);
|
||||||
|
}
|
||||||
|
|
||||||
static void session(tcp::socket &&sock)
|
static void session(tcp::socket &&sock)
|
||||||
{
|
{
|
||||||
boost::asio::ip::address remoteAddress;
|
ba::ip::address remoteAddress;
|
||||||
unsigned short remotePort = 0;
|
unsigned short remotePort = 0;
|
||||||
|
Response response;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
boost::system::error_code error;
|
|
||||||
std::vector<char> data;
|
std::vector<char> data;
|
||||||
data.resize(SOCKET_BUFFERLENGTH);
|
data.resize(SOCKET_BUFFERLENGTH);
|
||||||
|
|
||||||
@ -63,79 +72,59 @@ static void session(tcp::socket &&sock)
|
|||||||
+ std::to_string(remotePort) + ")",
|
+ std::to_string(remotePort) + ")",
|
||||||
LogLevel::notice);
|
LogLevel::notice);
|
||||||
|
|
||||||
size_t length = sock.read_some(boost::asio::buffer(data),
|
size_t length = sock.read_some(ba::buffer(data));
|
||||||
error);
|
|
||||||
if (error == boost::asio::error::eof)
|
|
||||||
return;
|
|
||||||
else if (error)
|
|
||||||
throw boost::system::system_error(error);
|
|
||||||
|
|
||||||
const std::string request(data.begin(), data.begin()+length);
|
// Get Request
|
||||||
|
const std::string requestString(data.begin(), data.begin()+length);
|
||||||
|
l(" Parsing request...", LogLevel::info);
|
||||||
|
Request request = Request::fromString(requestString);
|
||||||
|
|
||||||
Json::Reader reader;
|
switch (request.command) {
|
||||||
Json::Value root;
|
case Request::Command::Lock:
|
||||||
Response response;
|
case Request::Command::Unlock:
|
||||||
std::string command;
|
response = logic->request(request);
|
||||||
|
break;
|
||||||
|
|
||||||
if (!reader.parse(request, root, false))
|
case Request::Command::Subscribe:
|
||||||
{
|
if (remoteAddress.is_loopback() == false) {
|
||||||
response.message = "Request is no valid JSON";
|
response.code = Response::Code::AccessDenied;
|
||||||
response.code = Response::Code::JsonError;
|
response.message = "Subscriptions are only allowed from localhost";
|
||||||
l(response.message, LogLevel::warning);
|
} else {
|
||||||
goto out;
|
response = subscribe(sock);
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
command = getJsonOrFail<std::string>(root, "command");
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
response.code = Response::Code::JsonError;
|
|
||||||
response.message = "Error parsing JSON";
|
|
||||||
l(response.message, LogLevel::warning);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
l(" Command: " + command, LogLevel::notice);
|
|
||||||
if (command == "lock" || command == "unlock") {
|
|
||||||
response = logic->parseRequest(root);
|
|
||||||
} else if (command == "subscribe") {
|
|
||||||
if (remoteAddress.is_loopback() == false) {
|
|
||||||
response.code = Response::Code::AccessDenied;
|
|
||||||
response.message = "Subscriptions are only allowed from localhost";
|
|
||||||
l(response.message, LogLevel::warning);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
sock.write_some(boost::asio::buffer(logic->getClientMessage().toJson()));
|
|
||||||
|
|
||||||
while (run) {
|
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
|
||||||
onClientMessage.wait(lock);
|
|
||||||
|
|
||||||
if (run) {
|
|
||||||
sock.write_some(boost::asio::buffer(logic->getClientMessage().toJson()));
|
|
||||||
}
|
}
|
||||||
};
|
break;
|
||||||
} else {
|
|
||||||
response.code = Response::Code::UnknownCommand;
|
case Request::Command::Unknown:
|
||||||
response.message = "Received unknown command " + command;
|
default:
|
||||||
l(response.message, LogLevel::warning);
|
response.code = Response::Code::UnknownCommand;
|
||||||
|
response.message = "Received unknown command ";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
throw response;
|
||||||
sock.write_some(boost::asio::buffer(response.toJson()),
|
|
||||||
error);
|
|
||||||
if (error == boost::asio::error::eof)
|
|
||||||
return;
|
|
||||||
else if (error)
|
|
||||||
throw boost::system::system_error(error);
|
|
||||||
}
|
}
|
||||||
catch (const std::exception &e) {
|
catch (const Response &err) {
|
||||||
std::string message = "Exception in session " + remoteAddress.to_string()
|
response = err;
|
||||||
+ ":" + std::to_string(remotePort) + " : " + e.what();
|
|
||||||
l(message, LogLevel::error);
|
|
||||||
}
|
}
|
||||||
|
catch (const std::exception &err) {
|
||||||
|
response.code = Response::Code::Fail;
|
||||||
|
response.message = "Exception in session " + remoteAddress.to_string()
|
||||||
|
+ ":" + std::to_string(remotePort) + " : " + err.what();
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
response.code = Response::Code::Fail;
|
||||||
|
response.message = "Unhandled doorlockd error";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response) {
|
||||||
|
l(response.message, LogLevel::warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sock.is_open()) {
|
||||||
|
boost::system::error_code ec;
|
||||||
|
sock.write_some(ba::buffer(response.toJson()), ec);
|
||||||
|
}
|
||||||
|
|
||||||
l("Closing TCP connection from " + remoteAddress.to_string(), LogLevel::notice);
|
l("Closing TCP connection from " + remoteAddress.to_string(), LogLevel::notice);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +132,7 @@ static void server(unsigned short port)
|
|||||||
{
|
{
|
||||||
l(LogLevel::info, "Starting TCP Server");
|
l(LogLevel::info, "Starting TCP Server");
|
||||||
|
|
||||||
const auto endpoint = tcp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), port);
|
const auto endpoint = tcp::endpoint(ba::ip::address::from_string("127.0.0.1"), port);
|
||||||
tcp::acceptor a(io_service, endpoint);
|
tcp::acceptor a(io_service, endpoint);
|
||||||
|
|
||||||
tcp::socket sock(io_service);
|
tcp::socket sock(io_service);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include <json/json.h>
|
|
||||||
|
|
||||||
#include "clientmessage.h"
|
#include "clientmessage.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "response.h"
|
||||||
|
|
||||||
const std::string Clientmessage::_tokenKey = "token";
|
const std::string Clientmessage::_tokenKey = "token";
|
||||||
const std::string Clientmessage::_unlockButtonKey = "unlockButton";
|
const std::string Clientmessage::_unlockButtonKey = "unlockButton";
|
||||||
@ -40,21 +39,33 @@ const Doormessage& Clientmessage::doormessage() const
|
|||||||
return _doormessage;
|
return _doormessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
Clientmessage Clientmessage::fromJson(const std::string &json)
|
Clientmessage Clientmessage::fromJson(const Json::Value &root)
|
||||||
{
|
{
|
||||||
Json::Reader reader;
|
|
||||||
Json::Value root;
|
|
||||||
std::string token;
|
std::string token;
|
||||||
Doormessage doormessage;
|
Doormessage doormessage;
|
||||||
|
|
||||||
if (reader.parse(json, root) == false)
|
try {
|
||||||
throw std::runtime_error("Error parsing JSON");
|
token = getJsonOrFail<std::string>(root, _tokenKey);
|
||||||
|
doormessage.isLockButton = getJsonOrFail<bool>(root, _lockButtonKey);
|
||||||
token = getJsonOrFail<std::string>(root, _tokenKey);
|
doormessage.isUnlockButton = getJsonOrFail<bool>(root, _unlockButtonKey);
|
||||||
doormessage.isLockButton = getJsonOrFail<bool>(root, _lockButtonKey);
|
doormessage.isEmergencyUnlock = getJsonOrFail<bool>(root, _emergencyUnlockKey);
|
||||||
doormessage.isUnlockButton = getJsonOrFail<bool>(root, _unlockButtonKey);
|
doormessage.isOpen = getJsonOrFail<bool>(root, _isOpenKey);
|
||||||
doormessage.isEmergencyUnlock = getJsonOrFail<bool>(root, _emergencyUnlockKey);
|
}
|
||||||
doormessage.isOpen = getJsonOrFail<bool>(root, _isOpenKey);
|
catch (const std::exception &ex) {
|
||||||
|
throw Response(Response::Code::JsonError, ex.what());
|
||||||
|
}
|
||||||
|
|
||||||
return Clientmessage(token, doormessage);
|
return Clientmessage(token, doormessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Clientmessage Clientmessage::fromString(const std::string &string)
|
||||||
|
{
|
||||||
|
Json::Reader reader;
|
||||||
|
Json::Value root;
|
||||||
|
|
||||||
|
if (reader.parse(string, root) == false)
|
||||||
|
throw Response(Response::Code::NotJson,
|
||||||
|
"No valid JSON");
|
||||||
|
|
||||||
|
return fromJson(root);
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define CLIENTMESSAGE_H
|
#define CLIENTMESSAGE_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <json/json.h>
|
||||||
|
|
||||||
#include "doormessage.h"
|
#include "doormessage.h"
|
||||||
|
|
||||||
@ -13,7 +14,8 @@ public:
|
|||||||
Clientmessage(std::string token,
|
Clientmessage(std::string token,
|
||||||
Doormessage doormessage);
|
Doormessage doormessage);
|
||||||
|
|
||||||
static Clientmessage fromJson(const std::string &json);
|
static Clientmessage fromJson(const Json::Value &root);
|
||||||
|
static Clientmessage fromString(const std::string &json);
|
||||||
std::string toJson() const;
|
std::string toJson() const;
|
||||||
|
|
||||||
const std::string& token() const;
|
const std::string& token() const;
|
||||||
|
@ -133,7 +133,7 @@ void Door::lock()
|
|||||||
_heartbeatCondition.notify_one();
|
_heartbeatCondition.notify_one();
|
||||||
_heartbeatThread.join();
|
_heartbeatThread.join();
|
||||||
|
|
||||||
_logger(LogLevel::info, "Door closed");
|
_logger(LogLevel::notice , "Door closed");
|
||||||
|
|
||||||
out:
|
out:
|
||||||
_logger(LogLevel::notice, "Executing Post Lock Script");
|
_logger(LogLevel::notice, "Executing Post Lock Script");
|
||||||
@ -175,7 +175,7 @@ void Door::unlock()
|
|||||||
writeCMD(DOOR_CMD_LOCK);
|
writeCMD(DOOR_CMD_LOCK);
|
||||||
});
|
});
|
||||||
|
|
||||||
_logger(LogLevel::info, "Door opened");
|
_logger(LogLevel::notice, "Door opened");
|
||||||
|
|
||||||
out:
|
out:
|
||||||
_logger(LogLevel::notice, "Executing Post Unlock Script");
|
_logger(LogLevel::notice, "Executing Post Unlock Script");
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
#ifndef DOOR_H
|
#ifndef DOOR_H
|
||||||
#define DOOR_H
|
#define DOOR_H
|
||||||
|
|
||||||
#include <string>
|
#include <chrono>
|
||||||
#include <functional>
|
|
||||||
#include <thread>
|
|
||||||
#include <mutex>
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <boost/asio/serial_port.hpp>
|
#include <boost/asio/serial_port.hpp>
|
||||||
|
@ -1,26 +1,17 @@
|
|||||||
#include <chrono>
|
#include <errno.h>
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <json/json.h>
|
|
||||||
|
|
||||||
#define LDAP_DEPRECATED 1
|
#define LDAP_DEPRECATED 1
|
||||||
#include <ldap.h>
|
#include <ldap.h>
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "util.h"
|
|
||||||
#include "logic.h"
|
#include "logic.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
using namespace std;
|
Logic::Logic(const std::chrono::seconds tokenTimeout,
|
||||||
|
const std::string &ldapUri,
|
||||||
Logic::Logic(const chrono::seconds tokenTimeout,
|
const std::string &bindDN,
|
||||||
const string &ldapUri,
|
const std::string &webPrefix,
|
||||||
const string &bindDN,
|
const std::string &serDev,
|
||||||
const string &webPrefix,
|
|
||||||
const string &serDev,
|
|
||||||
const unsigned int baudrate,
|
const unsigned int baudrate,
|
||||||
condition_variable &onClientUpdate) :
|
std::condition_variable &onClientUpdate) :
|
||||||
_logger(Logger::get()),
|
_logger(Logger::get()),
|
||||||
_door(serDev, baudrate),
|
_door(serDev, baudrate),
|
||||||
_tokenTimeout(tokenTimeout),
|
_tokenTimeout(tokenTimeout),
|
||||||
@ -36,10 +27,10 @@ Logic::Logic(const chrono::seconds tokenTimeout,
|
|||||||
this,
|
this,
|
||||||
std::placeholders::_1));
|
std::placeholders::_1));
|
||||||
|
|
||||||
_tokenUpdater = thread([this] () {
|
_tokenUpdater = std::thread([this] () {
|
||||||
while (_run)
|
while (_run)
|
||||||
{
|
{
|
||||||
unique_lock<mutex> l(_mutex);
|
std::unique_lock<std::mutex> l(_mutex);
|
||||||
_tokenCondition.wait_for(l, _tokenTimeout);
|
_tokenCondition.wait_for(l, _tokenTimeout);
|
||||||
if (_run == false)
|
if (_run == false)
|
||||||
{
|
{
|
||||||
@ -58,58 +49,60 @@ Logic::~Logic()
|
|||||||
_tokenUpdater.join();
|
_tokenUpdater.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
Response Logic::parseRequest(const Json::Value &root)
|
Response Logic::processDoor(const DoorCommand &doorCommand)
|
||||||
{
|
{
|
||||||
unique_lock<mutex> l(_mutex);
|
|
||||||
|
|
||||||
_logger(LogLevel::info, "Incoming request...");
|
|
||||||
Response response;
|
Response response;
|
||||||
string command, user, password, ip, token;
|
|
||||||
|
|
||||||
try {
|
switch (doorCommand) {
|
||||||
command = getJsonOrFail<string>(root, "command");
|
case DoorCommand::Lock:
|
||||||
ip = getJsonOrFail<string>(root, "ip");
|
response = _lock();
|
||||||
user = getJsonOrFail<string>(root, "user");
|
break;
|
||||||
password = getJsonOrFail<string>(root, "password");
|
case DoorCommand::Unlock:
|
||||||
token = getJsonOrFail<string>(root, "token");
|
response = _unlock();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
response.code = Response::Code::UnknownCommand;
|
||||||
|
response.message = "Unknown DoorCommand";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
catch (...)
|
|
||||||
{
|
return response;
|
||||||
_logger(LogLevel::warning, "Error parsing JSON");
|
}
|
||||||
response.code = Response::Code::JsonError;
|
|
||||||
response.message = "Error parsing JSON";
|
Response Logic::request(const Request &request)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> l(_mutex);
|
||||||
|
Response response;
|
||||||
|
|
||||||
|
DoorCommand doorCommand;
|
||||||
|
|
||||||
|
switch (request.command) {
|
||||||
|
case Request::Command::Lock:
|
||||||
|
doorCommand = DoorCommand::Lock;
|
||||||
|
break;
|
||||||
|
case Request::Command::Unlock:
|
||||||
|
doorCommand = DoorCommand::Unlock;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
response.code = Response::Code::UnknownCommand;
|
||||||
|
response.message = "Unknown Command";
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
response = _checkToken(request.token);
|
||||||
|
if (!response) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
_logger(LogLevel::info, " -> Token check successful");
|
||||||
|
|
||||||
_logger(" User : " + user, LogLevel::notice);
|
response = _checkLDAP(request.user, request.password);
|
||||||
_logger(" IP : " + ip, LogLevel::notice);
|
if (!response) {
|
||||||
_logger(" Token : " + token, LogLevel::notice);
|
|
||||||
|
|
||||||
if (_checkToken(token) == false)
|
|
||||||
{
|
|
||||||
_logger(LogLevel::error, "User provided invalid token");
|
|
||||||
response.code = Response::Code::InvalidToken;
|
|
||||||
response.message = "User provided invalid token";
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
_logger(LogLevel::info, " -> LDAP check successful");
|
||||||
|
|
||||||
response = _checkLDAP(user,password);
|
response = processDoor(doorCommand);
|
||||||
if (!response)
|
_logger(LogLevel::info, " -> Door Command successful");
|
||||||
{
|
|
||||||
_logger(LogLevel::error, "Ldap error");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command == "lock")
|
|
||||||
{
|
|
||||||
response = _lock();
|
|
||||||
} else if (command == "unlock") {
|
|
||||||
response = _unlock();
|
|
||||||
} else {
|
|
||||||
response.code = Response::Code::UnknownCommand;
|
|
||||||
response.message = "Unknown Command: " + command;
|
|
||||||
_logger(response.message, LogLevel::error);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return response;
|
return response;
|
||||||
@ -122,14 +115,15 @@ Response Logic::_lock()
|
|||||||
{
|
{
|
||||||
response.code = Response::Code::AlreadyLocked;
|
response.code = Response::Code::AlreadyLocked;
|
||||||
response.message = "Unable to lock: already closed";
|
response.message = "Unable to lock: already closed";
|
||||||
_logger(response.message, LogLevel::warning);
|
|
||||||
} else {
|
} else {
|
||||||
_door.lock();
|
|
||||||
_createNewToken(false);
|
_createNewToken(false);
|
||||||
|
|
||||||
response.code = Response::Code::Success;
|
response.code = Response::Code::Success;
|
||||||
|
response.message = "Success";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_door.lock();
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,32 +139,38 @@ Response Logic::_unlock()
|
|||||||
{
|
{
|
||||||
response.code = Response::Code::AlreadyUnlocked;
|
response.code = Response::Code::AlreadyUnlocked;
|
||||||
response.message = "Unable to unlock: already unlocked";
|
response.message = "Unable to unlock: already unlocked";
|
||||||
_logger(response.message, LogLevel::warning);
|
_logger(response.message, LogLevel::info);
|
||||||
} else {
|
} else {
|
||||||
response.code = Response::Code::Success;
|
response.code = Response::Code::Success;
|
||||||
|
response.message = "Success";
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Logic::_checkToken(const string &strToken)
|
Response Logic::_checkToken(std::string token) const
|
||||||
{
|
{
|
||||||
try {
|
std::transform(token.begin(),
|
||||||
uint64_t token = toUint64(strToken);
|
token.end(),
|
||||||
if (token == _curToken || (_prevValid == true && token == _prevToken))
|
token.begin(),
|
||||||
{
|
::toupper);
|
||||||
_logger(LogLevel::info, "Token check successful");
|
|
||||||
return true;
|
if (token == _curToken)
|
||||||
}
|
return Response(Response::Code::Success);
|
||||||
}
|
|
||||||
catch (const char* const &ex)
|
if (_prevValid == true && token == _prevToken)
|
||||||
{
|
return Response(Response::Code::Success);
|
||||||
_logger(LogLevel::error, "Check Token failed for token \"%s\" (expected %s): %s", strToken.c_str(), toHexString(_curToken).c_str(), ex);
|
|
||||||
}
|
_logger("Check Token failed: got \"" + token
|
||||||
return false;
|
+ "\", expected \"" + _curToken +"\"",
|
||||||
|
LogLevel::error);
|
||||||
|
|
||||||
|
return Response(Response::InvalidToken,
|
||||||
|
"User provided invalid token");
|
||||||
}
|
}
|
||||||
|
|
||||||
Response Logic::_checkLDAP(const string &user, const string &password)
|
Response Logic::_checkLDAP(const std::string &user,
|
||||||
|
const std::string &password)
|
||||||
{
|
{
|
||||||
constexpr int BUFFERSIZE = 1024;
|
constexpr int BUFFERSIZE = 1024;
|
||||||
char buffer[BUFFERSIZE];
|
char buffer[BUFFERSIZE];
|
||||||
@ -180,16 +180,15 @@ Response Logic::_checkLDAP(const string &user, const string &password)
|
|||||||
LDAP* ld = nullptr;
|
LDAP* ld = nullptr;
|
||||||
unsigned long version = LDAP_VERSION3;
|
unsigned long version = LDAP_VERSION3;
|
||||||
|
|
||||||
_logger(LogLevel::notice, "Trying to authenticate as user \"%s\"", user.c_str());
|
_logger(LogLevel::info, " Trying to authenticate as user \"%s\"", user.c_str());
|
||||||
snprintf(buffer, BUFFERSIZE, _bindDN.c_str(), user.c_str());
|
snprintf(buffer, BUFFERSIZE, _bindDN.c_str(), user.c_str());
|
||||||
|
|
||||||
rc = ldap_initialize(&ld, _ldapUri.c_str());
|
rc = ldap_initialize(&ld, _ldapUri.c_str());
|
||||||
if(rc != LDAP_SUCCESS)
|
if(rc != LDAP_SUCCESS)
|
||||||
{
|
{
|
||||||
retval.message = (string)"LDAP initialize error: "
|
retval.message = (std::string)"LDAP initialize error: "
|
||||||
+ ldap_err2string(rc);
|
+ ldap_err2string(rc);
|
||||||
retval.code = Response::Code::LDAPInit;
|
retval.code = Response::Code::LDAPInit;
|
||||||
_logger(retval.message, LogLevel::error);
|
|
||||||
goto out2;
|
goto out2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +199,6 @@ Response Logic::_checkLDAP(const string &user, const string &password)
|
|||||||
{
|
{
|
||||||
retval.code = Response::Code::LDAPInit;
|
retval.code = Response::Code::LDAPInit;
|
||||||
retval.message = "LDAP set version failed";
|
retval.message = "LDAP set version failed";
|
||||||
_logger(retval.message, LogLevel::error);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,12 +208,11 @@ Response Logic::_checkLDAP(const string &user, const string &password)
|
|||||||
retval = Response::Code::InvalidCredentials;
|
retval = Response::Code::InvalidCredentials;
|
||||||
retval.message = "Credential check for user \"" + user
|
retval.message = "Credential check for user \"" + user
|
||||||
+ "\" failed: " + ldap_err2string(rc);
|
+ "\" failed: " + ldap_err2string(rc);
|
||||||
_logger(retval.message, LogLevel::error);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger(LogLevel::notice, "user \"%s\" successfully authenticated", user.c_str());
|
retval.code = Response::Code::Success;
|
||||||
retval = Response::Code::Success;
|
retval.message = "";
|
||||||
|
|
||||||
out:
|
out:
|
||||||
ldap_unbind(ld);
|
ldap_unbind(ld);
|
||||||
@ -231,11 +228,13 @@ void Logic::_createNewToken(const bool stillValid)
|
|||||||
_prevToken = _curToken;
|
_prevToken = _curToken;
|
||||||
_prevValid = stillValid;
|
_prevValid = stillValid;
|
||||||
|
|
||||||
_curToken = (((uint64_t)rand())<<32) | ((uint64_t)rand());
|
_curToken = toHexString((((uint64_t)rand())<<32) | ((uint64_t)rand()));
|
||||||
|
|
||||||
ostringstream message;
|
std::ostringstream message;
|
||||||
message << "New Token generated: " << toHexString(_curToken) << " old Token: " << toHexString(_prevToken) << " is " << (_prevValid?"still":"not") << " valid";
|
message << "New token: " << _curToken
|
||||||
_logger(message, LogLevel::info);
|
<< " old token: " << _prevToken << " is "
|
||||||
|
<< (_prevValid?"still":"not") << " valid";
|
||||||
|
_logger(message, LogLevel::notice);
|
||||||
|
|
||||||
_onClientUpdate.notify_all();
|
_onClientUpdate.notify_all();
|
||||||
}
|
}
|
||||||
@ -243,7 +242,7 @@ void Logic::_createNewToken(const bool stillValid)
|
|||||||
Clientmessage Logic::getClientMessage()
|
Clientmessage Logic::getClientMessage()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> l(_mutex);
|
std::lock_guard<std::mutex> l(_mutex);
|
||||||
Clientmessage retval(_webPrefix + toHexString(_curToken),
|
Clientmessage retval(_webPrefix + _curToken,
|
||||||
_doormessage);
|
_doormessage);
|
||||||
|
|
||||||
// Reset doormessage
|
// Reset doormessage
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
#ifndef LOGIC_H
|
#ifndef LOGIC_H
|
||||||
#define LOGIC_H
|
#define LOGIC_H
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <string>
|
|
||||||
#include <thread>
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "clientmessage.h"
|
||||||
#include "door.h"
|
#include "door.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
#include "request.h"
|
||||||
#include "response.h"
|
#include "response.h"
|
||||||
#include "clientmessage.h"
|
|
||||||
|
|
||||||
/* The "Logic" class
|
/* The "Logic" class
|
||||||
*
|
*
|
||||||
* This class is initilized by all settings.
|
* This class is initilized by all settings.
|
||||||
*
|
*
|
||||||
* It parses incoming JSON-Requests and returns the Response Code.
|
* It handles incoming requests and allows modifications of the door
|
||||||
*/
|
*/
|
||||||
class Logic
|
class Logic
|
||||||
{
|
{
|
||||||
@ -33,7 +33,11 @@ public:
|
|||||||
~Logic();
|
~Logic();
|
||||||
|
|
||||||
// Parse incoming JSON Requests
|
// Parse incoming JSON Requests
|
||||||
Response parseRequest(const Json::Value &root);
|
Response request(const Request &request);
|
||||||
|
|
||||||
|
// Send direct command to door without credential checks
|
||||||
|
enum class DoorCommand { Lock, Unlock };
|
||||||
|
Response processDoor(const DoorCommand &doorCommand);
|
||||||
|
|
||||||
// Returns the current Token
|
// Returns the current Token
|
||||||
Clientmessage getClientMessage();
|
Clientmessage getClientMessage();
|
||||||
@ -46,7 +50,7 @@ private:
|
|||||||
Response _unlock();
|
Response _unlock();
|
||||||
|
|
||||||
// Checks if the incoming token is valid
|
// Checks if the incoming token is valid
|
||||||
bool _checkToken(const std::string &token);
|
Response _checkToken(std::string token) const;
|
||||||
|
|
||||||
// Checks if incoming credentials against LDAP
|
// Checks if incoming credentials against LDAP
|
||||||
Response _checkLDAP(const std::string &user,
|
Response _checkLDAP(const std::string &user,
|
||||||
@ -63,13 +67,10 @@ private:
|
|||||||
// The door
|
// The door
|
||||||
Door _door;
|
Door _door;
|
||||||
|
|
||||||
// Tokens are 64-bit hexadecimal values
|
|
||||||
using Token = uint64_t;
|
|
||||||
|
|
||||||
// The current token
|
// The current token
|
||||||
Token _curToken = { 0x0000000000000000 };
|
std::string _curToken = { "0000000000000000" };
|
||||||
// The previous token
|
// The previous token
|
||||||
Token _prevToken = { 0x0000000000000000 };
|
std::string _prevToken = { "0000000000000000" };
|
||||||
// Indicates whether the previous token is valid
|
// Indicates whether the previous token is valid
|
||||||
bool _prevValid = { false };
|
bool _prevValid = { false };
|
||||||
|
|
||||||
|
69
doorlockd/lib/request.cpp
Normal file
69
doorlockd/lib/request.cpp
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#include "request.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
const std::string Request::_commandKey = "command";
|
||||||
|
|
||||||
|
Request::Command Request::_commandFromString(const std::string &command)
|
||||||
|
{
|
||||||
|
Command retval = Command::Unknown;
|
||||||
|
|
||||||
|
if (command == "lock")
|
||||||
|
retval = Command::Lock;
|
||||||
|
else if (command == "unlock")
|
||||||
|
retval = Command::Unlock;
|
||||||
|
else if (command == "subscribe")
|
||||||
|
retval = Command::Subscribe;
|
||||||
|
else
|
||||||
|
retval = Command::Unknown;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
Request Request::fromJson(const Json::Value &root)
|
||||||
|
{
|
||||||
|
Request retval;
|
||||||
|
const auto &l = Logger::get();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const auto commandStr =
|
||||||
|
getJsonOrFail<std::string>(root, _commandKey);
|
||||||
|
l(" command: " + commandStr, LogLevel::info);
|
||||||
|
retval.command = _commandFromString(commandStr);
|
||||||
|
|
||||||
|
// Stop parsing, if command is unknown
|
||||||
|
if (retval.command == Command::Unknown)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
if (retval.command == Command::Lock ||
|
||||||
|
retval.command == Command::Unlock) {
|
||||||
|
retval.user = getJsonOrFail<std::string>(root, "user");
|
||||||
|
l(" user: " + retval.user, LogLevel::info);
|
||||||
|
retval.password = getJsonOrFail<std::string>(root, "password");
|
||||||
|
l(" password: XXX", LogLevel::info);
|
||||||
|
retval.token = getJsonOrFail<std::string>(root, "token");
|
||||||
|
l(" token: " + retval.token, LogLevel::info);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retval.command == Command::Subscribe) {
|
||||||
|
// Nothing to do in this case
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &ex) {
|
||||||
|
throw Response(Response::Code::JsonError, ex.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
Request Request::fromString(const std::string &string)
|
||||||
|
{
|
||||||
|
Json::Reader reader;
|
||||||
|
Json::Value root;
|
||||||
|
|
||||||
|
if (reader.parse(string, root) == false)
|
||||||
|
throw Response(Response::Code::NotJson,
|
||||||
|
"No valid JSON");
|
||||||
|
|
||||||
|
return fromJson(root);
|
||||||
|
}
|
29
doorlockd/lib/request.h
Normal file
29
doorlockd/lib/request.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef REQUEST_H
|
||||||
|
#define REQUEST_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <json/json.h>
|
||||||
|
|
||||||
|
#include "response.h"
|
||||||
|
|
||||||
|
class Request
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static Request fromJson(const Json::Value &root);
|
||||||
|
static Request fromString(const std::string &string);
|
||||||
|
|
||||||
|
enum class Command { Lock, Unlock, Subscribe, Unknown }
|
||||||
|
command = { Command::Unknown };
|
||||||
|
std::string user = { };
|
||||||
|
std::string password = { };
|
||||||
|
std::string token = { };
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Command _commandFromString(const std::string &command);
|
||||||
|
|
||||||
|
const static std::string _commandKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // REQUEST_H
|
||||||
|
|
@ -8,6 +8,18 @@
|
|||||||
const std::string Response::_codeKey = "code";
|
const std::string Response::_codeKey = "code";
|
||||||
const std::string Response::_messageKey = "message";
|
const std::string Response::_messageKey = "message";
|
||||||
|
|
||||||
|
Response::Response():
|
||||||
|
code(Fail),
|
||||||
|
message("General failure")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Response::Response(Response::Code code, const std::string &what) :
|
||||||
|
code(code),
|
||||||
|
message(what)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Response::operator bool() const
|
Response::operator bool() const
|
||||||
{
|
{
|
||||||
return code == Response::Code::Success;
|
return code == Response::Code::Success;
|
||||||
@ -24,21 +36,34 @@ std::string Response::toJson() const
|
|||||||
return writer.write(response);
|
return writer.write(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
Response Response::fromJson(const std::string &json)
|
Response Response::fromJson(const Json::Value &root)
|
||||||
{
|
{
|
||||||
Json::Reader reader;
|
|
||||||
Json::Value root;
|
|
||||||
Response retval;
|
Response retval;
|
||||||
|
|
||||||
if (reader.parse(json, root) == false)
|
try {
|
||||||
throw std::runtime_error("Error parsing JSON");
|
retval.message = getJsonOrFail<std::string>(root, _messageKey);
|
||||||
|
|
||||||
retval.message = getJsonOrFail<std::string>(root, _messageKey);
|
const auto code = getJsonOrFail<int>(root, _codeKey);
|
||||||
|
if (code > Code::RESPONSE_NUM_ITEMS)
|
||||||
|
throw std::runtime_error("Error code out of range");
|
||||||
|
|
||||||
const auto code = getJsonOrFail<int>(root, _codeKey);
|
retval.code = static_cast<Code>(code);
|
||||||
if (code > Code::RESPONSE_NUM_ITEMS)
|
}
|
||||||
throw std::runtime_error("Error code out of range");
|
catch (const std::exception &ex) {
|
||||||
retval.code = static_cast<Code>(code);
|
throw Response(Response::Code::JsonError, ex.what());
|
||||||
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Response Response::fromString(const std::string &json)
|
||||||
|
{
|
||||||
|
Json::Reader reader;
|
||||||
|
Json::Value root;
|
||||||
|
|
||||||
|
if (reader.parse(json, root) == false)
|
||||||
|
throw Response(Response::Code::NotJson,
|
||||||
|
"No valid JSON");
|
||||||
|
|
||||||
|
return fromJson(root);
|
||||||
|
}
|
||||||
|
@ -3,8 +3,11 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
struct Response
|
#include <json/json.h>
|
||||||
|
|
||||||
|
class Response
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
enum Code {
|
enum Code {
|
||||||
Success = 0, // Request successful
|
Success = 0, // Request successful
|
||||||
Fail, // General non-specified error
|
Fail, // General non-specified error
|
||||||
@ -22,19 +25,11 @@ struct Response
|
|||||||
} code;
|
} code;
|
||||||
std::string message;
|
std::string message;
|
||||||
|
|
||||||
Response() :
|
Response();
|
||||||
code(Fail),
|
Response(Response::Code code, const std::string &message = "");
|
||||||
message("General failure")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Response(Response::Code code, const std::string &message = "") :
|
static Response fromJson(const Json::Value &root);
|
||||||
code(code),
|
static Response fromString(const std::string &json);
|
||||||
message(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static Response fromJson(const std::string &json);
|
|
||||||
std::string toJson() const;
|
std::string toJson() const;
|
||||||
|
|
||||||
// Returns true if code is success
|
// Returns true if code is success
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
int getJson(const Json::Value &root, const string &key)
|
int getJson(const Json::Value &root, const std::string &key)
|
||||||
{
|
{
|
||||||
auto val = root.get(key, Json::Value());
|
auto val = root.get(key, Json::Value());
|
||||||
if (val.isInt())
|
if (val.isInt())
|
||||||
@ -12,7 +10,7 @@ int getJson(const Json::Value &root, const string &key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
string getJson(const Json::Value &root, const string &key)
|
std::string getJson(const Json::Value &root, const std::string &key)
|
||||||
{
|
{
|
||||||
auto val = root.get(key, Json::Value());
|
auto val = root.get(key, Json::Value());
|
||||||
if (val.isString())
|
if (val.isString())
|
||||||
@ -21,7 +19,7 @@ string getJson(const Json::Value &root, const string &key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
size_t getJson(const Json::Value &root, const string &key)
|
size_t getJson(const Json::Value &root, const std::string &key)
|
||||||
{
|
{
|
||||||
auto val = root.get(key, Json::Value());
|
auto val = root.get(key, Json::Value());
|
||||||
if (val.isInt())
|
if (val.isInt())
|
||||||
@ -30,7 +28,7 @@ size_t getJson(const Json::Value &root, const string &key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
bool getJson(const Json::Value &root, const string &key)
|
bool getJson(const Json::Value &root, const std::string &key)
|
||||||
{
|
{
|
||||||
auto val = root.get(key, Json::Value());
|
auto val = root.get(key, Json::Value());
|
||||||
if (val.isBool())
|
if (val.isBool())
|
||||||
@ -39,7 +37,7 @@ bool getJson(const Json::Value &root, const string &key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
Json::Value getJson(const Json::Value &root, const string &key)
|
Json::Value getJson(const Json::Value &root, const std::string &key)
|
||||||
{
|
{
|
||||||
auto val = root.get(key, Json::Value());
|
auto val = root.get(key, Json::Value());
|
||||||
return val;
|
return val;
|
||||||
@ -57,9 +55,9 @@ static char nibble2hex(unsigned char input)
|
|||||||
return input - 0xA + 'A';
|
return input - 0xA + 'A';
|
||||||
}
|
}
|
||||||
|
|
||||||
string toHexString(const uint64_t c)
|
std::string toHexString(const uint64_t c)
|
||||||
{
|
{
|
||||||
string retval;
|
std::string retval;
|
||||||
|
|
||||||
retval = nibble2hex((c>>60) & 0xF);
|
retval = nibble2hex((c>>60) & 0xF);
|
||||||
retval += nibble2hex((c>>56) & 0xF);
|
retval += nibble2hex((c>>56) & 0xF);
|
||||||
@ -92,21 +90,3 @@ unsigned char hex2uchar(const char input)
|
|||||||
}
|
}
|
||||||
throw std::runtime_error("Malformed hexadecimal input");
|
throw std::runtime_error("Malformed hexadecimal input");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t toUint64(const string &s)
|
|
||||||
{
|
|
||||||
if (s.length() != (64/4))
|
|
||||||
{
|
|
||||||
throw std::runtime_error("Hex string has invalid length");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t retval = 0;
|
|
||||||
|
|
||||||
for (int i = 0 ; i < (64/4) ; i++)
|
|
||||||
{
|
|
||||||
retval <<= 4;
|
|
||||||
retval |= hex2uchar(s.at(i))&0xf;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
@ -14,13 +14,12 @@ T getJsonOrFail(const Json::Value &root, const std::string &key)
|
|||||||
const auto members = root.getMemberNames();
|
const auto members = root.getMemberNames();
|
||||||
if (std::find(members.begin(), members.end(), key) == members.end())
|
if (std::find(members.begin(), members.end(), key) == members.end())
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Json key not existing");
|
throw std::runtime_error("Json key \"" + key + "\" not existing");
|
||||||
}
|
}
|
||||||
|
|
||||||
return getJson<T>(root, key);
|
return getJson<T>(root, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toHexString(uint64_t c);
|
std::string toHexString(uint64_t c);
|
||||||
uint64_t toUint64(const std::string &s);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user