// SPDX-License-Identifier: GPL-2.0-only /** * Digital Voice Modem - Converged FNE Software * GPLv2 Open Source. Use is subject to license terms. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * @package DVM / Converged FNE Software * @license GPLv2 License (https://opensource.org/licenses/GPL-2.0) * * Copyright (C) 2023-2024 Bryan Biedenkapp, N2PLL * */ #if !defined(__FNE_NETWORK_H__) #define __FNE_NETWORK_H__ #include "fne/Defines.h" #include "common/network/BaseNetwork.h" #include "common/network/json/json.h" #include "common/lookups/AffiliationLookup.h" #include "common/lookups/RadioIdLookup.h" #include "common/lookups/TalkgroupRulesLookup.h" #include "host/network/Network.h" #include #include #include #include #include // --------------------------------------------------------------------------- // Class Prototypes // --------------------------------------------------------------------------- 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; } } namespace network { // --------------------------------------------------------------------------- // Constants // --------------------------------------------------------------------------- enum DVM_STATE { STATE_IDLE = 0U, // DMR STATE_DMR = 1U, // Project 25 STATE_P25 = 2U, // NXDN STATE_NXDN = 3U, }; // --------------------------------------------------------------------------- // Class Prototypes // --------------------------------------------------------------------------- class HOST_SW_API FNENetwork; // --------------------------------------------------------------------------- // Class Declaration // Represents an peer connection to the FNE. // --------------------------------------------------------------------------- class HOST_SW_API FNEPeerConnection { public: auto operator=(FNEPeerConnection&) -> FNEPeerConnection& = delete; auto operator=(FNEPeerConnection&&) -> FNEPeerConnection& = delete; FNEPeerConnection(FNEPeerConnection&) = delete; /// Initializes a new instance of the FNEPeerConnection class. FNEPeerConnection() : m_id(0U), m_currStreamId(0U), m_socketStorage(), m_sockStorageLen(0U), m_address(), m_port(), m_salt(0U), m_connected(false), m_connectionState(NET_STAT_INVALID), m_pingsReceived(0U), m_lastPing(0U), m_lastACLUpdate(0U), m_config(), m_pktLastSeq(0U), m_pktNextSeq(1U) { /* stub */ } /// Initializes a new instance of the FNEPeerConnection class. /// Unique ID of this modem on the network. /// /// FNEPeerConnection(uint32_t id, sockaddr_storage& socketStorage, uint32_t sockStorageLen) : m_id(id), m_currStreamId(0U), m_socketStorage(socketStorage), m_sockStorageLen(sockStorageLen), m_address(udp::Socket::address(socketStorage)), m_port(udp::Socket::port(socketStorage)), m_salt(0U), m_connected(false), m_connectionState(NET_STAT_INVALID), m_pingsReceived(0U), m_lastPing(0U), m_lastACLUpdate(0U), m_config(), m_pktLastSeq(0U), m_pktNextSeq(1U) { assert(id > 0U); assert(sockStorageLen > 0U); assert(!m_address.empty()); assert(m_port > 0U); } public: /// Peer ID. __PROPERTY_PLAIN(uint32_t, id); /// Current Stream ID. __PROPERTY_PLAIN(uint32_t, currStreamId); /// Unix socket storage containing the connected address. __PROPERTY_PLAIN(sockaddr_storage, socketStorage); /// Length of the sockaddr_storage structure. __PROPERTY_PLAIN(uint32_t, sockStorageLen); /// IP address peer connected with. __PROPERTY_PLAIN(std::string, address); /// Port number peer connected with. __PROPERTY_PLAIN(uint16_t, port); /// Salt value used for peer authentication. __PROPERTY_PLAIN(uint32_t, salt); /// Flag indicating whether or not the peer is connected. __PROPERTY_PLAIN(bool, connected); /// Connection state. __PROPERTY_PLAIN(NET_CONN_STATUS, connectionState); /// Number of pings received. __PROPERTY_PLAIN(uint32_t, pingsReceived); /// Last ping received. __PROPERTY_PLAIN(uint64_t, lastPing); /// Last ACL update sent. __PROPERTY_PLAIN(uint64_t, lastACLUpdate); /// JSON objecting containing peer configuration information. __PROPERTY_PLAIN(json::object, config); /// Last received RTP sequence. __PROPERTY_PLAIN(uint16_t, pktLastSeq); /// Calculated next RTP sequence. __PROPERTY_PLAIN(uint16_t, pktNextSeq); }; // --------------------------------------------------------------------------- // Structure Declaration // Represents the data required for a peer ACL update request thread. // --------------------------------------------------------------------------- struct ACLUpdateRequest { FNENetwork* network; uint32_t peerId; pthread_t thread; }; // --------------------------------------------------------------------------- // Structure Declaration // Represents the data required for a network packet handler thread. // --------------------------------------------------------------------------- struct NetPacketRequest { FNENetwork* network; uint32_t peerId; sockaddr_storage address; uint32_t addrLen; frame::RTPHeader rtpHeader; frame::RTPFNEHeader fneHeader; int length = 0U; uint8_t *buffer; pthread_t thread; }; // --------------------------------------------------------------------------- // Class Declaration // Implements the core FNE networking logic. // --------------------------------------------------------------------------- class HOST_SW_API FNENetwork : public BaseNetwork { public: /// Initializes a new instance of the FNENetwork class. FNENetwork(HostFNE* host, const std::string& address, uint16_t port, uint32_t peerId, const std::string& password, bool debug, bool verbose, bool reportPeerPing, bool dmr, bool p25, bool nxdn, uint32_t parrotDelay, bool parrotGrantDemand, bool allowActivityTransfer, bool allowDiagnosticTransfer, uint32_t pingTime, uint32_t updateLookupTime); /// Finalizes a instance of the FNENetwork class. ~FNENetwork() override; /// Helper to set configuration options. void setOptions(yaml::Node& conf, bool printOptions); /// Gets the current status of the network. NET_CONN_STATUS getStatus() { return m_status; } /// Gets the instance of the DMR traffic handler. fne::TagDMRData* dmrTrafficHandler() const { return m_tagDMR; } /// Gets the instance of the P25 traffic handler. fne::TagP25Data* p25TrafficHandler() const { return m_tagP25; } /// Gets the instance of the NXDN traffic handler. fne::TagNXDNData* nxdnTrafficHandler() const { return m_tagNXDN; } /// Sets the instances of the Radio ID and Talkgroup Rules lookup tables. void setLookups(lookups::RadioIdLookup* ridLookup, lookups::TalkgroupRulesLookup* tidLookup); /// Sets endpoint preshared encryption key. void setPresharedKey(const uint8_t* presharedKey); /// Process a data frames from the network. void processNetwork(); /// Updates the timer by the passed number of milliseconds. void clock(uint32_t ms) override; /// Opens connection to the network. bool open() override; /// Closes connection to the network. void close() override; private: friend class fne::TagDMRData; fne::TagDMRData* m_tagDMR; friend class fne::TagP25Data; fne::TagP25Data* m_tagP25; friend class fne::TagNXDNData; fne::TagNXDNData* m_tagNXDN; friend class ::RESTAPI; HostFNE* m_host; std::string m_address; uint16_t m_port; std::string m_password; bool m_dmrEnabled; bool m_p25Enabled; bool m_nxdnEnabled; uint32_t m_parrotDelay; bool m_parrotGrantDemand; lookups::RadioIdLookup* m_ridLookup; lookups::TalkgroupRulesLookup* m_tidLookup; NET_CONN_STATUS m_status; std::mutex m_peerMutex; typedef std::pair PeerMapPair; std::unordered_map m_peers; typedef std::pair PeerAffiliationMapPair; std::unordered_map m_peerAffiliations; Timer m_maintainenceTimer; uint32_t m_updateLookupTime; uint32_t m_softConnLimit; bool m_callInProgress; bool m_disallowP25AdjStsBcast; bool m_reportPeerPing; bool m_verbose; /// Entry point to process a given network packet. static void* threadedNetworkRx(void* arg); /// Helper to erase the peer from the peers affiliations list. bool erasePeerAffiliations(uint32_t peerId); /// Helper to erase the peer from the peers list. bool erasePeer(uint32_t peerId); /// Helper to complete setting up a repeater login request. void setupRepeaterLogin(uint32_t peerId, FNEPeerConnection* connection); /// Helper to send the ACL lists to the specified peer in a separate thread. void peerACLUpdate(uint32_t peerId); /// Entry point to send the ACL lists to the specified peer in a separate thread. static void* threadedACLUpdate(void* arg); /// Helper to send the list of whitelisted RIDs to the specified peer. void writeWhitelistRIDs(uint32_t peerId); /// Helper to send the list of blacklisted RIDs to the specified peer. void writeBlacklistRIDs(uint32_t peerId); /// Helper to send the list of active TGIDs to the specified peer. void writeTGIDs(uint32_t peerId); /// Helper to send the list of deactivated TGIDs to the specified peer. void writeDeactiveTGIDs(uint32_t peerId); /// Helper to send a data message to the specified peer. bool writePeer(uint32_t peerId, FrameQueue::OpcodePair opcode, const uint8_t* data, uint32_t length, uint16_t pktSeq, uint32_t streamId, bool queueOnly = false, bool directWrite = false) const; /// Helper to send a data message to the specified peer. bool writePeer(uint32_t peerId, FrameQueue::OpcodePair opcode, const uint8_t* data, uint32_t length, uint32_t streamId, bool queueOnly = false, bool incPktSeq = false, bool directWrite = false) const; /// Helper to send a command message to the specified peer. bool writePeerCommand(uint32_t peerId, FrameQueue::OpcodePair opcode, const uint8_t* data = nullptr, uint32_t length = 0U, bool incPktSeq = false) const; /// Helper to send a ACK response to the specified peer. bool writePeerACK(uint32_t peerId, const uint8_t* data = nullptr, uint32_t length = 0U); /// Helper to send a NAK response to the specified peer. bool writePeerNAK(uint32_t peerId, const char* tag, NET_CONN_NAK_REASON reason = NET_CONN_NAK_GENERAL_FAILURE); /// Helper to send a NAK response to the specified peer. bool writePeerNAK(uint32_t peerId, const char* tag, NET_CONN_NAK_REASON reason, sockaddr_storage& addr, uint32_t addrLen); }; } // namespace network #endif // __FNE_NETWORK_H__