|
|
|
|
@ -832,9 +832,10 @@ void TrafficNetwork::clock(uint32_t ms)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// cleanup possibly stale data calls
|
|
|
|
|
if (m_patchStatusEnabled && m_patchStatusRegistry.cleanupExpired() > 0U)
|
|
|
|
|
writePatchStatusToConsoles(m_patchStatusRegistry.snapshot());
|
|
|
|
|
|
|
|
|
|
// cleanup possibly stale data calls
|
|
|
|
|
m_tagDMR->packetData()->cleanupStale();
|
|
|
|
|
m_tagP25->packetData()->cleanupStale();
|
|
|
|
|
|
|
|
|
|
@ -1569,162 +1570,6 @@ json::object TrafficNetwork::fneConnObject(uint32_t peerId, FNEPeerConnection *c
|
|
|
|
|
return peerObj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper to send patch status state to one console peer. */
|
|
|
|
|
|
|
|
|
|
bool TrafficNetwork::writePatchStatusToPeer(uint32_t peerId, json::object obj)
|
|
|
|
|
{
|
|
|
|
|
if (peerId == 0U)
|
|
|
|
|
return false;
|
|
|
|
|
if (!m_patchStatusEnabled)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
bool ret = false;
|
|
|
|
|
m_peers.shared_lock();
|
|
|
|
|
auto it = std::find_if(m_peers.begin(), m_peers.end(), [&](PeerMapPair x) { return x.first == peerId; });
|
|
|
|
|
if (it != m_peers.end() && it->second != nullptr)
|
|
|
|
|
ret = writePatchStatusPayload(it->second, obj);
|
|
|
|
|
m_peers.shared_unlock();
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper to broadcast patch status state to connected console peers. */
|
|
|
|
|
|
|
|
|
|
void TrafficNetwork::writePatchStatusToConsoles(json::object obj, uint32_t exceptPeerId)
|
|
|
|
|
{
|
|
|
|
|
if (!m_patchStatusEnabled)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_peers.shared_lock();
|
|
|
|
|
if (m_peers.size() == 0U) {
|
|
|
|
|
m_peers.shared_unlock();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto peer : m_peers) {
|
|
|
|
|
if (peer.first == exceptPeerId)
|
|
|
|
|
continue;
|
|
|
|
|
if (peer.second == nullptr)
|
|
|
|
|
continue;
|
|
|
|
|
if (!peer.second->connected() || peer.second->peerClass() != PEER_CONN_CLASS_CONSOLE)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
writePatchStatusPayload(peer.second, obj);
|
|
|
|
|
}
|
|
|
|
|
m_peers.shared_unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper to replicate patch status state to neighboring FNE peers. */
|
|
|
|
|
|
|
|
|
|
void TrafficNetwork::replicatePatchStatus(json::object obj, uint32_t exceptPeerId)
|
|
|
|
|
{
|
|
|
|
|
if (!m_patchStatusEnabled)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
obj["type"].set<std::string>("publish");
|
|
|
|
|
|
|
|
|
|
if (m_host->m_peerNetworks.size() > 0U) {
|
|
|
|
|
for (auto peer : m_host->m_peerNetworks) {
|
|
|
|
|
if (peer.first == exceptPeerId)
|
|
|
|
|
continue;
|
|
|
|
|
if (peer.second != nullptr && peer.second->isEnabled() && peer.second->isReplica())
|
|
|
|
|
peer.second->writePatchStatus(obj);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_peers.shared_lock();
|
|
|
|
|
for (auto peer : m_peers) {
|
|
|
|
|
if (peer.first == exceptPeerId)
|
|
|
|
|
continue;
|
|
|
|
|
if (peer.second == nullptr)
|
|
|
|
|
continue;
|
|
|
|
|
if (!peer.second->connected() || peer.second->peerClass() != PEER_CONN_CLASS_NEIGHBOR || !peer.second->isReplica())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
writePatchStatusReplicationPayload(peer.second, obj);
|
|
|
|
|
}
|
|
|
|
|
m_peers.shared_unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper to serialize and queue a patch status transfer payload. */
|
|
|
|
|
|
|
|
|
|
bool TrafficNetwork::writePatchStatusPayload(FNEPeerConnection* connection, json::object obj)
|
|
|
|
|
{
|
|
|
|
|
if (connection == nullptr)
|
|
|
|
|
return false;
|
|
|
|
|
if (!m_patchStatusEnabled)
|
|
|
|
|
return false;
|
|
|
|
|
if (m_host->m_mdNetwork == nullptr)
|
|
|
|
|
return false;
|
|
|
|
|
if (!connection->connected())
|
|
|
|
|
return false;
|
|
|
|
|
if (connection->peerClass() != PEER_CONN_CLASS_CONSOLE)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
obj["type"].set<std::string>("registry");
|
|
|
|
|
json::value v = json::value(obj);
|
|
|
|
|
std::string payload = std::string(v.serialize());
|
|
|
|
|
uint32_t len = static_cast<uint32_t>(payload.length());
|
|
|
|
|
if ((len + 11U) > DATA_PACKET_LENGTH) {
|
|
|
|
|
LogError(LOG_MASTER, "PEER %u (%s) patch status registry payload too large, len = %u", connection->id(), connection->identWithQualifier().c_str(), len);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t buffer[DATA_PACKET_LENGTH];
|
|
|
|
|
::memset(buffer, 0x00U, DATA_PACKET_LENGTH);
|
|
|
|
|
::memcpy(buffer + 11U, payload.c_str(), len);
|
|
|
|
|
|
|
|
|
|
if (m_debug) {
|
|
|
|
|
LogDebug(LOG_MASTER, "PEER %u (%s) sending patch status registry, len = %u", connection->id(), connection->identWithQualifier().c_str(), len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return m_host->m_mdNetwork->writePeerMetadata(connection, m_peerId,
|
|
|
|
|
{ NET_FUNC::TRANSFER, NET_SUBFUNC::TRANSFER_SUBFUNC_PATCH_STATUS }, buffer, len + 11U, RTP_END_OF_CALL_SEQ, createStreamId());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper to serialize and queue a patch status replication payload. */
|
|
|
|
|
|
|
|
|
|
bool TrafficNetwork::writePatchStatusReplicationPayload(FNEPeerConnection* connection, json::object obj)
|
|
|
|
|
{
|
|
|
|
|
if (connection == nullptr)
|
|
|
|
|
return false;
|
|
|
|
|
if (!m_patchStatusEnabled)
|
|
|
|
|
return false;
|
|
|
|
|
if (m_host->m_mdNetwork == nullptr)
|
|
|
|
|
return false;
|
|
|
|
|
if (!connection->connected())
|
|
|
|
|
return false;
|
|
|
|
|
if (connection->peerClass() != PEER_CONN_CLASS_NEIGHBOR || !connection->isReplica())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
obj["type"].set<std::string>("publish");
|
|
|
|
|
json::value v = json::value(obj);
|
|
|
|
|
std::string json = std::string(v.serialize());
|
|
|
|
|
|
|
|
|
|
size_t len = json.length() + 9U;
|
|
|
|
|
DECLARE_CHAR_ARRAY(buffer, len);
|
|
|
|
|
|
|
|
|
|
::memcpy(buffer + 0U, TAG_PEER_REPLICA, 4U);
|
|
|
|
|
::snprintf(buffer + 8U, json.length() + 1U, "%s", json.c_str());
|
|
|
|
|
|
|
|
|
|
PacketBuffer pkt(true, "Peer Replication, Patch Status");
|
|
|
|
|
pkt.encode((uint8_t*)buffer, len);
|
|
|
|
|
|
|
|
|
|
uint32_t streamId = createStreamId();
|
|
|
|
|
LogInfoEx(LOG_REPL, "PEER %u (%s) Peer Replication, Patch Status, blocks %u, streamId = %u", connection->id(),
|
|
|
|
|
connection->identWithQualifier().c_str(), pkt.fragments.size(), streamId);
|
|
|
|
|
if (pkt.fragments.size() > 0U) {
|
|
|
|
|
for (auto frag : pkt.fragments) {
|
|
|
|
|
m_host->m_mdNetwork->writePeerMetadata(connection, m_peerId, { NET_FUNC::REPL, NET_SUBFUNC::REPL_PATCH_STATUS },
|
|
|
|
|
frag.second->data, FRAG_SIZE, RTP_END_OF_CALL_SEQ, streamId);
|
|
|
|
|
Thread::sleep(60U); // pace block transmission
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pkt.clear();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper to reset a peer connection. */
|
|
|
|
|
|
|
|
|
|
bool TrafficNetwork::resetPeer(uint32_t peerId)
|
|
|
|
|
@ -2102,6 +1947,166 @@ void TrafficNetwork::taskMetadataUpdate(MetadataUpdateRequest* req)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** Console Patch Registry
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Helper to send patch status state to one console peer. */
|
|
|
|
|
|
|
|
|
|
bool TrafficNetwork::writePatchStatusToPeer(uint32_t peerId, json::object obj)
|
|
|
|
|
{
|
|
|
|
|
if (peerId == 0U)
|
|
|
|
|
return false;
|
|
|
|
|
if (!m_patchStatusEnabled)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
bool ret = false;
|
|
|
|
|
m_peers.shared_lock();
|
|
|
|
|
auto it = std::find_if(m_peers.begin(), m_peers.end(), [&](PeerMapPair x) { return x.first == peerId; });
|
|
|
|
|
if (it != m_peers.end() && it->second != nullptr)
|
|
|
|
|
ret = writePatchStatusPayload(it->second, obj);
|
|
|
|
|
m_peers.shared_unlock();
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper to broadcast patch status state to connected console peers. */
|
|
|
|
|
|
|
|
|
|
void TrafficNetwork::writePatchStatusToConsoles(json::object obj, uint32_t exceptPeerId)
|
|
|
|
|
{
|
|
|
|
|
if (!m_patchStatusEnabled)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_peers.shared_lock();
|
|
|
|
|
if (m_peers.size() == 0U) {
|
|
|
|
|
m_peers.shared_unlock();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto peer : m_peers) {
|
|
|
|
|
if (peer.first == exceptPeerId)
|
|
|
|
|
continue;
|
|
|
|
|
if (peer.second == nullptr)
|
|
|
|
|
continue;
|
|
|
|
|
if (!peer.second->connected() || peer.second->peerClass() != PEER_CONN_CLASS_CONSOLE)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
writePatchStatusPayload(peer.second, obj);
|
|
|
|
|
}
|
|
|
|
|
m_peers.shared_unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper to replicate patch status state to neighboring FNE peers. */
|
|
|
|
|
|
|
|
|
|
void TrafficNetwork::replicatePatchStatus(json::object obj, uint32_t exceptPeerId)
|
|
|
|
|
{
|
|
|
|
|
if (!m_patchStatusEnabled)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
obj["type"].set<std::string>("publish");
|
|
|
|
|
|
|
|
|
|
if (m_host->m_peerNetworks.size() > 0U) {
|
|
|
|
|
for (auto peer : m_host->m_peerNetworks) {
|
|
|
|
|
if (peer.first == exceptPeerId)
|
|
|
|
|
continue;
|
|
|
|
|
if (peer.second != nullptr && peer.second->isEnabled() && peer.second->isReplica())
|
|
|
|
|
peer.second->writePatchStatus(obj);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_peers.shared_lock();
|
|
|
|
|
for (auto peer : m_peers) {
|
|
|
|
|
if (peer.first == exceptPeerId)
|
|
|
|
|
continue;
|
|
|
|
|
if (peer.second == nullptr)
|
|
|
|
|
continue;
|
|
|
|
|
if (!peer.second->connected() || peer.second->peerClass() != PEER_CONN_CLASS_NEIGHBOR || !peer.second->isReplica())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
writePatchStatusReplicationPayload(peer.second, obj);
|
|
|
|
|
}
|
|
|
|
|
m_peers.shared_unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper to serialize and queue a patch status transfer payload. */
|
|
|
|
|
|
|
|
|
|
bool TrafficNetwork::writePatchStatusPayload(FNEPeerConnection* connection, json::object obj)
|
|
|
|
|
{
|
|
|
|
|
if (connection == nullptr)
|
|
|
|
|
return false;
|
|
|
|
|
if (!m_patchStatusEnabled)
|
|
|
|
|
return false;
|
|
|
|
|
if (m_host->m_mdNetwork == nullptr)
|
|
|
|
|
return false;
|
|
|
|
|
if (!connection->connected())
|
|
|
|
|
return false;
|
|
|
|
|
if (connection->peerClass() != PEER_CONN_CLASS_CONSOLE)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
obj["type"].set<std::string>("registry");
|
|
|
|
|
json::value v = json::value(obj);
|
|
|
|
|
std::string payload = std::string(v.serialize());
|
|
|
|
|
uint32_t len = static_cast<uint32_t>(payload.length());
|
|
|
|
|
if ((len + 11U) > DATA_PACKET_LENGTH) {
|
|
|
|
|
LogError(LOG_MASTER, "PEER %u (%s) patch status registry payload too large, len = %u", connection->id(), connection->identWithQualifier().c_str(), len);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t buffer[DATA_PACKET_LENGTH];
|
|
|
|
|
::memset(buffer, 0x00U, DATA_PACKET_LENGTH);
|
|
|
|
|
::memcpy(buffer + 11U, payload.c_str(), len);
|
|
|
|
|
|
|
|
|
|
if (m_debug) {
|
|
|
|
|
LogDebug(LOG_MASTER, "PEER %u (%s) sending patch status registry, len = %u", connection->id(), connection->identWithQualifier().c_str(), len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return m_host->m_mdNetwork->writePeerMetadata(connection, m_peerId,
|
|
|
|
|
{ NET_FUNC::TRANSFER, NET_SUBFUNC::TRANSFER_SUBFUNC_PATCH_STATUS }, buffer, len + 11U, RTP_END_OF_CALL_SEQ, createStreamId());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper to serialize and queue a patch status replication payload. */
|
|
|
|
|
|
|
|
|
|
bool TrafficNetwork::writePatchStatusReplicationPayload(FNEPeerConnection* connection, json::object obj)
|
|
|
|
|
{
|
|
|
|
|
if (connection == nullptr)
|
|
|
|
|
return false;
|
|
|
|
|
if (!m_patchStatusEnabled)
|
|
|
|
|
return false;
|
|
|
|
|
if (m_host->m_mdNetwork == nullptr)
|
|
|
|
|
return false;
|
|
|
|
|
if (!connection->connected())
|
|
|
|
|
return false;
|
|
|
|
|
if (connection->peerClass() != PEER_CONN_CLASS_NEIGHBOR || !connection->isReplica())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
obj["type"].set<std::string>("publish");
|
|
|
|
|
json::value v = json::value(obj);
|
|
|
|
|
std::string json = std::string(v.serialize());
|
|
|
|
|
|
|
|
|
|
size_t len = json.length() + 9U;
|
|
|
|
|
DECLARE_CHAR_ARRAY(buffer, len);
|
|
|
|
|
|
|
|
|
|
::memcpy(buffer + 0U, TAG_PEER_REPLICA, 4U);
|
|
|
|
|
::snprintf(buffer + 8U, json.length() + 1U, "%s", json.c_str());
|
|
|
|
|
|
|
|
|
|
PacketBuffer pkt(true, "Peer Replication, Patch Status");
|
|
|
|
|
pkt.encode((uint8_t*)buffer, len);
|
|
|
|
|
|
|
|
|
|
uint32_t streamId = createStreamId();
|
|
|
|
|
LogInfoEx(LOG_REPL, "PEER %u (%s) Peer Replication, Patch Status, blocks %u, streamId = %u", connection->id(),
|
|
|
|
|
connection->identWithQualifier().c_str(), pkt.fragments.size(), streamId);
|
|
|
|
|
if (pkt.fragments.size() > 0U) {
|
|
|
|
|
for (auto frag : pkt.fragments) {
|
|
|
|
|
m_host->m_mdNetwork->writePeerMetadata(connection, m_peerId, { NET_FUNC::REPL, NET_SUBFUNC::REPL_PATCH_STATUS },
|
|
|
|
|
frag.second->data, FRAG_SIZE, RTP_END_OF_CALL_SEQ, streamId);
|
|
|
|
|
Thread::sleep(60U); // pace block transmission
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pkt.clear();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** ACL Message Writing
|
|
|
|
|
*/
|
|
|
|
|
|