add support to picojson for uint64_t; correct issue with conference bridge FNE never incrementing a connections ping counter; implement /status and /peerlist APIs for conference bridge REST API; implement support for /peerlist in dvmcmd;

pull/48/head
Bryan Biedenkapp 2 years ago
parent fd29093c33
commit bf72dcbee8

@ -134,6 +134,8 @@ const uint32_t REST_API_DEFAULT_PORT = 9990;
const uint8_t BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
enum HOST_STATE {
FNE_STATE = 240U,
HOST_STATE_LOCKOUT = 250U,
HOST_STATE_ERROR = 254U,
HOST_STATE_QUIT = 255U,

@ -11,7 +11,7 @@
// Licensed under the BSD-2-Clause License (https://opensource.org/licenses/BSD-2-Clause)
//
/*
* Copyright (C) 2023 by Bryan Biedenkapp N2PLL
* Copyright (C) 2023,2024 by Bryan Biedenkapp N2PLL
* Copyright 2009-2010 Cybozu Labs, Inc.
* Copyright 2011-2014 Kazuho Oku
* All rights reserved.
@ -57,6 +57,8 @@
#include <vector>
#include <utility>
#include <inttypes.h>
// for isnan/isinf
#if __cplusplus >= 201103L
#include <cmath>
@ -88,19 +90,6 @@ extern "C" {
#endif
#endif
// experimental support for int64_t (see README.mkdn for detail)
#ifdef PICOJSON_USE_INT64
#define __STDC_FORMAT_MACROS
#include <cerrno>
#if __cplusplus >= 201103L
#include <cinttypes>
#else
extern "C" {
#include <inttypes.h>
}
#endif
#endif
// to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0
#ifndef PICOJSON_USE_LOCALE
#define PICOJSON_USE_LOCALE 1
@ -136,10 +125,8 @@ namespace json
null_type,
boolean_type,
number_type,
#ifdef PICOJSON_USE_INT64
int64_type,
#endif
int32_type,
uint64_type,
uint32_type,
uint16_type,
uint8_type,
@ -165,10 +152,8 @@ namespace json
union _storage {
bool boolean_;
double number_;
#ifdef PICOJSON_USE_INT64
int64_t int64_;
#endif
int int32_;
uint64_t uint64_;
uint32_t uint32_;
uint16_t uint16_;
uint8_t uint8_;
@ -186,9 +171,6 @@ namespace json
value();
value(int type, bool);
explicit value(bool b);
#ifdef PICOJSON_USE_INT64
explicit value(int64_t i);
#endif
explicit value(double n);
explicit value(const std::string &s);
explicit value(const array &a);
@ -260,10 +242,8 @@ namespace json
INIT(boolean_, false);
INIT(number_, 0.0);
#ifdef PICOJSON_USE_INT64
INIT(int64_, 0);
#endif
INIT(int32_, 0);
INIT(uint64_, 0);
INIT(uint32_, 0);
INIT(uint16_, 0);
INIT(uint8_, 0);
@ -281,12 +261,6 @@ namespace json
u_.boolean_ = b;
}
#ifdef PICOJSON_USE_INT64
inline value::value(int64_t i) : type_(int64_type), u_() {
u_.int64_ = i;
}
#endif
inline value::value(double n) : type_(number_type), u_() {
if (
#ifdef _MSC_VER
@ -409,10 +383,8 @@ namespace json
IS(null, null)
IS(bool, boolean)
#ifdef PICOJSON_USE_INT64
IS(int64_t, int64)
#endif
IS_NUMBER(int, int32)
IS_NUMBER(uint64_t, uint64)
IS_NUMBER(uint32_t, uint32)
IS_NUMBER(uint16_t, uint16)
IS_NUMBER(uint8_t, uint8)
@ -424,11 +396,7 @@ namespace json
#undef IS_NUMBER
template <> inline bool value::is<double>() const {
return type_ == number_type
#ifdef PICOJSON_USE_INT64
|| type_ == int64_type
#endif
;
return type_ == number_type;
}
#define GET(ctype, var) \
@ -445,17 +413,13 @@ namespace json
GET(std::string, *u_.string_)
GET(array, *u_.array_)
GET(object, *u_.object_)
#ifdef PICOJSON_USE_INT64
GET(double,
(type_ == int64_type && (const_cast<value *>(this)->type_ = number_type, (const_cast<value *>(this)->u_.number_ = u_.int64_)),
u_.number_))
GET(int64_t, u_.int64_)
#else
GET(double, u_.number_)
#endif
GET(int,
(type_ == number_type && (const_cast<value *>(this)->type_ = int32_type, (const_cast<value *>(this)->u_.int32_ = u_.number_)),
u_.int32_))
GET(uint64_t,
(type_ == number_type && (const_cast<value *>(this)->type_ = uint64_type, (const_cast<value *>(this)->u_.uint64_ = u_.number_)),
u_.uint64_))
GET(uint32_t,
(type_ == number_type && (const_cast<value *>(this)->type_ = uint32_type, (const_cast<value *>(this)->u_.uint32_ = u_.number_)),
u_.uint32_))
@ -484,13 +448,11 @@ namespace json
SET(double, number, u_.number_ = _val;)
SET(int8_t, int32, u_.int32_ = _val;)
SET(int, int32, u_.int32_ = _val;)
SET(uint64_t, uint64, u_.uint64_ = _val;)
SET(uint32_t, uint32, u_.uint32_ = _val;)
SET(uint16_t, uint16, u_.uint16_ = _val;)
SET(uint8_t, uint8, u_.uint8_ = _val;)
SET(float, float, u_.float_ = _val;)
#ifdef PICOJSON_USE_INT64
SET(int64_t, int64, u_.int64_ = _val;)
#endif
#undef SET
#if PICOJSON_USE_RVALUE_REFERENCE
@ -515,18 +477,16 @@ namespace json
return u_.boolean_;
case number_type:
return u_.number_ != 0;
#ifdef PICOJSON_USE_INT64
case int64_type:
return u_.int64_ != 0;
#endif
case int32_type:
return u_.int32_ != 0;
case uint64_type:
return u_.uint64_ != 0;
case uint32_type:
return u_.uint32_ != 0;
case uint16_type:
return u_.uint32_ != 0;
return u_.uint16_ != 0;
case uint8_type:
return u_.uint32_ != 0;
return u_.uint8_ != 0;
case float_type:
return u_.float_ != 0;
case string_type:
@ -579,13 +539,6 @@ namespace json
return "null";
case boolean_type:
return u_.boolean_ ? "true" : "false";
#ifdef PICOJSON_USE_INT64
case int64_type: {
char buf[sizeof("-9223372036854775808")];
SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.int64_);
return buf;
}
#endif
case number_type: {
char buf[256];
double tmp;
@ -608,6 +561,11 @@ namespace json
SNPRINTF(buf, sizeof(buf), "%d", u_.int32_);
return buf;
}
case uint64_type: {
char buf[256];
SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.uint64_);
return buf;
}
case uint32_type: {
char buf[256];
SNPRINTF(buf, sizeof(buf), "%u", u_.uint32_);
@ -650,14 +608,12 @@ namespace json
return "null";
case boolean_type:
return "boolean";
#ifdef PICOJSON_USE_INT64
case int64_type:
return "int64";
#endif
case number_type:
return "number";
case int32_type:
return "int32";
case uint64_type:
return "uint64";
case uint32_type:
return "uint32";
case uint16_type:
@ -1113,18 +1069,6 @@ namespace json
return false;
}
#ifdef PICOJSON_USE_INT64
{
errno = 0;
intmax_t ival = strtoimax(num_str.c_str(), &endp, 10);
if (errno == 0 && std::numeric_limits<int64_t>::min() <= ival && ival <= std::numeric_limits<int64_t>::max() &&
endp == num_str.c_str() + num_str.size()) {
ctx.set_int64(ival);
return true;
}
}
#endif
f = strtod(num_str.c_str(), &endp);
if (endp == num_str.c_str() + num_str.size()) {
ctx.set_number(f);
@ -1154,12 +1098,6 @@ namespace json
return false;
}
#ifdef PICOJSON_USE_INT64
bool set_int64(int64_t) {
return false;
}
#endif
bool set_number(double) {
return false;
}
@ -1212,13 +1150,6 @@ namespace json
return true;
}
#ifdef PICOJSON_USE_INT64
bool set_int64(int64_t i) {
*out_ = value(i);
return true;
}
#endif
bool set_number(double f) {
*out_ = value(f);
return true;
@ -1300,12 +1231,6 @@ namespace json
return true;
}
#ifdef PICOJSON_USE_INT64
bool set_int64(int64_t) {
return true;
}
#endif
bool set_number(double) {
return true;
}

@ -429,6 +429,10 @@ bool HostFNE::createMasterNetwork()
m_network->setLookups(m_ridLookup, m_tidLookup);
if (m_RESTAPI != nullptr) {
m_RESTAPI->setNetwork(m_network);
}
bool ret = m_network->open();
if (!ret) {
delete m_network;

@ -485,7 +485,9 @@ void FNENetwork::clock(uint32_t ms)
// validate peer (simple validation really)
if (connection.connected() && connection.address() == ip) {
uint32_t pingsRx = connection.pingsReceived();
connection.pingsReceived(pingsRx++);
pingsRx++;
connection.pingsReceived(pingsRx);
connection.lastPing(now);
connection.pktLastSeq(connection.pktLastSeq() + 1);
@ -493,7 +495,7 @@ void FNENetwork::clock(uint32_t ms)
writePeerCommand(peerId, { NET_FUNC_PONG, NET_SUBFUNC_NOP });
if (m_debug) {
LogDebug(LOG_NET, "PEER %u ping received and answered", peerId);
LogDebug(LOG_NET, "PEER %u ping received and answered, pingsReceived = %u", peerId, connection.pingsReceived());
}
}
else {

@ -42,6 +42,7 @@
// ---------------------------------------------------------------------------
class HOST_SW_API HostFNE;
class HOST_SW_API RESTAPI;
namespace network { namespace fne { class HOST_SW_API TagDMRData; } }
namespace network { namespace fne { class HOST_SW_API TagP25Data; } }
namespace network { namespace fne { class HOST_SW_API TagNXDNData; } }
@ -212,6 +213,7 @@ namespace network
friend class fne::TagNXDNData;
fne::TagNXDNData* m_tagNXDN;
friend class ::RESTAPI;
HostFNE* m_host;
std::string m_address;

@ -154,6 +154,7 @@ RESTAPI::RESTAPI(const std::string& address, uint16_t port, const std::string& p
m_passwordHash(nullptr),
m_debug(debug),
m_host(host),
m_network(nullptr),
m_ridLookup(nullptr),
m_tidLookup(nullptr),
m_authTokens()
@ -204,6 +205,15 @@ void RESTAPI::setLookups(lookups::RadioIdLookup* ridLookup, lookups::TalkgroupRu
m_tidLookup = tidLookup;
}
/// <summary>
/// Sets the instance of the FNE network.
/// </summary>
/// <param name="network">FNE Network Instance</param>
void RESTAPI::setNetwork(network::FNENetwork* network)
{
m_network = network;
}
/// <summary>
/// Opens connection to the network.
/// </summary>
@ -245,6 +255,8 @@ void RESTAPI::initializeEndpoints()
m_dispatcher.match(PUT_AUTHENTICATE).put(REST_API_BIND(RESTAPI::restAPI_PutAuth, this));
m_dispatcher.match(GET_VERSION).get(REST_API_BIND(RESTAPI::restAPI_GetVersion, this));
m_dispatcher.match(GET_STATUS).get(REST_API_BIND(RESTAPI::restAPI_GetStatus, this));
m_dispatcher.match(GET_PEERLIST).get(REST_API_BIND(RESTAPI::restAPI_GetPeerList, this));
}
/// <summary>
@ -394,3 +406,86 @@ void RESTAPI::restAPI_GetVersion(const HTTPPayload& request, HTTPPayload& reply,
reply.payload(response);
}
/// <summary>
///
/// </summary>
/// <param name="request"></param>
/// <param name="reply"></param>
/// <param name="match"></param>
void RESTAPI::restAPI_GetStatus(const HTTPPayload& request, HTTPPayload& reply, const RequestMatch& match)
{
if (!validateAuth(request, reply)) {
return;
}
json::object response = json::object();
setResponseDefaultStatus(response);
yaml::Node systemConf = m_host->m_conf["system"];
yaml::Node masterConf = m_host->m_conf["master"];
{
uint8_t state = FNE_STATE;
response["state"].set<uint8_t>(state);
response["dmrEnabled"].set<bool>(m_host->m_dmrEnabled);
response["p25Enabled"].set<bool>(m_host->m_p25Enabled);
response["nxdnEnabled"].set<bool>(m_host->m_nxdnEnabled);
uint32_t peerId = masterConf["peerId"].as<uint32_t>();
response["peerId"].set<uint32_t>(peerId);
}
reply.payload(response);
}
/// <summary>
///
/// </summary>
/// <param name="request"></param>
/// <param name="reply"></param>
/// <param name="match"></param>
void RESTAPI::restAPI_GetPeerList(const HTTPPayload& request, HTTPPayload& reply, const RequestMatch& match)
{
if (!validateAuth(request, reply)) {
return;
}
json::object response = json::object();
setResponseDefaultStatus(response);
json::array peers = json::array();
if (m_network != nullptr) {
if (m_network->m_peers.size() > 0) {
for (auto entry : m_network->m_peers) {
uint32_t peerId = entry.first;
network::FNEPeerConnection peer = entry.second;
json::object peerObj = json::object();
peerObj["peerId"].set<uint32_t>(peerId);
std::string address = peer.address();
peerObj["address"].set<std::string>(address);
uint16_t port = peer.port();
peerObj["port"].set<uint16_t>(port);
bool connected = peer.connected();
peerObj["connected"].set<bool>(connected);
uint32_t connectionState = (uint32_t)peer.connectionState();
peerObj["connectionState"].set<uint32_t>(connectionState);
uint32_t pingsReceived = peer.pingsReceived();
peerObj["pingsReceived"].set<uint32_t>(pingsReceived);
uint64_t lastPing = peer.lastPing();
peerObj["lastPing"].set<uint64_t>(lastPing);
json::object peerConfig = peer.config();
if (peerConfig["rcon"].is<json::object>())
peerConfig.erase("rcon");
peerObj["config"].set<json::object>(peerConfig);
peers.push_back(json::value(peerObj));
}
}
}
response["peers"].set<json::array>(peers);
reply.payload(response);
}

@ -44,6 +44,7 @@
// ---------------------------------------------------------------------------
class HOST_SW_API HostFNE;
namespace network { class HOST_SW_API FNENetwork; }
// ---------------------------------------------------------------------------
// Class Declaration
@ -59,6 +60,8 @@ public:
/// <summary>Sets the instances of the Radio ID and Talkgroup ID lookup tables.</summary>
void setLookups(::lookups::RadioIdLookup* ridLookup, ::lookups::TalkgroupRulesLookup* tidLookup);
/// <summary>Sets the instance of the FNE network.</summary>
void setNetwork(::network::FNENetwork* network);
/// <summary>Opens connection to the network.</summary>
bool open();
@ -79,6 +82,7 @@ private:
bool m_debug;
HostFNE* m_host;
network::FNENetwork *m_network;
::lookups::RadioIdLookup* m_ridLookup;
::lookups::TalkgroupRulesLookup* m_tidLookup;
@ -102,6 +106,10 @@ private:
/// <summary></summary>
void restAPI_GetVersion(const HTTPPayload& request, HTTPPayload& reply, const network::rest::RequestMatch& match);
/// <summary></summary>
void restAPI_GetStatus(const HTTPPayload& request, HTTPPayload& reply, const network::rest::RequestMatch& match);
/// <summary></summary>
void restAPI_GetPeerList(const HTTPPayload& request, HTTPPayload& reply, const network::rest::RequestMatch& match);
};
#endif // __REST_API_H__

@ -23,19 +23,16 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__REST_DEFINES_H__)
#define __REST_DEFINES_H__
#if !defined(__FNE_REST_DEFINES_H__)
#define __FNE_REST_DEFINES_H__
#include "fne/Defines.h"
#include "host/network/RESTDefines.h"
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
#define DVM_REST_RAND_MAX 0xfffffffffffffffe
#define GET_PEERLIST "/peerlist"
#define PUT_AUTHENTICATE "/auth"
#define GET_VERSION "/version"
#endif // __REST_API_H__
#endif // __FNE_REST_DEFINES_H__

@ -103,4 +103,4 @@
#define GET_NXDN_DUMP_RCCH GET_NXDN_DUMP_RCCH_BASE"(\\d+)"
#define GET_NXDN_CC_DEDICATED "/nxdn/cc-enable"
#endif // __REST_API_H__
#endif // __REST_DEFINES_H__

@ -25,6 +25,7 @@
*/
#include "remote/RESTClient.h"
#include "host/network/RESTDefines.h"
#include "fne/network/RESTDefines.h"
#include "common/Thread.h"
#include "common/Log.h"
#include "common/Utils.h"
@ -53,6 +54,7 @@
#define RCD_GET_VERSION "version"
#define RCD_GET_STATUS "status"
#define RCD_GET_VOICE_CH "voice-ch"
#define RCD_GET_PEERLIST "peerlist"
#define RCD_MODE "mdm-mode"
#define RCD_MODE_OPT_IDLE "idle"
@ -187,6 +189,7 @@ void usage(const char* message, const char* arg)
reply += " version Display current version of host\r\n";
reply += " status Display current settings and operation mode\r\n";
reply += " voice-ch Retrieves the list of configured voice channels\r\n";
reply += " peerlist Retrieves the list of connected peers (FNE only)\r\n";
reply += "\r\n";
reply += " mdm-mode <mode> Set current mode of host (idle, lockout, dmr, p25, nxdn)\r\n";
reply += " mdm-kill Causes the host to quit\r\n";
@ -429,6 +432,9 @@ int main(int argc, char** argv)
else if (rcom == RCD_GET_VOICE_CH) {
retCode = client->send(HTTP_GET, GET_VOICE_CH, json::object(), response);
}
else if (rcom == RCD_GET_PEERLIST) {
retCode = client->send(HTTP_GET, GET_PEERLIST, json::object(), response);
}
else if (rcom == RCD_MODE && argCnt >= 1U) {
std::string mode = getArgString(args, 0U);

Loading…
Cancel
Save

Powered by TurnKey Linux.