void LimitedNodeList::fillPacketHeader(const NLPacket& packet, const QUuid& connectionSecret) { if (!NON_SOURCED_PACKETS.contains(packet.getType())) { packet.writeSourceID(getSessionUUID()); } if (!connectionSecret.isNull() && !NON_SOURCED_PACKETS.contains(packet.getType()) && !NON_VERIFIED_PACKETS.contains(packet.getType())) { packet.writeVerificationHashGivenSecret(connectionSecret); } }
qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const HifiSockAddr& sockAddr, const QUuid& connectionSecret) { Q_ASSERT(!packet.isPartOfMessage()); Q_ASSERT_X(!packet.isReliable(), "LimitedNodeList::sendUnreliablePacket", "Trying to send a reliable packet unreliably."); collectPacketStats(packet); fillPacketHeader(packet, connectionSecret); return _nodeSocket.writePacket(packet, sockAddr); }
qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const Node& destinationNode) { Q_ASSERT(!packet.isPartOfMessage()); if (!destinationNode.getActiveSocket()) { return 0; } emit dataSent(destinationNode.getType(), packet.getDataSize()); destinationNode.recordBytesSent(packet.getDataSize()); return sendUnreliablePacket(packet, *destinationNode.getActiveSocket(), destinationNode.getConnectionSecret()); }
qint64 LimitedNodeList::writePacket(const NLPacket& packet, const Node& destinationNode) { if (!destinationNode.getActiveSocket()) { return 0; } // TODO Move to transport layer when ready if (SEQUENCE_NUMBERED_PACKETS.contains(packet.getType())) { PacketSequenceNumber sequenceNumber = getNextSequenceNumberForPacket(destinationNode.getUUID(), packet.getType()); const_cast<NLPacket&>(packet).writeSequenceNumber(sequenceNumber); } emit dataSent(destinationNode.getType(), packet.getDataSize()); return writePacket(packet, *destinationNode.getActiveSocket(), destinationNode.getConnectionSecret()); }
Assignment::Assignment(NLPacket& packet) : _pool(), _location(GlobalLocation), _payload(), _walletUUID(), _nodeVersion() { if (packet.getType() == PacketType::RequestAssignment) { _command = Assignment::RequestCommand; } else if (packet.getType() == PacketType::CreateAssignment) { _command = Assignment::CreateCommand; } QDataStream packetStream(&packet); packetStream >> *this; }
void ReceivedMessage::appendPacket(NLPacket& packet) { Q_ASSERT_X(!_isComplete, "ReceivedMessage::appendPacket", "We should not be appending to a complete message"); // Limit progress signal to every X packets const int EMIT_PROGRESS_EVERY_X_PACKETS = 50; ++_numPackets; _data.append(packet.getPayload(), packet.getPayloadSize()); if (_numPackets % EMIT_PROGRESS_EVERY_X_PACKETS == 0) { emit progress(getSize()); } if (packet.getPacketPosition() == NLPacket::PacketPosition::LAST) { _isComplete = true; emit completed(); } }
bool LimitedNodeList::packetSourceAndHashMatch(const NLPacket& packet, SharedNodePointer& matchingNode) { if (NON_SOURCED_PACKETS.contains(packet.getType())) { return true; } else { // figure out which node this is from matchingNode = nodeWithUUID(packet.getSourceID()); if (matchingNode) { if (!NON_VERIFIED_PACKETS.contains(packet.getType())) { // check if the md5 hash in the header matches the hash we would expect if (packet.getVerificationHash() != packet.payloadHashWithConnectionUUID(matchingNode->getConnectionSecret())) { static QMultiMap<QUuid, PacketType::Value> hashDebugSuppressMap; const QUuid& senderID = packet.getSourceID(); if (!hashDebugSuppressMap.contains(senderID, packet.getType())) { qCDebug(networking) << "Packet hash mismatch on" << packet.getType() << "- Sender" << senderID; hashDebugSuppressMap.insert(senderID, packet.getType()); } return false; } } return true; } else { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("Packet of type \\d+ \\([\\sa-zA-Z]+\\) received from unknown node with UUID"); qCDebug(networking) << "Packet of type" << packet.getType() << "(" << qPrintable(nameForPacketType(packet.getType())) << ")" << "received from unknown node with UUID" << qPrintable(uuidStringWithoutCurlyBraces(packet.getSourceID())); } } return false; }
ReceivedMessage::ReceivedMessage(NLPacket& packet) : _data(packet.readAll()), _headData(_data.mid(0, HEAD_DATA_SIZE)), _numPackets(1), _sourceID(packet.getSourceID()), _packetType(packet.getType()), _packetVersion(packet.getVersion()), _senderSockAddr(packet.getSenderSockAddr()), _isComplete(packet.getPacketPosition() == NLPacket::ONLY) { }
qint64 LimitedNodeList::writePacket(const NLPacket& packet, const HifiSockAddr& destinationSockAddr, const QUuid& connectionSecret) { if (!NON_SOURCED_PACKETS.contains(packet.getType())) { const_cast<NLPacket&>(packet).writeSourceID(getSessionUUID()); } if (!connectionSecret.isNull() && !NON_SOURCED_PACKETS.contains(packet.getType()) && !NON_VERIFIED_PACKETS.contains(packet.getType())) { const_cast<NLPacket&>(packet).writeVerificationHash(packet.payloadHashWithConnectionUUID(connectionSecret)); } emit dataSent(NodeType::Unassigned, packet.getDataSize()); return writeDatagram(QByteArray::fromRawData(packet.getData(), packet.getDataSize()), destinationSockAddr); }
void LimitedNodeList::collectPacketStats(const NLPacket& packet) { // stat collection for packets ++_numCollectedPackets; _numCollectedBytes += packet.getDataSize(); }
int InboundAudioStream::parseData(NLPacket& packet) { // parse sequence number and track it quint16 sequence; packet.readPrimitive(&sequence); SequenceNumberStats::ArrivalInfo arrivalInfo = _incomingSequenceNumberStats.sequenceNumberReceived(sequence, packet.getSourceID()); packetReceivedUpdateTimingStats(); int networkSamples; // parse the info after the seq number and before the audio data (the stream properties) int prePropertyPosition = packet.pos(); int propertyBytes = parseStreamProperties(packet.getType(), packet.read(packet.bytesLeftToRead()), networkSamples); packet.seek(prePropertyPosition + propertyBytes); // handle this packet based on its arrival status. switch (arrivalInfo._status) { case SequenceNumberStats::Early: { // Packet is early; write droppable silent samples for each of the skipped packets. // NOTE: we assume that each dropped packet contains the same number of samples // as the packet we just received. int packetsDropped = arrivalInfo._seqDiffFromExpected; writeSamplesForDroppedPackets(packetsDropped * networkSamples); // fall through to OnTime case } case SequenceNumberStats::OnTime: { // Packet is on time; parse its data to the ringbuffer if (packet.getType() == PacketType::SilentAudioFrame) { writeDroppableSilentSamples(networkSamples); } else { parseAudioData(packet.getType(), packet.read(packet.bytesLeftToRead()), networkSamples); } break; } default: { // For now, late packets are ignored. It may be good in the future to insert the late audio packet data // into the ring buffer to fill in the missing frame if it hasn't been mixed yet. break; } } int framesAvailable = _ringBuffer.framesAvailable(); // if this stream was starved, check if we're still starved. if (_isStarved && framesAvailable >= _desiredJitterBufferFrames) { _isStarved = false; } // if the ringbuffer exceeds the desired size by more than the threshold specified, // drop the oldest frames so the ringbuffer is down to the desired size. if (framesAvailable > _desiredJitterBufferFrames + _maxFramesOverDesired) { int framesToDrop = framesAvailable - (_desiredJitterBufferFrames + DESIRED_JITTER_BUFFER_FRAMES_PADDING); _ringBuffer.shiftReadPosition(framesToDrop * _ringBuffer.getNumFrameSamples()); _framesAvailableStat.reset(); _currentJitterBufferFrames = 0; _oldFramesDropped += framesToDrop; } framesAvailableChanged(); return packet.pos(); }
int AudioMixerClientData::parseData(NLPacket& packet) { PacketType packetType = packet.getType(); if (packetType == PacketType::AudioStreamStats) { // skip over header, appendFlag, and num stats packed packet.seek(sizeof(quint8) + sizeof(quint16)); // read the downstream audio stream stats packet.readPrimitive(&_downstreamAudioStreamStats); return packet.pos(); } else { PositionalAudioStream* matchingStream = NULL; if (packetType == PacketType::MicrophoneAudioWithEcho || packetType == PacketType::MicrophoneAudioNoEcho || packetType == PacketType::SilentAudioFrame) { QUuid nullUUID = QUuid(); if (!_audioStreams.contains(nullUUID)) { // we don't have a mic stream yet, so add it // read the channel flag to see if our stream is stereo or not packet.seek(sizeof(quint16)); quint8 channelFlag; packet.readPrimitive(&channelFlag); bool isStereo = channelFlag == 1; _audioStreams.insert(nullUUID, matchingStream = new AvatarAudioStream(isStereo, AudioMixer::getStreamSettings())); } else { matchingStream = _audioStreams.value(nullUUID); } } else if (packetType == PacketType::InjectAudio) { // this is injected audio // grab the stream identifier for this injected audio packet.seek(sizeof(quint16)); QUuid streamIdentifier = QUuid::fromRfc4122(packet.readWithoutCopy(NUM_BYTES_RFC4122_UUID)); bool isStereo; packet.readPrimitive(&isStereo); if (!_audioStreams.contains(streamIdentifier)) { // we don't have this injected stream yet, so add it _audioStreams.insert(streamIdentifier, matchingStream = new InjectedAudioStream(streamIdentifier, isStereo, AudioMixer::getStreamSettings())); } else { matchingStream = _audioStreams.value(streamIdentifier); } } // seek to the beginning of the packet so that the next reader is in the right spot packet.seek(0); return matchingStream->parseData(packet); } return 0; }