//// OctreePacketProcessor.cpp// interface/src/octree//// Created by Brad Hefta-Gaub on 8/12/13.// Copyright 2013 High Fidelity, Inc.//// Distributed under the Apache License, Version 2.0.// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html//#include "OctreePacketProcessor.h"#include <PerfStat.h>#include "Application.h"#include "Menu.h"#include "SceneScriptingInterface.h"#ifndef Q_OS_ANDROID#include <shared/FileLogger.h>#endifOctreePacketProcessor::OctreePacketProcessor(): _safeLanding(new SafeLanding()){ setObjectName("Octree Packet Processor"); auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver(); const PacketReceiver::PacketTypeList octreePackets = { PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase, PacketType::EntityQueryInitialResultsComplete }; packetReceiver.registerDirectListenerForTypes(octreePackets, PacketReceiver::makeSourcedListenerReference<OctreePacketProcessor>(this, &OctreePacketProcessor::handleOctreePacket));}OctreePacketProcessor::~OctreePacketProcessor() { }void OctreePacketProcessor::handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) { queueReceivedPacket(message, senderNode);}void OctreePacketProcessor::processPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "OctreePacketProcessor::processPacket()");#ifndef Q_OS_ANDROID const int WAY_BEHIND = 300; if (packetsToProcessCount() > WAY_BEHIND && qApp->getLogger()->extraDebugging()) { qDebug("OctreePacketProcessor::processPacket() packets to process=%d", packetsToProcessCount()); }#endif bool wasStatsPacket = false; PacketType octreePacketType = message->getType(); // note: PacketType_OCTREE_STATS can have PacketType_VOXEL_DATA // immediately following them inside the same packet. So, we process the PacketType_OCTREE_STATS first // then process any remaining bytes as if it was another packet if (octreePacketType == PacketType::OctreeStats) { int statsMessageLength = processOctreeStats(*message, sendingNode); wasStatsPacket = true; int piggybackBytes = message->getSize() - statsMessageLength; if (piggybackBytes) { // construct a new packet from the piggybacked one auto buffer = std::unique_ptr<char[]>(new char[piggybackBytes]); memcpy(buffer.get(), message->getRawMessage() + statsMessageLength, piggybackBytes); auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggybackBytes, message->getSenderSockAddr()); message = QSharedPointer<ReceivedMessage>::create(*newPacket); } else { // Note... stats packets don't have sequence numbers, so we don't want to send those to trackIncomingVoxelPacket() return; // bail since no piggyback data } } // fall through to piggyback message PacketType packetType = message->getType(); // check version of piggyback packet against expected version if (message->getVersion() != versionForPacketType(message->getType())) { static QMultiMap<QUuid, PacketType> versionDebugSuppressMap; const QUuid& senderUUID = sendingNode->getUUID(); if (!versionDebugSuppressMap.contains(senderUUID, packetType)) { qDebug() << "Was stats packet? " << wasStatsPacket; qDebug() << "OctreePacketProcessor - piggyback packet version mismatch on" << packetType << "- Sender" << senderUUID << "sent" << (int) message->getVersion() << "but" << (int) versionForPacketType(packetType) << "expected."; emit packetVersionMismatch(); versionDebugSuppressMap.insert(senderUUID, packetType); } return; // bail since piggyback version doesn't match } if (packetType != PacketType::EntityQueryInitialResultsComplete) { trackIncomingOctreePacket(*message, sendingNode, wasStatsPacket); } // seek back to beginning of packet after tracking message->seek(0); switch(packetType) { case PacketType::EntityErase: { if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) { auto renderer = qApp->getEntities(); if (renderer) { renderer->processEraseMessage(*message, sendingNode); } } } break; case PacketType::EntityData: { if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) { auto renderer = qApp->getEntities(); if (renderer) { renderer->processDatagram(*message, sendingNode); if (_safeLanding && _safeLanding->isTracking()) { OCTREE_PACKET_SEQUENCE thisSequence = renderer->getLastOctreeMessageSequence(); _safeLanding->addToSequence(thisSequence); if (_safeLandingSequenceStart == SafeLanding::INVALID_SEQUENCE) { _safeLandingSequenceStart = thisSequence; } } } } } break; case PacketType::EntityQueryInitialResultsComplete: { // Read sequence # OCTREE_PACKET_SEQUENCE completionNumber; message->readPrimitive(&completionNumber); if (_safeLanding && _safeLanding->isTracking()) { _safeLanding->finishSequence(_safeLandingSequenceStart, completionNumber); } } break; default: { // nothing to do } break; }}void OctreePacketProcessor::startSafeLanding() { if (_safeLanding) { _safeLanding->startTracking(qApp->getEntities()); }}void OctreePacketProcessor::updateSafeLanding() { if (_safeLanding) { _safeLanding->updateTracking(); }}void OctreePacketProcessor::stopSafeLanding() { if (_safeLanding) { _safeLanding->stopTracking(); }}void OctreePacketProcessor::resetSafeLanding() { if (_safeLanding) { _safeLanding->reset(); } _safeLandingSequenceStart = SafeLanding::INVALID_SEQUENCE;}bool OctreePacketProcessor::safeLandingIsActive() const { return _safeLanding && _safeLanding->isTracking();}bool OctreePacketProcessor::safeLandingIsComplete() const { if (_safeLanding) { return _safeLanding->trackingIsComplete(); } return false;}int OctreePacketProcessor::processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode) { // parse the incoming stats datas stick it in a temporary object for now, while we // determine which server it belongs to int statsMessageLength = 0; const QUuid& nodeUUID = sendingNode->getUUID(); // now that we know the node ID, let's add these stats to the stats for that node... _octreeServerSceneStats.withWriteLock([&] { OctreeSceneStats& octreeStats = _octreeServerSceneStats[nodeUUID]; statsMessageLength = octreeStats.unpackFromPacket(message); if (octreeStats.isFullScene()) { _fullSceneReceivedCounter++; } }); return statsMessageLength;}void OctreePacketProcessor::trackIncomingOctreePacket(ReceivedMessage& message, SharedNodePointer sendingNode, bool wasStatsPacket) { // Attempt to identify the sender from its address. if (sendingNode) { const QUuid& nodeUUID = sendingNode->getUUID(); // now that we know the node ID, let's add these stats to the stats for that node... _octreeServerSceneStats.withWriteLock([&] { if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) { OctreeSceneStats& stats = _octreeServerSceneStats[nodeUUID]; stats.trackIncomingOctreePacket(message, wasStatsPacket, sendingNode->getClockSkewUsec()); } }); }}
//
// OctreePacketProcessor.cpp
// interface/src/octree
//
// Created by Brad Hefta-Gaub on 8/12/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "OctreePacketProcessor.h"
#include <PerfStat.h>
#include "Application.h"
#include "Menu.h"
#include "SceneScriptingInterface.h"
#ifndef Q_OS_ANDROID
#include <shared/FileLogger.h>
#endif
OctreePacketProcessor::OctreePacketProcessor():
_safeLanding(new SafeLanding())
{
setObjectName("Octree Packet Processor");
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
const PacketReceiver::PacketTypeList octreePackets =
{ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase, PacketType::EntityQueryInitialResultsComplete };
packetReceiver.registerDirectListenerForTypes(octreePackets,
PacketReceiver::makeSourcedListenerReference<OctreePacketProcessor>(this, &OctreePacketProcessor::handleOctreePacket));
}
OctreePacketProcessor::~OctreePacketProcessor() { }
void OctreePacketProcessor::handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
queueReceivedPacket(message, senderNode);
}
void OctreePacketProcessor::processPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"OctreePacketProcessor::processPacket()");
#ifndef Q_OS_ANDROID
const int WAY_BEHIND = 300;
if (packetsToProcessCount() > WAY_BEHIND && qApp->getLogger()->extraDebugging()) {
qDebug("OctreePacketProcessor::processPacket() packets to process=%d", packetsToProcessCount());
}
#endif
bool wasStatsPacket = false;
PacketType octreePacketType = message->getType();
// note: PacketType_OCTREE_STATS can have PacketType_VOXEL_DATA
// immediately following them inside the same packet. So, we process the PacketType_OCTREE_STATS first
// then process any remaining bytes as if it was another packet
if (octreePacketType == PacketType::OctreeStats) {
int statsMessageLength = processOctreeStats(*message, sendingNode);
wasStatsPacket = true;
int piggybackBytes = message->getSize() - statsMessageLength;
if (piggybackBytes) {
// construct a new packet from the piggybacked one
auto buffer = std::unique_ptr<char[]>(new char[piggybackBytes]);
memcpy(buffer.get(), message->getRawMessage() + statsMessageLength, piggybackBytes);
auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggybackBytes, message->getSenderSockAddr());
message = QSharedPointer<ReceivedMessage>::create(*newPacket);
} else {
// Note... stats packets don't have sequence numbers, so we don't want to send those to trackIncomingVoxelPacket()
return; // bail since no piggyback data
}
} // fall through to piggyback message
PacketType packetType = message->getType();
// check version of piggyback packet against expected version
if (message->getVersion() != versionForPacketType(message->getType())) {
static QMultiMap<QUuid, PacketType> versionDebugSuppressMap;
const QUuid& senderUUID = sendingNode->getUUID();
if (!versionDebugSuppressMap.contains(senderUUID, packetType)) {
qDebug() << "Was stats packet? " << wasStatsPacket;
qDebug() << "OctreePacketProcessor - piggyback packet version mismatch on" << packetType << "- Sender"
<< senderUUID << "sent" << (int) message->getVersion() << "but"
<< (int) versionForPacketType(packetType) << "expected.";
emit packetVersionMismatch();
versionDebugSuppressMap.insert(senderUUID, packetType);
}
return; // bail since piggyback version doesn't match
}
if (packetType != PacketType::EntityQueryInitialResultsComplete) {
trackIncomingOctreePacket(*message, sendingNode, wasStatsPacket);
}
// seek back to beginning of packet after tracking
message->seek(0);
switch(packetType) {
case PacketType::EntityErase: {
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
auto renderer = qApp->getEntities();
if (renderer) {
renderer->processEraseMessage(*message, sendingNode);
}
}
} break;
case PacketType::EntityData: {
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
auto renderer = qApp->getEntities();
if (renderer) {
renderer->processDatagram(*message, sendingNode);
if (_safeLanding && _safeLanding->isTracking()) {
OCTREE_PACKET_SEQUENCE thisSequence = renderer->getLastOctreeMessageSequence();
_safeLanding->addToSequence(thisSequence);
if (_safeLandingSequenceStart == SafeLanding::INVALID_SEQUENCE) {
_safeLandingSequenceStart = thisSequence;
}
}
}
}
} break;
case PacketType::EntityQueryInitialResultsComplete: {
// Read sequence #
OCTREE_PACKET_SEQUENCE completionNumber;
message->readPrimitive(&completionNumber);
if (_safeLanding && _safeLanding->isTracking()) {
_safeLanding->finishSequence(_safeLandingSequenceStart, completionNumber);
}
} break;
default: {
// nothing to do
} break;
}
}
void OctreePacketProcessor::startSafeLanding() {
if (_safeLanding) {
_safeLanding->startTracking(qApp->getEntities());
}
}
void OctreePacketProcessor::updateSafeLanding() {
if (_safeLanding) {
_safeLanding->updateTracking();
}
}
void OctreePacketProcessor::stopSafeLanding() {
if (_safeLanding) {
_safeLanding->stopTracking();
}
}
void OctreePacketProcessor::resetSafeLanding() {
if (_safeLanding) {
_safeLanding->reset();
}
_safeLandingSequenceStart = SafeLanding::INVALID_SEQUENCE;
}
bool OctreePacketProcessor::safeLandingIsActive() const {
return _safeLanding && _safeLanding->isTracking();
}
bool OctreePacketProcessor::safeLandingIsComplete() const {
if (_safeLanding) {
return _safeLanding->trackingIsComplete();
}
return false;
}
int OctreePacketProcessor::processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode) {
// parse the incoming stats datas stick it in a temporary object for now, while we
// determine which server it belongs to
int statsMessageLength = 0;
const QUuid& nodeUUID = sendingNode->getUUID();
// now that we know the node ID, let's add these stats to the stats for that node...
_octreeServerSceneStats.withWriteLock([&] {
OctreeSceneStats& octreeStats = _octreeServerSceneStats[nodeUUID];
statsMessageLength = octreeStats.unpackFromPacket(message);
if (octreeStats.isFullScene()) {
_fullSceneReceivedCounter++;
}
});
return statsMessageLength;
}
void OctreePacketProcessor::trackIncomingOctreePacket(ReceivedMessage& message, SharedNodePointer sendingNode, bool wasStatsPacket) {
// Attempt to identify the sender from its address.
if (sendingNode) {
const QUuid& nodeUUID = sendingNode->getUUID();
// now that we know the node ID, let's add these stats to the stats for that node...
_octreeServerSceneStats.withWriteLock([&] {
if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) {
OctreeSceneStats& stats = _octreeServerSceneStats[nodeUUID];
stats.trackIncomingOctreePacket(message, wasStatsPacket, sendingNode->getClockSkewUsec());
}
});
}
}