|
|
|
|
@ -27,6 +27,67 @@ using namespace network;
|
|
|
|
|
using namespace network::frame;
|
|
|
|
|
using namespace network::udp;
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// Class Declaration
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief TestableNetwork is a subclass of Network that exposes internal state for testing purposes. It allows
|
|
|
|
|
* direct manipulation of the network status, activity transfer flags, and diagnostic transfer flags. This class
|
|
|
|
|
*/
|
|
|
|
|
class TestableNetwork : public Network {
|
|
|
|
|
public:
|
|
|
|
|
using Network::Network;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Sets the network connection status for testing purposes.
|
|
|
|
|
* @param status The NET_CONN_STATUS value to set.
|
|
|
|
|
*/
|
|
|
|
|
void setStatusForTest(NET_CONN_STATUS status) { m_status = status; }
|
|
|
|
|
/**
|
|
|
|
|
* @brief Gets the current network connection status for testing purposes.
|
|
|
|
|
* @returns NET_CONN_STATUS The current network connection status.
|
|
|
|
|
*/
|
|
|
|
|
NET_CONN_STATUS getStatusForTest() const { return m_status; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Sets the allow activity transfer flag for testing purposes.
|
|
|
|
|
* @param enabled True to enable activity transfer, false to disable.
|
|
|
|
|
*/
|
|
|
|
|
void setAllowActivityTransferForTest(bool enabled) { m_allowActivityTransfer = enabled; }
|
|
|
|
|
/**
|
|
|
|
|
* @brief Sets the allow diagnostic transfer flag for testing purposes.
|
|
|
|
|
* @param enabled True to enable diagnostic transfer, false to disable.
|
|
|
|
|
*/
|
|
|
|
|
void setAllowDiagnosticTransferForTest(bool enabled) { m_allowDiagnosticTransfer = enabled; }
|
|
|
|
|
/**
|
|
|
|
|
* @brief Gets the allow activity transfer flag for testing purposes.
|
|
|
|
|
* @returns bool True if activity transfer is allowed, false otherwise.
|
|
|
|
|
*/
|
|
|
|
|
bool getAllowActivityTransferForTest() const { return m_allowActivityTransfer; }
|
|
|
|
|
/**
|
|
|
|
|
* @brief Gets the allow diagnostic transfer flag for testing purposes.
|
|
|
|
|
* @returns bool True if diagnostic transfer is allowed, false otherwise.
|
|
|
|
|
*/
|
|
|
|
|
bool getAllowDiagnosticTransferForTest() const { return m_allowDiagnosticTransfer; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Gets the duplicate connection flag for testing purposes.
|
|
|
|
|
* @returns bool True if a duplicate connection has been flagged, false otherwise.
|
|
|
|
|
*/
|
|
|
|
|
bool hasDuplicateConnFlagForTest() const { return m_flaggedDuplicateConn; }
|
|
|
|
|
/**
|
|
|
|
|
* @brief Gets the maximum retry count for testing purposes.
|
|
|
|
|
* @returns uint8_t The maximum retry count.
|
|
|
|
|
*/
|
|
|
|
|
uint8_t getMaxRetryCountForTest() const { return m_maxRetryCount; }
|
|
|
|
|
/**
|
|
|
|
|
* @brief Gets the current retry count for testing purposes.
|
|
|
|
|
* @returns uint8_t The current retry count.
|
|
|
|
|
*/
|
|
|
|
|
uint32_t getRemotePeerIdForTest() const { return m_remotePeerId; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// Global Functions
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
@ -128,6 +189,58 @@ static bool sendLoopbackFrame(FrameQueue& senderQueue, sockaddr_storage& destina
|
|
|
|
|
destination, destinationLen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Complete the handshake process for the TestableNetwork instance.
|
|
|
|
|
* @param network Reference to the TestableNetwork instance.
|
|
|
|
|
* @param masterReceiverQueue Reference to the FrameQueue for receiving messages from the master.
|
|
|
|
|
* @param masterSenderQueue Reference to the FrameQueue for sending messages to the master.
|
|
|
|
|
* @param networkDestination sockaddr_storage containing the destination address for the network.
|
|
|
|
|
* @param networkDestinationLen Length of the destination address.
|
|
|
|
|
* @param peerId Peer ID for the network.
|
|
|
|
|
*/
|
|
|
|
|
static void completeHandshake(TestableNetwork& network, FrameQueue& masterReceiverQueue, FrameQueue& masterSenderQueue,
|
|
|
|
|
sockaddr_storage& networkDestination, uint32_t networkDestinationLen, uint32_t peerId)
|
|
|
|
|
{
|
|
|
|
|
network.clock(11000U);
|
|
|
|
|
|
|
|
|
|
std::string loginPayload;
|
|
|
|
|
RTPHeader loginRtp;
|
|
|
|
|
RTPFNEHeader loginFne;
|
|
|
|
|
REQUIRE(waitForFrameMessage(masterReceiverQueue, loginPayload, loginRtp, loginFne));
|
|
|
|
|
REQUIRE(loginFne.getFunction() == NET_FUNC::RPTL);
|
|
|
|
|
|
|
|
|
|
std::array<uint8_t, 10U> saltPayload = {};
|
|
|
|
|
::memcpy(saltPayload.data() + 6U, "ABCD", 4U);
|
|
|
|
|
REQUIRE(sendLoopbackFrame(masterSenderQueue, networkDestination, networkDestinationLen, std::vector<uint8_t>(saltPayload.begin(), saltPayload.end()),
|
|
|
|
|
{ NET_FUNC::ACK, NET_SUBFUNC::NOP }, loginFne.getStreamId(), peerId, peerId, 0U));
|
|
|
|
|
|
|
|
|
|
network.clock(1000U);
|
|
|
|
|
|
|
|
|
|
std::string authPayload;
|
|
|
|
|
RTPHeader authRtp;
|
|
|
|
|
RTPFNEHeader authFne;
|
|
|
|
|
REQUIRE(waitForFrameMessage(masterReceiverQueue, authPayload, authRtp, authFne));
|
|
|
|
|
REQUIRE(authFne.getFunction() == NET_FUNC::RPTK);
|
|
|
|
|
|
|
|
|
|
std::array<uint8_t, 8U> ackPayload = {};
|
|
|
|
|
REQUIRE(sendLoopbackFrame(masterSenderQueue, networkDestination, networkDestinationLen, std::vector<uint8_t>(ackPayload.begin(), ackPayload.end()),
|
|
|
|
|
{ NET_FUNC::ACK, NET_SUBFUNC::NOP }, authFne.getStreamId(), peerId, peerId, 0U));
|
|
|
|
|
|
|
|
|
|
network.clock(1000U);
|
|
|
|
|
|
|
|
|
|
std::string configPayload;
|
|
|
|
|
RTPHeader configRtp;
|
|
|
|
|
RTPFNEHeader configFne;
|
|
|
|
|
REQUIRE(waitForFrameMessage(masterReceiverQueue, configPayload, configRtp, configFne));
|
|
|
|
|
REQUIRE(configFne.getFunction() == NET_FUNC::RPTC);
|
|
|
|
|
|
|
|
|
|
std::array<uint8_t, 8U> configAckPayload = { 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x80U, 0x00U };
|
|
|
|
|
REQUIRE(sendLoopbackFrame(masterSenderQueue, networkDestination, networkDestinationLen, std::vector<uint8_t>(configAckPayload.begin(), configAckPayload.end()),
|
|
|
|
|
{ NET_FUNC::ACK, NET_SUBFUNC::NOP }, configFne.getStreamId(), peerId, peerId, 0U));
|
|
|
|
|
|
|
|
|
|
network.clock(1000U);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
TEST_CASE("Network performs a full loopback login handshake", "[network][loopback]")
|
|
|
|
|
@ -302,45 +415,11 @@ TEST_CASE("Network invokes loopback in-call callbacks for incoming control frame
|
|
|
|
|
uint32_t networkDestinationLen = 0U;
|
|
|
|
|
REQUIRE(Socket::lookup("127.0.0.1", localPort, networkDestination, networkDestinationLen) == 0);
|
|
|
|
|
|
|
|
|
|
Network network("127.0.0.1", masterPort, localPort, 6000U, "loopback-password", true, false, true, false, false, false, true, true, true, true, false, false);
|
|
|
|
|
TestableNetwork network("127.0.0.1", masterPort, localPort, 6000U, "loopback-password", true, false, true, false, false, false, true, true, true, true, false, false);
|
|
|
|
|
network.enable(true);
|
|
|
|
|
REQUIRE(network.open());
|
|
|
|
|
|
|
|
|
|
network.clock(11000U);
|
|
|
|
|
|
|
|
|
|
std::string loginPayload;
|
|
|
|
|
RTPHeader loginRtp;
|
|
|
|
|
RTPFNEHeader loginFne;
|
|
|
|
|
REQUIRE(waitForFrameMessage(masterReceiverQueue, loginPayload, loginRtp, loginFne));
|
|
|
|
|
|
|
|
|
|
std::array<uint8_t, 10U> saltPayload = {};
|
|
|
|
|
::memcpy(saltPayload.data() + 6U, "ABCD", 4U);
|
|
|
|
|
REQUIRE(sendLoopbackFrame(masterSenderQueue, networkDestination, networkDestinationLen, std::vector<uint8_t>(saltPayload.begin(), saltPayload.end()),
|
|
|
|
|
{ NET_FUNC::ACK, NET_SUBFUNC::NOP }, loginFne.getStreamId(), 6000U, 6000U, 0U));
|
|
|
|
|
|
|
|
|
|
network.clock(1000U);
|
|
|
|
|
|
|
|
|
|
std::string authPayload;
|
|
|
|
|
RTPHeader authRtp;
|
|
|
|
|
RTPFNEHeader authFne;
|
|
|
|
|
REQUIRE(waitForFrameMessage(masterReceiverQueue, authPayload, authRtp, authFne));
|
|
|
|
|
|
|
|
|
|
std::array<uint8_t, 8U> ackPayload = {};
|
|
|
|
|
REQUIRE(sendLoopbackFrame(masterSenderQueue, networkDestination, networkDestinationLen, std::vector<uint8_t>(ackPayload.begin(), ackPayload.end()),
|
|
|
|
|
{ NET_FUNC::ACK, NET_SUBFUNC::NOP }, authFne.getStreamId(), 6000U, 6000U, 0U));
|
|
|
|
|
|
|
|
|
|
network.clock(1000U);
|
|
|
|
|
|
|
|
|
|
std::string configPayload;
|
|
|
|
|
RTPHeader configRtp;
|
|
|
|
|
RTPFNEHeader configFne;
|
|
|
|
|
REQUIRE(waitForFrameMessage(masterReceiverQueue, configPayload, configRtp, configFne));
|
|
|
|
|
|
|
|
|
|
std::array<uint8_t, 8U> configAckPayload = { 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x80U, 0x00U };
|
|
|
|
|
REQUIRE(sendLoopbackFrame(masterSenderQueue, networkDestination, networkDestinationLen, std::vector<uint8_t>(configAckPayload.begin(), configAckPayload.end()),
|
|
|
|
|
{ NET_FUNC::ACK, NET_SUBFUNC::NOP }, configFne.getStreamId(), 6000U, 6000U, 0U));
|
|
|
|
|
|
|
|
|
|
network.clock(1000U);
|
|
|
|
|
completeHandshake(network, masterReceiverQueue, masterSenderQueue, networkDestination, networkDestinationLen, 6000U);
|
|
|
|
|
|
|
|
|
|
bool callbackFired = false;
|
|
|
|
|
NET_ICC::ENUM lastCommand = NET_ICC::NOP;
|
|
|
|
|
@ -381,3 +460,240 @@ TEST_CASE("Network invokes loopback in-call callbacks for incoming control frame
|
|
|
|
|
|
|
|
|
|
masterReceiver.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_CASE("Network handles duplicate-connection NAKs by returning to waiting-connect", "[network][loopback]")
|
|
|
|
|
{
|
|
|
|
|
const uint16_t masterPort = reserveLoopbackPort();
|
|
|
|
|
REQUIRE(masterPort != 0U);
|
|
|
|
|
|
|
|
|
|
const uint16_t localPort = reserveLoopbackPort();
|
|
|
|
|
REQUIRE(localPort != 0U);
|
|
|
|
|
|
|
|
|
|
Socket masterReceiver("127.0.0.1", masterPort);
|
|
|
|
|
REQUIRE(masterReceiver.open(AF_INET));
|
|
|
|
|
|
|
|
|
|
FrameQueue masterReceiverQueue(&masterReceiver, 0xB1B2U, false);
|
|
|
|
|
FrameQueue masterSenderQueue(&masterReceiver, 0xD1D2U, false);
|
|
|
|
|
|
|
|
|
|
sockaddr_storage networkDestination = {};
|
|
|
|
|
uint32_t networkDestinationLen = 0U;
|
|
|
|
|
REQUIRE(Socket::lookup("127.0.0.1", localPort, networkDestination, networkDestinationLen) == 0);
|
|
|
|
|
|
|
|
|
|
TestableNetwork network("127.0.0.1", masterPort, localPort, 9001U, "loopback-password", true, false, true, false, false, false, true, true, true, true, false, false);
|
|
|
|
|
network.enable(true);
|
|
|
|
|
REQUIRE(network.open());
|
|
|
|
|
|
|
|
|
|
completeHandshake(network, masterReceiverQueue, masterSenderQueue, networkDestination, networkDestinationLen, 9001U);
|
|
|
|
|
|
|
|
|
|
std::vector<uint8_t> nakPayload(12U, 0x00U);
|
|
|
|
|
nakPayload[10U] = static_cast<uint8_t>((NET_CONN_NAK_FNE_DUPLICATE_CONN >> 8U) & 0xFFU);
|
|
|
|
|
nakPayload[11U] = static_cast<uint8_t>(NET_CONN_NAK_FNE_DUPLICATE_CONN & 0xFFU);
|
|
|
|
|
REQUIRE(sendLoopbackFrame(masterSenderQueue, networkDestination, networkDestinationLen, nakPayload,
|
|
|
|
|
{ NET_FUNC::NAK, NET_SUBFUNC::NOP }, 0x12345678U, 9001U, 9001U, 0x0102U));
|
|
|
|
|
|
|
|
|
|
network.clock(1000U);
|
|
|
|
|
|
|
|
|
|
REQUIRE(network.getStatusForTest() == NET_STAT_WAITING_CONNECT);
|
|
|
|
|
REQUIRE(network.hasDuplicateConnFlagForTest());
|
|
|
|
|
REQUIRE(network.getMaxRetryCountForTest() == 2U);
|
|
|
|
|
REQUIRE(network.getRemotePeerIdForTest() == 0U);
|
|
|
|
|
|
|
|
|
|
masterReceiver.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_CASE("Network enables or disables metadata-transfer flags from the config ack", "[network][loopback]")
|
|
|
|
|
{
|
|
|
|
|
const uint16_t masterPort = reserveLoopbackPort();
|
|
|
|
|
REQUIRE(masterPort != 0U);
|
|
|
|
|
|
|
|
|
|
const uint16_t localPort = reserveLoopbackPort();
|
|
|
|
|
REQUIRE(localPort != 0U);
|
|
|
|
|
|
|
|
|
|
Socket masterReceiver("127.0.0.1", masterPort);
|
|
|
|
|
REQUIRE(masterReceiver.open(AF_INET));
|
|
|
|
|
|
|
|
|
|
FrameQueue masterReceiverQueue(&masterReceiver, 0xE1E2U, false);
|
|
|
|
|
FrameQueue masterSenderQueue(&masterReceiver, 0xF1F2U, false);
|
|
|
|
|
|
|
|
|
|
sockaddr_storage networkDestination = {};
|
|
|
|
|
uint32_t networkDestinationLen = 0U;
|
|
|
|
|
REQUIRE(Socket::lookup("127.0.0.1", localPort, networkDestination, networkDestinationLen) == 0);
|
|
|
|
|
|
|
|
|
|
TestableNetwork network("127.0.0.1", masterPort, localPort, 9002U, "loopback-password", true, false, true, false, false, false, true, true, true, true, false, false);
|
|
|
|
|
network.enable(true);
|
|
|
|
|
REQUIRE(network.open());
|
|
|
|
|
|
|
|
|
|
network.setAllowActivityTransferForTest(false);
|
|
|
|
|
network.setAllowDiagnosticTransferForTest(false);
|
|
|
|
|
network.setStatusForTest(NET_STAT_WAITING_CONFIG);
|
|
|
|
|
|
|
|
|
|
std::array<uint8_t, 8U> configAckPayload = { 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U };
|
|
|
|
|
REQUIRE(sendLoopbackFrame(masterSenderQueue, networkDestination, networkDestinationLen, std::vector<uint8_t>(configAckPayload.begin(), configAckPayload.end()),
|
|
|
|
|
{ NET_FUNC::ACK, NET_SUBFUNC::NOP }, 0x12345678U, 9002U, 9002U, 0U));
|
|
|
|
|
|
|
|
|
|
network.clock(1000U);
|
|
|
|
|
|
|
|
|
|
REQUIRE(!network.getAllowActivityTransferForTest());
|
|
|
|
|
REQUIRE(!network.getAllowDiagnosticTransferForTest());
|
|
|
|
|
|
|
|
|
|
network.setAllowActivityTransferForTest(true);
|
|
|
|
|
network.setAllowDiagnosticTransferForTest(true);
|
|
|
|
|
|
|
|
|
|
network.setStatusForTest(NET_STAT_WAITING_CONFIG);
|
|
|
|
|
configAckPayload[6U] = 0x80U;
|
|
|
|
|
REQUIRE(sendLoopbackFrame(masterSenderQueue, networkDestination, networkDestinationLen, std::vector<uint8_t>(configAckPayload.begin(), configAckPayload.end()),
|
|
|
|
|
{ NET_FUNC::ACK, NET_SUBFUNC::NOP }, 0x12345678U, 9002U, 9002U, 0U));
|
|
|
|
|
|
|
|
|
|
network.clock(1000U);
|
|
|
|
|
|
|
|
|
|
REQUIRE(network.getAllowActivityTransferForTest());
|
|
|
|
|
REQUIRE(network.getAllowDiagnosticTransferForTest());
|
|
|
|
|
|
|
|
|
|
masterReceiver.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_CASE("BaseNetwork emits announcement frames with the expected payloads while running", "[network][loopback]")
|
|
|
|
|
{
|
|
|
|
|
const uint16_t masterPort = reserveLoopbackPort();
|
|
|
|
|
REQUIRE(masterPort != 0U);
|
|
|
|
|
|
|
|
|
|
const uint16_t localPort = reserveLoopbackPort();
|
|
|
|
|
REQUIRE(localPort != 0U);
|
|
|
|
|
|
|
|
|
|
Socket masterReceiver("127.0.0.1", masterPort);
|
|
|
|
|
REQUIRE(masterReceiver.open(AF_INET));
|
|
|
|
|
|
|
|
|
|
Socket metadataReceiver("127.0.0.1", masterPort + 1U);
|
|
|
|
|
REQUIRE(metadataReceiver.open(AF_INET));
|
|
|
|
|
|
|
|
|
|
FrameQueue masterReceiverQueue(&masterReceiver, 0x1111U, false);
|
|
|
|
|
FrameQueue masterSenderQueue(&masterReceiver, 0x2222U, false);
|
|
|
|
|
FrameQueue metadataReceiverQueue(&metadataReceiver, 0x3333U, false);
|
|
|
|
|
|
|
|
|
|
sockaddr_storage networkDestination = {};
|
|
|
|
|
uint32_t networkDestinationLen = 0U;
|
|
|
|
|
REQUIRE(Socket::lookup("127.0.0.1", localPort, networkDestination, networkDestinationLen) == 0);
|
|
|
|
|
|
|
|
|
|
TestableNetwork network("127.0.0.1", masterPort, localPort, 9003U, "loopback-password", true, false, true, false, false, false, true, true, true, true, false, false);
|
|
|
|
|
network.enable(true);
|
|
|
|
|
REQUIRE(network.open());
|
|
|
|
|
|
|
|
|
|
completeHandshake(network, masterReceiverQueue, masterSenderQueue, networkDestination, networkDestinationLen, 9003U);
|
|
|
|
|
|
|
|
|
|
REQUIRE(network.announceGroupAffiliation(0x123456U, 0x654321U));
|
|
|
|
|
std::string payload;
|
|
|
|
|
RTPHeader rtpHeader;
|
|
|
|
|
RTPFNEHeader fneHeader;
|
|
|
|
|
REQUIRE(waitForFrameMessage(metadataReceiverQueue, payload, rtpHeader, fneHeader));
|
|
|
|
|
REQUIRE(fneHeader.getFunction() == NET_FUNC::ANNOUNCE);
|
|
|
|
|
REQUIRE(fneHeader.getSubFunction() == NET_SUBFUNC::ANNC_SUBFUNC_GRP_AFFIL);
|
|
|
|
|
REQUIRE(payload.size() == MSG_ANNC_GRP_AFFIL);
|
|
|
|
|
const uint32_t grpSrc = GET_UINT24(reinterpret_cast<const uint8_t*>(payload.data()), 0U);
|
|
|
|
|
const uint32_t grpDst = GET_UINT24(reinterpret_cast<const uint8_t*>(payload.data()), 3U);
|
|
|
|
|
REQUIRE(grpSrc == 0x123456U);
|
|
|
|
|
REQUIRE(grpDst == 0x654321U);
|
|
|
|
|
|
|
|
|
|
REQUIRE(network.announceUnitRegistration(0x112233U));
|
|
|
|
|
REQUIRE(waitForFrameMessage(metadataReceiverQueue, payload, rtpHeader, fneHeader));
|
|
|
|
|
REQUIRE(fneHeader.getFunction() == NET_FUNC::ANNOUNCE);
|
|
|
|
|
REQUIRE(fneHeader.getSubFunction() == NET_SUBFUNC::ANNC_SUBFUNC_UNIT_REG);
|
|
|
|
|
REQUIRE(payload.size() == MSG_ANNC_UNIT_REG);
|
|
|
|
|
const uint32_t unitRegId = GET_UINT24(reinterpret_cast<const uint8_t*>(payload.data()), 0U);
|
|
|
|
|
REQUIRE(unitRegId == 0x112233U);
|
|
|
|
|
|
|
|
|
|
std::unordered_map<uint32_t, uint32_t> affs = { {0x111111U, 0x222222U}, {0x333333U, 0x444444U} };
|
|
|
|
|
REQUIRE(network.announceAffiliationUpdate(affs));
|
|
|
|
|
REQUIRE(waitForFrameMessage(metadataReceiverQueue, payload, rtpHeader, fneHeader));
|
|
|
|
|
REQUIRE(fneHeader.getFunction() == NET_FUNC::ANNOUNCE);
|
|
|
|
|
REQUIRE(fneHeader.getSubFunction() == NET_SUBFUNC::ANNC_SUBFUNC_AFFILS);
|
|
|
|
|
REQUIRE(payload.size() == 4U + (affs.size() * 8U));
|
|
|
|
|
|
|
|
|
|
std::vector<uint32_t> regs = { 0xAAAAAAU, 0xBBBBBBU };
|
|
|
|
|
REQUIRE(network.announceUnitRegUpdate(regs));
|
|
|
|
|
REQUIRE(waitForFrameMessage(metadataReceiverQueue, payload, rtpHeader, fneHeader));
|
|
|
|
|
REQUIRE(fneHeader.getFunction() == NET_FUNC::ANNOUNCE);
|
|
|
|
|
REQUIRE(fneHeader.getSubFunction() == NET_SUBFUNC::ANNC_SUBFUNC_UNIT_REGS);
|
|
|
|
|
REQUIRE(payload.size() == 4U + (regs.size() * 3U));
|
|
|
|
|
|
|
|
|
|
std::vector<uint32_t> peers = { 0x010203U, 0x040506U };
|
|
|
|
|
REQUIRE(network.announceSiteVCs(peers));
|
|
|
|
|
REQUIRE(waitForFrameMessage(metadataReceiverQueue, payload, rtpHeader, fneHeader));
|
|
|
|
|
REQUIRE(fneHeader.getFunction() == NET_FUNC::ANNOUNCE);
|
|
|
|
|
REQUIRE(fneHeader.getSubFunction() == NET_SUBFUNC::ANNC_SUBFUNC_SITE_VC);
|
|
|
|
|
REQUIRE(payload.size() == 4U + (peers.size() * 4U));
|
|
|
|
|
|
|
|
|
|
masterReceiver.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_CASE("BaseNetwork emits transfer and status frames over the metadata path when enabled", "[network][loopback]")
|
|
|
|
|
{
|
|
|
|
|
const uint16_t masterPort = reserveLoopbackPort();
|
|
|
|
|
REQUIRE(masterPort != 0U);
|
|
|
|
|
|
|
|
|
|
const uint16_t localPort = reserveLoopbackPort();
|
|
|
|
|
REQUIRE(localPort != 0U);
|
|
|
|
|
|
|
|
|
|
Socket masterReceiver("127.0.0.1", masterPort);
|
|
|
|
|
REQUIRE(masterReceiver.open(AF_INET));
|
|
|
|
|
|
|
|
|
|
Socket metadataReceiver("127.0.0.1", masterPort + 1U);
|
|
|
|
|
REQUIRE(metadataReceiver.open(AF_INET));
|
|
|
|
|
|
|
|
|
|
FrameQueue masterReceiverQueue(&masterReceiver, 0x3333U, false);
|
|
|
|
|
FrameQueue masterSenderQueue(&masterReceiver, 0x4444U, false);
|
|
|
|
|
FrameQueue metadataReceiverQueue(&metadataReceiver, 0x5555U, false);
|
|
|
|
|
|
|
|
|
|
sockaddr_storage networkDestination = {};
|
|
|
|
|
uint32_t networkDestinationLen = 0U;
|
|
|
|
|
REQUIRE(Socket::lookup("127.0.0.1", localPort, networkDestination, networkDestinationLen) == 0);
|
|
|
|
|
|
|
|
|
|
TestableNetwork network("127.0.0.1", masterPort, localPort, 9004U, "loopback-password", true, false, true, false, false, false, true, true, true, true, false, false);
|
|
|
|
|
network.enable(true);
|
|
|
|
|
REQUIRE(network.open());
|
|
|
|
|
|
|
|
|
|
completeHandshake(network, masterReceiverQueue, masterSenderQueue, networkDestination, networkDestinationLen, 9004U);
|
|
|
|
|
|
|
|
|
|
REQUIRE(network.writeActLog("activity-test"));
|
|
|
|
|
std::string payload;
|
|
|
|
|
RTPHeader rtpHeader;
|
|
|
|
|
RTPFNEHeader fneHeader;
|
|
|
|
|
REQUIRE(waitForFrameMessage(metadataReceiverQueue, payload, rtpHeader, fneHeader));
|
|
|
|
|
REQUIRE(fneHeader.getFunction() == NET_FUNC::TRANSFER);
|
|
|
|
|
REQUIRE(fneHeader.getSubFunction() == NET_SUBFUNC::TRANSFER_SUBFUNC_ACTIVITY);
|
|
|
|
|
REQUIRE(payload.find("activity-test") != std::string::npos);
|
|
|
|
|
|
|
|
|
|
REQUIRE(network.writeDiagLog("diagnostic-test"));
|
|
|
|
|
REQUIRE(waitForFrameMessage(metadataReceiverQueue, payload, rtpHeader, fneHeader));
|
|
|
|
|
REQUIRE(fneHeader.getFunction() == NET_FUNC::TRANSFER);
|
|
|
|
|
REQUIRE(fneHeader.getSubFunction() == NET_SUBFUNC::TRANSFER_SUBFUNC_DIAG);
|
|
|
|
|
REQUIRE(payload.find("diagnostic-test") != std::string::npos);
|
|
|
|
|
|
|
|
|
|
json::object statusObj;
|
|
|
|
|
REQUIRE(network.writePeerStatus(statusObj));
|
|
|
|
|
REQUIRE(waitForFrameMessage(metadataReceiverQueue, payload, rtpHeader, fneHeader));
|
|
|
|
|
REQUIRE(fneHeader.getFunction() == NET_FUNC::TRANSFER);
|
|
|
|
|
REQUIRE(fneHeader.getSubFunction() == NET_SUBFUNC::TRANSFER_SUBFUNC_STATUS);
|
|
|
|
|
REQUIRE(payload.size() > 0U);
|
|
|
|
|
|
|
|
|
|
masterReceiver.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_CASE("RTPStreamMultiplex detects lost and out-of-order sequences and resets on end-of-call", "[network][loopback]")
|
|
|
|
|
{
|
|
|
|
|
RTPStreamMultiplex mux;
|
|
|
|
|
|
|
|
|
|
mux.setPktSeq(0x1234U, 1U);
|
|
|
|
|
|
|
|
|
|
uint16_t lastSeq = 0U;
|
|
|
|
|
REQUIRE(mux.verifyStream(0x1234U, 1U, NET_FUNC::PROTOCOL, &lastSeq) == MUX_VALID_SUCCESS);
|
|
|
|
|
REQUIRE(lastSeq == 1U);
|
|
|
|
|
|
|
|
|
|
REQUIRE(mux.verifyStream(0x1234U, 3U, NET_FUNC::PROTOCOL, &lastSeq) == MUX_LOST_FRAMES);
|
|
|
|
|
REQUIRE(lastSeq == 1U);
|
|
|
|
|
|
|
|
|
|
REQUIRE(mux.verifyStream(0x1234U, 2U, NET_FUNC::PROTOCOL, &lastSeq) == MUX_OUT_OF_ORDER);
|
|
|
|
|
REQUIRE(lastSeq == 3U);
|
|
|
|
|
|
|
|
|
|
REQUIRE(mux.verifyStream(0x1234U, RTP_END_OF_CALL_SEQ, NET_FUNC::PROTOCOL, &lastSeq) == MUX_VALID_SUCCESS);
|
|
|
|
|
REQUIRE_FALSE(mux.hasPktSeq(0x1234U));
|
|
|
|
|
}
|
|
|
|
|
|