diff --git a/src/fne/network/TrafficNetwork.cpp b/src/fne/network/TrafficNetwork.cpp index eff07cbc..0a5842b9 100644 --- a/src/fne/network/TrafficNetwork.cpp +++ b/src/fne/network/TrafficNetwork.cpp @@ -1889,7 +1889,7 @@ void TrafficNetwork::taskNetworkRx(NetPacketRequest* req) FNEPeerConnection* connection = network->m_peers[peerId]; if (connection != nullptr) { std::string ip = udp::Socket::address(req->address); - lookups::AffiliationLookup* aff = network->m_peerAffiliations[peerId]; + std::shared_ptr aff = network->getPeerAffiliations(peerId); if (aff == nullptr) { LogError(LOG_MASTER, "PEER %u (%s) has uninitialized affiliations lookup?", peerId, connection->identWithQualifier().c_str()); network->writePeerNAK(peerId, streamId, TAG_ANNOUNCE, NET_CONN_NAK_INVALID); @@ -1928,7 +1928,7 @@ void TrafficNetwork::taskNetworkRx(NetPacketRequest* req) FNEPeerConnection* connection = network->m_peers[peerId]; if (connection != nullptr) { std::string ip = udp::Socket::address(req->address); - fne_lookups::AffiliationLookup* aff = network->m_peerAffiliations[peerId]; + std::shared_ptr aff = network->getPeerAffiliations(peerId); if (aff == nullptr) { LogError(LOG_MASTER, "PEER %u (%s) has uninitialized affiliations lookup?", peerId, connection->identWithQualifier().c_str()); network->writePeerNAK(peerId, streamId, TAG_ANNOUNCE, NET_CONN_NAK_INVALID); @@ -1965,7 +1965,7 @@ void TrafficNetwork::taskNetworkRx(NetPacketRequest* req) FNEPeerConnection* connection = network->m_peers[peerId]; if (connection != nullptr) { std::string ip = udp::Socket::address(req->address); - lookups::AffiliationLookup* aff = network->m_peerAffiliations[peerId]; + std::shared_ptr aff = network->getPeerAffiliations(peerId); if (aff == nullptr) { LogError(LOG_MASTER, "PEER %u (%s) has uninitialized affiliations lookup?", peerId, connection->identWithQualifier().c_str()); network->writePeerNAK(peerId, streamId, TAG_ANNOUNCE, NET_CONN_NAK_INVALID); @@ -2003,7 +2003,7 @@ void TrafficNetwork::taskNetworkRx(NetPacketRequest* req) FNEPeerConnection* connection = network->m_peers[peerId]; if (connection != nullptr) { std::string ip = udp::Socket::address(req->address); - lookups::AffiliationLookup* aff = network->m_peerAffiliations[peerId]; + std::shared_ptr aff = network->getPeerAffiliations(peerId); if (aff == nullptr) { LogError(LOG_MASTER, "PEER %u (%s) has uninitialized affiliations lookup?", peerId, connection->identWithQualifier().c_str()); network->writePeerNAK(peerId, streamId, TAG_ANNOUNCE, NET_CONN_NAK_INVALID); @@ -2044,7 +2044,7 @@ void TrafficNetwork::taskNetworkRx(NetPacketRequest* req) // validate peer (simple validation really) if (connection->connected() && connection->address() == ip) { - lookups::AffiliationLookup* aff = network->m_peerAffiliations[peerId]; + std::shared_ptr aff = network->getPeerAffiliations(peerId); if (aff == nullptr) { LogError(LOG_MASTER, "PEER %u (%s) has uninitialized affiliations lookup?", peerId, connection->identWithQualifier().c_str()); network->writePeerNAK(peerId, streamId, TAG_ANNOUNCE, NET_CONN_NAK_INVALID); @@ -2227,34 +2227,74 @@ void TrafficNetwork::eraseStreamPktSeq(uint32_t peerId, uint32_t streamId) void TrafficNetwork::createPeerAffiliations(uint32_t peerId, std::string peerName) { - erasePeerAffiliations(peerId); + std::lock_guard lock(m_peerAffiliationsMutex); + + auto it = m_peerAffiliations.find(peerId); + if (it != m_peerAffiliations.end()) { + m_peerAffiliations.erase(peerId); + } lookups::ChannelLookup* chLookup = new lookups::ChannelLookup(); - m_peerAffiliations[peerId] = new fne_lookups::AffiliationLookup(peerName, chLookup, m_verbose); - m_peerAffiliations[peerId]->setDisableUnitRegTimeout(true); // FNE doesn't allow unit registration timeouts (notification must come from the peers) + std::shared_ptr aff( + new fne_lookups::AffiliationLookup(peerName, chLookup, m_verbose), + [](fne_lookups::AffiliationLookup* p) { + if (p != nullptr) { + lookups::ChannelLookup* rfCh = p->rfCh(); + if (rfCh != nullptr) { + delete rfCh; + } + delete p; + } + }); + + aff->setDisableUnitRegTimeout(true); // FNE doesn't allow unit registration timeouts (notification must come from the peers) + m_peerAffiliations.insert(peerId, aff); } /* Helper to erase the peer from the peers affiliations list. */ bool TrafficNetwork::erasePeerAffiliations(uint32_t peerId) { - auto it = std::find_if(m_peerAffiliations.begin(), m_peerAffiliations.end(), [&](PeerAffiliationMapPair x) { return x.first == peerId; }); + std::lock_guard lock(m_peerAffiliationsMutex); + + auto it = m_peerAffiliations.find(peerId); if (it != m_peerAffiliations.end()) { - lookups::AffiliationLookup* aff = m_peerAffiliations[peerId]; - if (aff != nullptr) { - lookups::ChannelLookup* rfCh = aff->rfCh(); - if (rfCh != nullptr) - delete rfCh; - delete aff; - } m_peerAffiliations.erase(peerId); - return true; } return false; } +/* Helper to get the peer affiliations entry for a peer. */ + +std::shared_ptr TrafficNetwork::getPeerAffiliations(uint32_t peerId) const +{ + std::lock_guard lock(m_peerAffiliationsMutex); + + auto it = m_peerAffiliations.find(peerId); + if (it != m_peerAffiliations.end()) { + return it->second; + } + + return nullptr; +} + +/* Helper to create a snapshot of all peer affiliation entries. */ + +std::vector TrafficNetwork::peerAffiliationsSnapshot() const +{ + std::vector snapshot; + + std::lock_guard lock(m_peerAffiliationsMutex); + snapshot.reserve(m_peerAffiliations.size()); + for (auto it = m_peerAffiliations.begin(); it != m_peerAffiliations.end(); ++it) { + snapshot.push_back(*it); + } + + return snapshot; +} + /* Helper to disconnect a downstream peer. */ void TrafficNetwork::disconnectPeer(uint32_t peerId, FNEPeerConnection* connection) @@ -2356,8 +2396,9 @@ bool TrafficNetwork::isPeerLocal(uint32_t peerId) uint32_t TrafficNetwork::findPeerUnitReg(uint32_t srcId) { - for (auto it = m_peerAffiliations.begin(); it != m_peerAffiliations.end(); ++it) { - fne_lookups::AffiliationLookup* aff = it->second; + std::vector affSnapshot = peerAffiliationsSnapshot(); + for (const auto& entry : affSnapshot) { + std::shared_ptr aff = entry.second; if (aff != nullptr) { if (aff->isUnitReg(srcId)) { return aff->getSSRCByUnitReg(srcId); diff --git a/src/fne/network/TrafficNetwork.h b/src/fne/network/TrafficNetwork.h index 27d7f4d3..4ec8972d 100644 --- a/src/fne/network/TrafficNetwork.h +++ b/src/fne/network/TrafficNetwork.h @@ -46,6 +46,7 @@ #include #include #include +#include #include // --------------------------------------------------------------------------- @@ -339,8 +340,9 @@ namespace network typedef std::pair PeerMapPair; concurrent::shared_unordered_map m_peers; concurrent::unordered_map m_peerReplicaPeers; - typedef std::pair PeerAffiliationMapPair; - concurrent::unordered_map m_peerAffiliations; + typedef std::pair> PeerAffiliationMapPair; + concurrent::unordered_map> m_peerAffiliations; + mutable std::mutex m_peerAffiliationsMutex; concurrent::shared_unordered_map> m_ccPeerMap; static std::timed_mutex s_keyQueueMutex; std::unordered_map m_peerReplicaKeyQueue; @@ -470,6 +472,17 @@ namespace network * @returns bool True, if the peer affiliations were deleted, otherwise false. */ bool erasePeerAffiliations(uint32_t peerId); + /** + * @brief Helper to get the peer affiliations entry for a peer. + * @param peerId Peer ID. + * @returns std::shared_ptr Shared affiliations lookup instance. + */ + std::shared_ptr getPeerAffiliations(uint32_t peerId) const; + /** + * @brief Helper to create a snapshot of all peer affiliation entries. + * @returns std::vector Snapshot of peer affiliation entries. + */ + std::vector peerAffiliationsSnapshot() const; /** * @brief Helper to disconnect a downstream peer. * @param peerId Peer ID. diff --git a/src/fne/network/callhandler/TagAnalogData.cpp b/src/fne/network/callhandler/TagAnalogData.cpp index 2e0bb92c..13d161e3 100644 --- a/src/fne/network/callhandler/TagAnalogData.cpp +++ b/src/fne/network/callhandler/TagAnalogData.cpp @@ -646,7 +646,7 @@ bool TagAnalogData::isPeerPermitted(uint32_t peerId, data::NetData& data, uint32 } // check the affiliations for this peer to see if we can repeat traffic - lookups::AffiliationLookup* aff = m_network->m_peerAffiliations[lookupPeerId]; + std::shared_ptr aff = m_network->getPeerAffiliations(lookupPeerId); if (aff == nullptr) { std::string peerIdentity = m_network->resolvePeerIdentity(lookupPeerId); //LogError(LOG_NET, "PEER %u (%s) has an invalid affiliations lookup? This shouldn't happen BUGBUG.", lookupPeerId, peerIdentity.c_str()); diff --git a/src/fne/network/callhandler/TagDMRData.cpp b/src/fne/network/callhandler/TagDMRData.cpp index c643a72b..c370ea18 100644 --- a/src/fne/network/callhandler/TagDMRData.cpp +++ b/src/fne/network/callhandler/TagDMRData.cpp @@ -1067,7 +1067,7 @@ bool TagDMRData::isPeerPermitted(uint32_t peerId, data::NetData& data, uint32_t } // check the affiliations for this peer to see if we can repeat traffic - lookups::AffiliationLookup* aff = m_network->m_peerAffiliations[lookupPeerId]; + std::shared_ptr aff = m_network->getPeerAffiliations(lookupPeerId); if (aff == nullptr) { std::string peerIdentity = m_network->resolvePeerIdentity(lookupPeerId); //LogError(LOG_NET, "PEER %u (%s) has an invalid affiliations lookup? This shouldn't happen BUGBUG.", lookupPeerId, peerIdentity.c_str()); @@ -1405,7 +1405,7 @@ bool TagDMRData::write_CSBK_Grant(uint32_t peerId, uint32_t srcId, uint32_t dstI } // check the affiliations for this peer to see if we can grant traffic - lookups::AffiliationLookup* aff = m_network->m_peerAffiliations[peerId]; + std::shared_ptr aff = m_network->getPeerAffiliations(peerId); if (aff == nullptr) { std::string peerIdentity = m_network->resolvePeerIdentity(peerId); LogError(LOG_MASTER, "PEER %u (%s) has an invalid affiliations lookup? This shouldn't happen BUGBUG.", peerId, peerIdentity.c_str()); diff --git a/src/fne/network/callhandler/TagNXDNData.cpp b/src/fne/network/callhandler/TagNXDNData.cpp index e34b75e5..74579beb 100644 --- a/src/fne/network/callhandler/TagNXDNData.cpp +++ b/src/fne/network/callhandler/TagNXDNData.cpp @@ -941,7 +941,7 @@ bool TagNXDNData::isPeerPermitted(uint32_t peerId, lc::RTCH& lc, uint8_t message } // check the affiliations for this peer to see if we can repeat traffic - lookups::AffiliationLookup* aff = m_network->m_peerAffiliations[lookupPeerId]; + std::shared_ptr aff = m_network->getPeerAffiliations(lookupPeerId); if (aff == nullptr) { std::string peerIdentity = m_network->resolvePeerIdentity(lookupPeerId); //LogError(LOG_NET, "PEER %u (%s) has an invalid affiliations lookup? This shouldn't happen BUGBUG.", lookupPeerId, peerIdentity.c_str()); @@ -1186,7 +1186,7 @@ bool TagNXDNData::write_Message_Grant(uint32_t peerId, uint32_t srcId, uint32_t std::unique_ptr rcch = std::make_unique(); // check the affiliations for this peer to see if we can grant traffic - lookups::AffiliationLookup* aff = m_network->m_peerAffiliations[peerId]; + std::shared_ptr aff = m_network->getPeerAffiliations(peerId); if (aff == nullptr) { std::string peerIdentity = m_network->resolvePeerIdentity(peerId); LogError(LOG_MASTER, "PEER %u (%s) has an invalid affiliations lookup? This shouldn't happen BUGBUG.", peerId, peerIdentity.c_str()); diff --git a/src/fne/network/callhandler/TagP25Data.cpp b/src/fne/network/callhandler/TagP25Data.cpp index c52d39f2..4c09e4de 100644 --- a/src/fne/network/callhandler/TagP25Data.cpp +++ b/src/fne/network/callhandler/TagP25Data.cpp @@ -1286,7 +1286,7 @@ bool TagP25Data::processTSDUTo(uint8_t* buffer, uint32_t peerId, uint8_t duid) } // check the affiliations for this peer to see if we can repeat the TSDU - lookups::AffiliationLookup* aff = m_network->m_peerAffiliations[lookupPeerId]; + std::shared_ptr aff = m_network->getPeerAffiliations(lookupPeerId); if (aff == nullptr) { std::string peerIdentity = m_network->resolvePeerIdentity(lookupPeerId); //LogError(LOG_P25, "PEER %u (%s) has an invalid affiliations lookup? This shouldn't happen BUGBUG.", lookupPeerId, peerIdentity.c_str()); @@ -1513,7 +1513,7 @@ bool TagP25Data::isPeerPermitted(uint32_t peerId, lc::LC& control, DUID::E duid, } // check the affiliations for this peer to see if we can repeat traffic - lookups::AffiliationLookup* aff = m_network->m_peerAffiliations[lookupPeerId]; + std::shared_ptr aff = m_network->getPeerAffiliations(lookupPeerId); if (aff == nullptr) { std::string peerIdentity = m_network->resolvePeerIdentity(lookupPeerId); //LogError(LOG_NET, "PEER %u (%s) has an invalid affiliations lookup? This shouldn't happen BUGBUG.", lookupPeerId, peerIdentity.c_str()); @@ -1889,7 +1889,7 @@ bool TagP25Data::write_TSDU_Grant(uint32_t peerId, uint32_t srcId, uint32_t dstI } // check the affiliations for this peer to see if we can grant traffic - lookups::AffiliationLookup* aff = m_network->m_peerAffiliations[peerId]; + std::shared_ptr aff = m_network->getPeerAffiliations(peerId); if (aff == nullptr) { std::string peerIdentity = m_network->resolvePeerIdentity(peerId); LogError(LOG_MASTER, "PEER %u (%s) has an invalid affiliations lookup? This shouldn't happen BUGBUG.", peerId, peerIdentity.c_str()); diff --git a/src/fne/restapi/RESTAPI.cpp b/src/fne/restapi/RESTAPI.cpp index bf196b53..a3aed956 100644 --- a/src/fne/restapi/RESTAPI.cpp +++ b/src/fne/restapi/RESTAPI.cpp @@ -770,9 +770,9 @@ void RESTAPI::restAPI_PutAuth(const HTTPPayload& request, HTTPPayload& reply, co return; } - if (auth.size() > 64) { + if (auth.size() != 64) { invalidateHostToken(host); - errorPayload(reply, "auth cannot be longer than 64 characters"); + errorPayload(reply, "auth must be 64 characters"); return; } @@ -2083,40 +2083,44 @@ void RESTAPI::restAPI_GetAffList(const HTTPPayload& request, HTTPPayload& reply, if (m_network != nullptr) { uint32_t totalAffiliations = 0U; if (m_network->m_peers.size() > 0) { + std::vector peerIds = std::vector(); + m_network->m_peers.shared_lock(); - m_network->m_peerAffiliations.lock(false); for (auto entry : m_network->m_peers) { uint32_t peerId = entry.first; network::FNEPeerConnection* peer = entry.second; if (peer != nullptr) { - lookups::AffiliationLookup* affLookup = m_network->m_peerAffiliations[peerId]; - if (affLookup != nullptr) { - std::unordered_map affTable = affLookup->grpAffTable(); - - json::object peerObj = json::object(); - peerObj["peerId"].set(peerId); - - json::array peerAffs = json::array(); - if (affLookup->grpAffSize() > 0U) { - for (auto entry : affTable) { - uint32_t srcId = entry.first; - uint32_t dstId = entry.second; - - json::object affObj = json::object(); - affObj["srcId"].set(srcId); - affObj["dstId"].set(dstId); - peerAffs.push_back(json::value(affObj)); - } - } + peerIds.push_back(peerId); + } + } + m_network->m_peers.shared_unlock(); + + for (uint32_t peerId : peerIds) { + std::shared_ptr affLookup = m_network->getPeerAffiliations(peerId); + if (affLookup != nullptr) { + std::unordered_map affTable = affLookup->grpAffTable(); - peerObj["affiliations"].set(peerAffs); - affs.push_back(json::value(peerObj)); - ++totalAffiliations; + json::object peerObj = json::object(); + peerObj["peerId"].set(peerId); + + json::array peerAffs = json::array(); + if (affLookup->grpAffSize() > 0U) { + for (auto entry : affTable) { + uint32_t srcId = entry.first; + uint32_t dstId = entry.second; + + json::object affObj = json::object(); + affObj["srcId"].set(srcId); + affObj["dstId"].set(dstId); + peerAffs.push_back(json::value(affObj)); + } } + + peerObj["affiliations"].set(peerAffs); + affs.push_back(json::value(peerObj)); + ++totalAffiliations; } } - m_network->m_peerAffiliations.unlock(); - m_network->m_peers.shared_unlock(); } response["totalAffiliations"].set(totalAffiliations); diff --git a/src/host/restapi/RESTAPI.cpp b/src/host/restapi/RESTAPI.cpp index f1b818f3..5ebae98f 100644 --- a/src/host/restapi/RESTAPI.cpp +++ b/src/host/restapi/RESTAPI.cpp @@ -407,9 +407,9 @@ void RESTAPI::restAPI_PutAuth(const HTTPPayload& request, HTTPPayload& reply, co return; } - if (auth.size() > 64) { + if (auth.size() != 64) { invalidateHostToken(host); - errorPayload(reply, "auth cannot be longer than 64 characters"); + errorPayload(reply, "auth must be 64 characters"); return; }