From 9556fecbe2de298969769b005623cd19a513434c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 20 Jul 2015 17:10:22 -0700 Subject: [PATCH 001/549] initial changes to make _nodeSocket a udt::Socket --- assignment-client/src/audio/AudioMixer.cpp | 3 - domain-server/src/DomainServer.cpp | 2 +- libraries/networking/src/LimitedNodeList.cpp | 55 +--- libraries/networking/src/LimitedNodeList.h | 12 +- libraries/networking/src/NLPacket.cpp | 49 +++- libraries/networking/src/NLPacket.h | 11 +- libraries/networking/src/PacketReceiver.cpp | 265 +++++++++---------- libraries/networking/src/PacketReceiver.h | 5 +- libraries/networking/src/udt/Packet.cpp | 18 +- libraries/networking/src/udt/Socket.cpp | 68 +++++ libraries/networking/src/udt/Socket.h | 55 ++++ 11 files changed, 333 insertions(+), 210 deletions(-) create mode 100644 libraries/networking/src/udt/Socket.cpp create mode 100644 libraries/networking/src/udt/Socket.h diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index b68332210b..aa8e405d34 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -652,9 +652,6 @@ void AudioMixer::run() { auto nodeList = DependencyManager::get(); - // we do not want this event loop to be the handler for UDP datagrams, so disconnect - disconnect(&nodeList->getNodeSocket(), 0, this, 0); - nodeList->addNodeTypeToInterestSet(NodeType::Agent); nodeList->linkedDataCreateCallback = [](Node* node) { diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index c13de0449e..4532180ca7 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -259,7 +259,7 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { auto nodeList = DependencyManager::set(domainServerPort, domainServerDTLSPort); // no matter the local port, save it to shared mem so that local assignment clients can ask what it is - nodeList->putLocalPortIntoSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this, nodeList->getNodeSocket().localPort()); + nodeList->putLocalPortIntoSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this, nodeList->getSocketLocalPort()); // store our local http ports in shared memory quint16 localHttpPort = DOMAIN_SERVER_HTTP_PORT; diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index fdb3461c1f..c36931fa9e 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -82,7 +82,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short } const int LARGER_BUFFER_SIZE = 1048576; - changeSocketBufferSizes(LARGER_BUFFER_SIZE); + _nodeSocket.setBufferSizes(LARGER_BUFFER_SIZE); // check for local socket updates every so often const int LOCAL_SOCKET_UPDATE_INTERVAL_MSECS = 5 * 1000; @@ -96,10 +96,10 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short // check the local socket right now updateLocalSockAddr(); - - // TODO: Create a new thread, and move PacketReceiver to it - - connect(&_nodeSocket, &QUdpSocket::readyRead, _packetReceiver, &PacketReceiver::processDatagrams); + + // set &PacketReceiver::handleVerifiedPacket as the verified packet function for the udt::Socket + using std::placeholders::_1; + _nodeSocket.setVerifiedPacketFunction(std::bind(&PacketReceiver::handleVerifiedPacket, _packetReceiver, _1)); _packetStatTimer.start(); @@ -149,32 +149,6 @@ QUdpSocket& LimitedNodeList::getDTLSSocket() { return *_dtlsSocket; } -void LimitedNodeList::changeSocketBufferSizes(int numBytes) { - for (int i = 0; i < 2; i++) { - QAbstractSocket::SocketOption bufferOpt; - QString bufferTypeString; - if (i == 0) { - bufferOpt = QAbstractSocket::SendBufferSizeSocketOption; - bufferTypeString = "send"; - - } else { - bufferOpt = QAbstractSocket::ReceiveBufferSizeSocketOption; - bufferTypeString = "receive"; - } - int oldBufferSize = _nodeSocket.socketOption(bufferOpt).toInt(); - if (oldBufferSize < numBytes) { - int newBufferSize = _nodeSocket.socketOption(bufferOpt).toInt(); - - qCDebug(networking) << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to" - << newBufferSize << "bytes"; - } else { - // don't make the buffer smaller - qCDebug(networking) << "Did not change socket" << bufferTypeString << "buffer size from" << oldBufferSize - << "since it is larger than desired size of" << numBytes; - } - } -} - bool LimitedNodeList::packetSourceAndHashMatch(const NLPacket& packet, SharedNodePointer& matchingNode) { if (NON_SOURCED_PACKETS.contains(packet.getType())) { @@ -255,12 +229,7 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const HifiSock ++_numCollectedPackets; _numCollectedBytes += datagram.size(); - qint64 bytesWritten = _nodeSocket.writeDatagram(datagram, - destinationSockAddr.getAddress(), destinationSockAddr.getPort()); - - if (bytesWritten < 0) { - qCDebug(networking) << "ERROR in writeDatagram:" << _nodeSocket.error() << "-" << _nodeSocket.errorString(); - } + qint64 bytesWritten = _nodeSocket.writeDatagram(datagram, destinationSockAddr); return bytesWritten; } @@ -571,7 +540,7 @@ void LimitedNodeList::sendSTUNRequest() { ++_numInitialSTUNRequests; } - unsigned char stunRequestPacket[NUM_BYTES_STUN_HEADER]; + char stunRequestPacket[NUM_BYTES_STUN_HEADER]; int packetIndex = 0; @@ -597,15 +566,7 @@ void LimitedNodeList::sendSTUNRequest() { flagTimeForConnectionStep(ConnectionStep::SendSTUNRequest); - _nodeSocket.writeDatagram((char*) stunRequestPacket, sizeof(stunRequestPacket), - _stunSockAddr.getAddress(), _stunSockAddr.getPort()); -} - -void LimitedNodeList::rebindNodeSocket() { - quint16 oldPort = _nodeSocket.localPort(); - - _nodeSocket.close(); - _nodeSocket.bind(QHostAddress::AnyIPv4, oldPort); + _nodeSocket.writeDatagram(stunRequestPacket, _stunSockAddr); } bool LimitedNodeList::processSTUNResponse(QSharedPointer packet) { diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 33d490c960..8a4230be04 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -37,9 +37,10 @@ #include "DomainHandler.h" #include "Node.h" #include "NLPacket.h" -#include "udt/PacketHeaders.h" #include "PacketReceiver.h" #include "NLPacketList.h" +#include "udt/PacketHeaders.h" +#include "udt/Socket.h" #include "UUIDHasher.h" const quint64 NODE_SILENCE_THRESHOLD_MSECS = 2 * 1000; @@ -109,9 +110,8 @@ public: bool getThisNodeCanRez() const { return _thisNodeCanRez; } void setThisNodeCanRez(bool canRez); - - void rebindNodeSocket(); - QUdpSocket& getNodeSocket() { return _nodeSocket; } + + quint16 getSocketLocalPort() const { return _nodeSocket.localPort(); } QUdpSocket& getDTLSSocket(); bool packetSourceAndHashMatch(const NLPacket& packet, SharedNodePointer& matchingNode); @@ -256,8 +256,6 @@ protected: PacketSequenceNumber getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType::Value packetType); - void changeSocketBufferSizes(int numBytes); - void handleNodeKill(const SharedNodePointer& node); void stopInitialSTUNUpdate(bool success); @@ -272,7 +270,7 @@ protected: QUuid _sessionUUID; NodeHash _nodeHash; QReadWriteLock _nodeMutex; - QUdpSocket _nodeSocket; + udt::Socket _nodeSocket; QUdpSocket* _dtlsSocket; HifiSockAddr _localSockAddr; HifiSockAddr _publicSockAddr; diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 7a6503dbc3..7ccd33a1ed 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -63,6 +63,14 @@ std::unique_ptr NLPacket::fromReceivedPacket(std::unique_ptr dat } +std::unique_ptr NLPacket::fromBase(std::unique_ptr packet) { + // Fail with null packet + Q_ASSERT(packet); + + // call our constructor to create an NLPacket from this Packet + return std::unique_ptr(new NLPacket(std::move(packet))); +} + std::unique_ptr NLPacket::createCopy(const NLPacket& other) { return std::unique_ptr(new NLPacket(other)); } @@ -81,24 +89,59 @@ NLPacket::NLPacket(PacketType::Value type) : adjustPayloadStartAndCapacity(); } -NLPacket::NLPacket(const NLPacket& other) : Packet(other) { +NLPacket::NLPacket(std::unique_ptr packet) : + Packet(*packet) +{ + adjustPayloadStartAndCapacity(_payloadSize > 0); + readSourceID(); + readVerificationHash(); +} + +NLPacket::NLPacket(const NLPacket& other) : Packet(other) { + *this = other; +} + +NLPacket& NLPacket::operator=(const NLPacket& other) { + Packet::operator=(other); + + _sourceID = other._sourceID; + _verificationHash = other._verificationHash; + + return *this; } NLPacket::NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr) : Packet(std::move(data), size, senderSockAddr) { adjustPayloadStartAndCapacity(); - _payloadSize = _payloadCapacity; readSourceID(); readVerificationHash(); } -void NLPacket::adjustPayloadStartAndCapacity() { +NLPacket::NLPacket(NLPacket&& other) : + Packet(other) +{ + *this = std::move(other); +} + +NLPacket& NLPacket::operator=(NLPacket&& other) { + _sourceID = std::move(other._sourceID); + _verificationHash = std::move(other._verificationHash); + + return *this; +} + + +void NLPacket::adjustPayloadStartAndCapacity(bool shouldDecreasePayloadSize) { qint64 headerSize = localHeaderSize(_type); _payloadStart += headerSize; _payloadCapacity -= headerSize; + + if (shouldDecreasePayloadSize) { + _payloadSize -= headerSize; + } } void NLPacket::readSourceID() { diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index 669278ed65..eab0fa3a99 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -22,6 +22,8 @@ public: static std::unique_ptr create(PacketType::Value type, qint64 size = -1); static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); + static std::unique_ptr fromBase(std::unique_ptr packet); + // Provided for convenience, try to limit use static std::unique_ptr createCopy(const NLPacket& other); @@ -41,12 +43,19 @@ public: protected: - void adjustPayloadStartAndCapacity(); + void adjustPayloadStartAndCapacity(bool shouldDecreasePayloadSize = false); NLPacket(PacketType::Value type); NLPacket(PacketType::Value type, qint64 size); + NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); + NLPacket(std::unique_ptr packet); + NLPacket(const NLPacket& other); + NLPacket& operator=(const NLPacket& other); + + NLPacket(NLPacket&& other); + NLPacket& operator=(NLPacket&& other); void readSourceID(); void readVerificationHash(); diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index f59be35dc5..a97b212355 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -234,147 +234,134 @@ bool PacketReceiver::packetVersionMatch(const NLPacket& packet) { } } -void PacketReceiver::processDatagrams() { - //PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - //"PacketReceiver::processDatagrams()"); - +void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { + + // if we're supposed to drop this packet then break out here + if (_shouldDropPackets) { + return; + } + auto nodeList = DependencyManager::get(); - - while (nodeList && nodeList->getNodeSocket().hasPendingDatagrams()) { - // setup a buffer to read the packet into - int packetSizeWithHeader = nodeList->getNodeSocket().pendingDatagramSize(); - std::unique_ptr buffer = std::unique_ptr(new char[packetSizeWithHeader]); - - // if we're supposed to drop this packet then break out here - if (_shouldDropPackets) { - break; - } - - // setup a HifiSockAddr to read into - HifiSockAddr senderSockAddr; - - // pull the datagram - nodeList->getNodeSocket().readDatagram(buffer.get(), packetSizeWithHeader, - senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()); - - // setup an NLPacket from the data we just read - auto packet = NLPacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); + + // setup a HifiSockAddr to read into + HifiSockAddr senderSockAddr; + + // setup an NLPacket from the data we just read + auto nlPacket = NLPacket::fromBase(std::move(packet)); + + _inPacketCount++; + _inByteCount += nlPacket->getDataSize(); + + SharedNodePointer matchingNode; + if (!nlPacket->getSourceID().isNull()) { + matchingNode = nodeList->nodeWithUUID(nlPacket->getSourceID()); - _inPacketCount++; - _inByteCount += packetSizeWithHeader; - - if (packetVersionMatch(*packet)) { - - SharedNodePointer matchingNode; - if (nodeList->packetSourceAndHashMatch(*packet, matchingNode)) { - - if (matchingNode) { - // No matter if this packet is handled or not, we update the timestamp for the last time we heard - // from this sending node - matchingNode->setLastHeardMicrostamp(usecTimestampNow()); - } - - _packetListenerLock.lock(); - - bool listenerIsDead = false; - - auto it = _packetListenerMap.find(packet->getType()); - - if (it != _packetListenerMap.end()) { - - auto listener = it.value(); - - if (listener.first) { - - bool success = false; - - // check if this is a directly connected listener - _directConnectSetMutex.lock(); - - Qt::ConnectionType connectionType = - _directlyConnectedObjects.contains(listener.first) ? Qt::DirectConnection : Qt::AutoConnection; - - _directConnectSetMutex.unlock(); - - PacketType::Value packetType = packet->getType(); - - if (matchingNode) { - // if this was a sequence numbered packet we should store the last seq number for - // a packet of this type for this node - if (SEQUENCE_NUMBERED_PACKETS.contains(packet->getType())) { - matchingNode->setLastSequenceNumberForPacketType(packet->readSequenceNumber(), packet->getType()); - } - - emit dataReceived(matchingNode->getType(), packet->getDataSize()); - QMetaMethod metaMethod = listener.second; - - static const QByteArray QSHAREDPOINTER_NODE_NORMALIZED = QMetaObject::normalizedType("QSharedPointer"); - static const QByteArray SHARED_NODE_NORMALIZED = QMetaObject::normalizedType("SharedNodePointer"); - - // one final check on the QPointer before we go to invoke - if (listener.first) { - if (metaMethod.parameterTypes().contains(SHARED_NODE_NORMALIZED)) { - success = metaMethod.invoke(listener.first, - connectionType, - Q_ARG(QSharedPointer, - QSharedPointer(packet.release())), - Q_ARG(SharedNodePointer, matchingNode)); - - } else if (metaMethod.parameterTypes().contains(QSHAREDPOINTER_NODE_NORMALIZED)) { - success = metaMethod.invoke(listener.first, - connectionType, - Q_ARG(QSharedPointer, - QSharedPointer(packet.release())), - Q_ARG(QSharedPointer, matchingNode)); - - } else { - success = metaMethod.invoke(listener.first, - connectionType, - Q_ARG(QSharedPointer, - QSharedPointer(packet.release()))); - } - } else { - listenerIsDead = true; - } - - } else { - emit dataReceived(NodeType::Unassigned, packet->getDataSize()); - - success = listener.second.invoke(listener.first, - Q_ARG(QSharedPointer, QSharedPointer(packet.release()))); - } - - if (!success) { - qDebug().nospace() << "Error delivering packet " << packetType - << " (" << qPrintable(nameForPacketType(packetType)) << ") to listener " - << listener.first << "::" << qPrintable(listener.second.methodSignature()); - } - - } else { - listenerIsDead = true; - } - - if (listenerIsDead) { - qDebug().nospace() << "Listener for packet" << packet->getType() - << " (" << qPrintable(nameForPacketType(packet->getType())) << ")" - << " has been destroyed. Removing from listener map."; - it = _packetListenerMap.erase(it); - - // if it exists, remove the listener from _directlyConnectedObjects - _directConnectSetMutex.lock(); - _directlyConnectedObjects.remove(listener.first); - _directConnectSetMutex.unlock(); - } - - } else { - qWarning() << "No listener found for packet type " << nameForPacketType(packet->getType()); - - // insert a dummy listener so we don't print this again - _packetListenerMap.insert(packet->getType(), { nullptr, QMetaMethod() }); - } - - _packetListenerLock.unlock(); - } + if (matchingNode) { + // No matter if this packet is handled or not, we update the timestamp for the last time we heard + // from this sending node + matchingNode->setLastHeardMicrostamp(usecTimestampNow()); } } + + _packetListenerLock.lock(); + + bool listenerIsDead = false; + + auto it = _packetListenerMap.find(packet->getType()); + + if (it != _packetListenerMap.end()) { + + auto listener = it.value(); + + if (listener.first) { + + bool success = false; + + // check if this is a directly connected listener + _directConnectSetMutex.lock(); + + Qt::ConnectionType connectionType = + _directlyConnectedObjects.contains(listener.first) ? Qt::DirectConnection : Qt::AutoConnection; + + _directConnectSetMutex.unlock(); + + PacketType::Value packetType = packet->getType(); + + if (matchingNode) { + // if this was a sequence numbered packet we should store the last seq number for + // a packet of this type for this node + if (SEQUENCE_NUMBERED_PACKETS.contains(packet->getType())) { + matchingNode->setLastSequenceNumberForPacketType(packet->readSequenceNumber(), packet->getType()); + } + + emit dataReceived(matchingNode->getType(), packet->getDataSize()); + QMetaMethod metaMethod = listener.second; + + static const QByteArray QSHAREDPOINTER_NODE_NORMALIZED = QMetaObject::normalizedType("QSharedPointer"); + static const QByteArray SHARED_NODE_NORMALIZED = QMetaObject::normalizedType("SharedNodePointer"); + + // one final check on the QPointer before we go to invoke + if (listener.first) { + if (metaMethod.parameterTypes().contains(SHARED_NODE_NORMALIZED)) { + success = metaMethod.invoke(listener.first, + connectionType, + Q_ARG(QSharedPointer, + QSharedPointer(nlPacket.release())), + Q_ARG(SharedNodePointer, matchingNode)); + + } else if (metaMethod.parameterTypes().contains(QSHAREDPOINTER_NODE_NORMALIZED)) { + success = metaMethod.invoke(listener.first, + connectionType, + Q_ARG(QSharedPointer, + QSharedPointer(nlPacket.release())), + Q_ARG(QSharedPointer, matchingNode)); + + } else { + success = metaMethod.invoke(listener.first, + connectionType, + Q_ARG(QSharedPointer, + QSharedPointer(nlPacket.release()))); + } + } else { + listenerIsDead = true; + } + + } else { + emit dataReceived(NodeType::Unassigned, packet->getDataSize()); + + success = listener.second.invoke(listener.first, + Q_ARG(QSharedPointer, QSharedPointer(nlPacket.release()))); + } + + if (!success) { + qDebug().nospace() << "Error delivering packet " << packetType + << " (" << qPrintable(nameForPacketType(packetType)) << ") to listener " + << listener.first << "::" << qPrintable(listener.second.methodSignature()); + } + + } else { + listenerIsDead = true; + } + + if (listenerIsDead) { + qDebug().nospace() << "Listener for packet" << packet->getType() + << " (" << qPrintable(nameForPacketType(packet->getType())) << ")" + << " has been destroyed. Removing from listener map."; + it = _packetListenerMap.erase(it); + + // if it exists, remove the listener from _directlyConnectedObjects + _directConnectSetMutex.lock(); + _directlyConnectedObjects.remove(listener.first); + _directConnectSetMutex.unlock(); + } + + } else { + qWarning() << "No listener found for packet type " << nameForPacketType(packet->getType()); + + // insert a dummy listener so we don't print this again + _packetListenerMap.insert(packet->getType(), { nullptr, QMetaMethod() }); + } + + _packetListenerLock.unlock(); + } diff --git a/libraries/networking/src/PacketReceiver.h b/libraries/networking/src/PacketReceiver.h index 9fdccdfddf..ac38749a88 100644 --- a/libraries/networking/src/PacketReceiver.h +++ b/libraries/networking/src/PacketReceiver.h @@ -44,9 +44,8 @@ public: bool registerListenerForTypes(const QSet& types, QObject* listener, const char* slot); bool registerListener(PacketType::Value type, QObject* listener, const char* slot); void unregisterListener(QObject* listener); - -public slots: - void processDatagrams(); + + void handleVerifiedPacket(std::unique_ptr packet); signals: void dataReceived(quint8 channelType, int bytes); diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 02a44c4a4f..05b5f3fe50 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -98,12 +98,6 @@ Packet::Packet(const Packet& other) : QIODevice() { *this = other; - - if (other.isOpen()) { - this->open(other.openMode()); - } - - this->seek(other.pos()); } Packet& Packet::operator=(const Packet& other) { @@ -117,6 +111,12 @@ Packet& Packet::operator=(const Packet& other) { _payloadCapacity = other._payloadCapacity; _payloadSize = other._payloadSize; + + if (other.isOpen() && !isOpen()) { + open(other.openMode()); + } + + seek(other.pos()); return *this; } @@ -135,6 +135,12 @@ Packet& Packet::operator=(Packet&& other) { _payloadCapacity = other._payloadCapacity; _payloadSize = other._payloadSize; + + if (other.isOpen() && !isOpen()) { + open(other.openMode()); + } + + seek(other.pos()); return *this; } diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp new file mode 100644 index 0000000000..2e1e3481f9 --- /dev/null +++ b/libraries/networking/src/udt/Socket.cpp @@ -0,0 +1,68 @@ +// +// Socket.cpp +// libraries/networking/src/udt +// +// Created by Stephen Birarda on 2015-07-20. +// Copyright 2015 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 "Socket.h" + +#include "../NetworkLogging.h" + +using namespace udt; + +Socket::Socket(QObject* parent) : + QObject(parent) +{ + +} + +void Socket::rebind() { + quint16 oldPort = _udpSocket.localPort(); + + _udpSocket.close(); + _udpSocket.bind(QHostAddress::AnyIPv4, oldPort); +} + +void Socket::setBufferSizes(int numBytes) { + for (int i = 0; i < 2; i++) { + QAbstractSocket::SocketOption bufferOpt; + QString bufferTypeString; + + if (i == 0) { + bufferOpt = QAbstractSocket::SendBufferSizeSocketOption; + bufferTypeString = "send"; + + } else { + bufferOpt = QAbstractSocket::ReceiveBufferSizeSocketOption; + bufferTypeString = "receive"; + } + + int oldBufferSize = _udpSocket.socketOption(bufferOpt).toInt(); + + if (oldBufferSize < numBytes) { + int newBufferSize = _udpSocket.socketOption(bufferOpt).toInt(); + + qCDebug(networking) << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to" + << newBufferSize << "bytes"; + } else { + // don't make the buffer smaller + qCDebug(networking) << "Did not change socket" << bufferTypeString << "buffer size from" << oldBufferSize + << "since it is larger than desired size of" << numBytes; + } + } +} + +qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr) { + qint64 bytesWritten = _udpSocket.writeDatagram(datagram, sockAddr.getAddress(), sockAddr.getPort()); + + if (bytesWritten < 0) { + qCDebug(networking) << "ERROR in writeDatagram:" << _udpSocket.error() << "-" << _udpSocket.errorString(); + } + + return bytesWritten; +} diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h new file mode 100644 index 0000000000..23ad75db12 --- /dev/null +++ b/libraries/networking/src/udt/Socket.h @@ -0,0 +1,55 @@ +// +// Socket.h +// libraries/networking/src/udt +// +// Created by Stephen Birarda on 2015-07-20. +// Copyright 2015 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 +// + +#pragma once + +#ifndef hifi_Socket_h +#define hifi_Socket_h + +#include + +#include +#include + +#include "../HifiSockAddr.h" +#include "Packet.h" + +namespace udt { + +using VerifiedPacketFunction = std::function)>; + +class Socket : public QObject { + Q_OBJECT +public: + Socket(QObject* object = 0); + + quint16 localPort() const { return _udpSocket.localPort(); } + + qint64 writeDatagram(const char* data, qint64 size, const HifiSockAddr& sockAddr) + { return writeDatagram(QByteArray::fromRawData(data, size), sockAddr); } + qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr); + + void bind(const QHostAddress& address, quint16 port = 0) { _udpSocket.bind(address, port); } + void rebind(); + + void setVerifiedPacketFunction(VerifiedPacketFunction verifiedPacketFunction) + { _verifiedPacketFunction = verifiedPacketFunction; } + + void setBufferSizes(int numBytes); +private: + QUdpSocket _udpSocket { this }; + VerifiedPacketFunction _verifiedPacketFunction; +}; + +} + + +#endif // hifi_Socket_h From 796dfee687b1799035a77ff480146d26f1162911 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 20 Jul 2015 17:28:04 -0700 Subject: [PATCH 002/549] udt namespace fixes and NLPacket operator fixes --- ice-server/src/IceServer.cpp | 6 +++--- ice-server/src/IceServer.h | 2 +- libraries/networking/src/NLPacket.cpp | 11 ++++++++--- libraries/networking/src/NLPacket.h | 2 +- libraries/networking/src/NLPacketList.cpp | 2 +- libraries/networking/src/NLPacketList.h | 4 ++-- libraries/networking/src/PacketReceiver.cpp | 2 +- libraries/networking/src/PacketReceiver.h | 2 +- libraries/networking/src/udt/Packet.cpp | 2 ++ libraries/networking/src/udt/Packet.h | 6 +++++- libraries/networking/src/udt/PacketList.cpp | 2 ++ libraries/networking/src/udt/PacketList.h | 8 +++++++- libraries/networking/src/udt/Socket.cpp | 22 ++++++++++++++++++++- libraries/networking/src/udt/Socket.h | 4 ++++ 14 files changed, 59 insertions(+), 16 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index f56fe9202f..1a08426081 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -55,7 +55,7 @@ void IceServer::processDatagrams() { _serverSocket.readDatagram(buffer.get(), packetSizeWithHeader, sendingSockAddr.getAddressPointer(), sendingSockAddr.getPortPointer()); - auto packet = Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, sendingSockAddr); + auto packet = udt::Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, sendingSockAddr); PacketType::Value packetType = packet->getType(); @@ -100,7 +100,7 @@ void IceServer::processDatagrams() { } } -SharedNetworkPeer IceServer::addOrUpdateHeartbeatingPeer(Packet& packet) { +SharedNetworkPeer IceServer::addOrUpdateHeartbeatingPeer(udt::Packet& packet) { // pull the UUID, public and private sock addrs for this peer QUuid senderUUID; @@ -133,7 +133,7 @@ SharedNetworkPeer IceServer::addOrUpdateHeartbeatingPeer(Packet& packet) { } void IceServer::sendPeerInformationPacket(const NetworkPeer& peer, const HifiSockAddr* destinationSockAddr) { - auto peerPacket = Packet::create(PacketType::ICEServerPeerInformation); + auto peerPacket = udt::Packet::create(PacketType::ICEServerPeerInformation); // get the byte array for this peer peerPacket->write(peer.toByteArray()); diff --git a/ice-server/src/IceServer.h b/ice-server/src/IceServer.h index 7820ae2e22..e91dc4e064 100644 --- a/ice-server/src/IceServer.h +++ b/ice-server/src/IceServer.h @@ -33,7 +33,7 @@ private slots: void clearInactivePeers(); private: - SharedNetworkPeer addOrUpdateHeartbeatingPeer(Packet& incomingPacket); + SharedNetworkPeer addOrUpdateHeartbeatingPeer(udt::Packet& incomingPacket); void sendPeerInformationPacket(const NetworkPeer& peer, const HifiSockAddr* destinationSockAddr); QUuid _id; diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 7ccd33a1ed..5f24810d0b 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -99,12 +99,13 @@ NLPacket::NLPacket(std::unique_ptr packet) : } NLPacket::NLPacket(const NLPacket& other) : Packet(other) { - *this = other; + _sourceID = other._sourceID; + _verificationHash = other._verificationHash; } NLPacket& NLPacket::operator=(const NLPacket& other) { Packet::operator=(other); - + _sourceID = other._sourceID; _verificationHash = other._verificationHash; @@ -123,10 +124,14 @@ NLPacket::NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& NLPacket::NLPacket(NLPacket&& other) : Packet(other) { - *this = std::move(other); + _sourceID = std::move(other._sourceID); + _verificationHash = std::move(other._verificationHash); } NLPacket& NLPacket::operator=(NLPacket&& other) { + + Packet::operator=(other); + _sourceID = std::move(other._sourceID); _verificationHash = std::move(other._verificationHash); diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index eab0fa3a99..aaf6c5df75 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -16,7 +16,7 @@ #include "udt/Packet.h" -class NLPacket : public Packet { +class NLPacket : public udt::Packet { Q_OBJECT public: static std::unique_ptr create(PacketType::Value type, qint64 size = -1); diff --git a/libraries/networking/src/NLPacketList.cpp b/libraries/networking/src/NLPacketList.cpp index 8c794cf5f8..6b7b53e8e9 100644 --- a/libraries/networking/src/NLPacketList.cpp +++ b/libraries/networking/src/NLPacketList.cpp @@ -19,7 +19,7 @@ NLPacketList::NLPacketList(PacketType::Value packetType, QByteArray extendedHead } -std::unique_ptr NLPacketList::createPacket() { +std::unique_ptr NLPacketList::createPacket() { return NLPacket::create(getType()); } diff --git a/libraries/networking/src/NLPacketList.h b/libraries/networking/src/NLPacketList.h index 28fbde9112..33a8316f95 100644 --- a/libraries/networking/src/NLPacketList.h +++ b/libraries/networking/src/NLPacketList.h @@ -14,7 +14,7 @@ #include "udt/PacketList.h" -class NLPacketList : public PacketList { +class NLPacketList : public udt::PacketList { public: NLPacketList(PacketType::Value packetType, QByteArray extendedHeader = QByteArray()); @@ -22,7 +22,7 @@ private: NLPacketList(const NLPacketList& other) = delete; NLPacketList& operator=(const NLPacketList& other) = delete; - virtual std::unique_ptr createPacket(); + virtual std::unique_ptr createPacket(); }; #endif // hifi_PacketList_h diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index a97b212355..eacdff9704 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -234,7 +234,7 @@ bool PacketReceiver::packetVersionMatch(const NLPacket& packet) { } } -void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { +void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { // if we're supposed to drop this packet then break out here if (_shouldDropPackets) { diff --git a/libraries/networking/src/PacketReceiver.h b/libraries/networking/src/PacketReceiver.h index ac38749a88..9851521250 100644 --- a/libraries/networking/src/PacketReceiver.h +++ b/libraries/networking/src/PacketReceiver.h @@ -45,7 +45,7 @@ public: bool registerListener(PacketType::Value type, QObject* listener, const char* slot); void unregisterListener(QObject* listener); - void handleVerifiedPacket(std::unique_ptr packet); + void handleVerifiedPacket(std::unique_ptr packet); signals: void dataReceived(quint8 channelType, int bytes); diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 05b5f3fe50..b8c38f3b09 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -11,6 +11,8 @@ #include "Packet.h" +using namespace udt; + const qint64 Packet::PACKET_WRITE_ERROR = -1; qint64 Packet::localHeaderSize(PacketType::Value type) { diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index b4c53b8165..96e8f8c3d4 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -1,6 +1,6 @@ // // Packet.h -// libraries/networking/src +// libraries/networking/src/udt // // Created by Clement on 7/2/15. // Copyright 2015 High Fidelity, Inc. @@ -19,6 +19,8 @@ #include "../HifiSockAddr.h" #include "PacketHeaders.h" +namespace udt { + class Packet : public QIODevice { Q_OBJECT public: @@ -131,5 +133,7 @@ template qint64 Packet::writePrimitive(const T& data) { static_assert(!std::is_pointer::value, "T must not be a pointer"); return QIODevice::write(reinterpret_cast(&data), sizeof(T)); } + +} // namespace udt #endif // hifi_Packet_h diff --git a/libraries/networking/src/udt/PacketList.cpp b/libraries/networking/src/udt/PacketList.cpp index 5dcacfa9b1..47545eb910 100644 --- a/libraries/networking/src/udt/PacketList.cpp +++ b/libraries/networking/src/udt/PacketList.cpp @@ -15,6 +15,8 @@ #include "Packet.h" +using namespace udt; + PacketList::PacketList(PacketType::Value packetType, QByteArray extendedHeader) : _packetType(packetType), _extendedHeader(extendedHeader) diff --git a/libraries/networking/src/udt/PacketList.h b/libraries/networking/src/udt/PacketList.h index 30288dcaab..3d1166149c 100644 --- a/libraries/networking/src/udt/PacketList.h +++ b/libraries/networking/src/udt/PacketList.h @@ -18,6 +18,10 @@ #include "PacketHeaders.h" +class LimitedNodeList; + +namespace udt { + class Packet; class PacketList : public QIODevice { @@ -42,7 +46,7 @@ protected: virtual qint64 readData(char* data, qint64 maxSize) { return 0; } private: - friend class LimitedNodeList; + friend class ::LimitedNodeList; PacketList(const PacketList& other) = delete; PacketList& operator=(const PacketList& other) = delete; @@ -82,5 +86,7 @@ template std::unique_ptr PacketList::takeFront() { _packets.pop_front(); return std::unique_ptr(dynamic_cast(packet.release())); } + +} #endif // hifi_PacketList_h diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 2e1e3481f9..8f766594c6 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -18,7 +18,7 @@ using namespace udt; Socket::Socket(QObject* parent) : QObject(parent) { - + connect(&_udpSocket, &QUdpSocket::readyRead, this, &Socket::readPendingDatagrams); } void Socket::rebind() { @@ -66,3 +66,23 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc return bytesWritten; } + +void Socket::readPendingDatagrams() { + while (_udpSocket.hasPendingDatagrams()) { + // setup a HifiSockAddr to read into + HifiSockAddr senderSockAddr; + + // setup a buffer to read the packet into + int packetSizeWithHeader = _udpSocket.pendingDatagramSize(); + std::unique_ptr buffer = std::unique_ptr(new char[packetSizeWithHeader]); + + // pull the datagram + _udpSocket.readDatagram(buffer.get(), packetSizeWithHeader, + senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()); + + // setup a Packet from the data we just read + auto packet = Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); + + + } +} diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 23ad75db12..3ab568c952 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -44,6 +44,10 @@ public: { _verifiedPacketFunction = verifiedPacketFunction; } void setBufferSizes(int numBytes); + +private slots: + void readPendingDatagrams(); + private: QUdpSocket _udpSocket { this }; VerifiedPacketFunction _verifiedPacketFunction; From cea8e01a012517ad09fd3aca2328dd42574d019d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 20 Jul 2015 17:35:16 -0700 Subject: [PATCH 003/549] add a verify packet operator to verify packets --- libraries/networking/src/LimitedNodeList.cpp | 2 +- libraries/networking/src/udt/Socket.cpp | 7 ++++++- libraries/networking/src/udt/Socket.h | 11 +++++++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index c36931fa9e..b5c152d194 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -99,7 +99,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short // set &PacketReceiver::handleVerifiedPacket as the verified packet function for the udt::Socket using std::placeholders::_1; - _nodeSocket.setVerifiedPacketFunction(std::bind(&PacketReceiver::handleVerifiedPacket, _packetReceiver, _1)); + _nodeSocket.setVerifiedPacketCallback(std::bind(&PacketReceiver::handleVerifiedPacket, _packetReceiver, _1)); _packetStatTimer.start(); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 8f766594c6..8facac5cd4 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -83,6 +83,11 @@ void Socket::readPendingDatagrams() { // setup a Packet from the data we just read auto packet = Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); - + // call our verification operator to see if this packet is verified + if (!_verifyPacketOperator || _verifyPacketOperator(*packet)) { + + // call the verified packet callback to let it handle this packet + return _verifiedPacketCallback(std::move(packet)); + } } } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 3ab568c952..4d98667c3a 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -24,7 +24,8 @@ namespace udt { -using VerifiedPacketFunction = std::function)>; +using VerifyPacketOperator = std::function; +using VerifiedPacketCallback = std::function)>; class Socket : public QObject { Q_OBJECT @@ -40,8 +41,9 @@ public: void bind(const QHostAddress& address, quint16 port = 0) { _udpSocket.bind(address, port); } void rebind(); - void setVerifiedPacketFunction(VerifiedPacketFunction verifiedPacketFunction) - { _verifiedPacketFunction = verifiedPacketFunction; } + void setVerifyPacketOperator(VerifyPacketOperator verifyPacketOperator) { _verifyPacketOperator = verifyPacketOperator; } + void setVerifiedPacketCallback(VerifiedPacketCallback verifiedPacketCallback) + { _verifiedPacketCallback = verifiedPacketCallback; } void setBufferSizes(int numBytes); @@ -50,7 +52,8 @@ private slots: private: QUdpSocket _udpSocket { this }; - VerifiedPacketFunction _verifiedPacketFunction; + VerifyPacketOperator _verifyPacketOperator; + VerifiedPacketCallback _verifiedPacketCallback; }; } From 3901dbae33731060b1c0d8589886d38e90880115 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 21 Jul 2015 11:06:25 -0700 Subject: [PATCH 004/549] fix for broken move in NLPacket/Packet --- libraries/networking/src/LimitedNodeList.cpp | 2 +- libraries/networking/src/NLPacket.cpp | 6 +++--- libraries/networking/src/PacketReceiver.cpp | 16 ++++++++-------- libraries/networking/src/udt/Packet.cpp | 2 ++ libraries/networking/src/udt/Socket.cpp | 1 + 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index b5c152d194..94e8b97779 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -566,7 +566,7 @@ void LimitedNodeList::sendSTUNRequest() { flagTimeForConnectionStep(ConnectionStep::SendSTUNRequest); - _nodeSocket.writeDatagram(stunRequestPacket, _stunSockAddr); + _nodeSocket.writeDatagram(QByteArray::fromRawData(stunRequestPacket, sizeof(stunRequestPacket)), _stunSockAddr); } bool LimitedNodeList::processSTUNResponse(QSharedPointer packet) { diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 5f24810d0b..3a3fe47397 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -90,7 +90,7 @@ NLPacket::NLPacket(PacketType::Value type) : } NLPacket::NLPacket(std::unique_ptr packet) : - Packet(*packet) + Packet(std::move(*packet.release())) { adjustPayloadStartAndCapacity(_payloadSize > 0); @@ -122,7 +122,7 @@ NLPacket::NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& } NLPacket::NLPacket(NLPacket&& other) : - Packet(other) + Packet(other) { _sourceID = std::move(other._sourceID); _verificationHash = std::move(other._verificationHash); @@ -130,7 +130,7 @@ NLPacket::NLPacket(NLPacket&& other) : NLPacket& NLPacket::operator=(NLPacket&& other) { - Packet::operator=(other); + Packet::operator=(std::move(other)); _sourceID = std::move(other._sourceID); _verificationHash = std::move(other._verificationHash); diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index eacdff9704..70dad7b1a6 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -267,7 +267,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { bool listenerIsDead = false; - auto it = _packetListenerMap.find(packet->getType()); + auto it = _packetListenerMap.find(nlPacket->getType()); if (it != _packetListenerMap.end()) { @@ -285,16 +285,16 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { _directConnectSetMutex.unlock(); - PacketType::Value packetType = packet->getType(); + PacketType::Value packetType = nlPacket->getType(); if (matchingNode) { // if this was a sequence numbered packet we should store the last seq number for // a packet of this type for this node - if (SEQUENCE_NUMBERED_PACKETS.contains(packet->getType())) { + if (SEQUENCE_NUMBERED_PACKETS.contains(nlPacket->getType())) { matchingNode->setLastSequenceNumberForPacketType(packet->readSequenceNumber(), packet->getType()); } - emit dataReceived(matchingNode->getType(), packet->getDataSize()); + emit dataReceived(matchingNode->getType(), nlPacket->getDataSize()); QMetaMethod metaMethod = listener.second; static const QByteArray QSHAREDPOINTER_NODE_NORMALIZED = QMetaObject::normalizedType("QSharedPointer"); @@ -327,7 +327,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { } } else { - emit dataReceived(NodeType::Unassigned, packet->getDataSize()); + emit dataReceived(NodeType::Unassigned, nlPacket->getDataSize()); success = listener.second.invoke(listener.first, Q_ARG(QSharedPointer, QSharedPointer(nlPacket.release()))); @@ -344,8 +344,8 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { } if (listenerIsDead) { - qDebug().nospace() << "Listener for packet" << packet->getType() - << " (" << qPrintable(nameForPacketType(packet->getType())) << ")" + qDebug().nospace() << "Listener for packet" << nlPacket->getType() + << " (" << qPrintable(nameForPacketType(nlPacket->getType())) << ")" << " has been destroyed. Removing from listener map."; it = _packetListenerMap.erase(it); @@ -356,7 +356,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { } } else { - qWarning() << "No listener found for packet type " << nameForPacketType(packet->getType()); + qWarning() << "No listener found for packet type " << nameForPacketType(nlPacket->getType()); // insert a dummy listener so we don't print this again _packetListenerMap.insert(packet->getType(), { nullptr, QMetaMethod() }); diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index b8c38f3b09..45c6a6f75f 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -138,6 +138,8 @@ Packet& Packet::operator=(Packet&& other) { _payloadSize = other._payloadSize; + _senderSockAddr = std::move(other._senderSockAddr); + if (other.isOpen() && !isOpen()) { open(other.openMode()); } diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 8facac5cd4..661c27bef5 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -58,6 +58,7 @@ void Socket::setBufferSizes(int numBytes) { } qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr) { + qint64 bytesWritten = _udpSocket.writeDatagram(datagram, sockAddr.getAddress(), sockAddr.getPort()); if (bytesWritten < 0) { From ed6867e1a01e945301f48c71d772ab57ae2bd843 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 21 Jul 2015 11:47:06 -0700 Subject: [PATCH 005/549] add a method to LNL to verify packets --- libraries/networking/src/LimitedNodeList.cpp | 73 +++++++++++++++++--- libraries/networking/src/LimitedNodeList.h | 7 +- libraries/networking/src/NLPacket.cpp | 56 +++++++-------- libraries/networking/src/NLPacket.h | 11 ++- libraries/networking/src/PacketReceiver.cpp | 42 ----------- libraries/networking/src/PacketReceiver.h | 3 - 6 files changed, 99 insertions(+), 93 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 94e8b97779..821cd5e47b 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -101,6 +101,9 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short using std::placeholders::_1; _nodeSocket.setVerifiedPacketCallback(std::bind(&PacketReceiver::handleVerifiedPacket, _packetReceiver, _1)); + // set our isPacketVerified method as the verify operator for the udt::Socket + _nodeSocket.setVerifyPacketOperator(std::bind(&LimitedNodeList::isPacketVerified, this, _1)); + _packetStatTimer.start(); // make sure we handle STUN response packets @@ -149,27 +152,77 @@ QUdpSocket& LimitedNodeList::getDTLSSocket() { return *_dtlsSocket; } -bool LimitedNodeList::packetSourceAndHashMatch(const NLPacket& packet, SharedNodePointer& matchingNode) { +bool LimitedNodeList::isPacketVerified(const udt::Packet& packet) { + return packetVersionMatch(packet) && packetSourceAndHashMatch(packet); +} + +bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) { + + if (packet.getVersion() != versionForPacketType(packet.getType())) { + + static QMultiHash sourcedVersionDebugSuppressMap; + static QMultiHash versionDebugSuppressMap; + + bool hasBeenOutput = false; + QString senderString; + + if (NON_SOURCED_PACKETS.contains(packet.getType())) { + const HifiSockAddr& senderSockAddr = packet.getSenderSockAddr(); + hasBeenOutput = versionDebugSuppressMap.contains(senderSockAddr, packet.getType()); + + if (!hasBeenOutput) { + versionDebugSuppressMap.insert(senderSockAddr, packet.getType()); + senderString = QString("%1:%2").arg(senderSockAddr.getAddress().toString()).arg(senderSockAddr.getPort()); + } + } else { + QUuid sourceID = QUuid::fromRfc4122(QByteArray::fromRawData(packet.getPayload(), NUM_BYTES_RFC4122_UUID)); + + hasBeenOutput = sourcedVersionDebugSuppressMap.contains(sourceID, packet.getType()); + + if (!hasBeenOutput) { + sourcedVersionDebugSuppressMap.insert(sourceID, packet.getType()); + senderString = uuidStringWithoutCurlyBraces(sourceID.toString()); + } + } + + if (!hasBeenOutput) { + qCDebug(networking) << "Packet version mismatch on" << packet.getType() << "- Sender" + << senderString << "sent" << qPrintable(QString::number(packet.getVersion())) << "but" + << qPrintable(QString::number(versionForPacketType(packet.getType()))) << "expected."; + + emit packetVersionMismatch(packet.getType()); + } + + return false; + } else { + return true; + } +} + +bool LimitedNodeList::packetSourceAndHashMatch(const udt::Packet& packet) { if (NON_SOURCED_PACKETS.contains(packet.getType())) { return true; } else { + QUuid sourceID = NLPacket::sourceIDInHeader(packet); // figure out which node this is from - matchingNode = nodeWithUUID(packet.getSourceID()); + SharedNodePointer matchingNode = nodeWithUUID(sourceID); if (matchingNode) { if (!NON_VERIFIED_PACKETS.contains(packet.getType())) { + + QByteArray packetHeaderHash = NLPacket::verificationHashInHeader(packet); + QByteArray expectedHash = NLPacket::hashForPacketAndSecret(packet, matchingNode->getConnectionSecret()); + // check if the md5 hash in the header matches the hash we would expect - if (packet.getVerificationHash() != packet.payloadHashWithConnectionUUID(matchingNode->getConnectionSecret())) { + if (packetHeaderHash != expectedHash) { static QMultiMap hashDebugSuppressMap; - const QUuid& senderID = packet.getSourceID(); + if (!hashDebugSuppressMap.contains(sourceID, packet.getType())) { + qCDebug(networking) << "Packet hash mismatch on" << packet.getType() << "- Sender" << sourceID; - if (!hashDebugSuppressMap.contains(senderID, packet.getType())) { - qCDebug(networking) << "Packet hash mismatch on" << packet.getType() << "- Sender" << senderID; - - hashDebugSuppressMap.insert(senderID, packet.getType()); + hashDebugSuppressMap.insert(sourceID, packet.getType()); } return false; @@ -183,7 +236,7 @@ bool LimitedNodeList::packetSourceAndHashMatch(const NLPacket& packet, SharedNod = 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())); + << "received from unknown node with UUID" << qPrintable(uuidStringWithoutCurlyBraces(sourceID)); } } @@ -215,7 +268,7 @@ qint64 LimitedNodeList::writePacket(const NLPacket& packet, const HifiSockAddr& if (!connectionSecret.isNull() && !NON_SOURCED_PACKETS.contains(packet.getType()) && !NON_VERIFIED_PACKETS.contains(packet.getType())) { - const_cast(packet).writeVerificationHash(packet.payloadHashWithConnectionUUID(connectionSecret)); + const_cast(packet).writeVerificationHashGivenSecret(connectionSecret); } emit dataSent(NodeType::Unassigned, packet.getDataSize()); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 8a4230be04..f05ba4b0dc 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -114,8 +114,6 @@ public: quint16 getSocketLocalPort() const { return _nodeSocket.localPort(); } QUdpSocket& getDTLSSocket(); - bool packetSourceAndHashMatch(const NLPacket& packet, SharedNodePointer& matchingNode); - PacketReceiver& getPacketReceiver() { return *_packetReceiver; } qint64 sendUnreliablePacket(const NLPacket& packet, const Node& destinationNode); @@ -233,6 +231,7 @@ public slots: signals: void dataSent(quint8 channelType, int bytes); + void packetVersionMismatch(PacketType::Value type); void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID); void nodeAdded(SharedNodePointer); @@ -255,6 +254,10 @@ protected: qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr); PacketSequenceNumber getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType::Value packetType); + + bool isPacketVerified(const udt::Packet& packet); + bool packetVersionMatch(const udt::Packet& packet); + bool packetSourceAndHashMatch(const udt::Packet& packet); void handleNodeKill(const SharedNodePointer& node); diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 3a3fe47397..f9964c8eb1 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -95,19 +95,16 @@ NLPacket::NLPacket(std::unique_ptr packet) : adjustPayloadStartAndCapacity(_payloadSize > 0); readSourceID(); - readVerificationHash(); } NLPacket::NLPacket(const NLPacket& other) : Packet(other) { _sourceID = other._sourceID; - _verificationHash = other._verificationHash; } NLPacket& NLPacket::operator=(const NLPacket& other) { Packet::operator=(other); _sourceID = other._sourceID; - _verificationHash = other._verificationHash; return *this; } @@ -118,14 +115,12 @@ NLPacket::NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& adjustPayloadStartAndCapacity(); readSourceID(); - readVerificationHash(); } NLPacket::NLPacket(NLPacket&& other) : Packet(other) { _sourceID = std::move(other._sourceID); - _verificationHash = std::move(other._verificationHash); } NLPacket& NLPacket::operator=(NLPacket&& other) { @@ -133,11 +128,32 @@ NLPacket& NLPacket::operator=(NLPacket&& other) { Packet::operator=(std::move(other)); _sourceID = std::move(other._sourceID); - _verificationHash = std::move(other._verificationHash); return *this; } +QUuid NLPacket::sourceIDInHeader(const udt::Packet& packet) { + int offset = packet.localHeaderSize(); + return QUuid::fromRfc4122(QByteArray::fromRawData(packet.getData() + offset, NUM_BYTES_RFC4122_UUID)); +} + +QByteArray NLPacket::verificationHashInHeader(const udt::Packet& packet) { + int offset = packet.localHeaderSize() + NUM_BYTES_RFC4122_UUID; + return QByteArray(packet.getData() + offset, NUM_BYTES_MD5_HASH); +} + +QByteArray NLPacket::hashForPacketAndSecret(const udt::Packet& packet, const QUuid& connectionSecret) { + QCryptographicHash hash(QCryptographicHash::Md5); + + int offset = packet.localHeaderSize() + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH; + + // add the packet payload and the connection UUID + hash.addData(packet.getData(), packet.getDataSize() - offset); + hash.addData(connectionSecret.toRfc4122()); + + // return the hash + return hash.result(); +} void NLPacket::adjustPayloadStartAndCapacity(bool shouldDecreasePayloadSize) { qint64 headerSize = localHeaderSize(_type); @@ -151,15 +167,7 @@ void NLPacket::adjustPayloadStartAndCapacity(bool shouldDecreasePayloadSize) { void NLPacket::readSourceID() { if (!NON_SOURCED_PACKETS.contains(_type)) { - auto offset = Packet::localHeaderSize(); - _sourceID = QUuid::fromRfc4122(QByteArray::fromRawData(_packet.get() + offset, NUM_BYTES_RFC4122_UUID)); - } -} - -void NLPacket::readVerificationHash() { - if (!NON_SOURCED_PACKETS.contains(_type) && !NON_VERIFIED_PACKETS.contains(_type)) { - auto offset = Packet::localHeaderSize() + NUM_BYTES_RFC4122_UUID; - _verificationHash = QByteArray(_packet.get() + offset, NUM_BYTES_MD5_HASH); + _sourceID = sourceIDInHeader(*this); } } @@ -172,22 +180,10 @@ void NLPacket::writeSourceID(const QUuid& sourceID) { _sourceID = sourceID; } -void NLPacket::writeVerificationHash(const QByteArray& verificationHash) { +void NLPacket::writeVerificationHashGivenSecret(const QUuid& connectionSecret) { Q_ASSERT(!NON_SOURCED_PACKETS.contains(_type) && !NON_VERIFIED_PACKETS.contains(_type)); - + auto offset = Packet::localHeaderSize() + NUM_BYTES_RFC4122_UUID; + QByteArray verificationHash = hashForPacketAndSecret(*this, connectionSecret); memcpy(_packet.get() + offset, verificationHash.data(), verificationHash.size()); - - _verificationHash = verificationHash; -} - -QByteArray NLPacket::payloadHashWithConnectionUUID(const QUuid& connectionUUID) const { - QCryptographicHash hash(QCryptographicHash::Md5); - - // add the packet payload and the connection UUID - hash.addData(_payloadStart, _payloadSize); - hash.addData(connectionUUID.toRfc4122()); - - // return the hash - return hash.result(); } diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index aaf6c5df75..9b2b78c3f9 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -26,6 +26,10 @@ public: // Provided for convenience, try to limit use static std::unique_ptr createCopy(const NLPacket& other); + + static QUuid sourceIDInHeader(const udt::Packet& packet); + static QByteArray verificationHashInHeader(const udt::Packet& packet); + static QByteArray hashForPacketAndSecret(const udt::Packet& packet, const QUuid& connectionSecret); static qint64 localHeaderSize(PacketType::Value type); static qint64 maxPayloadSize(PacketType::Value type); @@ -34,12 +38,9 @@ public: virtual qint64 localHeaderSize() const; // Current level's header size const QUuid& getSourceID() const { return _sourceID; } - const QByteArray& getVerificationHash() const { return _verificationHash; } void writeSourceID(const QUuid& sourceID); - void writeVerificationHash(const QByteArray& verificationHash); - - QByteArray payloadHashWithConnectionUUID(const QUuid& connectionUUID) const; + void writeVerificationHashGivenSecret(const QUuid& connectionSecret); protected: @@ -58,10 +59,8 @@ protected: NLPacket& operator=(NLPacket&& other); void readSourceID(); - void readVerificationHash(); QUuid _sourceID; - QByteArray _verificationHash; }; #endif // hifi_NLPacket_h diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 70dad7b1a6..16ee775afa 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -192,48 +192,6 @@ void PacketReceiver::unregisterListener(QObject* listener) { _directConnectSetMutex.unlock(); } -bool PacketReceiver::packetVersionMatch(const NLPacket& packet) { - - if (packet.getVersion() != versionForPacketType(packet.getType()) - && packet.getType() != PacketType::StunResponse) { - - static QMultiHash sourcedVersionDebugSuppressMap; - static QMultiHash versionDebugSuppressMap; - - bool hasBeenOutput = false; - QString senderString; - - if (NON_SOURCED_PACKETS.contains(packet.getType())) { - const HifiSockAddr& senderSockAddr = packet.getSenderSockAddr(); - hasBeenOutput = versionDebugSuppressMap.contains(senderSockAddr, packet.getType()); - - if (!hasBeenOutput) { - versionDebugSuppressMap.insert(senderSockAddr, packet.getType()); - senderString = QString("%1:%2").arg(senderSockAddr.getAddress().toString()).arg(senderSockAddr.getPort()); - } - } else { - hasBeenOutput = sourcedVersionDebugSuppressMap.contains(packet.getSourceID(), packet.getType()); - - if (!hasBeenOutput) { - sourcedVersionDebugSuppressMap.insert(packet.getSourceID(), packet.getType()); - senderString = uuidStringWithoutCurlyBraces(packet.getSourceID().toString()); - } - } - - if (!hasBeenOutput) { - qCDebug(networking) << "Packet version mismatch on" << packet.getType() << "- Sender" - << senderString << "sent" << qPrintable(QString::number(packet.getVersion())) << "but" - << qPrintable(QString::number(versionForPacketType(packet.getType()))) << "expected."; - - emit packetVersionMismatch(packet.getType()); - } - - return false; - } else { - return true; - } -} - void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { // if we're supposed to drop this packet then break out here diff --git a/libraries/networking/src/PacketReceiver.h b/libraries/networking/src/PacketReceiver.h index 9851521250..25bf9656be 100644 --- a/libraries/networking/src/PacketReceiver.h +++ b/libraries/networking/src/PacketReceiver.h @@ -49,15 +49,12 @@ public: signals: void dataReceived(quint8 channelType, int bytes); - void packetVersionMismatch(PacketType::Value type); private: // these are brutal hacks for now - ideally GenericThread / ReceivedPacketProcessor // should be changed to have a true event loop and be able to handle our QMetaMethod::invoke void registerDirectListenerForTypes(const QSet& types, QObject* listener, const char* slot); void registerDirectListener(PacketType::Value type, QObject* listener, const char* slot); - - bool packetVersionMatch(const NLPacket& packet); QMetaMethod matchingMethodForListener(PacketType::Value type, QObject* object, const char* slot) const; void registerVerifiedListener(PacketType::Value type, QObject* listener, const QMetaMethod& slot); From a61c04aa92e4d5d9f6095aed6a4054181a7cc9f9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 21 Jul 2015 12:00:16 -0700 Subject: [PATCH 006/549] allow socket owner to specify unfiltered packets --- interface/src/Application.cpp | 3 +-- libraries/networking/src/LimitedNodeList.cpp | 1 + libraries/networking/src/LimitedNodeList.h | 2 ++ libraries/networking/src/udt/Socket.cpp | 2 +- libraries/networking/src/udt/Socket.h | 4 ++++ 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f0dcdd1a8a..e920c760ba 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -452,8 +452,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(nodeList.data(), &NodeList::uuidChanged, _myAvatar, &MyAvatar::setSessionUUID); connect(nodeList.data(), &NodeList::uuidChanged, this, &Application::setSessionUUID); connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, nodeList.data(), &NodeList::reset); - connect(&nodeList->getPacketReceiver(), &PacketReceiver::packetVersionMismatch, - this, &Application::notifyPacketVersionMismatch); + connect(&nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch); // connect to appropriate slots on AccountManager AccountManager& accountManager = AccountManager::getInstance(); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 821cd5e47b..4d8b7e48a3 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -710,6 +710,7 @@ void LimitedNodeList::startSTUNPublicSocketUpdate() { // if we don't know the STUN IP yet we need to have ourselves be called once it is known if (_stunSockAddr.getAddress().isNull()) { connect(&_stunSockAddr, &HifiSockAddr::lookupCompleted, this, &LimitedNodeList::startSTUNPublicSocketUpdate); + connect(&_stunSockAddr, &HifiSockAddr::lookupCompleted, this, &LimitedNodeList::addSTUNSockAddrToUnfiltered); // in case we just completely fail to lookup the stun socket - add a 10s timeout that will trigger the fail case const quint64 STUN_DNS_LOOKUP_TIMEOUT_MSECS = 10 * 1000; diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index f05ba4b0dc..ebfe77cc8b 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -310,9 +310,11 @@ protected: functor(it); } } + private slots: void flagTimeForConnectionStep(ConnectionStep connectionStep, quint64 timestamp); void possiblyTimeoutSTUNAddressLookup(); + void addSTUNSockAddrToUnfiltered() { _nodeSocket.addUnfilteredSockAddr(_stunSockAddr); } // called once STUN socket known }; #endif // hifi_LimitedNodeList_h diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 661c27bef5..0192e306c3 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -85,7 +85,7 @@ void Socket::readPendingDatagrams() { auto packet = Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); // call our verification operator to see if this packet is verified - if (!_verifyPacketOperator || _verifyPacketOperator(*packet)) { + if (_unfilteredSockAddrs.contains(senderSockAddr) || !_verifyPacketOperator || _verifyPacketOperator(*packet)) { // call the verified packet callback to let it handle this packet return _verifiedPacketCallback(std::move(packet)); diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 4d98667c3a..36f11213ff 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -46,6 +46,8 @@ public: { _verifiedPacketCallback = verifiedPacketCallback; } void setBufferSizes(int numBytes); + + void addUnfilteredSockAddr(const HifiSockAddr& senderSockAddr) { _unfilteredSockAddrs.insert(senderSockAddr); } private slots: void readPendingDatagrams(); @@ -54,6 +56,8 @@ private: QUdpSocket _udpSocket { this }; VerifyPacketOperator _verifyPacketOperator; VerifiedPacketCallback _verifiedPacketCallback; + + QSet _unfilteredSockAddrs; }; } From da761d4c952d280d335462a8d90b8bacf1046307 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 21 Jul 2015 12:12:15 -0700 Subject: [PATCH 007/549] fix static methods to handle header read/write --- libraries/networking/src/NLPacket.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index f9964c8eb1..fdfb94f107 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -133,19 +133,19 @@ NLPacket& NLPacket::operator=(NLPacket&& other) { } QUuid NLPacket::sourceIDInHeader(const udt::Packet& packet) { - int offset = packet.localHeaderSize(); + int offset = packet.Packet::localHeaderSize(); return QUuid::fromRfc4122(QByteArray::fromRawData(packet.getData() + offset, NUM_BYTES_RFC4122_UUID)); } QByteArray NLPacket::verificationHashInHeader(const udt::Packet& packet) { - int offset = packet.localHeaderSize() + NUM_BYTES_RFC4122_UUID; + int offset = packet.Packet::localHeaderSize() + NUM_BYTES_RFC4122_UUID; return QByteArray(packet.getData() + offset, NUM_BYTES_MD5_HASH); } QByteArray NLPacket::hashForPacketAndSecret(const udt::Packet& packet, const QUuid& connectionSecret) { QCryptographicHash hash(QCryptographicHash::Md5); - int offset = packet.localHeaderSize() + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH; + int offset = packet.Packet::localHeaderSize() + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH; // add the packet payload and the connection UUID hash.addData(packet.getData(), packet.getDataSize() - offset); @@ -185,5 +185,6 @@ void NLPacket::writeVerificationHashGivenSecret(const QUuid& connectionSecret) { auto offset = Packet::localHeaderSize() + NUM_BYTES_RFC4122_UUID; QByteArray verificationHash = hashForPacketAndSecret(*this, connectionSecret); + memcpy(_packet.get() + offset, verificationHash.data(), verificationHash.size()); } From 4604bc5a3a3e02fd5398bd2351d86397e13fdc69 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 21 Jul 2015 12:27:27 -0700 Subject: [PATCH 008/549] leverage udt::Socket in ice-server --- ice-server/src/IceServer.cpp | 95 +++++++++----------- ice-server/src/IceServer.h | 7 +- libraries/networking/src/LimitedNodeList.cpp | 10 +-- libraries/networking/src/LimitedNodeList.h | 2 +- libraries/networking/src/udt/Socket.cpp | 4 + libraries/networking/src/udt/Socket.h | 2 + 6 files changed, 57 insertions(+), 63 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 1d38802f4e..fb7433aa10 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -34,8 +34,9 @@ IceServer::IceServer(int argc, char* argv[]) : qDebug() << "monitoring http endpoint is listening on " << ICE_SERVER_MONITORING_PORT; _serverSocket.bind(QHostAddress::AnyIPv4, ICE_SERVER_DEFAULT_PORT); - // call our process datagrams slot when the UDP socket has packets ready - connect(&_serverSocket, &QUdpSocket::readyRead, this, &IceServer::processDatagrams); + // set processPacket as the verified packet callback for the udt::Socket + using std::placeholders::_1; + _serverSocket.setVerifiedPacketCallback(std::bind(&IceServer::processPacket, this, _1)); // setup our timer to clear inactive peers QTimer* inactivePeerTimer = new QTimer(this); @@ -44,58 +45,45 @@ IceServer::IceServer(int argc, char* argv[]) : } -void IceServer::processDatagrams() { - HifiSockAddr sendingSockAddr; - - while (_serverSocket.hasPendingDatagrams()) { - // setup a buffer to read the packet into - int packetSizeWithHeader = _serverSocket.pendingDatagramSize(); - std::unique_ptr buffer = std::unique_ptr(new char[packetSizeWithHeader]); - - _serverSocket.readDatagram(buffer.get(), packetSizeWithHeader, - sendingSockAddr.getAddressPointer(), sendingSockAddr.getPortPointer()); +void IceServer::processPacket(std::unique_ptr packet) { + PacketType::Value packetType = packet->getType(); + + if (packetType == PacketType::ICEServerHeartbeat) { + SharedNetworkPeer peer = addOrUpdateHeartbeatingPeer(*packet); - auto packet = udt::Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, sendingSockAddr); - - PacketType::Value packetType = packet->getType(); - - if (packetType == PacketType::ICEServerHeartbeat) { - SharedNetworkPeer peer = addOrUpdateHeartbeatingPeer(*packet); - - // so that we can send packets to the heartbeating peer when we need, we need to activate a socket now - peer->activateMatchingOrNewSymmetricSocket(sendingSockAddr); - } else if (packetType == PacketType::ICEServerQuery) { - QDataStream heartbeatStream(packet.get()); - - // this is a node hoping to connect to a heartbeating peer - do we have the heartbeating peer? - QUuid senderUUID; - heartbeatStream >> senderUUID; - - // pull the public and private sock addrs for this peer - HifiSockAddr publicSocket, localSocket; - heartbeatStream >> publicSocket >> localSocket; - - // check if this node also included a UUID that they would like to connect to - QUuid connectRequestID; - heartbeatStream >> connectRequestID; + // so that we can send packets to the heartbeating peer when we need, we need to activate a socket now + peer->activateMatchingOrNewSymmetricSocket(packet->getSenderSockAddr()); + } else if (packetType == PacketType::ICEServerQuery) { + QDataStream heartbeatStream(packet.get()); + + // this is a node hoping to connect to a heartbeating peer - do we have the heartbeating peer? + QUuid senderUUID; + heartbeatStream >> senderUUID; + + // pull the public and private sock addrs for this peer + HifiSockAddr publicSocket, localSocket; + heartbeatStream >> publicSocket >> localSocket; + + // check if this node also included a UUID that they would like to connect to + QUuid connectRequestID; + heartbeatStream >> connectRequestID; + + SharedNetworkPeer matchingPeer = _activePeers.value(connectRequestID); + + if (matchingPeer) { - SharedNetworkPeer matchingPeer = _activePeers.value(connectRequestID); - - if (matchingPeer) { - - qDebug() << "Sending information for peer" << connectRequestID << "to peer" << senderUUID; - - // we have the peer they want to connect to - send them pack the information for that peer - sendPeerInformationPacket(*(matchingPeer.data()), &sendingSockAddr); - - // we also need to send them to the active peer they are hoping to connect to - // create a dummy peer object we can pass to sendPeerInformationPacket - - NetworkPeer dummyPeer(senderUUID, publicSocket, localSocket); - sendPeerInformationPacket(dummyPeer, matchingPeer->getActiveSocket()); - } else { - qDebug() << "Peer" << senderUUID << "asked for" << connectRequestID << "but no matching peer found"; - } + qDebug() << "Sending information for peer" << connectRequestID << "to peer" << senderUUID; + + // we have the peer they want to connect to - send them pack the information for that peer + sendPeerInformationPacket(*(matchingPeer.data()), &packet->getSenderSockAddr()); + + // we also need to send them to the active peer they are hoping to connect to + // create a dummy peer object we can pass to sendPeerInformationPacket + + NetworkPeer dummyPeer(senderUUID, publicSocket, localSocket); + sendPeerInformationPacket(dummyPeer, matchingPeer->getActiveSocket()); + } else { + qDebug() << "Peer" << senderUUID << "asked for" << connectRequestID << "but no matching peer found"; } } } @@ -139,8 +127,7 @@ void IceServer::sendPeerInformationPacket(const NetworkPeer& peer, const HifiSoc peerPacket->write(peer.toByteArray()); // write the current packet - _serverSocket.writeDatagram(peerPacket->getData(), peerPacket->getDataSize(), - destinationSockAddr->getAddress(), destinationSockAddr->getPort()); + _serverSocket.writeUnreliablePacket(*peerPacket, *destinationSockAddr); } void IceServer::clearInactivePeers() { diff --git a/ice-server/src/IceServer.h b/ice-server/src/IceServer.h index e91dc4e064..092ece6c3f 100644 --- a/ice-server/src/IceServer.h +++ b/ice-server/src/IceServer.h @@ -20,6 +20,7 @@ #include #include #include +#include typedef QHash NetworkPeerHash; @@ -29,15 +30,15 @@ public: IceServer(int argc, char* argv[]); bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false); private slots: - void processDatagrams(); void clearInactivePeers(); private: - + void processPacket(std::unique_ptr packet); + SharedNetworkPeer addOrUpdateHeartbeatingPeer(udt::Packet& incomingPacket); void sendPeerInformationPacket(const NetworkPeer& peer, const HifiSockAddr* destinationSockAddr); QUuid _id; - QUdpSocket _serverSocket; + udt::Socket _serverSocket; NetworkPeerHash _activePeers; HTTPManager _httpManager; }; diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 4d8b7e48a3..45deb80c16 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -97,7 +97,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short // check the local socket right now updateLocalSockAddr(); - // set &PacketReceiver::handleVerifiedPacket as the verified packet function for the udt::Socket + // set &PacketReceiver::handleVerifiedPacket as the verified packet callback for the udt::Socket using std::placeholders::_1; _nodeSocket.setVerifiedPacketCallback(std::bind(&PacketReceiver::handleVerifiedPacket, _packetReceiver, _1)); @@ -273,16 +273,16 @@ qint64 LimitedNodeList::writePacket(const NLPacket& packet, const HifiSockAddr& emit dataSent(NodeType::Unassigned, packet.getDataSize()); - return writeDatagram(QByteArray::fromRawData(packet.getData(), packet.getDataSize()), destinationSockAddr); + return writePacketAndCollectStats(packet, destinationSockAddr); } -qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr) { +qint64 LimitedNodeList::writePacketAndCollectStats(const NLPacket& packet, const HifiSockAddr& destinationSockAddr) { // XXX can BandwidthRecorder be used for this? // stat collection for packets ++_numCollectedPackets; - _numCollectedBytes += datagram.size(); + _numCollectedBytes += packet.getDataSize(); - qint64 bytesWritten = _nodeSocket.writeDatagram(datagram, destinationSockAddr); + qint64 bytesWritten = _nodeSocket.writeUnreliablePacket(packet, destinationSockAddr); return bytesWritten; } diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index ebfe77cc8b..67dc707815 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -251,7 +251,7 @@ protected: qint64 writePacket(const NLPacket& packet, const Node& destinationNode); qint64 writePacket(const NLPacket& packet, const HifiSockAddr& destinationSockAddr, const QUuid& connectionSecret = QUuid()); - qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr); + qint64 writePacketAndCollectStats(const NLPacket& packet, const HifiSockAddr& destinationSockAddr); PacketSequenceNumber getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType::Value packetType); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 0192e306c3..33ad4159c2 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -57,6 +57,10 @@ void Socket::setBufferSizes(int numBytes) { } } +qint64 Socket::writeUnreliablePacket(const Packet& packet, const HifiSockAddr& sockAddr) { + return writeDatagram(packet.getData(), packet.getDataSize(), sockAddr); +} + qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr) { qint64 bytesWritten = _udpSocket.writeDatagram(datagram, sockAddr.getAddress(), sockAddr.getPort()); diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 36f11213ff..6997986e91 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -34,6 +34,8 @@ public: quint16 localPort() const { return _udpSocket.localPort(); } + qint64 writeUnreliablePacket(const Packet& packet, const HifiSockAddr& sockAddr); + qint64 writeDatagram(const char* data, qint64 size, const HifiSockAddr& sockAddr) { return writeDatagram(QByteArray::fromRawData(data, size), sockAddr); } qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr); From 086e4efe4490ed6a19ef472ba8b5fc81d0c3e666 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 21 Jul 2015 13:03:39 -0700 Subject: [PATCH 009/549] verify packet versions at ice-server --- ice-server/src/IceServer.cpp | 14 ++++++++++++ ice-server/src/IceServer.h | 1 + interface/src/Application.cpp | 2 +- libraries/networking/src/NetworkPeer.cpp | 28 ++++++++++++++---------- libraries/networking/src/udt/Socket.h | 2 +- 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index fb7433aa10..e86ed0b4ea 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -37,6 +37,9 @@ IceServer::IceServer(int argc, char* argv[]) : // set processPacket as the verified packet callback for the udt::Socket using std::placeholders::_1; _serverSocket.setVerifiedPacketCallback(std::bind(&IceServer::processPacket, this, _1)); + + // set packetVersionMatch as the verify packet operator for the udt::Socket + _serverSocket.setVerifyPacketOperator(std::bind(&IceServer::packetVersionMatch, this, _1)); // setup our timer to clear inactive peers QTimer* inactivePeerTimer = new QTimer(this); @@ -45,6 +48,17 @@ IceServer::IceServer(int argc, char* argv[]) : } +bool IceServer::packetVersionMatch(const udt::Packet& packet) { + if (packet.getVersion() == versionForPacketType(packet.getType())) { + return true; + } else { + qDebug() << "Packet version mismatch for packet" << packet.getType() + << "(" << nameForPacketType(packet.getType()) << ") from" << packet.getSenderSockAddr(); + + return false; + } +} + void IceServer::processPacket(std::unique_ptr packet) { PacketType::Value packetType = packet->getType(); diff --git a/ice-server/src/IceServer.h b/ice-server/src/IceServer.h index 092ece6c3f..3ab6df9044 100644 --- a/ice-server/src/IceServer.h +++ b/ice-server/src/IceServer.h @@ -32,6 +32,7 @@ public: private slots: void clearInactivePeers(); private: + bool packetVersionMatch(const udt::Packet& packet); void processPacket(std::unique_ptr packet); SharedNetworkPeer addOrUpdateHeartbeatingPeer(udt::Packet& incomingPacket); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e920c760ba..652d12ade0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -452,7 +452,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(nodeList.data(), &NodeList::uuidChanged, _myAvatar, &MyAvatar::setSessionUUID); connect(nodeList.data(), &NodeList::uuidChanged, this, &Application::setSessionUUID); connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, nodeList.data(), &NodeList::reset); - connect(&nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch); + connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch); // connect to appropriate slots on AccountManager AccountManager& accountManager = AccountManager::getInstance(); diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index 398d4106c1..28f19d4f60 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -54,12 +54,14 @@ void NetworkPeer::setPublicSocket(const HifiSockAddr& publicSocket) { // if the active socket was the public socket then reset it to NULL _activeSocket = NULL; } - - if (!_publicSocket.isNull()) { - qCDebug(networking) << "Public socket change for node" << *this; - } + + bool wasOldSocketNull = _publicSocket.isNull(); _publicSocket = publicSocket; + + if (!wasOldSocketNull) { + qCDebug(networking) << "Public socket change for node" << *this; + } } } @@ -69,12 +71,14 @@ void NetworkPeer::setLocalSocket(const HifiSockAddr& localSocket) { // if the active socket was the local socket then reset it to NULL _activeSocket = NULL; } + + bool wasOldSocketNull = _localSocket.isNull(); + + _localSocket = localSocket; - if (!_localSocket.isNull()) { + if (!wasOldSocketNull) { qCDebug(networking) << "Local socket change for node" << *this; } - - _localSocket = localSocket; } } @@ -84,12 +88,14 @@ void NetworkPeer::setSymmetricSocket(const HifiSockAddr& symmetricSocket) { // if the active socket was the symmetric socket then reset it to NULL _activeSocket = NULL; } - - if (!_symmetricSocket.isNull()) { + + bool wasOldSocketNull = _symmetricSocket.isNull(); + + _symmetricSocket = symmetricSocket; + + if (!wasOldSocketNull) { qCDebug(networking) << "Symmetric socket change for node" << *this; } - - _symmetricSocket = symmetricSocket; } } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 6997986e91..2ebeb179bc 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -24,7 +24,7 @@ namespace udt { -using VerifyPacketOperator = std::function; +using VerifyPacketOperator = std::function; using VerifiedPacketCallback = std::function)>; class Socket : public QObject { From 30225ba3c1d0829ff57c185b6dc3a3ee17503bda Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 21 Jul 2015 13:05:38 -0700 Subject: [PATCH 010/549] fix spacing for multi-line QDebug in PacketReceiver --- libraries/networking/src/PacketReceiver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 16ee775afa..502563489b 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -293,8 +293,8 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { if (!success) { qDebug().nospace() << "Error delivering packet " << packetType - << " (" << qPrintable(nameForPacketType(packetType)) << ") to listener " - << listener.first << "::" << qPrintable(listener.second.methodSignature()); + << " (" << qPrintable(nameForPacketType(packetType)) << ") to listener " + << listener.first << "::" << qPrintable(listener.second.methodSignature()); } } else { @@ -303,8 +303,8 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { if (listenerIsDead) { qDebug().nospace() << "Listener for packet" << nlPacket->getType() - << " (" << qPrintable(nameForPacketType(nlPacket->getType())) << ")" - << " has been destroyed. Removing from listener map."; + << " (" << qPrintable(nameForPacketType(nlPacket->getType())) << ")" + << " has been destroyed. Removing from listener map."; it = _packetListenerMap.erase(it); // if it exists, remove the listener from _directlyConnectedObjects From 240f53ddd2dfc4ae19c0f4805c8e79dcbf209980 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jul 2015 09:51:13 -0700 Subject: [PATCH 011/549] bunch up the NLPacket constructors --- libraries/networking/src/NLPacket.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index 9b2b78c3f9..aad6e6d072 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -48,13 +48,10 @@ protected: NLPacket(PacketType::Value type); NLPacket(PacketType::Value type, qint64 size); - NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); NLPacket(std::unique_ptr packet); - NLPacket(const NLPacket& other); NLPacket& operator=(const NLPacket& other); - NLPacket(NLPacket&& other); NLPacket& operator=(NLPacket&& other); From 7f53eda0d99cc5df1b053d56e98798e6f622abc3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jul 2015 10:01:24 -0700 Subject: [PATCH 012/549] naming changes to udt::Socket handlers --- ice-server/src/IceServer.cpp | 4 ++-- libraries/networking/src/LimitedNodeList.cpp | 4 ++-- libraries/networking/src/udt/Socket.cpp | 9 +++++---- libraries/networking/src/udt/Socket.h | 13 ++++++------- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index e86ed0b4ea..c4dd2cf532 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -36,10 +36,10 @@ IceServer::IceServer(int argc, char* argv[]) : // set processPacket as the verified packet callback for the udt::Socket using std::placeholders::_1; - _serverSocket.setVerifiedPacketCallback(std::bind(&IceServer::processPacket, this, _1)); + _serverSocket.setVerifiedPacketHandler(std::bind(&IceServer::processPacket, this, _1)); // set packetVersionMatch as the verify packet operator for the udt::Socket - _serverSocket.setVerifyPacketOperator(std::bind(&IceServer::packetVersionMatch, this, _1)); + _serverSocket.setPacketVerificationHandler(std::bind(&IceServer::packetVersionMatch, this, _1)); // setup our timer to clear inactive peers QTimer* inactivePeerTimer = new QTimer(this); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 45deb80c16..e6b0b27712 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -99,10 +99,10 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short // set &PacketReceiver::handleVerifiedPacket as the verified packet callback for the udt::Socket using std::placeholders::_1; - _nodeSocket.setVerifiedPacketCallback(std::bind(&PacketReceiver::handleVerifiedPacket, _packetReceiver, _1)); + _nodeSocket.setVerifiedPacketHandler(std::bind(&PacketReceiver::handleVerifiedPacket, _packetReceiver, _1)); // set our isPacketVerified method as the verify operator for the udt::Socket - _nodeSocket.setVerifyPacketOperator(std::bind(&LimitedNodeList::isPacketVerified, this, _1)); + _nodeSocket.setPacketVerificationHandler(std::bind(&LimitedNodeList::isPacketVerified, this, _1)); _packetStatTimer.start(); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 33ad4159c2..685689f4e6 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -89,10 +89,11 @@ void Socket::readPendingDatagrams() { auto packet = Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); // call our verification operator to see if this packet is verified - if (_unfilteredSockAddrs.contains(senderSockAddr) || !_verifyPacketOperator || _verifyPacketOperator(*packet)) { - - // call the verified packet callback to let it handle this packet - return _verifiedPacketCallback(std::move(packet)); + if (_unfilteredSockAddrs.contains(senderSockAddr) || !_packetVerificationHandler || _packetVerificationHandler(*packet)) { + if (_verifiedPacketHandler) { + // call the verified packet callback to let it handle this packet + return _verifiedPacketHandler(std::move(packet)); + } } } } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 2ebeb179bc..fcade487a3 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -24,8 +24,8 @@ namespace udt { -using VerifyPacketOperator = std::function; -using VerifiedPacketCallback = std::function)>; +using PacketVerificationHandler = std::function; +using VerifiedPacketHandler = std::function)>; class Socket : public QObject { Q_OBJECT @@ -43,9 +43,8 @@ public: void bind(const QHostAddress& address, quint16 port = 0) { _udpSocket.bind(address, port); } void rebind(); - void setVerifyPacketOperator(VerifyPacketOperator verifyPacketOperator) { _verifyPacketOperator = verifyPacketOperator; } - void setVerifiedPacketCallback(VerifiedPacketCallback verifiedPacketCallback) - { _verifiedPacketCallback = verifiedPacketCallback; } + void setPacketVerificationHandler(PacketVerificationHandler handler) { _packetVerificationHandler = handler; } + void setVerifiedPacketHandler(VerifiedPacketHandler handler) { _verifiedPacketHandler = handler; } void setBufferSizes(int numBytes); @@ -56,8 +55,8 @@ private slots: private: QUdpSocket _udpSocket { this }; - VerifyPacketOperator _verifyPacketOperator; - VerifiedPacketCallback _verifiedPacketCallback; + PacketVerificationHandler _packetVerificationHandler; + VerifiedPacketHandler _verifiedPacketHandler; QSet _unfilteredSockAddrs; }; From fb7130120ac2a25d0147778e6dde9c51c74d9d1d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jul 2015 10:16:26 -0700 Subject: [PATCH 013/549] another rename to Socket callbacks --- ice-server/src/IceServer.cpp | 4 ++-- libraries/networking/src/LimitedNodeList.cpp | 4 ++-- libraries/networking/src/udt/Socket.cpp | 6 +++--- libraries/networking/src/udt/Socket.h | 12 ++++++------ 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index c4dd2cf532..5da906a1f3 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -36,10 +36,10 @@ IceServer::IceServer(int argc, char* argv[]) : // set processPacket as the verified packet callback for the udt::Socket using std::placeholders::_1; - _serverSocket.setVerifiedPacketHandler(std::bind(&IceServer::processPacket, this, _1)); + _serverSocket.setPacketHandler(std::bind(&IceServer::processPacket, this, _1)); // set packetVersionMatch as the verify packet operator for the udt::Socket - _serverSocket.setPacketVerificationHandler(std::bind(&IceServer::packetVersionMatch, this, _1)); + _serverSocket.setPacketFilterOperator(std::bind(&IceServer::packetVersionMatch, this, _1)); // setup our timer to clear inactive peers QTimer* inactivePeerTimer = new QTimer(this); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index e6b0b27712..648fb7f2a0 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -99,10 +99,10 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short // set &PacketReceiver::handleVerifiedPacket as the verified packet callback for the udt::Socket using std::placeholders::_1; - _nodeSocket.setVerifiedPacketHandler(std::bind(&PacketReceiver::handleVerifiedPacket, _packetReceiver, _1)); + _nodeSocket.setPacketHandler(std::bind(&PacketReceiver::handleVerifiedPacket, _packetReceiver, _1)); // set our isPacketVerified method as the verify operator for the udt::Socket - _nodeSocket.setPacketVerificationHandler(std::bind(&LimitedNodeList::isPacketVerified, this, _1)); + _nodeSocket.setPacketFilterOperator(std::bind(&LimitedNodeList::isPacketVerified, this, _1)); _packetStatTimer.start(); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 685689f4e6..ea4340065a 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -89,10 +89,10 @@ void Socket::readPendingDatagrams() { auto packet = Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); // call our verification operator to see if this packet is verified - if (_unfilteredSockAddrs.contains(senderSockAddr) || !_packetVerificationHandler || _packetVerificationHandler(*packet)) { - if (_verifiedPacketHandler) { + if (_unfilteredSockAddrs.contains(senderSockAddr) || !_packetFilterOperator || _packetFilterOperator(*packet)) { + if (_packetHandler) { // call the verified packet callback to let it handle this packet - return _verifiedPacketHandler(std::move(packet)); + return _packetHandler(std::move(packet)); } } } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index fcade487a3..5043616dec 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -24,8 +24,8 @@ namespace udt { -using PacketVerificationHandler = std::function; -using VerifiedPacketHandler = std::function)>; +using PacketFilterOperator = std::function; +using PacketHandler = std::function)>; class Socket : public QObject { Q_OBJECT @@ -43,8 +43,8 @@ public: void bind(const QHostAddress& address, quint16 port = 0) { _udpSocket.bind(address, port); } void rebind(); - void setPacketVerificationHandler(PacketVerificationHandler handler) { _packetVerificationHandler = handler; } - void setVerifiedPacketHandler(VerifiedPacketHandler handler) { _verifiedPacketHandler = handler; } + void setPacketFilterOperator(PacketFilterOperator filterOperator) { _packetFilterOperator = filterOperator; } + void setPacketHandler(PacketHandler handler) { _packetHandler = handler; } void setBufferSizes(int numBytes); @@ -55,8 +55,8 @@ private slots: private: QUdpSocket _udpSocket { this }; - PacketVerificationHandler _packetVerificationHandler; - VerifiedPacketHandler _verifiedPacketHandler; + PacketFilterOperator _packetFilterOperator; + PacketHandler _packetHandler; QSet _unfilteredSockAddrs; }; From 1386aa57da4a1c5994e5aa9027b7b91e8ea065b7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jul 2015 11:02:45 -0700 Subject: [PATCH 014/549] repair to NLPacket creation from Packet and char* --- libraries/networking/src/LimitedNodeList.cpp | 2 +- libraries/networking/src/NLPacket.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 648fb7f2a0..1aee0e2da4 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -619,7 +619,7 @@ void LimitedNodeList::sendSTUNRequest() { flagTimeForConnectionStep(ConnectionStep::SendSTUNRequest); - _nodeSocket.writeDatagram(QByteArray::fromRawData(stunRequestPacket, sizeof(stunRequestPacket)), _stunSockAddr); + _nodeSocket.writeDatagram(stunRequestPacket, sizeof(stunRequestPacket), _stunSockAddr); } bool LimitedNodeList::processSTUNResponse(QSharedPointer packet) { diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index fdfb94f107..1af8dd0019 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -112,7 +112,7 @@ NLPacket& NLPacket::operator=(const NLPacket& other) { NLPacket::NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr) : Packet(std::move(data), size, senderSockAddr) { - adjustPayloadStartAndCapacity(); + adjustPayloadStartAndCapacity(_payloadSize > 0); readSourceID(); } @@ -148,7 +148,7 @@ QByteArray NLPacket::hashForPacketAndSecret(const udt::Packet& packet, const QUu int offset = packet.Packet::localHeaderSize() + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH; // add the packet payload and the connection UUID - hash.addData(packet.getData(), packet.getDataSize() - offset); + hash.addData(packet.getData() + offset, packet.getDataSize() - offset); hash.addData(connectionSecret.toRfc4122()); // return the hash From 8bf507dd243876f20a2545d4538a3fe586d31c54 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jul 2015 11:06:13 -0700 Subject: [PATCH 015/549] add a sanity check for data NLPacket ctor --- libraries/networking/src/NLPacket.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 1af8dd0019..ad90659ffe 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -112,6 +112,9 @@ NLPacket& NLPacket::operator=(const NLPacket& other) { NLPacket::NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr) : Packet(std::move(data), size, senderSockAddr) { + // sanity check before we decrease the payloadSize with the payloadCapacity + Q_ASSERT(_payloadSize == _payloadCapacity); + adjustPayloadStartAndCapacity(_payloadSize > 0); readSourceID(); From 3fbda89f1d77ba156308c5fa252eeeaa54e373ef Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jul 2015 11:17:50 -0700 Subject: [PATCH 016/549] copy version in Packet move ctor/assignment --- interface/src/octree/OctreePacketProcessor.cpp | 4 ++-- libraries/networking/src/udt/Packet.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index 7bb94323b7..386ebacc6d 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -77,8 +77,8 @@ void OctreePacketProcessor::processPacket(QSharedPointer packet, Share const QUuid& senderUUID = packet->getSourceID(); if (!versionDebugSuppressMap.contains(senderUUID, packetType)) { - qDebug() << "Packet version mismatch on" << packetType << "- Sender" - << senderUUID << "sent" << (int) packetType << "but" + qDebug() << "OctreePacketProcessor - piggyback packet version mismatch on" << packetType << "- Sender" + << senderUUID << "sent" << (int) packet->getVersion() << "but" << (int) versionForPacketType(packetType) << "expected."; emit packetVersionMismatch(); diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 45c6a6f75f..91f9661b9d 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -104,6 +104,7 @@ Packet::Packet(const Packet& other) : Packet& Packet::operator=(const Packet& other) { _type = other._type; + _version = other._version; _packetSize = other._packetSize; _packet = std::unique_ptr(new char[_packetSize]); @@ -129,6 +130,7 @@ Packet::Packet(Packet&& other) { Packet& Packet::operator=(Packet&& other) { _type = other._type; + _version = other._version; _packetSize = other._packetSize; _packet = std::move(other._packet); From 12e684bea1ebf45811f3332002b793709ac3c2bb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jul 2015 11:21:31 -0700 Subject: [PATCH 017/549] fix identation for NLPacket move ctor --- libraries/networking/src/NLPacket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index ad90659ffe..fb2561486a 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -121,7 +121,7 @@ NLPacket::NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& } NLPacket::NLPacket(NLPacket&& other) : - Packet(other) + Packet(other) { _sourceID = std::move(other._sourceID); } From 4a11bdc22e6862b291dd77d957253ffef95c66c9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jul 2015 11:26:28 -0700 Subject: [PATCH 018/549] indentation and spacing fixes --- libraries/networking/src/PacketReceiver.cpp | 2 +- libraries/networking/src/udt/Socket.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 502563489b..ce89b60af6 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -239,7 +239,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { _directConnectSetMutex.lock(); Qt::ConnectionType connectionType = - _directlyConnectedObjects.contains(listener.first) ? Qt::DirectConnection : Qt::AutoConnection; + _directlyConnectedObjects.contains(listener.first) ? Qt::DirectConnection : Qt::AutoConnection; _directConnectSetMutex.unlock(); diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 5043616dec..e8d6e5c6fa 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -61,7 +61,6 @@ private: QSet _unfilteredSockAddrs; }; -} - +} // namespace udt #endif // hifi_Socket_h From 023f3b81346dd9b9915b24d2aab27b3c523c38a9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jul 2015 11:34:30 -0700 Subject: [PATCH 019/549] fix sequence number read in PacketReceiver --- libraries/networking/src/PacketReceiver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index ce89b60af6..5dfd35f70d 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -249,7 +249,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { // if this was a sequence numbered packet we should store the last seq number for // a packet of this type for this node if (SEQUENCE_NUMBERED_PACKETS.contains(nlPacket->getType())) { - matchingNode->setLastSequenceNumberForPacketType(packet->readSequenceNumber(), packet->getType()); + matchingNode->setLastSequenceNumberForPacketType(nlPacket->readSequenceNumber(), nlPacket->getType()); } emit dataReceived(matchingNode->getType(), nlPacket->getDataSize()); From 5bed3502ef16d3955d3167fc26f81cca482ed593 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jul 2015 14:15:17 -0700 Subject: [PATCH 020/549] fix order of ctors and assignment operators --- libraries/networking/src/NLPacket.cpp | 16 ++++++++-------- libraries/networking/src/NLPacket.h | 3 ++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index fb2561486a..39dc296f85 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -101,14 +101,6 @@ NLPacket::NLPacket(const NLPacket& other) : Packet(other) { _sourceID = other._sourceID; } -NLPacket& NLPacket::operator=(const NLPacket& other) { - Packet::operator=(other); - - _sourceID = other._sourceID; - - return *this; -} - NLPacket::NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr) : Packet(std::move(data), size, senderSockAddr) { @@ -126,6 +118,14 @@ NLPacket::NLPacket(NLPacket&& other) : _sourceID = std::move(other._sourceID); } +NLPacket& NLPacket::operator=(const NLPacket& other) { + Packet::operator=(other); + + _sourceID = other._sourceID; + + return *this; +} + NLPacket& NLPacket::operator=(NLPacket&& other) { Packet::operator=(std::move(other)); diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index aad6e6d072..57c099764a 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -51,8 +51,9 @@ protected: NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); NLPacket(std::unique_ptr packet); NLPacket(const NLPacket& other); - NLPacket& operator=(const NLPacket& other); NLPacket(NLPacket&& other); + + NLPacket& operator=(const NLPacket& other); NLPacket& operator=(NLPacket&& other); void readSourceID(); From 2c965eee9101599fb390fa2391df8722ccb65e24 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jul 2015 14:42:44 -0700 Subject: [PATCH 021/549] fix ugly deref of matchingPeer --- ice-server/src/IceServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 5da906a1f3..0545e0d274 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -89,7 +89,7 @@ void IceServer::processPacket(std::unique_ptr packet) { qDebug() << "Sending information for peer" << connectRequestID << "to peer" << senderUUID; // we have the peer they want to connect to - send them pack the information for that peer - sendPeerInformationPacket(*(matchingPeer.data()), &packet->getSenderSockAddr()); + sendPeerInformationPacket(*matchingPeer, &packet->getSenderSockAddr()); // we also need to send them to the active peer they are hoping to connect to // create a dummy peer object we can pass to sendPeerInformationPacket From dce1fc68553a6269433b6b4f46d810cd7ced035a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Jul 2015 11:18:52 -0700 Subject: [PATCH 022/549] SendQueue first draft --- libraries/networking/src/udt/SendQueue.cpp | 82 ++++++++++++++++++++++ libraries/networking/src/udt/SendQueue.h | 68 ++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 libraries/networking/src/udt/SendQueue.cpp create mode 100644 libraries/networking/src/udt/SendQueue.h diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp new file mode 100644 index 0000000000..af19162bb8 --- /dev/null +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -0,0 +1,82 @@ +// +// SendQueue.cpp +// libraries/networking/src/udt +// +// Created by Clement on 7/21/15. +// Copyright 2015 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 "SendQueue.h" + +#include +#include + +#include + +namespace udt { + +std::unique_ptr SendQueue::create() { + return std::unique_ptr(new SendQueue()); +} + +SendQueue::SendQueue() { + _sendTimer.reset(new QTimer(this)); + _sendTimer->setSingleShot(true); + QObject::connect(_sendTimer.get(), &QTimer::timeout, this, &SendQueue::sendNextPacket); + + _packetSendPeriod = DEFAULT_SEND_PERIOD; + _lastSendTimestamp = 0; +} + +void SendQueue::queuePacket(std::unique_ptr packet) { + QWriteLocker locker(&_packetsLock); + _packets.push_back(std::move(packet)); +} + +void SendQueue::start() { + // We need to make sure this is called on the right thread + if (thread() != QThread::currentThread()) { + QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection); + } + // This will send a packet and fire the send timer + sendNextPacket(); +} + +void SendQueue::stop() { + // We need to make sure this is called on the right thread + if (thread() != QThread::currentThread()) { + QMetaObject::invokeMethod(this, "stop", Qt::QueuedConnection); + } + // Stopping the timer will stop the sending of packets + _sendTimer->stop(); +} + +void SendQueue::sendNextPacket() { + // Record timing + auto sendTime = msecTimestampNow(); // msec + _lastSendTimestamp = sendTime; + // TODO send packet + + // Insert the packet we have just sent in the sent list + _sentPackets[_nextPacket->readSequenceNumber()].swap(_nextPacket); + Q_ASSERT(!_nextPacket); // There should be no packet where we inserted + + { // Grab next packet to be sent + QWriteLocker locker(&_packetsLock); + _nextPacket.swap(_packets.front()); + _packets.pop_front(); + } + + // How long before next packet send + auto timeToSleep = (sendTime + _packetSendPeriod) - msecTimestampNow(); // msec + if (timeToSleep > 0) { + _sendTimer->start(timeToSleep); + } else { + _sendTimer->start(0); + } +} + +} diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h new file mode 100644 index 0000000000..9767cfe7aa --- /dev/null +++ b/libraries/networking/src/udt/SendQueue.h @@ -0,0 +1,68 @@ +// +// SendQueue.h +// libraries/networking/src/udt +// +// Created by Clement on 7/21/15. +// Copyright 2015 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 +// + +#ifndef hifi_SendQueue_h +#define hifi_SendQueue_h + +#include +#include + +#include +#include + +#include "Packet.h" + +class QTimer; + +namespace udt { + +class SendQueue : public QObject { + Q_OBJECT + +public: + static const int DEFAULT_SEND_PERIOD = 16; // msec + + static std::unique_ptr create(); + + void queuePacket(std::unique_ptr packet); + int getQueueSize() const { return _packets.size(); } + + quint64 getLastSendTimestamp() const { return _lastSendTimestamp; } + + int getPacketSendPeriod() const { return _packetSendPeriod; } + void setPacketSendPeriod(int newPeriod) { _packetSendPeriod = newPeriod; } + +public slots: + void start(); + void stop(); + +private slots: + void sendNextPacket(); + +private: + SendQueue(); + SendQueue(SendQueue& other) = delete; + SendQueue(SendQueue&& other) = delete; + + QReadWriteLock _packetsLock; // Protects the packets to be sent list. + std::list> _packets; // List of packets to be sent + std::unique_ptr _nextPacket; + + std::unique_ptr _sendTimer; // Send timer + std::atomic _packetSendPeriod; // Interval between two packet send envent in msec + std::atomic _lastSendTimestamp; // Record last time of packet departure + + std::unordered_map> _sentPackets; // Packets waiting for ACK. +}; + +} + +#endif // hifi_SendQueue_h From aa08bee69fc2f9ea53f415535da51496a6a995d1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Jul 2015 11:59:37 -0700 Subject: [PATCH 023/549] initial work to make sequence # and bitfield lead all packets --- assignment-client/src/avatars/AvatarMixer.cpp | 6 +-- .../src/avatars/AvatarMixerClientData.cpp | 9 +++-- .../src/avatars/AvatarMixerClientData.h | 11 ++++-- libraries/avatars/src/AvatarData.cpp | 5 ++- libraries/networking/src/HifiSockAddr.cpp | 2 +- libraries/networking/src/HifiSockAddr.h | 12 ++++++ libraries/networking/src/LimitedNodeList.cpp | 15 -------- libraries/networking/src/LimitedNodeList.h | 4 -- libraries/networking/src/Node.cpp | 8 ---- libraries/networking/src/Node.h | 8 +--- libraries/networking/src/PacketReceiver.cpp | 6 --- libraries/networking/src/UUIDHasher.h | 2 +- libraries/networking/src/udt/Packet.cpp | 37 +++++++------------ libraries/networking/src/udt/Packet.h | 6 ++- .../networking/src/udt/PacketHeaders.cpp | 2 - libraries/networking/src/udt/PacketHeaders.h | 6 --- libraries/networking/src/udt/Socket.cpp | 3 ++ libraries/networking/src/udt/Socket.h | 3 ++ 18 files changed, 61 insertions(+), 84 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 3a3176b78d..1b0d93e2c5 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -259,8 +259,8 @@ void AvatarMixer::broadcastAvatarData() { return; } - PacketSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(otherNode->getUUID()); - PacketSequenceNumber lastSeqFromSender = otherNode->getLastSequenceNumberForPacketType(PacketType::AvatarData); + uint16_t lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(otherNode->getUUID()); + uint16_t lastSeqFromSender = otherNodeData->getLastReceivedSequenceNumber(); if (lastSeqToReceiver > lastSeqFromSender) { // Did we somehow get out of order packets from the sender? @@ -289,7 +289,7 @@ void AvatarMixer::broadcastAvatarData() { // set the last sent sequence number for this sender on the receiver nodeData->setLastBroadcastSequenceNumber(otherNode->getUUID(), - otherNode->getLastSequenceNumberForPacketType(PacketType::AvatarData)); + otherNodeData->getLastReceivedSequenceNumber()); // start a new segment in the PacketList for this avatar avatarPacketList.startSegment(); diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index fec51f76cb..eb47f748c8 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -14,7 +14,10 @@ #include "AvatarMixerClientData.h" int AvatarMixerClientData::parseData(NLPacket& packet) { - // compute the offset to the data payload + // pull the sequence number from the data first + packet.readPrimitive(&_lastReceivedSequenceNumber); + + // read the remaining data return _avatar.parseDataFromBuffer(packet.read(packet.bytesLeftToRead())); } @@ -24,13 +27,13 @@ bool AvatarMixerClientData::checkAndSetHasReceivedFirstPackets() { return oldValue; } -PacketSequenceNumber AvatarMixerClientData::getLastBroadcastSequenceNumber(const QUuid& nodeUUID) const { +uint16_t AvatarMixerClientData::getLastBroadcastSequenceNumber(const QUuid& nodeUUID) const { // return the matching PacketSequenceNumber, or the default if we don't have it auto nodeMatch = _lastBroadcastSequenceNumbers.find(nodeUUID); if (nodeMatch != _lastBroadcastSequenceNumbers.end()) { return nodeMatch->second; } else { - return DEFAULT_SEQUENCE_NUMBER; + return 0; } } diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index dfd61dafbc..fd0971294c 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -36,10 +36,12 @@ public: bool checkAndSetHasReceivedFirstPackets(); - PacketSequenceNumber getLastBroadcastSequenceNumber(const QUuid& nodeUUID) const; - void setLastBroadcastSequenceNumber(const QUuid& nodeUUID, PacketSequenceNumber sequenceNumber) + uint16_t getLastBroadcastSequenceNumber(const QUuid& nodeUUID) const; + void setLastBroadcastSequenceNumber(const QUuid& nodeUUID, uint16_t sequenceNumber) { _lastBroadcastSequenceNumbers[nodeUUID] = sequenceNumber; } Q_INVOKABLE void removeLastBroadcastSequenceNumber(const QUuid& nodeUUID) { _lastBroadcastSequenceNumbers.erase(nodeUUID); } + + uint16_t getLastReceivedSequenceNumber() const { return _lastReceivedSequenceNumber; } quint64 getBillboardChangeTimestamp() const { return _billboardChangeTimestamp; } void setBillboardChangeTimestamp(quint64 billboardChangeTimestamp) { _billboardChangeTimestamp = billboardChangeTimestamp; } @@ -77,8 +79,9 @@ public: void loadJSONStats(QJsonObject& jsonObject) const; private: AvatarData _avatar; - - std::unordered_map _lastBroadcastSequenceNumbers; + + uint16_t _lastReceivedSequenceNumber { 0 }; + std::unordered_map _lastBroadcastSequenceNumbers; bool _hasReceivedFirstPackets = false; quint64 _billboardChangeTimestamp = 0; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 3a3b895c66..19f1c35a2b 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1093,8 +1093,11 @@ void AvatarData::sendAvatarDataPacket() { auto nodeList = DependencyManager::get(); QByteArray avatarByteArray = toByteArray(); + + static uint16_t sequenceNumber = 0; - auto avatarPacket = NLPacket::create(PacketType::AvatarData, avatarByteArray.size()); + auto avatarPacket = NLPacket::create(PacketType::AvatarData, avatarByteArray.size() + sizeof(sequenceNumber)); + avatarPacket->writePrimitive(sequenceNumber++); avatarPacket->write(avatarByteArray); nodeList->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer); diff --git a/libraries/networking/src/HifiSockAddr.cpp b/libraries/networking/src/HifiSockAddr.cpp index 8951da58c9..39210db81e 100644 --- a/libraries/networking/src/HifiSockAddr.cpp +++ b/libraries/networking/src/HifiSockAddr.cpp @@ -150,5 +150,5 @@ QHostAddress getLocalAddress() { uint qHash(const HifiSockAddr& key, uint seed) { // use the existing QHostAddress and quint16 hash functions to get our hash - return qHash(key.getAddress(), seed) + qHash(key.getPort(), seed); + return qHash(key.getAddress(), seed) ^ qHash(key.getPort(), seed); } diff --git a/libraries/networking/src/HifiSockAddr.h b/libraries/networking/src/HifiSockAddr.h index 9151e51af2..25f7ad2194 100644 --- a/libraries/networking/src/HifiSockAddr.h +++ b/libraries/networking/src/HifiSockAddr.h @@ -12,6 +12,8 @@ #ifndef hifi_HifiSockAddr_h #define hifi_HifiSockAddr_h +#include + #ifdef WIN32 #include #include @@ -53,6 +55,7 @@ public: friend QDebug operator<<(QDebug debug, const HifiSockAddr& sockAddr); friend QDataStream& operator<<(QDataStream& dataStream, const HifiSockAddr& sockAddr); friend QDataStream& operator>>(QDataStream& dataStream, HifiSockAddr& sockAddr); + private slots: void handleLookupResult(const QHostInfo& hostInfo); signals: @@ -65,6 +68,15 @@ private: uint qHash(const HifiSockAddr& key, uint seed); +template <> +struct std::hash { + std::size_t operator()(const HifiSockAddr& sockAddr) const { + // use XOR of implemented std::hash templates for new hash + return std::hash()(sockAddr.getAddress().toString().toStdString()) + ^ std::hash()((uint16_t) sockAddr.getPort()); + } +}; + QHostAddress getLocalAddress(); Q_DECLARE_METATYPE(HifiSockAddr) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 1aee0e2da4..2760ed8277 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -248,12 +248,6 @@ qint64 LimitedNodeList::writePacket(const NLPacket& packet, const Node& destinat 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(packet).writeSequenceNumber(sequenceNumber); - } - emit dataSent(destinationNode.getType(), packet.getDataSize()); return writePacket(packet, *destinationNode.getActiveSocket(), destinationNode.getConnectionSecret()); @@ -344,15 +338,6 @@ qint64 LimitedNodeList::sendPacket(std::unique_ptr packet, const Node& return sendPacket(std::move(packet), destinationSockAddr, destinationNode.getConnectionSecret()); } -PacketSequenceNumber LimitedNodeList::getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType::Value packetType) { - // Thanks to std::map and std::unordered_map this line either default constructs the - // PacketType::SequenceMap and the PacketSequenceNumber or returns the existing value. - // We use the postfix increment so that the stored value is incremented and the next - // return gives the correct value. - - return _packetSequenceNumbers[nodeUUID][packetType]++; -} - int LimitedNodeList::updateNodeWithDataFromPacket(QSharedPointer packet, SharedNodePointer sendingNode) { QMutexLocker locker(&sendingNode->getMutex()); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 67dc707815..ead858a239 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -253,8 +253,6 @@ protected: const QUuid& connectionSecret = QUuid()); qint64 writePacketAndCollectStats(const NLPacket& packet, const HifiSockAddr& destinationSockAddr); - PacketSequenceNumber getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType::Value packetType); - bool isPacketVerified(const udt::Packet& packet); bool packetVersionMatch(const udt::Packet& packet); bool packetSourceAndHashMatch(const udt::Packet& packet); @@ -289,8 +287,6 @@ protected: bool _thisNodeCanAdjustLocks; bool _thisNodeCanRez; - std::unordered_map _packetSequenceNumbers; - QPointer _initialSTUNTimer; int _numInitialSTUNRequests = 0; bool _hasCompletedInitialSTUN = false; diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 667e975398..8aff66e3a0 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -67,14 +67,6 @@ void Node::updateClockSkewUsec(int clockSkewSample) { _clockSkewUsec = (int)_clockSkewMovingPercentile.getValueAtPercentile(); } -PacketSequenceNumber Node::getLastSequenceNumberForPacketType(PacketType::Value packetType) const { - auto typeMatch = _lastSequenceNumbers.find(packetType); - if (typeMatch != _lastSequenceNumbers.end()) { - return typeMatch->second; - } else { - return DEFAULT_SEQUENCE_NUMBER; - } -} QDataStream& operator<<(QDataStream& out, const Node& node) { out << node._type; diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 0b5a985b35..c8106f5fd8 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -24,7 +24,7 @@ #include "NetworkPeer.h" #include "NodeData.h" #include "NodeType.h" -#include "udt/PacketHeaders.h" +#include "udt/Packet.h" #include "SimpleMovingAverage.h" #include "MovingPercentile.h" @@ -65,10 +65,6 @@ public: void setCanRez(bool canRez) { _canRez = canRez; } bool getCanRez() { return _canRez; } - void setLastSequenceNumberForPacketType(PacketSequenceNumber sequenceNumber, PacketType::Value packetType) - { _lastSequenceNumbers[packetType] = sequenceNumber; } - PacketSequenceNumber getLastSequenceNumberForPacketType(PacketType::Value packetType) const; - friend QDataStream& operator<<(QDataStream& out, const Node& node); friend QDataStream& operator>>(QDataStream& in, Node& node); @@ -89,7 +85,7 @@ private: bool _canAdjustLocks; bool _canRez; - PacketTypeSequenceMap _lastSequenceNumbers; + std::map _lastSequenceNumbers; }; typedef QSharedPointer SharedNodePointer; diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 5dfd35f70d..6fb34f05e7 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -246,12 +246,6 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { PacketType::Value packetType = nlPacket->getType(); if (matchingNode) { - // if this was a sequence numbered packet we should store the last seq number for - // a packet of this type for this node - if (SEQUENCE_NUMBERED_PACKETS.contains(nlPacket->getType())) { - matchingNode->setLastSequenceNumberForPacketType(nlPacket->readSequenceNumber(), nlPacket->getType()); - } - emit dataReceived(matchingNode->getType(), nlPacket->getDataSize()); QMetaMethod metaMethod = listener.second; diff --git a/libraries/networking/src/UUIDHasher.h b/libraries/networking/src/UUIDHasher.h index 5429e151c7..3ece236812 100644 --- a/libraries/networking/src/UUIDHasher.h +++ b/libraries/networking/src/UUIDHasher.h @@ -26,4 +26,4 @@ public: } }; -#endif // hifi_UUIDHasher_h \ No newline at end of file +#endif // hifi_UUIDHasher_h diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 91f9661b9d..154d526833 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -16,8 +16,8 @@ using namespace udt; const qint64 Packet::PACKET_WRITE_ERROR = -1; qint64 Packet::localHeaderSize(PacketType::Value type) { - qint64 size = numBytesForArithmeticCodedPacketType(type) + sizeof(PacketVersion) + - ((SEQUENCE_NUMBERED_PACKETS.contains(type)) ? sizeof(SequenceNumber) : 0); + // TODO: check the bitfield to see if the message is included + qint64 size = sizeof(SequenceNumberAndBitField); return size; } @@ -75,13 +75,8 @@ Packet::Packet(PacketType::Value type, qint64 size) : // Sanity check Q_ASSERT(size >= 0 || size < maxPayload); - // copy packet type and version in header - writePacketTypeAndVersion(type); - - // Set control bit and sequence number to 0 if necessary - if (SEQUENCE_NUMBERED_PACKETS.contains(type)) { - writeSequenceNumber(0); - } + // set the UDT header to default values + writeSequenceNumber(0); } Packet::Packet(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr) : @@ -187,24 +182,20 @@ PacketVersion Packet::readVersion() const { return *reinterpret_cast(_packet.get() + numBytesForArithmeticCodedPacketType(_type)); } +static const uint32_t CONTROL_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 1); +static const uint32_t RELIABILITY_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 2); +static const uint32_t MESSAGE_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 3); +static const uint32_t BIT_FIELD_MASK = CONTROL_BIT_MASK | RELIABILITY_BIT_MASK | MESSAGE_BIT_MASK; + + Packet::SequenceNumber Packet::readSequenceNumber() const { - if (SEQUENCE_NUMBERED_PACKETS.contains(_type)) { - SequenceNumber seqNum = *reinterpret_cast(_packet.get() + - numBytesForArithmeticCodedPacketType(_type) + - sizeof(PacketVersion)); - return seqNum & ~(1 << 15); // remove control bit - } - return -1; + SequenceNumberAndBitField seqNumBitField = *reinterpret_cast(_packet.get()); + return seqNumBitField & ~BIT_FIELD_MASK; // Remove the bit field } bool Packet::readIsControlPacket() const { - if (SEQUENCE_NUMBERED_PACKETS.contains(_type)) { - SequenceNumber seqNum = *reinterpret_cast(_packet.get() + - numBytesForArithmeticCodedPacketType(_type) + - sizeof(PacketVersion)); - return seqNum & (1 << 15); // Only keep control bit - } - return false; + SequenceNumberAndBitField seqNumBitField = *reinterpret_cast(_packet.get()); + return seqNumBitField & CONTROL_BIT_MASK; // Only keep control bit } void Packet::writePacketTypeAndVersion(PacketType::Value type) { diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index 96e8f8c3d4..b74834c82a 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -24,7 +24,11 @@ namespace udt { class Packet : public QIODevice { Q_OBJECT public: - using SequenceNumber = uint16_t; + // NOTE: The SequenceNumber must actually only be 29 bits MAX to leave room for a bit field + using SequenceNumber = uint32_t; + using SequenceNumberAndBitField = uint32_t; + + static const uint32_t DEFAULT_SEQUENCE_NUMBER = 0; static const qint64 PACKET_WRITE_ERROR; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 0591ac30fe..b71f4107df 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -22,8 +22,6 @@ const QSet NON_VERIFIED_PACKETS = QSet() << OctreeDataNack << EntityEditNack << DomainListRequest << StopNode; -const QSet SEQUENCE_NUMBERED_PACKETS = QSet() << AvatarData; - const QSet NON_SOURCED_PACKETS = QSet() << StunResponse << CreateAssignment << RequestAssignment << DomainServerRequireDTLS << DomainConnectRequest diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 3f3f165e87..d134125ca3 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -84,13 +84,7 @@ const int MAX_PACKET_HEADER_BYTES = 4 + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_H typedef char PacketVersion; -typedef uint16_t PacketSequenceNumber; -const PacketSequenceNumber DEFAULT_SEQUENCE_NUMBER = 0; - -typedef std::map PacketTypeSequenceMap; - extern const QSet NON_VERIFIED_PACKETS; -extern const QSet SEQUENCE_NUMBERED_PACKETS; extern const QSet NON_SOURCED_PACKETS; QString nameForPacketType(PacketType::Value packetType); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index ea4340065a..8b912637a8 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -65,6 +65,9 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc qint64 bytesWritten = _udpSocket.writeDatagram(datagram, sockAddr.getAddress(), sockAddr.getPort()); + // TODO:: + // const_cast(packet).writeSequenceNumber(sequenceNumber); + if (bytesWritten < 0) { qCDebug(networking) << "ERROR in writeDatagram:" << _udpSocket.error() << "-" << _udpSocket.errorString(); } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index e8d6e5c6fa..f4b4ea4ee0 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -15,6 +15,7 @@ #define hifi_Socket_h #include +#include #include #include @@ -59,6 +60,8 @@ private: PacketHandler _packetHandler; QSet _unfilteredSockAddrs; + + std::unordered_map _packetSequenceNumbers; }; } // namespace udt From 9e7fb9ae1609d19957f39a6509f40d2911d155fd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Jul 2015 13:56:47 -0700 Subject: [PATCH 024/549] shuffle Packet headers, use static enum for PacketType --- assignment-client/src/audio/AudioMixer.cpp | 2 +- .../src/audio/AudioMixerClientData.cpp | 2 +- .../src/audio/AvatarAudioStream.cpp | 2 +- .../src/audio/AvatarAudioStream.h | 2 +- .../src/entities/EntityNodeData.h | 2 +- assignment-client/src/entities/EntityServer.h | 4 +- .../octree/OctreeInboundPacketProcessor.cpp | 2 +- .../src/octree/OctreeQueryNode.h | 4 +- assignment-client/src/octree/OctreeServer.h | 4 +- ice-server/src/IceServer.cpp | 28 ++-- ice-server/src/IceServer.h | 4 +- interface/src/Application.cpp | 2 +- interface/src/Application.h | 2 +- .../src/octree/OctreePacketProcessor.cpp | 8 +- libraries/audio/src/InboundAudioStream.cpp | 4 +- libraries/audio/src/InboundAudioStream.h | 4 +- libraries/audio/src/InjectedAudioStream.cpp | 2 +- libraries/audio/src/InjectedAudioStream.h | 2 +- .../audio/src/MixedProcessedAudioStream.cpp | 2 +- .../audio/src/MixedProcessedAudioStream.h | 2 +- .../src/EntityTreeRenderer.h | 4 +- .../entities/src/EntityEditPacketSender.cpp | 4 +- .../entities/src/EntityEditPacketSender.h | 4 +- .../entities/src/EntityItemProperties.cpp | 2 +- libraries/entities/src/EntityItemProperties.h | 2 +- .../entities/src/EntityScriptingInterface.cpp | 2 +- .../entities/src/EntityScriptingInterface.h | 2 +- libraries/entities/src/EntityTree.cpp | 2 +- libraries/entities/src/EntityTree.h | 4 +- .../entities/src/EntityTreeHeadlessViewer.h | 4 +- libraries/networking/src/LimitedNodeList.cpp | 46 +++--- libraries/networking/src/LimitedNodeList.h | 4 +- libraries/networking/src/NLPacket.cpp | 81 ++++++++--- libraries/networking/src/NLPacket.h | 37 +++-- libraries/networking/src/NLPacketList.cpp | 2 +- libraries/networking/src/NLPacketList.h | 2 +- libraries/networking/src/Node.h | 2 +- libraries/networking/src/NodeList.cpp | 4 +- libraries/networking/src/PacketReceiver.cpp | 26 ++-- libraries/networking/src/PacketReceiver.h | 14 +- libraries/networking/src/udt/Packet.cpp | 108 ++++++-------- libraries/networking/src/udt/Packet.h | 52 +++---- .../networking/src/udt/PacketHeaders.cpp | 134 ++++++++++-------- libraries/networking/src/udt/PacketHeaders.h | 112 ++++++++------- libraries/networking/src/udt/PacketList.cpp | 5 +- libraries/networking/src/udt/PacketList.h | 6 +- libraries/octree/src/Octree.cpp | 10 +- libraries/octree/src/Octree.h | 4 +- .../octree/src/OctreeEditPacketSender.cpp | 4 +- libraries/octree/src/OctreeEditPacketSender.h | 8 +- libraries/octree/src/OctreeHeadlessViewer.cpp | 2 +- libraries/octree/src/OctreePacketData.h | 2 +- libraries/octree/src/OctreeRenderer.h | 4 +- 53 files changed, 426 insertions(+), 357 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index aa8e405d34..0cf5ffb3ca 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -97,7 +97,7 @@ AudioMixer::AudioMixer(NLPacket& packet) : auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - QSet nodeAudioPackets { + QSet nodeAudioPackets { PacketType::MicrophoneAudioNoEcho, PacketType::MicrophoneAudioWithEcho, PacketType::InjectAudio, PacketType::SilentAudioFrame, PacketType::AudioStreamStats diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 10a5992fd8..e27682de68 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -50,7 +50,7 @@ AvatarAudioStream* AudioMixerClientData::getAvatarAudioStream() const { } int AudioMixerClientData::parseData(NLPacket& packet) { - PacketType::Value packetType = packet.getType(); + PacketType packetType = packet.getType(); if (packetType == PacketType::AudioStreamStats) { diff --git a/assignment-client/src/audio/AvatarAudioStream.cpp b/assignment-client/src/audio/AvatarAudioStream.cpp index 4c71777d01..da995c999d 100644 --- a/assignment-client/src/audio/AvatarAudioStream.cpp +++ b/assignment-client/src/audio/AvatarAudioStream.cpp @@ -18,7 +18,7 @@ AvatarAudioStream::AvatarAudioStream(bool isStereo, const InboundAudioStream::Se { } -int AvatarAudioStream::parseStreamProperties(PacketType::Value type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { +int AvatarAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { int readBytes = 0; if (type == PacketType::SilentAudioFrame) { diff --git a/assignment-client/src/audio/AvatarAudioStream.h b/assignment-client/src/audio/AvatarAudioStream.h index 7dc87f7d41..cc2ff1aca7 100644 --- a/assignment-client/src/audio/AvatarAudioStream.h +++ b/assignment-client/src/audio/AvatarAudioStream.h @@ -25,7 +25,7 @@ private: AvatarAudioStream(const AvatarAudioStream&); AvatarAudioStream& operator= (const AvatarAudioStream&); - int parseStreamProperties(PacketType::Value type, const QByteArray& packetAfterSeqNum, int& numAudioSamples); + int parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples); }; #endif // hifi_AvatarAudioStream_h diff --git a/assignment-client/src/entities/EntityNodeData.h b/assignment-client/src/entities/EntityNodeData.h index d779a0b58d..e4008fcb03 100644 --- a/assignment-client/src/entities/EntityNodeData.h +++ b/assignment-client/src/entities/EntityNodeData.h @@ -22,7 +22,7 @@ public: OctreeQueryNode(), _lastDeletedEntitiesSentAt(0) { } - virtual PacketType::Value getMyPacketType() const { return PacketType::EntityData; } + virtual PacketType getMyPacketType() const { return PacketType::EntityData; } quint64 getLastDeletedEntitiesSentAt() const { return _lastDeletedEntitiesSentAt; } void setLastDeletedEntitiesSentAt(quint64 sentAt) { _lastDeletedEntitiesSentAt = sentAt; } diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index 1c4eda3cc0..159fc04bf5 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -28,11 +28,11 @@ public: // Subclasses must implement these methods virtual OctreeQueryNode* createOctreeQueryNode(); virtual char getMyNodeType() const { return NodeType::EntityServer; } - virtual PacketType::Value getMyQueryMessageType() const { return PacketType::EntityQuery; } + virtual PacketType getMyQueryMessageType() const { return PacketType::EntityQuery; } virtual const char* getMyServerName() const { return MODEL_SERVER_NAME; } virtual const char* getMyLoggingServerTargetName() const { return MODEL_SERVER_LOGGING_TARGET_NAME; } virtual const char* getMyDefaultPersistFilename() const { return LOCAL_MODELS_PERSIST_FILE; } - virtual PacketType::Value getMyEditNackType() const { return PacketType::EntityEditNack; } + virtual PacketType getMyEditNackType() const { return PacketType::EntityEditNack; } virtual QString getMyDomainSettingsKey() const { return QString("entity_server_settings"); } // subclass may implement these method diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index fe61a3945c..d664b35ead 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -89,7 +89,7 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer packet } // Ask our tree subclass if it can handle the incoming packet... - PacketType::Value packetType = packet->getType(); + PacketType packetType = packet->getType(); if (_myServer->getOctree()->handlesEditPacketType(packetType)) { PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE", debugProcessPacket); diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 5982eeb4bc..0c691a06a2 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -34,7 +34,7 @@ public: virtual ~OctreeQueryNode(); void init(); // called after creation to set up some virtual items - virtual PacketType::Value getMyPacketType() const = 0; + virtual PacketType getMyPacketType() const = 0; void resetOctreePacket(); // resets octree packet to after "V" header @@ -150,7 +150,7 @@ private: quint64 _lastRootTimestamp; - PacketType::Value _myPacketType; + PacketType _myPacketType; bool _isShuttingDown; SentPacketHistory _sentPacketHistory; diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 419cdabc58..edaf6283f7 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -63,11 +63,11 @@ public: // Subclasses must implement these methods virtual OctreeQueryNode* createOctreeQueryNode() = 0; virtual char getMyNodeType() const = 0; - virtual PacketType::Value getMyQueryMessageType() const = 0; + virtual PacketType getMyQueryMessageType() const = 0; virtual const char* getMyServerName() const = 0; virtual const char* getMyLoggingServerTargetName() const = 0; virtual const char* getMyDefaultPersistFilename() const = 0; - virtual PacketType::Value getMyEditNackType() const = 0; + virtual PacketType getMyEditNackType() const = 0; virtual QString getMyDomainSettingsKey() const { return QString("octree_server_settings"); } // subclass may implement these method diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 0545e0d274..9ddb67677d 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -49,26 +49,30 @@ IceServer::IceServer(int argc, char* argv[]) : } bool IceServer::packetVersionMatch(const udt::Packet& packet) { - if (packet.getVersion() == versionForPacketType(packet.getType())) { + PacketType headerType = NLPacket::typeInHeader(packet); + PacketVersion headerVersion = NLPacket::versionInHeader(packet); + + if (headerVersion == versionForPacketType(headerType)) { return true; } else { - qDebug() << "Packet version mismatch for packet" << packet.getType() - << "(" << nameForPacketType(packet.getType()) << ") from" << packet.getSenderSockAddr(); + qDebug() << "Packet version mismatch for packet" << headerType + << "(" << nameForPacketType(headerType) << ") from" << packet.getSenderSockAddr(); return false; } } void IceServer::processPacket(std::unique_ptr packet) { - PacketType::Value packetType = packet->getType(); - if (packetType == PacketType::ICEServerHeartbeat) { - SharedNetworkPeer peer = addOrUpdateHeartbeatingPeer(*packet); + auto nlPacket = NLPacket::fromBase(std::move(packet)); + + if (nlPacket->getType() == PacketType::ICEServerHeartbeat) { + SharedNetworkPeer peer = addOrUpdateHeartbeatingPeer(*nlPacket); // so that we can send packets to the heartbeating peer when we need, we need to activate a socket now - peer->activateMatchingOrNewSymmetricSocket(packet->getSenderSockAddr()); - } else if (packetType == PacketType::ICEServerQuery) { - QDataStream heartbeatStream(packet.get()); + peer->activateMatchingOrNewSymmetricSocket(nlPacket->getSenderSockAddr()); + } else if (nlPacket->getType() == PacketType::ICEServerQuery) { + QDataStream heartbeatStream(nlPacket.get()); // this is a node hoping to connect to a heartbeating peer - do we have the heartbeating peer? QUuid senderUUID; @@ -89,7 +93,7 @@ void IceServer::processPacket(std::unique_ptr packet) { qDebug() << "Sending information for peer" << connectRequestID << "to peer" << senderUUID; // we have the peer they want to connect to - send them pack the information for that peer - sendPeerInformationPacket(*matchingPeer, &packet->getSenderSockAddr()); + sendPeerInformationPacket(*matchingPeer, &nlPacket->getSenderSockAddr()); // we also need to send them to the active peer they are hoping to connect to // create a dummy peer object we can pass to sendPeerInformationPacket @@ -102,7 +106,7 @@ void IceServer::processPacket(std::unique_ptr packet) { } } -SharedNetworkPeer IceServer::addOrUpdateHeartbeatingPeer(udt::Packet& packet) { +SharedNetworkPeer IceServer::addOrUpdateHeartbeatingPeer(NLPacket& packet) { // pull the UUID, public and private sock addrs for this peer QUuid senderUUID; @@ -135,7 +139,7 @@ SharedNetworkPeer IceServer::addOrUpdateHeartbeatingPeer(udt::Packet& packet) { } void IceServer::sendPeerInformationPacket(const NetworkPeer& peer, const HifiSockAddr* destinationSockAddr) { - auto peerPacket = udt::Packet::create(PacketType::ICEServerPeerInformation); + auto peerPacket = NLPacket::create(PacketType::ICEServerPeerInformation); // get the byte array for this peer peerPacket->write(peer.toByteArray()); diff --git a/ice-server/src/IceServer.h b/ice-server/src/IceServer.h index 3ab6df9044..f1c2c06b65 100644 --- a/ice-server/src/IceServer.h +++ b/ice-server/src/IceServer.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include typedef QHash NetworkPeerHash; @@ -35,7 +35,7 @@ private: bool packetVersionMatch(const udt::Packet& packet); void processPacket(std::unique_ptr packet); - SharedNetworkPeer addOrUpdateHeartbeatingPeer(udt::Packet& incomingPacket); + SharedNetworkPeer addOrUpdateHeartbeatingPeer(NLPacket& incomingPacket); void sendPeerInformationPacket(const NetworkPeer& peer, const HifiSockAddr* destinationSockAddr); QUuid _id; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7c3b5a620e..8a9042ad51 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2706,7 +2706,7 @@ int Application::sendNackPackets() { return packetsSent; } -void Application::queryOctree(NodeType_t serverType, PacketType::Value packetType, NodeToJurisdictionMap& jurisdictions) { +void Application::queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions) { //qCDebug(interfaceapp) << ">>> inside... queryOctree()... _viewFrustum.getFieldOfView()=" << _viewFrustum.getFieldOfView(); bool wantExtraDebugging = getLogger()->extraDebugging(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 3a07fb656d..220ef04abc 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -478,7 +478,7 @@ private: void renderLookatIndicator(glm::vec3 pointOfInterest); - void queryOctree(NodeType_t serverType, PacketType::Value packetType, NodeToJurisdictionMap& jurisdictions); + void queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions); void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum); glm::vec3 getSunDirection(); diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index 386ebacc6d..e35e841a7b 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -19,7 +19,7 @@ OctreePacketProcessor::OctreePacketProcessor() { auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - QSet types { + QSet types { PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase, PacketType::OctreeStats }; @@ -44,7 +44,7 @@ void OctreePacketProcessor::processPacket(QSharedPointer packet, Share Application* app = Application::getInstance(); bool wasStatsPacket = false; - PacketType::Value octreePacketType = packet->getType(); + PacketType octreePacketType = packet->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 @@ -68,11 +68,11 @@ void OctreePacketProcessor::processPacket(QSharedPointer packet, Share } } // fall through to piggyback message - PacketType::Value packetType = packet->getType(); + PacketType packetType = packet->getType(); // check version of piggyback packet against expected version if (packet->getVersion() != versionForPacketType(packet->getType())) { - static QMultiMap versionDebugSuppressMap; + static QMultiMap versionDebugSuppressMap; const QUuid& senderUUID = packet->getSourceID(); if (!versionDebugSuppressMap.contains(senderUUID, packetType)) { diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 8888c9bae5..d3b5600166 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -164,7 +164,7 @@ int InboundAudioStream::parseData(NLPacket& packet) { return packet.pos(); } -int InboundAudioStream::parseStreamProperties(PacketType::Value type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { +int InboundAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { if (type == PacketType::SilentAudioFrame) { quint16 numSilentSamples = 0; memcpy(&numSilentSamples, packetAfterSeqNum.constData(), sizeof(quint16)); @@ -177,7 +177,7 @@ int InboundAudioStream::parseStreamProperties(PacketType::Value type, const QByt } } -int InboundAudioStream::parseAudioData(PacketType::Value type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) { +int InboundAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) { return _ringBuffer.writeData(packetAfterStreamProperties.data(), numAudioSamples * sizeof(int16_t)); } diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index a0994e42bd..5dfb75272b 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -194,11 +194,11 @@ protected: /// parses the info between the seq num and the audio data in the network packet and calculates /// how many audio samples this packet contains (used when filling in samples for dropped packets). /// default implementation assumes no stream properties and raw audio samples after stream propertiess - virtual int parseStreamProperties(PacketType::Value type, const QByteArray& packetAfterSeqNum, int& networkSamples); + virtual int parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& networkSamples); /// parses the audio data in the network packet. /// default implementation assumes packet contains raw audio samples after stream properties - virtual int parseAudioData(PacketType::Value type, const QByteArray& packetAfterStreamProperties, int networkSamples); + virtual int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int networkSamples); /// writes silent samples to the buffer that may be dropped to reduce latency caused by the buffer virtual int writeDroppableSilentSamples(int silentSamples); diff --git a/libraries/audio/src/InjectedAudioStream.cpp b/libraries/audio/src/InjectedAudioStream.cpp index e7633c49e7..54e0f92bea 100644 --- a/libraries/audio/src/InjectedAudioStream.cpp +++ b/libraries/audio/src/InjectedAudioStream.cpp @@ -30,7 +30,7 @@ InjectedAudioStream::InjectedAudioStream(const QUuid& streamIdentifier, const bo const uchar MAX_INJECTOR_VOLUME = 255; -int InjectedAudioStream::parseStreamProperties(PacketType::Value type, +int InjectedAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { // setup a data stream to read from this packet diff --git a/libraries/audio/src/InjectedAudioStream.h b/libraries/audio/src/InjectedAudioStream.h index 2460f83f40..60c36dfb12 100644 --- a/libraries/audio/src/InjectedAudioStream.h +++ b/libraries/audio/src/InjectedAudioStream.h @@ -31,7 +31,7 @@ private: InjectedAudioStream& operator= (const InjectedAudioStream&); AudioStreamStats getAudioStreamStats() const; - int parseStreamProperties(PacketType::Value type, const QByteArray& packetAfterSeqNum, int& numAudioSamples); + int parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples); const QUuid _streamIdentifier; float _radius; diff --git a/libraries/audio/src/MixedProcessedAudioStream.cpp b/libraries/audio/src/MixedProcessedAudioStream.cpp index f596c3a8b3..d236ac7aad 100644 --- a/libraries/audio/src/MixedProcessedAudioStream.cpp +++ b/libraries/audio/src/MixedProcessedAudioStream.cpp @@ -42,7 +42,7 @@ int MixedProcessedAudioStream::writeLastFrameRepeatedWithFade(int samples) { return deviceSamplesWritten; } -int MixedProcessedAudioStream::parseAudioData(PacketType::Value type, const QByteArray& packetAfterStreamProperties, int networkSamples) { +int MixedProcessedAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int networkSamples) { emit addedStereoSamples(packetAfterStreamProperties); diff --git a/libraries/audio/src/MixedProcessedAudioStream.h b/libraries/audio/src/MixedProcessedAudioStream.h index 265095597b..5ea0157421 100644 --- a/libraries/audio/src/MixedProcessedAudioStream.h +++ b/libraries/audio/src/MixedProcessedAudioStream.h @@ -35,7 +35,7 @@ public: protected: int writeDroppableSilentSamples(int silentSamples); int writeLastFrameRepeatedWithFade(int samples); - int parseAudioData(PacketType::Value type, const QByteArray& packetAfterStreamProperties, int networkSamples); + int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int networkSamples); private: int networkToDeviceSamples(int networkSamples); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 39f088f06d..051776d380 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -43,8 +43,8 @@ public: virtual ~EntityTreeRenderer(); virtual char getMyNodeType() const { return NodeType::EntityServer; } - virtual PacketType::Value getMyQueryMessageType() const { return PacketType::EntityQuery; } - virtual PacketType::Value getExpectedPacketType() const { return PacketType::EntityData; } + virtual PacketType getMyQueryMessageType() const { return PacketType::EntityQuery; } + virtual PacketType getExpectedPacketType() const { return PacketType::EntityData; } virtual void renderElement(OctreeElement* element, RenderArgs* args); virtual float getSizeScale() const; virtual int getBoundaryLevelAdjust() const; diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index 5905f7924c..48809287a3 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -28,13 +28,13 @@ void EntityEditPacketSender::processEntityEditNackPacket(QSharedPointer packet, SharedNodePointer sendingNode); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 61253ba6ba..d71a69ae7d 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -618,7 +618,7 @@ void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue &object // // TODO: Implement support for script and visible properties. // -bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, EntityItemID id, const EntityItemProperties& properties, +bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties, QByteArray& buffer) { OctreePacketData ourDataPacket(false, buffer.size()); // create a packetData object to add out packet details too. OctreePacketData* packetData = &ourDataPacket; // we want a pointer to this so we can use our APPEND_ENTITY_PROPERTY macro diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 4532ffd67b..4cfcf9a0ab 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -174,7 +174,7 @@ public: void setGlowLevel(float value) { _glowLevel = value; _glowLevelChanged = true; } void setLocalRenderAlpha(float value) { _localRenderAlpha = value; _localRenderAlphaChanged = true; } - static bool encodeEntityEditPacket(PacketType::Value command, EntityItemID id, const EntityItemProperties& properties, + static bool encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties, QByteArray& buffer); static bool encodeEraseEntityMessage(const EntityItemID& entityItemID, QByteArray& buffer); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 36fcc17a71..7db55f9c84 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -32,7 +32,7 @@ EntityScriptingInterface::EntityScriptingInterface() : connect(nodeList.data(), &NodeList::canRezChanged, this, &EntityScriptingInterface::canRezChanged); } -void EntityScriptingInterface::queueEntityMessage(PacketType::Value packetType, +void EntityScriptingInterface::queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties) { getEntityPacketSender()->queueEditEntityMessage(packetType, entityID, properties); } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index c232437757..5c1e4141a6 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -164,7 +164,7 @@ private: bool actionWorker(const QUuid& entityID, std::function actor); bool setVoxels(QUuid entityID, std::function actor); bool setPoints(QUuid entityID, std::function actor); - void queueEntityMessage(PacketType::Value packetType, EntityItemID entityID, const EntityItemProperties& properties); + void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties); /// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType, diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index ba2691aa3b..d72e075bf2 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -63,7 +63,7 @@ void EntityTree::eraseAllOctreeElements(bool createNewRoot) { resetClientEditStats(); } -bool EntityTree::handlesEditPacketType(PacketType::Value packetType) const { +bool EntityTree::handlesEditPacketType(PacketType packetType) const { // we handle these types of "edit" packets switch (packetType) { case PacketType::EntityAdd: diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 4ade0afc6d..e82e715d69 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -62,10 +62,10 @@ public: // These methods will allow the OctreeServer to send your tree inbound edit packets of your // own definition. Implement these to allow your octree based server to support editing virtual bool getWantSVOfileVersions() const { return true; } - virtual PacketType::Value expectedDataPacketType() const { return PacketType::EntityData; } + virtual PacketType expectedDataPacketType() const { return PacketType::EntityData; } virtual bool canProcessVersion(PacketVersion thisVersion) const { return thisVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS; } - virtual bool handlesEditPacketType(PacketType::Value packetType) const; + virtual bool handlesEditPacketType(PacketType packetType) const; virtual int processEditPacketData(NLPacket& packet, const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode); diff --git a/libraries/entities/src/EntityTreeHeadlessViewer.h b/libraries/entities/src/EntityTreeHeadlessViewer.h index a14fe14a71..2f6483ae19 100644 --- a/libraries/entities/src/EntityTreeHeadlessViewer.h +++ b/libraries/entities/src/EntityTreeHeadlessViewer.h @@ -31,8 +31,8 @@ public: virtual ~EntityTreeHeadlessViewer(); virtual char getMyNodeType() const { return NodeType::EntityServer; } - virtual PacketType::Value getMyQueryMessageType() const { return PacketType::EntityQuery; } - virtual PacketType::Value getExpectedPacketType() const { return PacketType::EntityData; } + virtual PacketType getMyQueryMessageType() const { return PacketType::EntityQuery; } + virtual PacketType getExpectedPacketType() const { return PacketType::EntityData; } void update(); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 2760ed8277..acac81f8ff 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -157,40 +157,42 @@ bool LimitedNodeList::isPacketVerified(const udt::Packet& packet) { } bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) { + PacketType headerType = NLPacket::typeInHeader(packet); + PacketVersion headerVersion = NLPacket::versionInHeader(packet); - if (packet.getVersion() != versionForPacketType(packet.getType())) { + if (headerVersion != versionForPacketType(headerType)) { - static QMultiHash sourcedVersionDebugSuppressMap; - static QMultiHash versionDebugSuppressMap; + static QMultiHash sourcedVersionDebugSuppressMap; + static QMultiHash versionDebugSuppressMap; bool hasBeenOutput = false; QString senderString; - if (NON_SOURCED_PACKETS.contains(packet.getType())) { + if (NON_SOURCED_PACKETS.contains(headerType)) { const HifiSockAddr& senderSockAddr = packet.getSenderSockAddr(); - hasBeenOutput = versionDebugSuppressMap.contains(senderSockAddr, packet.getType()); + hasBeenOutput = versionDebugSuppressMap.contains(senderSockAddr, headerType); if (!hasBeenOutput) { - versionDebugSuppressMap.insert(senderSockAddr, packet.getType()); + versionDebugSuppressMap.insert(senderSockAddr, headerType); senderString = QString("%1:%2").arg(senderSockAddr.getAddress().toString()).arg(senderSockAddr.getPort()); } } else { - QUuid sourceID = QUuid::fromRfc4122(QByteArray::fromRawData(packet.getPayload(), NUM_BYTES_RFC4122_UUID)); + QUuid sourceID = NLPacket::sourceIDInHeader(packet); - hasBeenOutput = sourcedVersionDebugSuppressMap.contains(sourceID, packet.getType()); + hasBeenOutput = sourcedVersionDebugSuppressMap.contains(sourceID, headerType); if (!hasBeenOutput) { - sourcedVersionDebugSuppressMap.insert(sourceID, packet.getType()); + sourcedVersionDebugSuppressMap.insert(sourceID, headerType); senderString = uuidStringWithoutCurlyBraces(sourceID.toString()); } } if (!hasBeenOutput) { - qCDebug(networking) << "Packet version mismatch on" << packet.getType() << "- Sender" - << senderString << "sent" << qPrintable(QString::number(packet.getVersion())) << "but" - << qPrintable(QString::number(versionForPacketType(packet.getType()))) << "expected."; + qCDebug(networking) << "Packet version mismatch on" << headerType << "- Sender" + << senderString << "sent" << qPrintable(QString::number(headerVersion)) << "but" + << qPrintable(QString::number(versionForPacketType(headerType))) << "expected."; - emit packetVersionMismatch(packet.getType()); + emit packetVersionMismatch(headerType); } return false; @@ -201,7 +203,9 @@ bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) { bool LimitedNodeList::packetSourceAndHashMatch(const udt::Packet& packet) { - if (NON_SOURCED_PACKETS.contains(packet.getType())) { + PacketType headerType = NLPacket::typeInHeader(packet); + + if (NON_SOURCED_PACKETS.contains(headerType)) { return true; } else { QUuid sourceID = NLPacket::sourceIDInHeader(packet); @@ -210,19 +214,19 @@ bool LimitedNodeList::packetSourceAndHashMatch(const udt::Packet& packet) { SharedNodePointer matchingNode = nodeWithUUID(sourceID); if (matchingNode) { - if (!NON_VERIFIED_PACKETS.contains(packet.getType())) { + if (!NON_VERIFIED_PACKETS.contains(headerType)) { QByteArray packetHeaderHash = NLPacket::verificationHashInHeader(packet); QByteArray expectedHash = NLPacket::hashForPacketAndSecret(packet, matchingNode->getConnectionSecret()); // check if the md5 hash in the header matches the hash we would expect if (packetHeaderHash != expectedHash) { - static QMultiMap hashDebugSuppressMap; + static QMultiMap hashDebugSuppressMap; - if (!hashDebugSuppressMap.contains(sourceID, packet.getType())) { - qCDebug(networking) << "Packet hash mismatch on" << packet.getType() << "- Sender" << sourceID; + if (!hashDebugSuppressMap.contains(sourceID, headerType)) { + qCDebug(networking) << "Packet hash mismatch on" << headerType << "- Sender" << sourceID; - hashDebugSuppressMap.insert(sourceID, packet.getType()); + hashDebugSuppressMap.insert(sourceID, headerType); } return false; @@ -235,7 +239,7 @@ bool LimitedNodeList::packetSourceAndHashMatch(const udt::Packet& packet) { 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())) << ")" + qCDebug(networking) << "Packet of type" << headerType << "(" << qPrintable(nameForPacketType(headerType)) << ")" << "received from unknown node with UUID" << qPrintable(uuidStringWithoutCurlyBraces(sourceID)); } } @@ -786,7 +790,7 @@ void LimitedNodeList::sendPeerQueryToIceServer(const HifiSockAddr& iceServerSock sendPacketToIceServer(PacketType::ICEServerQuery, iceServerSockAddr, clientID, peerID); } -void LimitedNodeList::sendPacketToIceServer(PacketType::Value packetType, const HifiSockAddr& iceServerSockAddr, +void LimitedNodeList::sendPacketToIceServer(PacketType packetType, const HifiSockAddr& iceServerSockAddr, const QUuid& clientID, const QUuid& peerID) { auto icePacket = NLPacket::create(packetType); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index ead858a239..4047668350 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -231,7 +231,7 @@ public slots: signals: void dataSent(quint8 channelType, int bytes); - void packetVersionMismatch(PacketType::Value type); + void packetVersionMismatch(PacketType type); void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID); void nodeAdded(SharedNodePointer); @@ -261,7 +261,7 @@ protected: void stopInitialSTUNUpdate(bool success); - void sendPacketToIceServer(PacketType::Value packetType, const HifiSockAddr& iceServerSockAddr, const QUuid& clientID, + void sendPacketToIceServer(PacketType packetType, const HifiSockAddr& iceServerSockAddr, const QUuid& clientID, const QUuid& peerRequestID = QUuid()); qint64 sendPacket(std::unique_ptr packet, const Node& destinationNode, diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 39dc296f85..7d2726d9c0 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -11,14 +11,18 @@ #include "NLPacket.h" -qint64 NLPacket::localHeaderSize(PacketType::Value type) { +qint64 NLPacket::maxPayloadSize(PacketType type) { + return Packet::maxPayloadSize(false) - localHeaderSize(type); +} + +qint64 NLPacket::localHeaderSize(PacketType type) { qint64 size = ((NON_SOURCED_PACKETS.contains(type)) ? 0 : NUM_BYTES_RFC4122_UUID) + - ((NON_SOURCED_PACKETS.contains(type) || NON_VERIFIED_PACKETS.contains(type)) ? 0 : NUM_BYTES_MD5_HASH); + ((NON_SOURCED_PACKETS.contains(type) || NON_VERIFIED_PACKETS.contains(type)) ? 0 : NUM_BYTES_MD5_HASH); return size; } -qint64 NLPacket::maxPayloadSize(PacketType::Value type) { - return Packet::maxPayloadSize(type) - localHeaderSize(type); +qint64 NLPacket::maxPayloadSize() const { + return Packet::maxPayloadSize() - localHeaderSize(); } qint64 NLPacket::totalHeadersSize() const { @@ -29,7 +33,7 @@ qint64 NLPacket::localHeaderSize() const { return localHeaderSize(_type); } -std::unique_ptr NLPacket::create(PacketType::Value type, qint64 size) { +std::unique_ptr NLPacket::create(PacketType type, qint64 size) { std::unique_ptr packet; if (size == -1) { @@ -75,17 +79,21 @@ std::unique_ptr NLPacket::createCopy(const NLPacket& other) { return std::unique_ptr(new NLPacket(other)); } -NLPacket::NLPacket(PacketType::Value type, qint64 size) : - Packet(type, localHeaderSize(type) + size) +NLPacket::NLPacket(PacketType type, bool isReliable, bool isPartOfMessage) : + Packet(-1, isReliable, isPartOfMessage), + _type(type), + _version(versionForPacketType(type)) { - Q_ASSERT(size >= 0); - adjustPayloadStartAndCapacity(); } -NLPacket::NLPacket(PacketType::Value type) : - Packet(type, -1) +NLPacket::NLPacket(PacketType type, qint64 size, bool isReliable, bool isPartOfMessage) : + Packet(localHeaderSize(type) + size, isReliable, isPartOfMessage), + _type(type), + _version(versionForPacketType(type)) { + Q_ASSERT(size >= 0); + adjustPayloadStartAndCapacity(); } @@ -103,12 +111,14 @@ NLPacket::NLPacket(const NLPacket& other) : Packet(other) { NLPacket::NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr) : Packet(std::move(data), size, senderSockAddr) -{ +{ // sanity check before we decrease the payloadSize with the payloadCapacity Q_ASSERT(_payloadSize == _payloadCapacity); adjustPayloadStartAndCapacity(_payloadSize > 0); - + + readType(); + readVersion(); readSourceID(); } @@ -135,20 +145,29 @@ NLPacket& NLPacket::operator=(NLPacket&& other) { return *this; } +PacketType NLPacket::typeInHeader(const udt::Packet& packet) { + return *reinterpret_cast(packet.getData()); +} + +PacketVersion NLPacket::versionInHeader(const udt::Packet& packet) { + return *reinterpret_cast(packet.getData() + sizeof(PacketType)); +} + QUuid NLPacket::sourceIDInHeader(const udt::Packet& packet) { - int offset = packet.Packet::localHeaderSize(); + int offset = packet.Packet::localHeaderSize() + sizeof(PacketType) + sizeof(PacketVersion); return QUuid::fromRfc4122(QByteArray::fromRawData(packet.getData() + offset, NUM_BYTES_RFC4122_UUID)); } QByteArray NLPacket::verificationHashInHeader(const udt::Packet& packet) { - int offset = packet.Packet::localHeaderSize() + NUM_BYTES_RFC4122_UUID; + int offset = packet.Packet::localHeaderSize() + sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID; return QByteArray(packet.getData() + offset, NUM_BYTES_MD5_HASH); } QByteArray NLPacket::hashForPacketAndSecret(const udt::Packet& packet, const QUuid& connectionSecret) { QCryptographicHash hash(QCryptographicHash::Md5); - int offset = packet.Packet::localHeaderSize() + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH; + int offset = packet.Packet::localHeaderSize() + sizeof(PacketType) + sizeof(PacketVersion) + + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH; // add the packet payload and the connection UUID hash.addData(packet.getData() + offset, packet.getDataSize() - offset); @@ -158,6 +177,36 @@ QByteArray NLPacket::hashForPacketAndSecret(const udt::Packet& packet, const QUu return hash.result(); } +void NLPacket::writePacketTypeAndVersion() { + // Pack the packet type + memcpy(_packet.get(), &_type, sizeof(PacketType)); + + // Pack the packet version + auto version = versionForPacketType(_type); + memcpy(_packet.get() + sizeof(PacketType), &version, sizeof(version)); +} + +void NLPacket::setType(PacketType type) { + auto currentHeaderSize = totalHeadersSize(); + + _type = type; + _version = versionForPacketType(_type); + + writePacketTypeAndVersion(); + + // Setting new packet type with a different header size not currently supported + Q_ASSERT(currentHeaderSize == totalHeadersSize()); + Q_UNUSED(currentHeaderSize); +} + +void NLPacket::readType() { + _type = NLPacket::typeInHeader(*this); +} + +void NLPacket::readVersion() { + _version = NLPacket::versionInHeader(*this); +} + void NLPacket::adjustPayloadStartAndCapacity(bool shouldDecreasePayloadSize) { qint64 headerSize = localHeaderSize(_type); _payloadStart += headerSize; diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index 57c099764a..3045af3f09 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -19,7 +19,7 @@ class NLPacket : public udt::Packet { Q_OBJECT public: - static std::unique_ptr create(PacketType::Value type, qint64 size = -1); + static std::unique_ptr create(PacketType type, qint64 size = -1); static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); static std::unique_ptr fromBase(std::unique_ptr packet); @@ -27,15 +27,24 @@ public: // Provided for convenience, try to limit use static std::unique_ptr createCopy(const NLPacket& other); + static PacketType typeInHeader(const udt::Packet& packet); + static PacketVersion versionInHeader(const udt::Packet& packet); + static QUuid sourceIDInHeader(const udt::Packet& packet); static QByteArray verificationHashInHeader(const udt::Packet& packet); static QByteArray hashForPacketAndSecret(const udt::Packet& packet, const QUuid& connectionSecret); - - static qint64 localHeaderSize(PacketType::Value type); - static qint64 maxPayloadSize(PacketType::Value type); - + + static qint64 maxPayloadSize(PacketType type); + static qint64 localHeaderSize(PacketType type); + + virtual qint64 maxPayloadSize() const; // The maximum payload size this packet can use to fit in MTU virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers virtual qint64 localHeaderSize() const; // Current level's header size + + PacketType getType() const { return _type; } + void setType(PacketType type); + + PacketVersion getVersion() const { return _version; } const QUuid& getSourceID() const { return _sourceID; } @@ -44,10 +53,8 @@ public: protected: - void adjustPayloadStartAndCapacity(bool shouldDecreasePayloadSize = false); - - NLPacket(PacketType::Value type); - NLPacket(PacketType::Value type, qint64 size); + NLPacket(PacketType type, bool forceReliable = false, bool isPartOfMessage = false); + NLPacket(PacketType type, qint64 size, bool forceReliable = false, bool isPartOfMessage = false); NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); NLPacket(std::unique_ptr packet); NLPacket(const NLPacket& other); @@ -55,9 +62,19 @@ protected: NLPacket& operator=(const NLPacket& other); NLPacket& operator=(NLPacket&& other); + + void adjustPayloadStartAndCapacity(bool shouldDecreasePayloadSize = false); + + // Header writers + void writePacketTypeAndVersion(); + // Header readers, used to set member variables after getting a packet from the network + void readType(); + void readVersion(); void readSourceID(); - + + PacketType _type; + PacketVersion _version; QUuid _sourceID; }; diff --git a/libraries/networking/src/NLPacketList.cpp b/libraries/networking/src/NLPacketList.cpp index 6b7b53e8e9..df36228e7a 100644 --- a/libraries/networking/src/NLPacketList.cpp +++ b/libraries/networking/src/NLPacketList.cpp @@ -13,7 +13,7 @@ #include "NLPacket.h" -NLPacketList::NLPacketList(PacketType::Value packetType, QByteArray extendedHeader) : +NLPacketList::NLPacketList(PacketType packetType, QByteArray extendedHeader) : PacketList(packetType, extendedHeader) { diff --git a/libraries/networking/src/NLPacketList.h b/libraries/networking/src/NLPacketList.h index 33a8316f95..512ec23d22 100644 --- a/libraries/networking/src/NLPacketList.h +++ b/libraries/networking/src/NLPacketList.h @@ -16,7 +16,7 @@ class NLPacketList : public udt::PacketList { public: - NLPacketList(PacketType::Value packetType, QByteArray extendedHeader = QByteArray()); + NLPacketList(PacketType packetType, QByteArray extendedHeader = QByteArray()); private: NLPacketList(const NLPacketList& other) = delete; diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index c8106f5fd8..8cd524e539 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -85,7 +85,7 @@ private: bool _canAdjustLocks; bool _canRez; - std::map _lastSequenceNumbers; + std::map _lastSequenceNumbers; }; typedef QSharedPointer SharedNodePointer; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index dfa3ef86a5..1660312e5d 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -231,7 +231,7 @@ void NodeList::sendDomainServerCheckIn() { } else if (!_domainHandler.getIP().isNull()) { bool isUsingDTLS = false; - PacketType::Value domainPacketType = !_domainHandler.isConnected() + PacketType domainPacketType = !_domainHandler.isConnected() ? PacketType::DomainConnectRequest : PacketType::DomainListRequest; if (!_domainHandler.isConnected()) { @@ -525,7 +525,7 @@ void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) { void NodeList::sendAssignment(Assignment& assignment) { - PacketType::Value assignmentPacketType = assignment.getCommand() == Assignment::CreateCommand + PacketType assignmentPacketType = assignment.getCommand() == Assignment::CreateCommand ? PacketType::CreateAssignment : PacketType::RequestAssignment; diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 6fb34f05e7..1389f271bf 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -24,11 +24,11 @@ PacketReceiver::PacketReceiver(QObject* parent) : qRegisterMetaType>(); } -bool PacketReceiver::registerListenerForTypes(const QSet& types, QObject* listener, const char* slot) { - QSet nonSourcedTypes; - QSet sourcedTypes; +bool PacketReceiver::registerListenerForTypes(const QSet& types, QObject* listener, const char* slot) { + QSet nonSourcedTypes; + QSet sourcedTypes; - foreach(PacketType::Value type, types) { + foreach(PacketType type, types) { if (NON_SOURCED_PACKETS.contains(type)) { nonSourcedTypes << type; } else { @@ -41,7 +41,7 @@ bool PacketReceiver::registerListenerForTypes(const QSet& typ if (nonSourcedTypes.size() > 0) { QMetaMethod nonSourcedMethod = matchingMethodForListener(*nonSourcedTypes.begin(), listener, slot); if (nonSourcedMethod.isValid()) { - foreach(PacketType::Value type, nonSourcedTypes) { + foreach(PacketType type, nonSourcedTypes) { registerVerifiedListener(type, listener, nonSourcedMethod); } } else { @@ -52,7 +52,7 @@ bool PacketReceiver::registerListenerForTypes(const QSet& typ if (sourcedTypes.size() > 0) { QMetaMethod sourcedMethod = matchingMethodForListener(*sourcedTypes.begin(), listener, slot); if (sourcedMethod.isValid()) { - foreach(PacketType::Value type, sourcedTypes) { + foreach(PacketType type, sourcedTypes) { registerVerifiedListener(type, listener, sourcedMethod); } } else { @@ -63,7 +63,7 @@ bool PacketReceiver::registerListenerForTypes(const QSet& typ return true; } -void PacketReceiver::registerDirectListener(PacketType::Value type, QObject* listener, const char* slot) { +void PacketReceiver::registerDirectListener(PacketType type, QObject* listener, const char* slot) { bool success = registerListener(type, listener, slot); if (success) { _directConnectSetMutex.lock(); @@ -75,7 +75,7 @@ void PacketReceiver::registerDirectListener(PacketType::Value type, QObject* lis } } -void PacketReceiver::registerDirectListenerForTypes(const QSet& types, +void PacketReceiver::registerDirectListenerForTypes(const QSet& types, QObject* listener, const char* slot) { // just call register listener for types to start bool success = registerListenerForTypes(types, listener, slot); @@ -89,7 +89,7 @@ void PacketReceiver::registerDirectListenerForTypes(const QSet packet) { _directConnectSetMutex.unlock(); - PacketType::Value packetType = nlPacket->getType(); + PacketType packetType = nlPacket->getType(); if (matchingNode) { emit dataReceived(matchingNode->getType(), nlPacket->getDataSize()); @@ -311,7 +311,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { qWarning() << "No listener found for packet type " << nameForPacketType(nlPacket->getType()); // insert a dummy listener so we don't print this again - _packetListenerMap.insert(packet->getType(), { nullptr, QMetaMethod() }); + _packetListenerMap.insert(nlPacket->getType(), { nullptr, QMetaMethod() }); } _packetListenerLock.unlock(); diff --git a/libraries/networking/src/PacketReceiver.h b/libraries/networking/src/PacketReceiver.h index 25bf9656be..531a8e60be 100644 --- a/libraries/networking/src/PacketReceiver.h +++ b/libraries/networking/src/PacketReceiver.h @@ -41,8 +41,8 @@ public: void resetCounters() { _inPacketCount = 0; _inByteCount = 0; } - bool registerListenerForTypes(const QSet& types, QObject* listener, const char* slot); - bool registerListener(PacketType::Value type, QObject* listener, const char* slot); + bool registerListenerForTypes(const QSet& types, QObject* listener, const char* slot); + bool registerListener(PacketType type, QObject* listener, const char* slot); void unregisterListener(QObject* listener); void handleVerifiedPacket(std::unique_ptr packet); @@ -53,16 +53,16 @@ signals: private: // these are brutal hacks for now - ideally GenericThread / ReceivedPacketProcessor // should be changed to have a true event loop and be able to handle our QMetaMethod::invoke - void registerDirectListenerForTypes(const QSet& types, QObject* listener, const char* slot); - void registerDirectListener(PacketType::Value type, QObject* listener, const char* slot); + void registerDirectListenerForTypes(const QSet& types, QObject* listener, const char* slot); + void registerDirectListener(PacketType type, QObject* listener, const char* slot); - QMetaMethod matchingMethodForListener(PacketType::Value type, QObject* object, const char* slot) const; - void registerVerifiedListener(PacketType::Value type, QObject* listener, const QMetaMethod& slot); + QMetaMethod matchingMethodForListener(PacketType type, QObject* object, const char* slot) const; + void registerVerifiedListener(PacketType type, QObject* listener, const QMetaMethod& slot); using ObjectMethodPair = std::pair, QMetaMethod>; QMutex _packetListenerLock; - QHash _packetListenerMap; + QHash _packetListenerMap; int _inPacketCount = 0; int _inByteCount = 0; bool _shouldDropPackets = false; diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 154d526833..439b185661 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -15,18 +15,8 @@ using namespace udt; const qint64 Packet::PACKET_WRITE_ERROR = -1; -qint64 Packet::localHeaderSize(PacketType::Value type) { - // TODO: check the bitfield to see if the message is included - qint64 size = sizeof(SequenceNumberAndBitField); - return size; -} - -qint64 Packet::maxPayloadSize(PacketType::Value type) { - return MAX_PACKET_SIZE - localHeaderSize(type); -} - -std::unique_ptr Packet::create(PacketType::Value type, qint64 size) { - auto packet = std::unique_ptr(new Packet(type, size)); +std::unique_ptr Packet::create(qint64 size, bool isReliable, bool isPartOfMessage) { + auto packet = std::unique_ptr(new Packet(size, isReliable, isPartOfMessage)); packet->open(QIODevice::ReadWrite); @@ -49,25 +39,38 @@ std::unique_ptr Packet::createCopy(const Packet& other) { return std::unique_ptr(new Packet(other)); } +qint64 Packet::maxPayloadSize(bool isPartOfMessage) { + return MAX_PACKET_SIZE - localHeaderSize(isPartOfMessage); +} + +qint64 Packet::localHeaderSize(bool isPartOfMessage) { + return sizeof(SequenceNumberAndBitField) + (isPartOfMessage ? sizeof(MessageNumberAndBitField) : 0); +} + +qint64 Packet::maxPayloadSize() const { + return MAX_PACKET_SIZE - localHeaderSize(); +} + qint64 Packet::totalHeadersSize() const { return localHeaderSize(); } qint64 Packet::localHeaderSize() const { - return localHeaderSize(_type); + return localHeaderSize(_isPartOfMessage); } -Packet::Packet(PacketType::Value type, qint64 size) : - _type(type), - _version(0) +Packet::Packet(qint64 size, bool isReliable, bool isPartOfMessage) : + _isReliable(isReliable), + _isPartOfMessage(isPartOfMessage) { - auto maxPayload = maxPayloadSize(type); + auto maxPayload = maxPayloadSize(); + if (size == -1) { // default size of -1, means biggest packet possible size = maxPayload; } - _packetSize = localHeaderSize(type) + size; + _packetSize = localHeaderSize() + size; _packet.reset(new char[_packetSize]); _payloadCapacity = size; _payloadStart = _packet.get() + (_packetSize - _payloadCapacity); @@ -84,9 +87,11 @@ Packet::Packet(std::unique_ptr data, qint64 size, const HifiSockAddr& send _packet(std::move(data)), _senderSockAddr(senderSockAddr) { - _type = readType(); - _version = readVersion(); - _payloadCapacity = _packetSize - localHeaderSize(_type); + readIsReliable(); + readIsPartOfMessage(); + readSequenceNumber(); + + _payloadCapacity = _packetSize - localHeaderSize(); _payloadSize = _payloadCapacity; _payloadStart = _packet.get() + (_packetSize - _payloadCapacity); } @@ -98,9 +103,6 @@ Packet::Packet(const Packet& other) : } Packet& Packet::operator=(const Packet& other) { - _type = other._type; - _version = other._version; - _packetSize = other._packetSize; _packet = std::unique_ptr(new char[_packetSize]); memcpy(_packet.get(), other._packet.get(), _packetSize); @@ -124,9 +126,6 @@ Packet::Packet(Packet&& other) { } Packet& Packet::operator=(Packet&& other) { - _type = other._type; - _version = other._version; - _packetSize = other._packetSize; _packet = std::move(other._packet); @@ -164,55 +163,38 @@ bool Packet::reset() { return QIODevice::reset(); } -void Packet::setType(PacketType::Value type) { - auto currentHeaderSize = totalHeadersSize(); - _type = type; - writePacketTypeAndVersion(_type); - - // Setting new packet type with a different header size not currently supported - Q_ASSERT(currentHeaderSize == totalHeadersSize()); - Q_UNUSED(currentHeaderSize); -} - -PacketType::Value Packet::readType() const { - return (PacketType::Value)arithmeticCodingValueFromBuffer(_packet.get()); -} - -PacketVersion Packet::readVersion() const { - return *reinterpret_cast(_packet.get() + numBytesForArithmeticCodedPacketType(_type)); -} - static const uint32_t CONTROL_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 1); static const uint32_t RELIABILITY_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 2); static const uint32_t MESSAGE_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 3); +static const int BIT_FIELD_LENGTH = 3; static const uint32_t BIT_FIELD_MASK = CONTROL_BIT_MASK | RELIABILITY_BIT_MASK | MESSAGE_BIT_MASK; - -Packet::SequenceNumber Packet::readSequenceNumber() const { +void Packet::readIsReliable() { SequenceNumberAndBitField seqNumBitField = *reinterpret_cast(_packet.get()); - return seqNumBitField & ~BIT_FIELD_MASK; // Remove the bit field + _isReliable = (bool) (seqNumBitField & RELIABILITY_BIT_MASK); // Only keep reliability bit } -bool Packet::readIsControlPacket() const { +void Packet::readIsPartOfMessage() { SequenceNumberAndBitField seqNumBitField = *reinterpret_cast(_packet.get()); - return seqNumBitField & CONTROL_BIT_MASK; // Only keep control bit + _isReliable = (bool) (seqNumBitField & MESSAGE_BIT_MASK); // Only keep message bit } -void Packet::writePacketTypeAndVersion(PacketType::Value type) { - // Pack the packet type - auto offset = packArithmeticallyCodedValue(type, _packet.get()); - - // Pack the packet version - auto version = versionForPacketType(type); - memcpy(_packet.get() + offset, &version, sizeof(version)); +void Packet::readSequenceNumber() { + SequenceNumberAndBitField seqNumBitField = *reinterpret_cast(_packet.get()); + _sequenceNumber = (seqNumBitField & ~BIT_FIELD_MASK); // Remove the bit field } -void Packet::writeSequenceNumber(SequenceNumber seqNum) { - // Here we are overriding the control bit to 0. - // But that is not an issue since we should only ever set the seqNum - // for data packets going out - memcpy(_packet.get() + numBytesForArithmeticCodedPacketType(_type) + sizeof(PacketVersion), - &seqNum, sizeof(seqNum)); +static const uint32_t MAX_SEQUENCE_NUMBER = UINT32_MAX >> BIT_FIELD_LENGTH; + +void Packet::writeSequenceNumber(SequenceNumber sequenceNumber) { + // make sure this is a sequence number <= 29 bit unsigned max (536,870,911) + Q_ASSERT(sequenceNumber <= MAX_SEQUENCE_NUMBER); + + // grab pointer to current SequenceNumberAndBitField + SequenceNumberAndBitField* seqNumBitField = reinterpret_cast(_packet.get()); + + // write new value by ORing (old value & BIT_FIELD_MASK) with new seqNum + *seqNumBitField = (*seqNumBitField & BIT_FIELD_MASK) | sequenceNumber; } QByteArray Packet::read(qint64 maxSize) { diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index b74834c82a..1bd9ee9619 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -24,25 +24,33 @@ namespace udt { class Packet : public QIODevice { Q_OBJECT public: - // NOTE: The SequenceNumber must actually only be 29 bits MAX to leave room for a bit field + // NOTE: The SequenceNumber is only actually 29 bits to leave room for a bit field using SequenceNumber = uint32_t; using SequenceNumberAndBitField = uint32_t; + // NOTE: The MessageNumber is only actually 29 bits to leave room for a bit field + using MessageNumber = uint32_t; + using MessageNumberAndBitField = uint32_t; + static const uint32_t DEFAULT_SEQUENCE_NUMBER = 0; static const qint64 PACKET_WRITE_ERROR; - static std::unique_ptr create(PacketType::Value type, qint64 size = -1); + static std::unique_ptr create(qint64 size = -1, bool isReliable = false, bool isPartOfMessage = false); static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); // Provided for convenience, try to limit use static std::unique_ptr createCopy(const Packet& other); - - static qint64 localHeaderSize(PacketType::Value type); - static qint64 maxPayloadSize(PacketType::Value type); - + + // The maximum payload size this packet can use to fit in MTU + static qint64 maxPayloadSize(bool isPartOfMessage); + virtual qint64 maxPayloadSize() const; + + // Current level's header size + static qint64 localHeaderSize(bool isPartOfMessage); + virtual qint64 localHeaderSize() const; + virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers - virtual qint64 localHeaderSize() const; // Current level's header size // Payload direct access to the payload, use responsibly! char* getPayload() { return _payloadStart; } @@ -51,11 +59,6 @@ public: // Return direct access to the entire packet, use responsibly! char* getData() { return _packet.get(); } const char* getData() const { return _packet.get(); } - - PacketType::Value getType() const { return _type; } - void setType(PacketType::Value type); - - PacketVersion getVersion() const { return _version; } // Returns the size of the packet, including the header qint64 getDataSize() const { return totalHeadersSize() + _payloadSize; } @@ -75,9 +78,7 @@ public: HifiSockAddr& getSenderSockAddr() { return _senderSockAddr; } const HifiSockAddr& getSenderSockAddr() const { return _senderSockAddr; } - void writeSequenceNumber(SequenceNumber seqNum); - SequenceNumber readSequenceNumber() const; - bool readIsControlPacket() const; + void writeSequenceNumber(SequenceNumber sequenceNumber); // QIODevice virtual functions // WARNING: Those methods all refer to the payload ONLY and NOT the entire packet @@ -93,26 +94,21 @@ public: template qint64 writePrimitive(const T& data); protected: - Packet(PacketType::Value type, qint64 size); + Packet(qint64 size, bool isReliable = false, bool isPartOfMessage = false); Packet(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); Packet(const Packet& other); Packet& operator=(const Packet& other); Packet(Packet&& other); Packet& operator=(Packet&& other); - // Header readers - PacketType::Value readType() const; - PacketVersion readVersion() const; - // QIODevice virtual functions virtual qint64 writeData(const char* data, qint64 maxSize); virtual qint64 readData(char* data, qint64 maxSize); - - // Header writers - void writePacketTypeAndVersion(PacketType::Value type); - - PacketType::Value _type; // Packet type - PacketVersion _version; // Packet version + + // Header readers - these read data to member variables after pulling packet off wire + void readIsPartOfMessage(); + void readIsReliable(); + void readSequenceNumber(); qint64 _packetSize = 0; // Total size of the allocated memory std::unique_ptr _packet; // Allocated memory @@ -121,6 +117,10 @@ protected: qint64 _payloadCapacity = 0; // Total capacity of the payload qint64 _payloadSize = 0; // How much of the payload is actually used + + bool _isReliable { false }; + bool _isPartOfMessage { false }; + SequenceNumber _sequenceNumber { 0 }; HifiSockAddr _senderSockAddr; // sender address for packet (only used on receiving end) }; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index b71f4107df..e3a8761e6d 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -15,22 +15,22 @@ #include -using namespace PacketType; +const QSet NON_VERIFIED_PACKETS = QSet() + << PacketType::NodeJsonStats << PacketType::EntityQuery + << PacketType::OctreeDataNack << PacketType::EntityEditNack + << PacketType::DomainListRequest << PacketType::StopNode; -const QSet NON_VERIFIED_PACKETS = QSet() - << NodeJsonStats << EntityQuery - << OctreeDataNack << EntityEditNack - << DomainListRequest << StopNode; +const QSet NON_SOURCED_PACKETS = QSet() + << PacketType::StunResponse << PacketType::CreateAssignment << PacketType::RequestAssignment + << PacketType::DomainServerRequireDTLS << PacketType::DomainConnectRequest + << PacketType::DomainList << PacketType::DomainConnectionDenied + << PacketType::DomainServerPathQuery << PacketType::DomainServerPathResponse + << PacketType::DomainServerAddedNode + << PacketType::ICEServerPeerInformation << PacketType::ICEServerQuery << PacketType::ICEServerHeartbeat + << PacketType::ICEPing << PacketType::ICEPingReply + << PacketType::AssignmentClientStatus << PacketType::StopNode; -const QSet NON_SOURCED_PACKETS = QSet() - << StunResponse << CreateAssignment << RequestAssignment - << DomainServerRequireDTLS << DomainConnectRequest - << DomainList << DomainConnectionDenied - << DomainServerPathQuery << DomainServerPathResponse - << DomainServerAddedNode - << ICEServerPeerInformation << ICEServerQuery << ICEServerHeartbeat - << ICEPing << ICEPingReply - << AssignmentClientStatus << StopNode; +const QSet RELIABLE_PACKETS = QSet(); int arithmeticCodingValueFromBuffer(const char* checkValue) { if (((uchar) *checkValue) < 255) { @@ -60,11 +60,11 @@ int packArithmeticallyCodedValue(int value, char* destination) { } } -PacketVersion versionForPacketType(PacketType::Value packetType) { +PacketVersion versionForPacketType(PacketType packetType) { switch (packetType) { - case EntityAdd: - case EntityEdit: - case EntityData: + case PacketType::EntityAdd: + case PacketType::EntityEdit: + case PacketType::EntityData: return VERSION_ENTITIES_NEW_PROTOCOL_LAYER; default: return 11; @@ -73,56 +73,66 @@ PacketVersion versionForPacketType(PacketType::Value packetType) { #define PACKET_TYPE_NAME_LOOKUP(x) case x: return QString(#x); -QString nameForPacketType(PacketType::Value packetType) { +QString nameForPacketType(PacketType packetType) { switch (packetType) { - PACKET_TYPE_NAME_LOOKUP(Unknown); - PACKET_TYPE_NAME_LOOKUP(StunResponse); - PACKET_TYPE_NAME_LOOKUP(DomainList); - PACKET_TYPE_NAME_LOOKUP(Ping); - PACKET_TYPE_NAME_LOOKUP(PingReply); - PACKET_TYPE_NAME_LOOKUP(KillAvatar); - PACKET_TYPE_NAME_LOOKUP(AvatarData); - PACKET_TYPE_NAME_LOOKUP(InjectAudio); - PACKET_TYPE_NAME_LOOKUP(MixedAudio); - PACKET_TYPE_NAME_LOOKUP(MicrophoneAudioNoEcho); - PACKET_TYPE_NAME_LOOKUP(MicrophoneAudioWithEcho); - PACKET_TYPE_NAME_LOOKUP(BulkAvatarData); - PACKET_TYPE_NAME_LOOKUP(SilentAudioFrame); - PACKET_TYPE_NAME_LOOKUP(DomainListRequest); - PACKET_TYPE_NAME_LOOKUP(RequestAssignment); - PACKET_TYPE_NAME_LOOKUP(CreateAssignment); - PACKET_TYPE_NAME_LOOKUP(DomainConnectionDenied); - PACKET_TYPE_NAME_LOOKUP(MuteEnvironment); - PACKET_TYPE_NAME_LOOKUP(AudioStreamStats); - PACKET_TYPE_NAME_LOOKUP(OctreeStats); - PACKET_TYPE_NAME_LOOKUP(Jurisdiction); - PACKET_TYPE_NAME_LOOKUP(JurisdictionRequest); - PACKET_TYPE_NAME_LOOKUP(AvatarIdentity); - PACKET_TYPE_NAME_LOOKUP(AvatarBillboard); - PACKET_TYPE_NAME_LOOKUP(DomainConnectRequest); - PACKET_TYPE_NAME_LOOKUP(DomainServerRequireDTLS); - PACKET_TYPE_NAME_LOOKUP(NodeJsonStats); - PACKET_TYPE_NAME_LOOKUP(EntityQuery); - PACKET_TYPE_NAME_LOOKUP(EntityData); - PACKET_TYPE_NAME_LOOKUP(EntityErase); - PACKET_TYPE_NAME_LOOKUP(OctreeDataNack); - PACKET_TYPE_NAME_LOOKUP(StopNode); - PACKET_TYPE_NAME_LOOKUP(AudioEnvironment); - PACKET_TYPE_NAME_LOOKUP(EntityEditNack); - PACKET_TYPE_NAME_LOOKUP(ICEServerHeartbeat); - PACKET_TYPE_NAME_LOOKUP(DomainServerAddedNode); - PACKET_TYPE_NAME_LOOKUP(ICEServerQuery); - PACKET_TYPE_NAME_LOOKUP(ICEServerPeerInformation); - PACKET_TYPE_NAME_LOOKUP(ICEPing); - PACKET_TYPE_NAME_LOOKUP(ICEPingReply); - PACKET_TYPE_NAME_LOOKUP(EntityAdd); - PACKET_TYPE_NAME_LOOKUP(EntityEdit); + PACKET_TYPE_NAME_LOOKUP(PacketType::Unknown); + PACKET_TYPE_NAME_LOOKUP(PacketType::StunResponse); + PACKET_TYPE_NAME_LOOKUP(PacketType::DomainList); + PACKET_TYPE_NAME_LOOKUP(PacketType::Ping); + PACKET_TYPE_NAME_LOOKUP(PacketType::PingReply); + PACKET_TYPE_NAME_LOOKUP(PacketType::KillAvatar); + PACKET_TYPE_NAME_LOOKUP(PacketType::AvatarData); + PACKET_TYPE_NAME_LOOKUP(PacketType::InjectAudio); + PACKET_TYPE_NAME_LOOKUP(PacketType::MixedAudio); + PACKET_TYPE_NAME_LOOKUP(PacketType::MicrophoneAudioNoEcho); + PACKET_TYPE_NAME_LOOKUP(PacketType::MicrophoneAudioWithEcho); + PACKET_TYPE_NAME_LOOKUP(PacketType::BulkAvatarData); + PACKET_TYPE_NAME_LOOKUP(PacketType::SilentAudioFrame); + PACKET_TYPE_NAME_LOOKUP(PacketType::DomainListRequest); + PACKET_TYPE_NAME_LOOKUP(PacketType::RequestAssignment); + PACKET_TYPE_NAME_LOOKUP(PacketType::CreateAssignment); + PACKET_TYPE_NAME_LOOKUP(PacketType::DomainConnectionDenied); + PACKET_TYPE_NAME_LOOKUP(PacketType::MuteEnvironment); + PACKET_TYPE_NAME_LOOKUP(PacketType::AudioStreamStats); + PACKET_TYPE_NAME_LOOKUP(PacketType::OctreeStats); + PACKET_TYPE_NAME_LOOKUP(PacketType::Jurisdiction); + PACKET_TYPE_NAME_LOOKUP(PacketType::JurisdictionRequest); + PACKET_TYPE_NAME_LOOKUP(PacketType::AvatarIdentity); + PACKET_TYPE_NAME_LOOKUP(PacketType::AvatarBillboard); + PACKET_TYPE_NAME_LOOKUP(PacketType::DomainConnectRequest); + PACKET_TYPE_NAME_LOOKUP(PacketType::DomainServerRequireDTLS); + PACKET_TYPE_NAME_LOOKUP(PacketType::NodeJsonStats); + PACKET_TYPE_NAME_LOOKUP(PacketType::EntityQuery); + PACKET_TYPE_NAME_LOOKUP(PacketType::EntityData); + PACKET_TYPE_NAME_LOOKUP(PacketType::EntityErase); + PACKET_TYPE_NAME_LOOKUP(PacketType::OctreeDataNack); + PACKET_TYPE_NAME_LOOKUP(PacketType::StopNode); + PACKET_TYPE_NAME_LOOKUP(PacketType::AudioEnvironment); + PACKET_TYPE_NAME_LOOKUP(PacketType::EntityEditNack); + PACKET_TYPE_NAME_LOOKUP(PacketType::ICEServerHeartbeat); + PACKET_TYPE_NAME_LOOKUP(PacketType::DomainServerAddedNode); + PACKET_TYPE_NAME_LOOKUP(PacketType::ICEServerQuery); + PACKET_TYPE_NAME_LOOKUP(PacketType::ICEServerPeerInformation); + PACKET_TYPE_NAME_LOOKUP(PacketType::ICEPing); + PACKET_TYPE_NAME_LOOKUP(PacketType::ICEPingReply); + PACKET_TYPE_NAME_LOOKUP(PacketType::EntityAdd); + PACKET_TYPE_NAME_LOOKUP(PacketType::EntityEdit); default: return QString("Type: ") + QString::number((int)packetType); } return QString("unexpected"); } -int numBytesForArithmeticCodedPacketType(PacketType::Value packetType) { +int numBytesForArithmeticCodedPacketType(PacketType packetType) { return (int) ceilf((float) packetType / 255); } + +uint qHash(const PacketType& key, uint seed) { + // seems odd that Qt couldn't figure out this cast itself, but this fixes a compile error after switch to + // strongly typed enum for PacketType + return qHash((quint8) key, seed); +} + +QDebug operator<<(QDebug debug, const PacketType& type) { + return debug.nospace() << (uint8_t) type << " (" << qPrintable(nameForPacketType(type)) << ")"; +} diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index d134125ca3..2d3f7f25fe 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -26,55 +26,53 @@ // NOTE: if adding a new packet packetType, you can replace one marked usable or add at the end // NOTE: if you want the name of the packet packetType to be available for debugging or logging, update nameForPacketType() as well -namespace PacketType { - enum Value { - Unknown, - StunResponse, - DomainList, - Ping, - PingReply, - KillAvatar, - AvatarData, - InjectAudio, - MixedAudio, - MicrophoneAudioNoEcho, - MicrophoneAudioWithEcho, - BulkAvatarData, - SilentAudioFrame, - DomainListRequest, - RequestAssignment, - CreateAssignment, - DomainConnectionDenied, - MuteEnvironment, - AudioStreamStats, - DomainServerPathQuery, - DomainServerPathResponse, - DomainServerAddedNode, - ICEServerPeerInformation, - ICEServerQuery, - OctreeStats, - Jurisdiction, - JurisdictionRequest, - AssignmentClientStatus, - NoisyMute, - AvatarIdentity, - AvatarBillboard, - DomainConnectRequest, - DomainServerRequireDTLS, - NodeJsonStats, - OctreeDataNack, - StopNode, - AudioEnvironment, - EntityEditNack, - ICEServerHeartbeat, - ICEPing, - ICEPingReply, - EntityData, - EntityQuery, - EntityAdd, - EntityErase, - EntityEdit - }; +enum class PacketType : uint8_t { + Unknown, + StunResponse, + DomainList, + Ping, + PingReply, + KillAvatar, + AvatarData, + InjectAudio, + MixedAudio, + MicrophoneAudioNoEcho, + MicrophoneAudioWithEcho, + BulkAvatarData, + SilentAudioFrame, + DomainListRequest, + RequestAssignment, + CreateAssignment, + DomainConnectionDenied, + MuteEnvironment, + AudioStreamStats, + DomainServerPathQuery, + DomainServerPathResponse, + DomainServerAddedNode, + ICEServerPeerInformation, + ICEServerQuery, + OctreeStats, + Jurisdiction, + JurisdictionRequest, + AssignmentClientStatus, + NoisyMute, + AvatarIdentity, + AvatarBillboard, + DomainConnectRequest, + DomainServerRequireDTLS, + NodeJsonStats, + OctreeDataNack, + StopNode, + AudioEnvironment, + EntityEditNack, + ICEServerHeartbeat, + ICEPing, + ICEPingReply, + EntityData, + EntityQuery, + EntityAdd, + EntityErase, + EntityEdit }; const int NUM_BYTES_MD5_HASH = 16; @@ -84,19 +82,23 @@ const int MAX_PACKET_HEADER_BYTES = 4 + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_H typedef char PacketVersion; -extern const QSet NON_VERIFIED_PACKETS; -extern const QSet NON_SOURCED_PACKETS; +extern const QSet NON_VERIFIED_PACKETS; +extern const QSet NON_SOURCED_PACKETS; +extern const QSet RELIABLE_PACKETS; -QString nameForPacketType(PacketType::Value packetType); -PacketVersion versionForPacketType(PacketType::Value packetType); +QString nameForPacketType(PacketType packetType); +PacketVersion versionForPacketType(PacketType packetType); -int numBytesForArithmeticCodedPacketType(PacketType::Value packetType); -int numBytesForPacketHeaderGivenPacketType(PacketType::Value packetType); +int numBytesForArithmeticCodedPacketType(PacketType packetType); +int numBytesForPacketHeaderGivenPacketType(PacketType packetType); int packArithmeticallyCodedValue(int value, char* destination); int arithmeticCodingValueFromBuffer(const char* checkValue); int numBytesArithmeticCodingFromBuffer(const char* checkValue); +uint qHash(const PacketType& key, uint seed); +QDebug operator<<(QDebug debug, const PacketType& type); + const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1; const PacketVersion VERSION_ENTITIES_HAVE_ANIMATION = 1; const PacketVersion VERSION_ROOT_ELEMENT_HAS_DATA = 2; diff --git a/libraries/networking/src/udt/PacketList.cpp b/libraries/networking/src/udt/PacketList.cpp index 47545eb910..494587971b 100644 --- a/libraries/networking/src/udt/PacketList.cpp +++ b/libraries/networking/src/udt/PacketList.cpp @@ -17,7 +17,7 @@ using namespace udt; -PacketList::PacketList(PacketType::Value packetType, QByteArray extendedHeader) : +PacketList::PacketList(PacketType packetType, QByteArray extendedHeader) : _packetType(packetType), _extendedHeader(extendedHeader) { @@ -34,7 +34,8 @@ void PacketList::endSegment() { std::unique_ptr PacketList::createPacket() { // use the static create method to create a new packet - return Packet::create(getType()); + // TODO: create a packet with correct reliability and messaging + return Packet::create(); } std::unique_ptr PacketList::createPacketWithExtendedHeader() { diff --git a/libraries/networking/src/udt/PacketList.h b/libraries/networking/src/udt/PacketList.h index 3d1166149c..18acb7fa17 100644 --- a/libraries/networking/src/udt/PacketList.h +++ b/libraries/networking/src/udt/PacketList.h @@ -27,14 +27,14 @@ class Packet; class PacketList : public QIODevice { Q_OBJECT public: - PacketList(PacketType::Value packetType, QByteArray extendedHeader = QByteArray()); + PacketList(PacketType packetType, QByteArray extendedHeader = QByteArray()); virtual bool isSequential() const { return true; } void startSegment(); void endSegment(); - PacketType::Value getType() const { return _packetType; } + PacketType getType() const { return _packetType; } int getNumPackets() const { return _packets.size() + (_currentPacket ? 1 : 0); } void closeCurrentPacket(bool shouldSendEmpty = false); @@ -58,7 +58,7 @@ private: virtual std::unique_ptr createPacket(); std::unique_ptr createPacketWithExtendedHeader(); - PacketType::Value _packetType; + PacketType _packetType; bool _isOrdered = false; std::unique_ptr _currentPacket; diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 203ff2b072..a8a3f28f9a 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1894,7 +1894,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr bool wantImportProgress = true; - PacketType::Value expectedType = expectedDataPacketType(); + PacketType expectedType = expectedDataPacketType(); PacketVersion expectedVersion = versionForPacketType(expectedType); bool hasBufferBreaks = versionHasSVOfileBreaks(expectedVersion); @@ -1902,7 +1902,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr if (getWantSVOfileVersions()) { // read just enough of the file to parse the header... - const unsigned long HEADER_LENGTH = sizeof(PacketType::Value) + sizeof(PacketVersion); + const unsigned long HEADER_LENGTH = sizeof(PacketType) + sizeof(PacketVersion); unsigned char fileHeader[HEADER_LENGTH]; inputStream.readRawData((char*)&fileHeader, HEADER_LENGTH); @@ -1912,7 +1912,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr unsigned long dataLength = HEADER_LENGTH; // if so, read the first byte of the file and see if it matches the expected version code - PacketType::Value gotType; + PacketType gotType; memcpy(&gotType, dataAt, sizeof(gotType)); dataAt += sizeof(expectedType); @@ -2055,7 +2055,7 @@ void Octree::writeToJSONFile(const char* fileName, OctreeElement* element) { } // include the "bitstream" version - PacketType::Value expectedType = expectedDataPacketType(); + PacketType expectedType = expectedDataPacketType(); PacketVersion expectedVersion = versionForPacketType(expectedType); entityDescription["Version"] = (int) expectedVersion; @@ -2076,7 +2076,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* element) { if(file.is_open()) { qCDebug(octree, "Saving binary SVO to file %s...", fileName); - PacketType::Value expectedType = expectedDataPacketType(); + PacketType expectedType = expectedDataPacketType(); PacketVersion expectedVersion = versionForPacketType(expectedType); bool hasBufferBreaks = versionHasSVOfileBreaks(expectedVersion); diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index e00434be80..c8db9ba17a 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -228,11 +228,11 @@ public: // These methods will allow the OctreeServer to send your tree inbound edit packets of your // own definition. Implement these to allow your octree based server to support editing virtual bool getWantSVOfileVersions() const { return false; } - virtual PacketType::Value expectedDataPacketType() const { return PacketType::Unknown; } + virtual PacketType expectedDataPacketType() const { return PacketType::Unknown; } virtual bool canProcessVersion(PacketVersion thisVersion) const { return thisVersion == versionForPacketType(expectedDataPacketType()); } virtual PacketVersion expectedVersion() const { return versionForPacketType(expectedDataPacketType()); } - virtual bool handlesEditPacketType(PacketType::Value packetType) const { return false; } + virtual bool handlesEditPacketType(PacketType packetType) const { return false; } virtual int processEditPacketData(NLPacket& packet, const unsigned char* editData, int maxLength, const SharedNodePointer& sourceNode) { return 0; } diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index e2e17a6606..0d67e2391d 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -194,7 +194,7 @@ void OctreeEditPacketSender::queuePacketToNodes(std::unique_ptr packet // NOTE: editMessage - is JUST the octcode/color and does not contain the packet header -void OctreeEditPacketSender::queueOctreeEditMessage(PacketType::Value type, QByteArray& editMessage) { +void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, QByteArray& editMessage) { if (!_shouldSend) { return; // bail early @@ -315,7 +315,7 @@ void OctreeEditPacketSender::releaseQueuedPacket(const QUuid& nodeID, std::uniqu _releaseQueuedPacketMutex.unlock(); } -std::unique_ptr OctreeEditPacketSender::initializePacket(PacketType::Value type, int nodeClockSkew) { +std::unique_ptr OctreeEditPacketSender::initializePacket(PacketType type, int nodeClockSkew) { auto newPacket = NLPacket::create(type); // skip over sequence number for now; will be packed when packet is ready to be sent out diff --git a/libraries/octree/src/OctreeEditPacketSender.h b/libraries/octree/src/OctreeEditPacketSender.h index 8c77a1e388..be44aec88d 100644 --- a/libraries/octree/src/OctreeEditPacketSender.h +++ b/libraries/octree/src/OctreeEditPacketSender.h @@ -36,7 +36,7 @@ public: /// Queues a single edit message. Will potentially send a pending multi-command packet. Determines which server /// node or nodes the packet should be sent to. Can be called even before servers are known, in which case up to /// MaxPendingMessages will be buffered and processed when servers are known. - void queueOctreeEditMessage(PacketType::Value type, QByteArray& editMessage); + void queueOctreeEditMessage(PacketType type, QByteArray& editMessage); /// Releases all queued messages even if those messages haven't filled an MTU packet. This will move the packed message /// packets onto the send queue. If running in threaded mode, the caller does not need to do any further processing to @@ -81,7 +81,7 @@ public: // you must override these... virtual char getMyNodeType() const = 0; - virtual void adjustEditPacketForClockSkew(PacketType::Value type, QByteArray& buffer, int clockSkew) { } + virtual void adjustEditPacketForClockSkew(PacketType type, QByteArray& buffer, int clockSkew) { } void processNackPacket(NLPacket& packet, SharedNodePointer sendingNode); @@ -89,13 +89,13 @@ public slots: void nodeKilled(SharedNodePointer node); protected: - using EditMessagePair = std::pair; + using EditMessagePair = std::pair; bool _shouldSend; void queuePacketToNode(const QUuid& nodeID, std::unique_ptr packet); void queuePendingPacketToNodes(std::unique_ptr packet); void queuePacketToNodes(std::unique_ptr packet); - std::unique_ptr initializePacket(PacketType::Value type, int nodeClockSkew); + std::unique_ptr initializePacket(PacketType type, int nodeClockSkew); void releaseQueuedPacket(const QUuid& nodeUUID, std::unique_ptr packetBuffer); // releases specific queued packet void processPreServerExistsPackets(); diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index 5714ddcb03..ca50fc001e 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -33,7 +33,7 @@ void OctreeHeadlessViewer::init() { void OctreeHeadlessViewer::queryOctree() { char serverType = getMyNodeType(); - PacketType::Value packetType = getMyQueryMessageType(); + PacketType packetType = getMyQueryMessageType(); NodeToJurisdictionMap& jurisdictions = *_jurisdictionListener->getJurisdictions(); bool wantExtraDebugging = false; diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 439a07087c..2c9d587254 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -42,7 +42,7 @@ typedef quint64 OCTREE_PACKET_SENT_TIME; typedef uint16_t OCTREE_PACKET_INTERNAL_SECTION_SIZE; const int MAX_OCTREE_PACKET_SIZE = MAX_PACKET_SIZE; -// this is overly conservative - sizeof(PacketType) is 8 bytes but a packed PacketType::Value could be as small as one byte +// this is overly conservative - sizeof(PacketType) is 8 bytes but a packed PacketType could be as small as one byte const unsigned int OCTREE_PACKET_EXTRA_HEADERS_SIZE = sizeof(OCTREE_PACKET_FLAGS) + sizeof(OCTREE_PACKET_SEQUENCE) + sizeof(OCTREE_PACKET_SENT_TIME); diff --git a/libraries/octree/src/OctreeRenderer.h b/libraries/octree/src/OctreeRenderer.h index 85a193a3e6..032551d13e 100644 --- a/libraries/octree/src/OctreeRenderer.h +++ b/libraries/octree/src/OctreeRenderer.h @@ -36,8 +36,8 @@ public: virtual ~OctreeRenderer(); virtual char getMyNodeType() const = 0; - virtual PacketType::Value getMyQueryMessageType() const = 0; - virtual PacketType::Value getExpectedPacketType() const = 0; + virtual PacketType getMyQueryMessageType() const = 0; + virtual PacketType getExpectedPacketType() const = 0; virtual void renderElement(OctreeElement* element, RenderArgs* args) = 0; virtual float getSizeScale() const { return DEFAULT_OCTREE_SIZE_SCALE; } virtual int getBoundaryLevelAdjust() const { return 0; } From 19d0bf403c34003dd81142688b66e898094bd857 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Jul 2015 14:06:10 -0700 Subject: [PATCH 025/549] change NLPacket create signature for new headers --- .../src/octree/OctreeInboundPacketProcessor.cpp | 6 +++--- libraries/networking/src/NLPacket.cpp | 6 +++--- libraries/networking/src/NLPacket.h | 4 +++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index d664b35ead..8d76be2c78 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -153,7 +153,7 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer packet if (debugProcessPacket) { qDebug() << " --- inside while loop ---"; qDebug() << " maxSize=" << maxSize; - qDebug("OctreeInboundPacketProcessor::processPacket() %c " + qDebug("OctreeInboundPacketProcessor::processPacket() %hhu " "payload=%p payloadLength=%lld editData=%p payloadPosition=%lld maxSize=%d", packetType, packet->getPayload(), packet->getPayloadSize(), editData, packet->pos(), maxSize); @@ -191,7 +191,7 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer packet } if (debugProcessPacket) { - qDebug("OctreeInboundPacketProcessor::processPacket() DONE LOOPING FOR %c " + qDebug("OctreeInboundPacketProcessor::processPacket() DONE LOOPING FOR %hhu " "payload=%p payloadLength=%lld editData=%p payloadPosition=%lld", packetType, packet->getPayload(), packet->getPayloadSize(), editData, packet->pos()); } @@ -210,7 +210,7 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer packet } trackInboundPacket(nodeUUID, sequence, transitTime, editsInPacket, processTime, lockWaitTime); } else { - qDebug("unknown packet ignored... packetType=%d", packetType); + qDebug("unknown packet ignored... packetType=%hhu", packetType); } } diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 7d2726d9c0..221ef7da98 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -33,16 +33,16 @@ qint64 NLPacket::localHeaderSize() const { return localHeaderSize(_type); } -std::unique_ptr NLPacket::create(PacketType type, qint64 size) { +std::unique_ptr NLPacket::create(PacketType type, qint64 size, bool isReliable, bool isPartOfMessage) { std::unique_ptr packet; if (size == -1) { - packet = std::unique_ptr(new NLPacket(type)); + packet = std::unique_ptr(new NLPacket(type, isReliable, isPartOfMessage)); } else { // Fail with invalid size Q_ASSERT(size >= 0); - packet = std::unique_ptr(new NLPacket(type, size)); + packet = std::unique_ptr(new NLPacket(type, size, isReliable, isPartOfMessage)); } packet->open(QIODevice::ReadWrite); diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index 3045af3f09..cd2168cc4e 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -19,7 +19,9 @@ class NLPacket : public udt::Packet { Q_OBJECT public: - static std::unique_ptr create(PacketType type, qint64 size = -1); + static std::unique_ptr create(PacketType type, qint64 size = -1, + bool isReliable = false, bool isPartOfMessage = false); + static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); static std::unique_ptr fromBase(std::unique_ptr packet); From e5955e39b7d0d473a5997af6edad392800269f8d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Jul 2015 14:06:40 -0700 Subject: [PATCH 026/549] fix QDebug signature for Node --- libraries/networking/src/Node.cpp | 2 +- libraries/networking/src/Node.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 8aff66e3a0..355aa6994e 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -90,7 +90,7 @@ QDataStream& operator>>(QDataStream& in, Node& node) { return in; } -QDebug operator<<(QDebug debug, const Node &node) { +QDebug operator<<(QDebug debug, const Node& node) { debug.nospace() << NodeType::getNodeTypeName(node.getType()); if (node.getType() == NodeType::Unassigned) { debug.nospace() << " (1)"; diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 8cd524e539..178146c948 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -91,6 +91,6 @@ private: typedef QSharedPointer SharedNodePointer; Q_DECLARE_METATYPE(SharedNodePointer) -QDebug operator<<(QDebug debug, const Node &message); +QDebug operator<<(QDebug debug, const Node& node); #endif // hifi_Node_h From c5901c3f6b2ac0a0b23129551f4ce375f9aedbd3 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Jul 2015 15:00:32 -0700 Subject: [PATCH 027/549] Sequence Numbers helper class --- libraries/networking/src/udt/SeqNum.cpp | 38 +++++++++++ libraries/networking/src/udt/SeqNum.h | 84 +++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 libraries/networking/src/udt/SeqNum.cpp create mode 100644 libraries/networking/src/udt/SeqNum.h diff --git a/libraries/networking/src/udt/SeqNum.cpp b/libraries/networking/src/udt/SeqNum.cpp new file mode 100644 index 0000000000..29347a9249 --- /dev/null +++ b/libraries/networking/src/udt/SeqNum.cpp @@ -0,0 +1,38 @@ +// +// SeqNum.cpp +// +// +// Created by Clement on 7/23/15. +// Copyright 2015 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 "SeqNum.h" + +namespace udt { + +int seqcmp(const SeqNum& seq1, const SeqNum& seq2) { + return (glm::abs(seq1._value - seq2._value) < SeqNum::THRESHOLD) ? (seq1._value - seq2._value) + : (seq2._value - seq1._value); +} + +int seqlen(const SeqNum& seq1, const SeqNum& seq2) { + return (seq1._value <= seq2._value) ? (seq2._value - seq1._value + 1) + : (seq2._value - seq1._value + SeqNum::MAX + 2); +} + +int seqoff(const SeqNum& seq1, const SeqNum& seq2) { + if (glm::abs(seq1._value - seq2._value) < SeqNum::THRESHOLD) { + return seq2._value - seq1._value; + } + + if (seq1._value < seq2._value) { + return seq2._value - seq1._value - SeqNum::MAX - 1; + } + + return seq2._value - seq1._value + SeqNum::MAX + 1; +} + +} diff --git a/libraries/networking/src/udt/SeqNum.h b/libraries/networking/src/udt/SeqNum.h new file mode 100644 index 0000000000..058ddcb6cc --- /dev/null +++ b/libraries/networking/src/udt/SeqNum.h @@ -0,0 +1,84 @@ +// +// SeqNum.h +// libraries/networking/src/udt +// +// Created by Clement on 7/23/15. +// Copyright 2015 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 +// + +#ifndef hifi_SeqNum_h +#define hifi_SeqNum_h + +#include + +namespace udt { + +class SeqNum { +public: + // Base type of sequence numbers + using Type = uint32_t; + + // Values are for 29 bit SeqNum + static const Type THRESHOLD = 0x0FFFFFFF; // threshold for comparing sequence numbers + static const Type MAX = 0x1FFFFFFF; // maximum sequence number used in UDT + + SeqNum() : _value(0) {} + + // Only explicit conversions + explicit SeqNum(Type value) { *this = value; } + explicit operator Type() { return _value; } + + inline SeqNum& operator++() { + _value = (_value == MAX) ? 0 : ++_value; + return *this; + } + inline SeqNum& operator--() { + _value = (_value == 0) ? MAX : --_value; + return *this; + } + inline SeqNum operator++(int) { + SeqNum before = *this; + (*this)++; + return before; + } + inline SeqNum operator--(int) { + SeqNum before = *this; + (*this)--; + return before; + } + + inline SeqNum& operator=(Type value) { + _value = (value <= MAX) ? value : MAX; + return *this; + } + inline SeqNum& operator=(SeqNum& other) { + _value = other._value; + return *this; + } + inline SeqNum& operator+=(Type inc) { + _value = (_value + inc > MAX) ? _value + inc - (MAX + 1) : _value + inc; + return *this; + } + inline SeqNum& operator-=(Type dec) { + _value = (_value < dec) ? MAX - (dec - _value + 1) : _value - dec; + return *this; + } + + friend int seqcmp(const SeqNum& seq1, const SeqNum& seq2); + friend int seqlen(const SeqNum& seq1, const SeqNum& seq2); + friend int seqoff(const SeqNum& seq1, const SeqNum& seq2); + +private: + Type _value; +}; + +int seqcmp(const SeqNum& seq1, const SeqNum& seq2); +int seqlen(const SeqNum& seq1, const SeqNum& seq2); +int seqoff(const SeqNum& seq1, const SeqNum& seq2); + +} + +#endif // hifi_SeqNum_h From 82545df26615599499d252bf8f367bf95f356c23 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Jul 2015 15:01:46 -0700 Subject: [PATCH 028/549] Added msecTimestampNow as usecTimestampNow narrowing --- libraries/shared/src/SharedUtil.cpp | 4 ++++ libraries/shared/src/SharedUtil.h | 1 + 2 files changed, 5 insertions(+) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index f78c8c47e0..d73e8f446e 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -39,6 +39,10 @@ void usecTimestampNowForceClockSkew(int clockSkew) { ::usecTimestampNowAdjust = clockSkew; } +quint64 msecTimestampNow(bool wantDebug) { + return usecTimestampNow() / 1000; +} + quint64 usecTimestampNow(bool wantDebug) { static bool usecTimestampNowIsInitialized = false; static qint64 TIME_REFERENCE = 0; // in usec diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 17a32e7910..a60c0defd0 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -64,6 +64,7 @@ inline bool operator!=(const xColor& lhs, const xColor& rhs) // Use a custom User-Agent to avoid ModSecurity filtering, e.g. by hosting providers. const QByteArray HIGH_FIDELITY_USER_AGENT = "Mozilla/5.0 (HighFidelityInterface)"; +quint64 msecTimestampNow(bool wantDebug = false); quint64 usecTimestampNow(bool wantDebug = false); void usecTimestampNowForceClockSkew(int clockSkew); From 9a51aef712e556fa9ccda96ec2c6272a84ae2476 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Jul 2015 15:02:34 -0700 Subject: [PATCH 029/549] Added congestion control base classes --- .../networking/src/udt/CongestionControl.cpp | 148 ++++++++++++++++++ .../networking/src/udt/CongestionControl.h | 115 ++++++++++++++ 2 files changed, 263 insertions(+) create mode 100644 libraries/networking/src/udt/CongestionControl.cpp create mode 100644 libraries/networking/src/udt/CongestionControl.h diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp new file mode 100644 index 0000000000..75ebc0929c --- /dev/null +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -0,0 +1,148 @@ +// +// CongestionControl.cpp +// +// +// Created by Clement on 7/23/15. +// Copyright 2015 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 "CongestionControl.h" + +#include + +namespace udt { + +void UdtCC::init() { + _rcInterval = _synInterval; + _lastRCTime = usecTimestampNow(); + setAckTimer(_rcInterval); + + _lastAck = _sendCurrSeqNum; + _lastDecSeq = SeqNum::MAX; + + _congestionWindowSize = 16.0; + _packetSendPeriod = 1.0; +} + +void UdtCC::onACK(SeqNum ackNum) { + int64_t B = 0; + double inc = 0; + // Note: 1/24/2012 + // The minimum increase parameter is increased from "1.0 / _mss" to 0.01 + // because the original was too small and caused sending rate to stay at low level + // for long time. + const double min_inc = 0.01; + + uint64_t currtime = usecTimestampNow(); + if (currtime - _lastRCTime < (uint64_t)_rcInterval) { + return; + } + + _lastRCTime = currtime; + + if (_slowStart) { + _congestionWindowSize += seqlen(_lastAck, ackNum); + _lastAck = ackNum; + + if (_congestionWindowSize > _maxCongestionWindowSize) { + _slowStart = false; + if (_recvieveRate > 0) { + _packetSendPeriod = 1000000.0 / _recvieveRate; + } else { + _packetSendPeriod = (_rtt + _rcInterval) / _congestionWindowSize; + } + } + } else { + _congestionWindowSize = _recvieveRate / 1000000.0 * (_rtt + _rcInterval) + 16; + } + + // During Slow Start, no rate increase + if (_slowStart) { + return; + } + + if (_loss) { + _loss = false; + return; + } + + B = (int64_t)(_bandwidth - 1000000.0 / _packetSendPeriod); + if ((_packetSendPeriod > _lastDecPeriod) && ((_bandwidth / 9) < B)) { + B = _bandwidth / 9; + } + if (B <= 0) { + inc = min_inc; + } else { + // inc = max(10 ^ ceil(log10( B * MSS * 8 ) * Beta / MSS, 1/MSS) + // Beta = 1.5 * 10^(-6) + + inc = pow(10.0, ceil(log10(B * _mss * 8.0))) * 0.0000015 / _mss; + + if (inc < min_inc) { + inc = min_inc; + } + } + + _packetSendPeriod = (_packetSendPeriod * _rcInterval) / (_packetSendPeriod * inc + _rcInterval); +} + +void UdtCC::onLoss(const std::vector& losslist) { + //Slow Start stopped, if it hasn't yet + if (_slowStart) { + _slowStart = false; + if (_recvieveRate > 0) { + // Set the sending rate to the receiving rate. + _packetSendPeriod = 1000000.0 / _recvieveRate; + return; + } + // If no receiving rate is observed, we have to compute the sending + // rate according to the current window size, and decrease it + // using the method below. + _packetSendPeriod = _congestionWindowSize / (_rtt + _rcInterval); + } + + _loss = true; + + if (seqcmp(losslist[0], _lastDecSeq) > 0) { + _lastDecPeriod = _packetSendPeriod; + _packetSendPeriod = ceil(_packetSendPeriod * 1.125); + + _avgNAKNum = (int)ceil(_avgNAKNum * 0.875 + _nakCount * 0.125); + _nakCount = 1; + _decCount = 1; + + _lastDecSeq = _sendCurrSeqNum; + + // remove global synchronization using randomization + srand((uint32_t)_lastDecSeq); + _decRandom = (int)ceil(_avgNAKNum * (double(rand()) / RAND_MAX)); + if (_decRandom < 1) + _decRandom = 1; + } else if ((_decCount ++ < 5) && (0 == (++ _nakCount % _decRandom))) { + // 0.875^5 = 0.51, rate should not be decreased by more than half within a congestion period + _packetSendPeriod = ceil(_packetSendPeriod * 1.125); + _lastDecSeq = _sendCurrSeqNum; + } +} + +void UdtCC::onTimeout() { + if (_slowStart) { + _slowStart = false; + if (_recvieveRate > 0) { + _packetSendPeriod = 1000000.0 / _recvieveRate; + } else { + _packetSendPeriod = _congestionWindowSize / (_rtt + _rcInterval); + } + } else { + /* + _lastDecPeriod = _packetSendPeriod; + _packetSendPeriod = ceil(_packetSendPeriod * 2); + _lastDecSeq = _lastAck; + */ + } +} + +} \ No newline at end of file diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h new file mode 100644 index 0000000000..fdf8803ec0 --- /dev/null +++ b/libraries/networking/src/udt/CongestionControl.h @@ -0,0 +1,115 @@ +// +// CongestionControl.h +// +// +// Created by Clement on 7/23/15. +// Copyright 2015 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 +// + +#ifndef hifi_CongestionControl_h +#define hifi_CongestionControl_h + +#include + +#include "SeqNum.h" + +namespace udt { + +class Packet; + +class CongestionControl { +public: + static const int32_t DEFAULT_SYN_INTERVAL = 10000; // 10 ms + + CongestionControl() {} + virtual ~CongestionControl() {} + + virtual void init() {} + virtual void close() {} + virtual void onAck(SeqNum ackNum) {} + virtual void onLoss(const std::vector& lossList) {} + virtual void onPacketSent(const Packet& packet) {} + virtual void onPacketReceived(const Packet& packet) {} + +protected: + void setAckTimer(int syn) { _ackPeriod = (syn > _synInterval) ? _synInterval : syn; } + void setAckInterval(int interval) { _ackInterval = interval; } + void setRto(int rto) { _userDefinedRto = true; _rto = rto; } + + int32_t _synInterval = DEFAULT_SYN_INTERVAL; // UDT constant parameter, SYN + + double _packetSendPeriod = 1.0; // Packet sending period, in microseconds + double _congestionWindowSize = 16.0; // Congestion window size, in packets + + int _bandwidth = 0; // estimated bandwidth, packets per second + double _maxCongestionWindowSize = 0.0; // maximum cwnd size, in packets + + int _mss = 0; // Maximum Packet Size, including all packet headers + SeqNum _sendCurrSeqNum; // current maximum seq num sent out + int _recvieveRate = 0; // packet arrive rate at receiver side, packets per second + int _rtt = 0; // current estimated RTT, microsecond + +private: + CongestionControl(const CongestionControl& other) = delete; + CongestionControl& operator=(const CongestionControl& other) = delete; + + void setMss(int mss) { _mss = mss; } + void setMaxCongestionWindowSize(int window) { _maxCongestionWindowSize = window; } + void setBandwidth(int bandwidth) { _bandwidth = bandwidth; } + void setSndCurrSeqNum(SeqNum seqNum) { _sendCurrSeqNum = seqNum; } + void setRcvRate(int rate) { _recvieveRate = rate; } + void setRtt(int rtt) { _rtt = rtt; } + + int _ackPeriod = 0; // Periodical timer to send an ACK, in milliseconds + int _ackInterval = 0; // How many packets to send one ACK, in packets + + bool _userDefinedRto = false; // if the RTO value is defined by users + int _rto = -1; // RTO value, microseconds +}; + + +class CongestionControlVirtualFactory { +public: + virtual ~CongestionControlVirtualFactory() {} + + virtual std::unique_ptr create() = 0; +}; + +template class CongestionControlFactory: public CongestionControlVirtualFactory +{ +public: + virtual ~CongestionControlFactory() {} + + virtual std::unique_ptr create() { return std::unique_ptr(new T()); } +}; + +class UdtCC: public CongestionControl { +public: + UdtCC() {} + +public: + virtual void init(); + virtual void onACK(SeqNum ackNum); + virtual void onLoss(const std::vector& lossList); + virtual void onTimeout(); + +private: + int _rcInterval = 0; // UDT Rate control interval + uint64_t _lastRCTime = 0; // last rate increase time + bool _slowStart = true; // if in slow start phase + SeqNum _lastAck; // last ACKed seq num + bool _loss = false; // if loss happened since last rate increase + SeqNum _lastDecSeq; // max pkt seq num sent out when last decrease happened + double _lastDecPeriod = 1; // value of pktsndperiod when last decrease happened + int _nakCount = 0; // NAK counter + int _decRandom = 1; // random threshold on decrease by number of loss events + int _avgNAKNum = 0; // average number of NAKs per congestion + int _decCount = 0; // number of decreases in a congestion epoch +}; + +} + +#endif // hifi_CongestionControl_h \ No newline at end of file From bf9bfb4575730f01f034f981712f845e8544301b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Jul 2015 15:07:20 -0700 Subject: [PATCH 030/549] Add AssetServer --- assignment-client/src/assets/AssetServer.cpp | 149 +++++++++++++++++++ assignment-client/src/assets/AssetServer.h | 40 +++++ 2 files changed, 189 insertions(+) create mode 100644 assignment-client/src/assets/AssetServer.cpp create mode 100644 assignment-client/src/assets/AssetServer.h diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp new file mode 100644 index 0000000000..1a384271e0 --- /dev/null +++ b/assignment-client/src/assets/AssetServer.cpp @@ -0,0 +1,149 @@ +// +// AssetServer.cpp +// +// Created by Ryan Huffman on 2015/07/21 +// Copyright 2015 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 "AssetServer.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server"; +const int HASH_HEX_LENGTH = 32; +using MessageID = int; + +AssetServer::AssetServer(NLPacket& packet) : ThreadedAssignment(packet) { + auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); + packetReceiver.registerListener(PacketType::AssetGet, this, "handleAssetGet"); + packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload"); +} + +AssetServer::~AssetServer() { +} + +void AssetServer::run() { + ThreadedAssignment::commonInit(ASSET_SERVER_LOGGING_TARGET_NAME, NodeType::AssetServer); + + auto nodeList = DependencyManager::get(); + nodeList->addNodeTypeToInterestSet(NodeType::Agent); + + _resourcesDirectory = QDir(QCoreApplication::applicationDirPath()).filePath("resources/assets"); + if (!_resourcesDirectory.exists()) { + qDebug() << "Creating resources directory"; + _resourcesDirectory.mkpath("."); + } + qDebug() << "Serving files from: " << _resourcesDirectory.path(); + + // Scan for new files + qDebug() << "Looking for new files in asset directory"; + auto files = _resourcesDirectory.entryInfoList(QDir::Files); + QRegExp filenameRegex { "^[a-f0-9]{32}$" }; + for (auto fileInfo : files) { + auto filename = fileInfo.fileName(); + if (!filenameRegex.exactMatch(filename)) { + qDebug() << "Found file: " << filename; + if (!fileInfo.isReadable()) { + qDebug() << "\tCan't open file for reading: " << filename; + continue; + } + } + } + + while (!_isFinished) { + // since we're a while loop we need to help Qt's event processing + QCoreApplication::processEvents(); + } +} + +void AssetServer::handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode) { + QByteArray assetHash; + + if (packet->getPayloadSize() < HASH_HEX_LENGTH) { + qDebug() << "ERROR bad file request"; + return; + } + + assetHash = packet->read(HASH_HEX_LENGTH); + qDebug() << "Got a request for the file: " << assetHash; + + // We need to reply... + QFile file { _resourcesDirectory.filePath(QString(assetHash)) }; + qDebug() << "Opening file: " << QString(QFileInfo(assetHash).fileName()); + bool found = file.open(QIODevice::ReadOnly); + + auto assetPacket = NLPacket::create(PacketType::AssetGetReply); + + assetPacket->write(assetHash, HASH_HEX_LENGTH); + assetPacket->writePrimitive(found); + + const int MAX_LENGTH = 1024; + + if (found) { + QByteArray data = file.read(MAX_LENGTH); + assetPacket->writePrimitive(data.size()); + assetPacket->write(data, data.size()); + } else { + qDebug() << "File not found"; + } + + auto nodeList = DependencyManager::get(); + nodeList->sendPacket(std::move(assetPacket), *senderNode); +} + +void AssetServer::handleAssetUpload(QSharedPointer packet, SharedNodePointer senderNode) { + MessageID messageID; + packet->readPrimitive(&messageID); + + char extensionLength; + packet->readPrimitive(&extensionLength); + + char extension[extensionLength]; + packet->read(extension, extensionLength); + + qDebug() << "Got extension: " << extension; + + int fileSize; + packet->readPrimitive(&fileSize); + + const int MAX_LENGTH = 1024; + fileSize = std::min(MAX_LENGTH, fileSize); + qDebug() << "Receiving a file of size " << fileSize; + + QByteArray data = packet->read(fileSize); + + QString hash = QString(QCryptographicHash::hash(data, QCryptographicHash::Md5).toHex()); + + qDebug() << "Got data: (" << hash << ") " << data; + + QFile file { _resourcesDirectory.filePath(QString(hash)) }; + + if (file.exists()) { + qDebug() << "[WARNING] This file already exists"; + } else { + file.open(QIODevice::WriteOnly); + file.write(data); + } + + auto replyPacket = NLPacket::create(PacketType::AssetUploadReply); + + replyPacket->writePrimitive(messageID); + + replyPacket->writePrimitive(true); + replyPacket->write(hash.toLatin1().constData(), HASH_HEX_LENGTH); + + auto nodeList = DependencyManager::get(); + nodeList->sendPacket(std::move(replyPacket), *senderNode); +} diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h new file mode 100644 index 0000000000..ef658fae4a --- /dev/null +++ b/assignment-client/src/assets/AssetServer.h @@ -0,0 +1,40 @@ +// +// AssetServer.h +// +// Created by Ryan Huffman on 2015/07/21 +// Copyright 2015 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 +// + +#ifndef hifi_AssetServer_h +#define hifi_AssetServer_h + +#include + +#include + +class AssetServer : public ThreadedAssignment { + Q_OBJECT +public: + AssetServer(NLPacket& packet); + ~AssetServer(); + + enum ServerResponse { + ASSET_NOT_FOUND = 0, + ASSET_UPLOADED = 1, + }; + +public slots: + void run(); + +private slots: + void handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode); + void handleAssetUpload(QSharedPointer packet, SharedNodePointer senderNode); + +private: + QDir _resourcesDirectory; +}; + +#endif From 4c42edf7fabed01521dcb8174763c6f09a3ca1ec Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Jul 2015 15:07:40 -0700 Subject: [PATCH 031/549] Add AssetServer to AssignmentFactory --- assignment-client/src/AssignmentFactory.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/assignment-client/src/AssignmentFactory.cpp b/assignment-client/src/AssignmentFactory.cpp index c6ad2c9f09..cacc523ebd 100644 --- a/assignment-client/src/AssignmentFactory.cpp +++ b/assignment-client/src/AssignmentFactory.cpp @@ -16,6 +16,7 @@ #include "audio/AudioMixer.h" #include "avatars/AvatarMixer.h" #include "entities/EntityServer.h" +#include "assets/AssetServer.h" ThreadedAssignment* AssignmentFactory::unpackAssignment(NLPacket& packet) { @@ -33,6 +34,8 @@ ThreadedAssignment* AssignmentFactory::unpackAssignment(NLPacket& packet) { return new Agent(packet); case Assignment::EntityServerType: return new EntityServer(packet); + case Assignment::AssetServerType: + return new AssetServer(packet); default: return NULL; } From ee5a1028f796c6c2a4dfd17f6cab58875d6a729e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Jul 2015 15:08:38 -0700 Subject: [PATCH 032/549] Add AssetClient --- libraries/networking/src/AssetClient.cpp | 124 +++++++++++++++++++++++ libraries/networking/src/AssetClient.h | 51 ++++++++++ 2 files changed, 175 insertions(+) create mode 100644 libraries/networking/src/AssetClient.cpp create mode 100644 libraries/networking/src/AssetClient.h diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp new file mode 100644 index 0000000000..e8131a40f2 --- /dev/null +++ b/libraries/networking/src/AssetClient.cpp @@ -0,0 +1,124 @@ +// +// AssetClient.cpp +// +// Created by Ryan Huffman on 2015/07/21 +// Copyright 2015 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 "AssetClient.h" + +#include "NodeList.h" +#include "PacketReceiver.h" + +const int HASH_HEX_LENGTH = 32; +MessageID AssetClient::_currentID = 0; + +AssetClient::AssetClient() { + auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); + packetReceiver.registerListener(PacketType::AssetGetReply, this, "handleAssetGetReply"); + packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); +} + +bool AssetClient::getAsset(QString hash, ReceivedAssetCallback callback) { + if (hash.length() != 32) { + qDebug() << "Invalid hash size"; + return false; + } + + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + + if (assetServer) { + auto packet = NLPacket::create(PacketType::AssetGet); + packet->write(hash.toLatin1().constData(), 32); + nodeList->sendPacket(std::move(packet), *assetServer); + + _pendingRequests[hash] = callback; + + return true; + } + + return false; +} + +void AssetClient::handleAssetGetReply(QSharedPointer packet, SharedNodePointer senderNode) { + auto assetHash = packet->read(HASH_HEX_LENGTH); + qDebug() << "Got reply for asset: " << assetHash; + + bool success; + packet->readPrimitive(&success); + QByteArray data; + + if (success) { + int length; + packet->readPrimitive(&length); + char assetData[length]; + packet->read(assetData, length); + + data = QByteArray(assetData, length); + } else { + qDebug() << "Failure getting asset"; + } + + if (_pendingRequests.contains(assetHash)) { + auto callback = _pendingRequests.take(assetHash); + callback(success, data); + } +} + +bool AssetClient::uploadAsset(QByteArray data, QString extension, UploadResultCallback callback) { + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + if (assetServer) { + auto packet = NLPacket::create(PacketType::AssetUpload); + + auto messageID = _currentID++; + packet->writePrimitive(messageID); + + packet->writePrimitive(static_cast(extension.length())); + packet->write(extension.toLatin1().constData(), extension.length()); + + qDebug() << "Extension length: " << extension.length(); + qDebug() << "Extension: " << extension; + + int size = data.length(); + packet->writePrimitive(size); + packet->write(data.constData(), size); + + nodeList->sendPacket(std::move(packet), *assetServer); + + _pendingUploads[messageID] = callback; + + return true; + } + return false; +} + +void AssetClient::handleAssetUploadReply(QSharedPointer packet, SharedNodePointer senderNode) { + qDebug() << "Got asset upload reply"; + MessageID messageID; + packet->readPrimitive(&messageID); + + bool success; + packet->readPrimitive(&success); + + QString hashString { "" }; + + if (success) { + auto hashData = packet->read(HASH_HEX_LENGTH); + + hashString = QString(hashData); + + qDebug() << "Hash: " << hashString; + } else { + qDebug() << "Error uploading file"; + } + + if (_pendingUploads.contains(messageID)) { + auto callback = _pendingUploads.take(messageID); + callback(success, hashString); + } +} diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h new file mode 100644 index 0000000000..87da601563 --- /dev/null +++ b/libraries/networking/src/AssetClient.h @@ -0,0 +1,51 @@ +// +// AssetClient.h +// +// Created by Ryan Huffman on 2015/07/21 +// Copyright 2015 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 +// + + +#ifndef hifi_AssetClient_h +#define hifi_AssetClient_h + +#include +#include + +#include + +#include "LimitedNodeList.h" +#include "NLPacket.h" + +using ReceivedAssetCallback = std::function; +using UploadResultCallback = std::function; +using MessageID = int; + +class AssetClient : public QObject, public Dependency { + Q_OBJECT +public: + AssetClient(); + + enum RequestResult { + SUCCESS = 0, + FAILURE, + TIMEOUT + }; + + bool getAsset(QString hash, ReceivedAssetCallback callback); + bool uploadAsset(QByteArray data, QString extension, UploadResultCallback callback); + +private slots: + void handleAssetGetReply(QSharedPointer packet, SharedNodePointer senderNode); + void handleAssetUploadReply(QSharedPointer packet, SharedNodePointer senderNode); + +private: + static MessageID _currentID; + QMap _pendingRequests; + QMap _pendingUploads; +}; + +#endif From 52e422198b338462259c0b1dd47ea5fb196a8df6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Jul 2015 15:09:59 -0700 Subject: [PATCH 033/549] Add AssetScriptingInterface --- interface/src/AssetScriptingInterface.cpp | 43 +++++++++++++++++++++++ interface/src/AssetScriptingInterface.h | 31 ++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 interface/src/AssetScriptingInterface.cpp create mode 100644 interface/src/AssetScriptingInterface.h diff --git a/interface/src/AssetScriptingInterface.cpp b/interface/src/AssetScriptingInterface.cpp new file mode 100644 index 0000000000..c03e9ee8c2 --- /dev/null +++ b/interface/src/AssetScriptingInterface.cpp @@ -0,0 +1,43 @@ +// +// AssetScriptingInterface.cpp +// +// Created by Ryan Huffman on 2015/07/22 +// Copyright 2015 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 "AssetScriptingInterface.h" + +#include + +#include +#include +#include +#include +#include + +#include + +const int HASH_HEX_LENGTH = 32; + +AssetScriptingInterface::AssetScriptingInterface() { +} + +QScriptValue AssetScriptingInterface::getAsset(QString url, QScriptValue callback) { + bool success = AssetManager::getAsset(QUrl(url), [callback](AssetRequestUpdateType type, QByteArray data) mutable { + auto result = callback.engine()->newVariant(data); + QList arguments { type == AssetRequestUpdateType::COMPLETE, result }; + callback.call(QScriptValue(), arguments); + }); + return success; +} + +QScriptValue AssetScriptingInterface::uploadAsset(QString data, QString extension, QScriptValue callback) { + auto assetClient = DependencyManager::get(); + return assetClient->uploadAsset(data.toLatin1(), extension, [callback](bool success, QString hash) mutable { + QList arguments { success, hash }; + auto result = callback.call(QScriptValue(), arguments); + }); +} diff --git a/interface/src/AssetScriptingInterface.h b/interface/src/AssetScriptingInterface.h new file mode 100644 index 0000000000..8c0f7a71a1 --- /dev/null +++ b/interface/src/AssetScriptingInterface.h @@ -0,0 +1,31 @@ +// +// AssetScriptingInterface.h +// +// Created by Ryan Huffman on 2015/07/22 +// Copyright 2015 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 +// + +#ifndef hifi_AssetScriptingInterface_h +#define hifi_AssetScriptingInterface_h + +#include +#include + +#include +#include +#include + +class AssetScriptingInterface : public QObject, public Dependency { + Q_OBJECT +public: + AssetScriptingInterface(); + +public slots: + QScriptValue getAsset(QString hash, QScriptValue callback); + QScriptValue uploadAsset(QString data, QString extension, QScriptValue callback); +}; + +#endif From 0b2e896ea48b7c0de6ca0e256a8abe24e48f8699 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Jul 2015 15:13:56 -0700 Subject: [PATCH 034/549] Add Asset-related types and packets --- interface/src/Application.cpp | 9 ++++++++- libraries/networking/src/Assignment.cpp | 2 ++ libraries/networking/src/Assignment.h | 3 ++- libraries/networking/src/NodeType.h | 1 + libraries/networking/src/udt/PacketHeaders.h | 6 +++++- 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7de69ef602..137f3ffa83 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -52,6 +52,8 @@ #include #include +#include +#include #include #include #include @@ -287,6 +289,8 @@ bool setupEssentials(int& argc, char** argv) { auto autoUpdater = DependencyManager::set(); auto pathUtils = DependencyManager::set(); auto actionFactory = DependencyManager::set(); + auto assetClient = DependencyManager::set(); + auto assetScriptingInterface = DependencyManager::set(); return true; } @@ -494,7 +498,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : // tell the NodeList instance who to tell the domain server we care about nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer - << NodeType::EntityServer); + << NodeType::EntityServer << NodeType::AssetServer); // connect to the packet sent signal of the _entityEditSender connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent); @@ -1738,6 +1742,7 @@ void Application::sendPingPackets() { case NodeType::AvatarMixer: case NodeType::AudioMixer: case NodeType::EntityServer: + case NodeType::AssetServer: return true; default: return false; @@ -3750,6 +3755,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri qScriptRegisterMetaType(scriptEngine, RayToOverlayIntersectionResultToScriptValue, RayToOverlayIntersectionResultFromScriptValue); + scriptEngine->registerGlobalObject("Assets", DependencyManager::get().data()); + QScriptValue windowValue = scriptEngine->registerGlobalObject("Window", DependencyManager::get().data()); scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, LocationScriptingInterface::locationSetter, windowValue); diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index 293d86475f..795b775d25 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -27,6 +27,8 @@ Assignment::Type Assignment::typeForNodeType(NodeType_t nodeType) { return Assignment::AgentType; case NodeType::EntityServer: return Assignment::EntityServerType; + case NodeType::AssetServer: + return Assignment::AssetServerType; default: return Assignment::AllTypes; } diff --git a/libraries/networking/src/Assignment.h b/libraries/networking/src/Assignment.h index 67f861f850..db20c6d06a 100644 --- a/libraries/networking/src/Assignment.h +++ b/libraries/networking/src/Assignment.h @@ -33,7 +33,8 @@ public: UNUSED_1 = 4, UNUSED_2 = 5, EntityServerType = 6, - AllTypes = 7 + AssetServerType = 7, + AllTypes = 8 }; enum Command { diff --git a/libraries/networking/src/NodeType.h b/libraries/networking/src/NodeType.h index 4427b87158..ab3d4a1dbe 100644 --- a/libraries/networking/src/NodeType.h +++ b/libraries/networking/src/NodeType.h @@ -23,6 +23,7 @@ namespace NodeType { const NodeType_t Agent = 'I'; const NodeType_t AudioMixer = 'M'; const NodeType_t AvatarMixer = 'W'; + const NodeType_t AssetServer = 'A'; const NodeType_t Unassigned = 1; void init(); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 3f3f165e87..b133319a57 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -73,7 +73,11 @@ namespace PacketType { EntityQuery, EntityAdd, EntityErase, - EntityEdit + EntityEdit, + AssetGet, + AssetGetReply, + AssetUpload, + AssetUploadReply, }; }; From cf20701275cb858ed0903ac62ea0e2fee6fe56c7 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Jul 2015 15:14:25 -0700 Subject: [PATCH 035/549] Update soloNodeOfType to take NodeType_t --- libraries/networking/src/LimitedNodeList.cpp | 2 +- libraries/networking/src/LimitedNodeList.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index fdb3461c1f..2f3be63ba8 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -510,7 +510,7 @@ unsigned int LimitedNodeList::broadcastToNodes(std::unique_ptr packet, return n; } -SharedNodePointer LimitedNodeList::soloNodeOfType(char nodeType) { +SharedNodePointer LimitedNodeList::soloNodeOfType(NodeType_t nodeType) { return nodeMatchingPredicate([&](const SharedNodePointer& node){ return node->getType() == nodeType; }); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 33d490c960..c3980fd099 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -151,7 +151,7 @@ public: int updateNodeWithDataFromPacket(QSharedPointer packet, SharedNodePointer matchingNode); unsigned int broadcastToNodes(std::unique_ptr packet, const NodeSet& destinationNodeTypes); - SharedNodePointer soloNodeOfType(char nodeType); + SharedNodePointer soloNodeOfType(NodeType_t nodeType); void getPacketStats(float &packetsPerSecond, float &bytesPerSecond); void resetPacketStats(); From df47f1dd0bbfbfa54c51f5fa913c91c9d5851f14 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Jul 2015 15:20:37 -0700 Subject: [PATCH 036/549] add a BasePacket class for headerless packets --- libraries/avatars/src/AvatarData.cpp | 3 +- libraries/networking/src/LimitedNodeList.cpp | 19 +- libraries/networking/src/LimitedNodeList.h | 4 +- libraries/networking/src/NetworkPacket.cpp | 42 ----- libraries/networking/src/NetworkPacket.h | 37 ---- libraries/networking/src/PacketReceiver.cpp | 14 +- libraries/networking/src/udt/BasePacket.cpp | 175 ++++++++++++++++++ libraries/networking/src/udt/BasePacket.h | 116 ++++++++++++ libraries/networking/src/udt/Packet.cpp | 129 ++----------- libraries/networking/src/udt/Packet.h | 72 +------ .../networking/src/udt/PacketHeaders.cpp | 4 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- libraries/networking/src/udt/Socket.cpp | 14 +- libraries/networking/src/udt/Socket.h | 7 +- libraries/octree/src/OctreePacketData.h | 13 +- libraries/octree/src/OctreeSceneStats.cpp | 2 +- 16 files changed, 358 insertions(+), 296 deletions(-) delete mode 100644 libraries/networking/src/NetworkPacket.cpp delete mode 100644 libraries/networking/src/NetworkPacket.h create mode 100644 libraries/networking/src/udt/BasePacket.cpp create mode 100644 libraries/networking/src/udt/BasePacket.h diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 19f1c35a2b..cb54278119 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -144,8 +144,7 @@ QByteArray AvatarData::toByteArray() { _headData->_isFaceTrackerConnected = true; } - QByteArray avatarDataByteArray; - avatarDataByteArray.resize(MAX_PACKET_SIZE); + QByteArray avatarDataByteArray(udt::MAX_PACKET_SIZE, 0); unsigned char* destinationBuffer = reinterpret_cast(avatarDataByteArray.data()); unsigned char* startPosition = destinationBuffer; diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index acac81f8ff..66165a95cc 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -105,9 +105,6 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short _nodeSocket.setPacketFilterOperator(std::bind(&LimitedNodeList::isPacketVerified, this, _1)); _packetStatTimer.start(); - - // make sure we handle STUN response packets - _packetReceiver->registerListener(PacketType::StunResponse, this, "processSTUNResponse"); } void LimitedNodeList::setSessionUUID(const QUuid& sessionUUID) { @@ -239,7 +236,7 @@ bool LimitedNodeList::packetSourceAndHashMatch(const udt::Packet& packet) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("Packet of type \\d+ \\([\\sa-zA-Z]+\\) received from unknown node with UUID"); - qCDebug(networking) << "Packet of type" << headerType << "(" << qPrintable(nameForPacketType(headerType)) << ")" + qCDebug(networking) << "Packet of type" << headerType << "received from unknown node with UUID" << qPrintable(uuidStringWithoutCurlyBraces(sourceID)); } } @@ -611,7 +608,7 @@ void LimitedNodeList::sendSTUNRequest() { _nodeSocket.writeDatagram(stunRequestPacket, sizeof(stunRequestPacket), _stunSockAddr); } -bool LimitedNodeList::processSTUNResponse(QSharedPointer packet) { +void LimitedNodeList::processSTUNResponse(std::unique_ptr packet) { // check the cookie to make sure this is actually a STUN response // and read the first attribute and make sure it is a XOR_MAPPED_ADDRESS const int NUM_BYTES_MESSAGE_TYPE_AND_LENGTH = 4; @@ -672,8 +669,6 @@ bool LimitedNodeList::processSTUNResponse(QSharedPointer packet) { flagTimeForConnectionStep(ConnectionStep::SetPublicSocketFromSTUN); } - - return true; } } else { // push forward attributeStartIndex by the length of this attribute @@ -688,8 +683,6 @@ bool LimitedNodeList::processSTUNResponse(QSharedPointer packet) { } } } - - return false; } void LimitedNodeList::startSTUNPublicSocketUpdate() { @@ -699,7 +692,7 @@ void LimitedNodeList::startSTUNPublicSocketUpdate() { // if we don't know the STUN IP yet we need to have ourselves be called once it is known if (_stunSockAddr.getAddress().isNull()) { connect(&_stunSockAddr, &HifiSockAddr::lookupCompleted, this, &LimitedNodeList::startSTUNPublicSocketUpdate); - connect(&_stunSockAddr, &HifiSockAddr::lookupCompleted, this, &LimitedNodeList::addSTUNSockAddrToUnfiltered); + connect(&_stunSockAddr, &HifiSockAddr::lookupCompleted, this, &LimitedNodeList::addSTUNHandlerToUnfiltered); // in case we just completely fail to lookup the stun socket - add a 10s timeout that will trigger the fail case const quint64 STUN_DNS_LOOKUP_TIMEOUT_MSECS = 10 * 1000; @@ -730,6 +723,12 @@ void LimitedNodeList::possiblyTimeoutSTUNAddressLookup() { } } +void LimitedNodeList::addSTUNHandlerToUnfiltered() { + // make ourselves the handler of STUN packets when they come in + using std::placeholders::_1; + _nodeSocket.addUnfilteredHandler(_stunSockAddr, std::bind(&LimitedNodeList::processSTUNResponse, this, _1)); +} + void LimitedNodeList::stopInitialSTUNUpdate(bool success) { _hasCompletedInitialSTUN = true; diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 4047668350..e09617b88f 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -225,7 +225,6 @@ public slots: void startSTUNPublicSocketUpdate(); virtual void sendSTUNRequest(); - bool processSTUNResponse(QSharedPointer packet); void killNodeWithUUID(const QUuid& nodeUUID); @@ -256,6 +255,7 @@ protected: bool isPacketVerified(const udt::Packet& packet); bool packetVersionMatch(const udt::Packet& packet); bool packetSourceAndHashMatch(const udt::Packet& packet); + void processSTUNResponse(std::unique_ptr packet); void handleNodeKill(const SharedNodePointer& node); @@ -310,7 +310,7 @@ protected: private slots: void flagTimeForConnectionStep(ConnectionStep connectionStep, quint64 timestamp); void possiblyTimeoutSTUNAddressLookup(); - void addSTUNSockAddrToUnfiltered() { _nodeSocket.addUnfilteredSockAddr(_stunSockAddr); } // called once STUN socket known + void addSTUNHandlerToUnfiltered(); // called once STUN socket known }; #endif // hifi_LimitedNodeList_h diff --git a/libraries/networking/src/NetworkPacket.cpp b/libraries/networking/src/NetworkPacket.cpp deleted file mode 100644 index e99ef1ab8b..0000000000 --- a/libraries/networking/src/NetworkPacket.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// -// NetworkPacket.cpp -// libraries/networking/src -// -// Created by Brad Hefta-Gaub on 8/9/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 -#include -#include - -#include "SharedUtil.h" -#include "NetworkLogging.h" - -#include "NetworkPacket.h" - -void NetworkPacket::copyContents(const SharedNodePointer& node, const QByteArray& packet) { - if (packet.size() && packet.size() <= MAX_PACKET_SIZE) { - _node = node; - _byteArray = packet; - } else { - qCDebug(networking, ">>> NetworkPacket::copyContents() unexpected length = %d", packet.size()); - } -} - -NetworkPacket::NetworkPacket(const NetworkPacket& packet) { - copyContents(packet.getNode(), packet.getByteArray()); -} - -NetworkPacket::NetworkPacket(const SharedNodePointer& node, const QByteArray& packet) { - copyContents(node, packet); -}; - -// copy assignment -NetworkPacket& NetworkPacket::operator=(NetworkPacket const& other) { - copyContents(other.getNode(), other.getByteArray()); - return *this; -} diff --git a/libraries/networking/src/NetworkPacket.h b/libraries/networking/src/NetworkPacket.h deleted file mode 100644 index a7e5a6b3cd..0000000000 --- a/libraries/networking/src/NetworkPacket.h +++ /dev/null @@ -1,37 +0,0 @@ -// -// NetworkPacket.h -// libraries/networking/src -// -// Created by Brad Hefta-Gaub on 8/9/13. -// Copyright 2013 High Fidelity, Inc. -// -// A really simple class that stores a network packet between being received and being processed -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_NetworkPacket_h -#define hifi_NetworkPacket_h - -#include "NodeList.h" - -/// Storage of not-yet processed inbound, or not yet sent outbound generic UDP network packet -class NetworkPacket { -public: - NetworkPacket() { } - NetworkPacket(const NetworkPacket& packet); // copy constructor - NetworkPacket& operator= (const NetworkPacket& other); // copy assignment - NetworkPacket(const SharedNodePointer& node, const QByteArray& byteArray); - - const SharedNodePointer& getNode() const { return _node; } - const QByteArray& getByteArray() const { return _byteArray; } - -private: - void copyContents(const SharedNodePointer& node, const QByteArray& byteArray); - - SharedNodePointer _node; - QByteArray _byteArray; -}; - -#endif // hifi_NetworkPacket_h diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 1389f271bf..c2c65eed8f 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -139,8 +139,7 @@ QMetaMethod PacketReceiver::matchingMethodForListener(PacketType type, QObject* if (methodIndex < 0) { qDebug() << "PacketReceiver::registerListener expected a slot with one of the following signatures:" << possibleSignatures.toList() << "- but such a slot was not found." - << "Could not complete listener registration for type" - << type << "-" << nameForPacketType(type); + << "Could not complete listener registration for type" << type; } Q_ASSERT(methodIndex >= 0); @@ -160,7 +159,6 @@ void PacketReceiver::registerVerifiedListener(PacketType type, QObject* object, if (_packetListenerMap.contains(type)) { qDebug() << "Warning: Registering a packet listener for packet type" << type - << "(" << qPrintable(nameForPacketType(type)) << ")" << "that will remove a previously registered listener"; } @@ -204,7 +202,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { // setup a HifiSockAddr to read into HifiSockAddr senderSockAddr; - // setup an NLPacket from the data we just read + // setup an NLPacket from the packet we were passed auto nlPacket = NLPacket::fromBase(std::move(packet)); _inPacketCount++; @@ -286,8 +284,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { } if (!success) { - qDebug().nospace() << "Error delivering packet " << packetType - << " (" << qPrintable(nameForPacketType(packetType)) << ") to listener " + qDebug().nospace() << "Error delivering packet " << packetType << " to listener " << listener.first << "::" << qPrintable(listener.second.methodSignature()); } @@ -296,8 +293,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { } if (listenerIsDead) { - qDebug().nospace() << "Listener for packet" << nlPacket->getType() - << " (" << qPrintable(nameForPacketType(nlPacket->getType())) << ")" + qDebug().nospace() << "Listener for packet " << nlPacket->getType() << " has been destroyed. Removing from listener map."; it = _packetListenerMap.erase(it); @@ -308,7 +304,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { } } else { - qWarning() << "No listener found for packet type " << nameForPacketType(nlPacket->getType()); + qWarning() << "No listener found for packet type" << nlPacket->getType(); // insert a dummy listener so we don't print this again _packetListenerMap.insert(nlPacket->getType(), { nullptr, QMetaMethod() }); diff --git a/libraries/networking/src/udt/BasePacket.cpp b/libraries/networking/src/udt/BasePacket.cpp new file mode 100644 index 0000000000..d615f0cc1e --- /dev/null +++ b/libraries/networking/src/udt/BasePacket.cpp @@ -0,0 +1,175 @@ +// +// BasePacket.cpp +// libraries/networking/src/udt +// +// Created by Stephen Birarda on 2015-07-23. +// Copyright 2015 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 "BasePacket.h" + +using namespace udt; + +const qint64 BasePacket::PACKET_WRITE_ERROR = -1; + +std::unique_ptr BasePacket::create(qint64 size) { + auto packet = std::unique_ptr(new BasePacket(size)); + + packet->open(QIODevice::ReadWrite); + + return packet; +} + +std::unique_ptr BasePacket::fromReceivedPacket(std::unique_ptr data, + qint64 size, + const HifiSockAddr& senderSockAddr) { + // Fail with invalid size + Q_ASSERT(size >= 0); + + // allocate memory + auto packet = std::unique_ptr(new BasePacket(std::move(data), size, senderSockAddr)); + + packet->open(QIODevice::ReadOnly); + + return packet; +} + +BasePacket::BasePacket(qint64 size) { + auto maxPayload = maxPayloadSize(); + + if (size == -1) { + // default size of -1, means biggest packet possible + size = maxPayload; + } + + // Sanity check + Q_ASSERT(size >= 0 || size < maxPayload); + + _packetSize = size; + _packet.reset(new char[_packetSize]); + _payloadCapacity = _packetSize; + _payloadSize = 0; + _payloadStart = _packet.get(); +} + +BasePacket::BasePacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr) : + _packetSize(size), + _packet(std::move(data)), + _payloadStart(_packet.get()), + _payloadCapacity(size), + _payloadSize(size), + _senderSockAddr(senderSockAddr) +{ + +} + +BasePacket::BasePacket(const BasePacket& other) { + *this = other; +} + +BasePacket& BasePacket::operator=(const BasePacket& other) { + _packetSize = other._packetSize; + _packet = std::unique_ptr(new char[_packetSize]); + memcpy(_packet.get(), other._packet.get(), _packetSize); + + _payloadStart = _packet.get() + (other._payloadStart - other._packet.get()); + _payloadCapacity = other._payloadCapacity; + + _payloadSize = other._payloadSize; + + if (other.isOpen() && !isOpen()) { + open(other.openMode()); + } + + seek(other.pos()); + + return *this; +} + +BasePacket::BasePacket(BasePacket&& other) { + *this = std::move(other); +} + +BasePacket& BasePacket::operator=(BasePacket&& other) { + _packetSize = other._packetSize; + _packet = std::move(other._packet); + + _payloadStart = other._payloadStart; + _payloadCapacity = other._payloadCapacity; + + _payloadSize = other._payloadSize; + + _senderSockAddr = std::move(other._senderSockAddr); + + if (other.isOpen() && !isOpen()) { + open(other.openMode()); + } + + seek(other.pos()); + + return *this; +} + +void BasePacket::setPayloadSize(qint64 payloadSize) { + if (isWritable()) { + Q_ASSERT(payloadSize <= _payloadCapacity); + _payloadSize = payloadSize; + } else { + qDebug() << "You can not call setPayloadSize for a non-writeable Packet."; + Q_ASSERT(false); + } +} + +QByteArray BasePacket::read(qint64 maxSize) { + qint64 sizeToRead = std::min(size() - pos(), maxSize); + QByteArray data { QByteArray::fromRawData(getPayload() + pos(), sizeToRead) }; + seek(pos() + sizeToRead); + return data; +} + +bool BasePacket::reset() { + if (isWritable()) { + _payloadSize = 0; + } + + return QIODevice::reset(); +} + +qint64 BasePacket::writeData(const char* data, qint64 maxSize) { + + // make sure we have the space required to write this block + if (maxSize <= bytesAvailableForWrite()) { + qint64 currentPos = pos(); + + Q_ASSERT(currentPos < _payloadCapacity); + + // good to go - write the data + memcpy(_payloadStart + currentPos, data, maxSize); + + // keep track of _payloadSize so we can just write the actual data when packet is about to be sent + _payloadSize = std::max(currentPos + maxSize, _payloadSize); + + // return the number of bytes written + return maxSize; + } else { + // not enough space left for this write - return an error + return PACKET_WRITE_ERROR; + } +} + +qint64 BasePacket::readData(char* dest, qint64 maxSize) { + // we're either reading what is left from the current position or what was asked to be read + qint64 numBytesToRead = std::min(bytesLeftToRead(), maxSize); + + if (numBytesToRead > 0) { + int currentPosition = pos(); + + // read out the data + memcpy(dest, _payloadStart + currentPosition, numBytesToRead); + } + + return numBytesToRead; +} diff --git a/libraries/networking/src/udt/BasePacket.h b/libraries/networking/src/udt/BasePacket.h new file mode 100644 index 0000000000..cd31240d67 --- /dev/null +++ b/libraries/networking/src/udt/BasePacket.h @@ -0,0 +1,116 @@ +// +// BasePacket.h +// libraries/networking/src/udt +// +// Created by Stephen Birarda on 2015-07-23. +// Copyright 2015 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 +// + +#pragma once + +#ifndef hifi_BasePacket_h +#define hifi_BasePacket_h + +#include + +#include "../HifiSockAddr.h" + +namespace udt { + +static const int MAX_PACKET_SIZE = 1450; + +class BasePacket : public QIODevice { + Q_OBJECT +public: + static const qint64 PACKET_WRITE_ERROR; + + static std::unique_ptr create(qint64 size = -1); + static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); + + static qint64 maxPayloadSize() { return MAX_PACKET_SIZE; } // The maximum payload size this packet can use to fit in MTU + static qint64 localHeaderSize() { return 0; } // Current level's header size + + virtual qint64 totalHeadersSize() const { return 0; } // Cumulated size of all the headers + + // Payload direct access to the payload, use responsibly! + char* getPayload() { return _payloadStart; } + const char* getPayload() const { return _payloadStart; } + + // Return direct access to the entire packet, use responsibly! + char* getData() { return _packet.get(); } + const char* getData() const { return _packet.get(); } + + // Returns the size of the packet, including the header + qint64 getDataSize() const { return totalHeadersSize() + _payloadSize; } + + // Returns the size of the payload only + qint64 getPayloadSize() const { return _payloadSize; } + + // Allows a writer to change the size of the payload used when writing directly + void setPayloadSize(qint64 payloadSize); + + // Returns the number of bytes allocated for the payload + qint64 getPayloadCapacity() const { return _payloadCapacity; } + + qint64 bytesLeftToRead() const { return _payloadSize - pos(); } + qint64 bytesAvailableForWrite() const { return _payloadCapacity - pos(); } + + HifiSockAddr& getSenderSockAddr() { return _senderSockAddr; } + const HifiSockAddr& getSenderSockAddr() const { return _senderSockAddr; } + + // QIODevice virtual functions + // WARNING: Those methods all refer to the payload ONLY and NOT the entire packet + virtual bool isSequential() const { return false; } + virtual bool reset(); + virtual qint64 size() const { return _payloadCapacity; } + + using QIODevice::read; + QByteArray read(qint64 maxSize); + + template qint64 peekPrimitive(T* data); + template qint64 readPrimitive(T* data); + template qint64 writePrimitive(const T& data); + +protected: + BasePacket(qint64 size); + BasePacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); + BasePacket(const BasePacket& other); + BasePacket& operator=(const BasePacket& other); + BasePacket(BasePacket&& other); + BasePacket& operator=(BasePacket&& other); + + // QIODevice virtual functions + virtual qint64 writeData(const char* data, qint64 maxSize); + virtual qint64 readData(char* data, qint64 maxSize); + + qint64 _packetSize = 0; // Total size of the allocated memory + std::unique_ptr _packet; // Allocated memory + + char* _payloadStart = nullptr; // Start of the payload + qint64 _payloadCapacity = 0; // Total capacity of the payload + + qint64 _payloadSize = 0; // How much of the payload is actually used + + HifiSockAddr _senderSockAddr; // sender address for packet (only used on receiving end) +}; + +template qint64 BasePacket::peekPrimitive(T* data) { + return QIODevice::peek(reinterpret_cast(data), sizeof(T)); +} + +template qint64 BasePacket::readPrimitive(T* data) { + return QIODevice::read(reinterpret_cast(data), sizeof(T)); +} + +template qint64 BasePacket::writePrimitive(const T& data) { + static_assert(!std::is_pointer::value, "T must not be a pointer"); + return QIODevice::write(reinterpret_cast(&data), sizeof(T)); +} + +} // namespace udt + + +#endif // hifi_BasePacket_h diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 439b185661..3746f877ba 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -13,8 +13,6 @@ using namespace udt; -const qint64 Packet::PACKET_WRITE_ERROR = -1; - std::unique_ptr Packet::create(qint64 size, bool isReliable, bool isPartOfMessage) { auto packet = std::unique_ptr(new Packet(size, isReliable, isPartOfMessage)); @@ -60,32 +58,19 @@ qint64 Packet::localHeaderSize() const { } Packet::Packet(qint64 size, bool isReliable, bool isPartOfMessage) : + BasePacket(size), _isReliable(isReliable), _isPartOfMessage(isPartOfMessage) { - auto maxPayload = maxPayloadSize(); - - if (size == -1) { - // default size of -1, means biggest packet possible - size = maxPayload; - } - - _packetSize = localHeaderSize() + size; - _packet.reset(new char[_packetSize]); _payloadCapacity = size; _payloadStart = _packet.get() + (_packetSize - _payloadCapacity); - // Sanity check - Q_ASSERT(size >= 0 || size < maxPayload); - // set the UDT header to default values writeSequenceNumber(0); } Packet::Packet(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr) : - _packetSize(size), - _packet(std::move(data)), - _senderSockAddr(senderSockAddr) + BasePacket(std::move(data), size, senderSockAddr) { readIsReliable(); readIsPartOfMessage(); @@ -97,72 +82,41 @@ Packet::Packet(std::unique_ptr data, qint64 size, const HifiSockAddr& send } Packet::Packet(const Packet& other) : - QIODevice() + BasePacket(other) { - *this = other; + _isReliable = other._isReliable; + _isPartOfMessage = other._isPartOfMessage; + _sequenceNumber = other._sequenceNumber; } Packet& Packet::operator=(const Packet& other) { - _packetSize = other._packetSize; - _packet = std::unique_ptr(new char[_packetSize]); - memcpy(_packet.get(), other._packet.get(), _packetSize); - - _payloadStart = _packet.get() + (other._payloadStart - other._packet.get()); - _payloadCapacity = other._payloadCapacity; - - _payloadSize = other._payloadSize; + BasePacket::operator=(other); - if (other.isOpen() && !isOpen()) { - open(other.openMode()); - } - - seek(other.pos()); + _isReliable = other._isReliable; + _isPartOfMessage = other._isPartOfMessage; + _sequenceNumber = other._sequenceNumber; return *this; } -Packet::Packet(Packet&& other) { - *this = std::move(other); +Packet::Packet(Packet&& other) : + BasePacket(other) +{ + _isReliable = other._isReliable; + _isPartOfMessage = other._isPartOfMessage; + _sequenceNumber = other._sequenceNumber; } Packet& Packet::operator=(Packet&& other) { - _packetSize = other._packetSize; - _packet = std::move(other._packet); - - _payloadStart = other._payloadStart; - _payloadCapacity = other._payloadCapacity; - - _payloadSize = other._payloadSize; + BasePacket::operator=(std::move(other)); - _senderSockAddr = std::move(other._senderSockAddr); - - if (other.isOpen() && !isOpen()) { - open(other.openMode()); - } - - seek(other.pos()); + _isReliable = other._isReliable; + _isPartOfMessage = other._isPartOfMessage; + _sequenceNumber = other._sequenceNumber; return *this; } -void Packet::setPayloadSize(qint64 payloadSize) { - if (isWritable()) { - Q_ASSERT(payloadSize <= _payloadCapacity); - _payloadSize = payloadSize; - } else { - qDebug() << "You can not call setPayloadSize for a non-writeable Packet."; - Q_ASSERT(false); - } -} - -bool Packet::reset() { - if (isWritable()) { - _payloadSize = 0; - } - - return QIODevice::reset(); -} - static const uint32_t CONTROL_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 1); static const uint32_t RELIABILITY_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 2); static const uint32_t MESSAGE_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 3); @@ -196,46 +150,3 @@ void Packet::writeSequenceNumber(SequenceNumber sequenceNumber) { // write new value by ORing (old value & BIT_FIELD_MASK) with new seqNum *seqNumBitField = (*seqNumBitField & BIT_FIELD_MASK) | sequenceNumber; } - -QByteArray Packet::read(qint64 maxSize) { - qint64 sizeToRead = std::min(size() - pos(), maxSize); - QByteArray data { QByteArray::fromRawData(getPayload() + pos(), sizeToRead) }; - seek(pos() + sizeToRead); - return data; -} - -qint64 Packet::writeData(const char* data, qint64 maxSize) { - - // make sure we have the space required to write this block - if (maxSize <= bytesAvailableForWrite()) { - qint64 currentPos = pos(); - - Q_ASSERT(currentPos < _payloadCapacity); - - // good to go - write the data - memcpy(_payloadStart + currentPos, data, maxSize); - - // keep track of _payloadSize so we can just write the actual data when packet is about to be sent - _payloadSize = std::max(currentPos + maxSize, _payloadSize); - - // return the number of bytes written - return maxSize; - } else { - // not enough space left for this write - return an error - return PACKET_WRITE_ERROR; - } -} - -qint64 Packet::readData(char* dest, qint64 maxSize) { - // we're either reading what is left from the current position or what was asked to be read - qint64 numBytesToRead = std::min(bytesLeftToRead(), maxSize); - - if (numBytesToRead > 0) { - int currentPosition = pos(); - - // read out the data - memcpy(dest, _payloadStart + currentPosition, numBytesToRead); - } - - return numBytesToRead; -} diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index 1bd9ee9619..e33a075a1f 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -16,12 +16,12 @@ #include -#include "../HifiSockAddr.h" +#include "BasePacket.h" #include "PacketHeaders.h" namespace udt { -class Packet : public QIODevice { +class Packet : public BasePacket { Q_OBJECT public: // NOTE: The SequenceNumber is only actually 29 bits to leave room for a bit field @@ -34,8 +34,6 @@ public: static const uint32_t DEFAULT_SEQUENCE_NUMBER = 0; - static const qint64 PACKET_WRITE_ERROR; - static std::unique_ptr create(qint64 size = -1, bool isReliable = false, bool isPartOfMessage = false); static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); @@ -52,47 +50,8 @@ public: virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers - // Payload direct access to the payload, use responsibly! - char* getPayload() { return _payloadStart; } - const char* getPayload() const { return _payloadStart; } - - // Return direct access to the entire packet, use responsibly! - char* getData() { return _packet.get(); } - const char* getData() const { return _packet.get(); } - - // Returns the size of the packet, including the header - qint64 getDataSize() const { return totalHeadersSize() + _payloadSize; } - - // Returns the size of the payload only - qint64 getPayloadSize() const { return _payloadSize; } - - // Allows a writer to change the size of the payload used when writing directly - void setPayloadSize(qint64 payloadSize); - - // Returns the number of bytes allocated for the payload - qint64 getPayloadCapacity() const { return _payloadCapacity; } - - qint64 bytesLeftToRead() const { return _payloadSize - pos(); } - qint64 bytesAvailableForWrite() const { return _payloadCapacity - pos(); } - - HifiSockAddr& getSenderSockAddr() { return _senderSockAddr; } - const HifiSockAddr& getSenderSockAddr() const { return _senderSockAddr; } - void writeSequenceNumber(SequenceNumber sequenceNumber); - // QIODevice virtual functions - // WARNING: Those methods all refer to the payload ONLY and NOT the entire packet - virtual bool isSequential() const { return false; } - virtual bool reset(); - virtual qint64 size() const { return _payloadCapacity; } - - using QIODevice::read; - QByteArray read(qint64 maxSize); - - template qint64 peekPrimitive(T* data); - template qint64 readPrimitive(T* data); - template qint64 writePrimitive(const T& data); - protected: Packet(qint64 size, bool isReliable = false, bool isPartOfMessage = false); Packet(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); @@ -101,42 +60,15 @@ protected: Packet(Packet&& other); Packet& operator=(Packet&& other); - // QIODevice virtual functions - virtual qint64 writeData(const char* data, qint64 maxSize); - virtual qint64 readData(char* data, qint64 maxSize); - // Header readers - these read data to member variables after pulling packet off wire void readIsPartOfMessage(); void readIsReliable(); void readSequenceNumber(); - qint64 _packetSize = 0; // Total size of the allocated memory - std::unique_ptr _packet; // Allocated memory - - char* _payloadStart = nullptr; // Start of the payload - qint64 _payloadCapacity = 0; // Total capacity of the payload - - qint64 _payloadSize = 0; // How much of the payload is actually used - bool _isReliable { false }; bool _isPartOfMessage { false }; SequenceNumber _sequenceNumber { 0 }; - - HifiSockAddr _senderSockAddr; // sender address for packet (only used on receiving end) }; - -template qint64 Packet::peekPrimitive(T* data) { - return QIODevice::peek(reinterpret_cast(data), sizeof(T)); -} - -template qint64 Packet::readPrimitive(T* data) { - return QIODevice::read(reinterpret_cast(data), sizeof(T)); -} - -template qint64 Packet::writePrimitive(const T& data) { - static_assert(!std::is_pointer::value, "T must not be a pointer"); - return QIODevice::write(reinterpret_cast(&data), sizeof(T)); -} } // namespace udt diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index e3a8761e6d..f3d3042b34 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -65,9 +65,9 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITIES_NEW_PROTOCOL_LAYER; + return VERSION_ENTITIES_PROTOCOL_HEADER_SWAP; default: - return 11; + return 12; } } diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 2d3f7f25fe..0cb20b2247 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -76,8 +76,6 @@ enum class PacketType : uint8_t { }; const int NUM_BYTES_MD5_HASH = 16; - -const int MAX_PACKET_SIZE = 1450; const int MAX_PACKET_HEADER_BYTES = 4 + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH; typedef char PacketVersion; @@ -135,5 +133,6 @@ const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP = 31; const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP_FIX = 32; const PacketVersion VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE = 33; const PacketVersion VERSION_ENTITIES_NEW_PROTOCOL_LAYER = 35; +const PacketVersion VERSION_ENTITIES_PROTOCOL_HEADER_SWAP = 36; #endif // hifi_PacketHeaders_h diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 8b912637a8..25afb5424d 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -88,11 +88,23 @@ void Socket::readPendingDatagrams() { _udpSocket.readDatagram(buffer.get(), packetSizeWithHeader, senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()); + auto it = _unfilteredHandlers.find(senderSockAddr); + + if (it != _unfilteredHandlers.end()) { + // we have a registered unfiltered handler for this HifiSockAddr - call that and return + if (it->second) { + auto basePacket = BasePacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); + it->second(std::move(basePacket)); + } + + return; + } + // setup a Packet from the data we just read auto packet = Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); // call our verification operator to see if this packet is verified - if (_unfilteredSockAddrs.contains(senderSockAddr) || !_packetFilterOperator || _packetFilterOperator(*packet)) { + if (!_packetFilterOperator || _packetFilterOperator(*packet)) { if (_packetHandler) { // call the verified packet callback to let it handle this packet return _packetHandler(std::move(packet)); diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index f4b4ea4ee0..68985133ac 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -26,6 +26,8 @@ namespace udt { using PacketFilterOperator = std::function; + +using BasePacketHandler = std::function)>; using PacketHandler = std::function)>; class Socket : public QObject { @@ -49,7 +51,8 @@ public: void setBufferSizes(int numBytes); - void addUnfilteredSockAddr(const HifiSockAddr& senderSockAddr) { _unfilteredSockAddrs.insert(senderSockAddr); } + void addUnfilteredHandler(const HifiSockAddr& senderSockAddr, BasePacketHandler handler) + { _unfilteredHandlers[senderSockAddr] = handler; } private slots: void readPendingDatagrams(); @@ -59,7 +62,7 @@ private: PacketFilterOperator _packetFilterOperator; PacketHandler _packetHandler; - QSet _unfilteredSockAddrs; + std::unordered_map _unfilteredHandlers; std::unordered_map _packetSequenceNumbers; }; diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 2c9d587254..a242f9117f 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -26,11 +26,11 @@ #include #include -#include // for MAX_PACKET_SIZE -#include // for MAX_PACKET_HEADER_BYTES +#include #include #include -#include +#include +#include #include "OctreeConstants.h" #include "OctreeElement.h" @@ -40,14 +40,13 @@ typedef uint16_t OCTREE_PACKET_SEQUENCE; const uint16_t MAX_OCTREE_PACKET_SEQUENCE = 65535; typedef quint64 OCTREE_PACKET_SENT_TIME; typedef uint16_t OCTREE_PACKET_INTERNAL_SECTION_SIZE; -const int MAX_OCTREE_PACKET_SIZE = MAX_PACKET_SIZE; +const int MAX_OCTREE_PACKET_SIZE = udt::MAX_PACKET_SIZE; -// this is overly conservative - sizeof(PacketType) is 8 bytes but a packed PacketType could be as small as one byte const unsigned int OCTREE_PACKET_EXTRA_HEADERS_SIZE = sizeof(OCTREE_PACKET_FLAGS) + sizeof(OCTREE_PACKET_SEQUENCE) + sizeof(OCTREE_PACKET_SENT_TIME); -const unsigned int MAX_OCTREE_PACKET_DATA_SIZE = MAX_PACKET_SIZE - (MAX_PACKET_HEADER_BYTES + OCTREE_PACKET_EXTRA_HEADERS_SIZE); - +const unsigned int MAX_OCTREE_PACKET_DATA_SIZE = + udt::MAX_PACKET_SIZE - (MAX_PACKET_HEADER_BYTES + OCTREE_PACKET_EXTRA_HEADERS_SIZE); const unsigned int MAX_OCTREE_UNCOMRESSED_PACKET_SIZE = MAX_OCTREE_PACKET_DATA_SIZE; const unsigned int MINIMUM_ATTEMPT_MORE_PACKING = sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) + 40; diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 55213fdb7a..d83ee9a89e 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -791,6 +791,6 @@ void OctreeSceneStats::trackIncomingOctreePacket(NLPacket& packet, bool wasStats _incomingPacket++; _incomingBytes += packet.getDataSize(); if (!wasStatsPacket) { - _incomingWastedBytes += (MAX_PACKET_SIZE - packet.getDataSize()); + _incomingWastedBytes += (udt::MAX_PACKET_SIZE - packet.getDataSize()); } } From 862c788aecfc775229960864ce44f6cb7a57eb58 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Jul 2015 15:27:32 -0700 Subject: [PATCH 037/549] move payload adjustments to Packet --- .../src/octree/OctreeQueryNode.cpp | 2 +- .../src/octree/OctreeSendThread.cpp | 6 +++--- libraries/networking/src/NLPacket.cpp | 10 ---------- libraries/networking/src/NLPacket.h | 2 -- libraries/networking/src/udt/Packet.cpp | 19 +++++++++++++------ libraries/networking/src/udt/Packet.h | 5 ++++- 6 files changed, 21 insertions(+), 23 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 6395397c51..f342f2e479 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -24,7 +24,7 @@ OctreeQueryNode::OctreeQueryNode() : _viewSent(false), _octreePacket(), _octreePacketWaiting(false), - _lastOctreePayload(new char[MAX_PACKET_SIZE]), + _lastOctreePayload(new char[udt::MAX_PACKET_SIZE]), _lastOctreePacketLength(0), _duplicatePacketCount(0), _firstSuppressedPacket(usecTimestampNow()), diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 62517e698b..417df3204a 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -219,7 +219,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes packetSent = true; int packetSizeWithHeader = nodeData->getPacket().getDataSize(); - thisWastedBytes = MAX_PACKET_SIZE - packetSizeWithHeader; + thisWastedBytes = udt::MAX_PACKET_SIZE - packetSizeWithHeader; _totalWastedBytes += thisWastedBytes; _totalBytes += nodeData->getPacket().getDataSize(); _totalPackets++; @@ -251,7 +251,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes packetSent = true; int packetSizeWithHeader = nodeData->getPacket().getDataSize(); - int thisWastedBytes = MAX_PACKET_SIZE - packetSizeWithHeader; + int thisWastedBytes = udt::MAX_PACKET_SIZE - packetSizeWithHeader; _totalWastedBytes += thisWastedBytes; _totalBytes += packetSizeWithHeader; _totalPackets++; @@ -598,7 +598,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus _totalBytes += packet->getDataSize(); _totalPackets++; - _totalWastedBytes += MAX_PACKET_SIZE - packet->getDataSize(); + _totalWastedBytes += udt::MAX_PACKET_SIZE - packet->getDataSize(); } } diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 221ef7da98..3660ac9ba2 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -207,16 +207,6 @@ void NLPacket::readVersion() { _version = NLPacket::versionInHeader(*this); } -void NLPacket::adjustPayloadStartAndCapacity(bool shouldDecreasePayloadSize) { - qint64 headerSize = localHeaderSize(_type); - _payloadStart += headerSize; - _payloadCapacity -= headerSize; - - if (shouldDecreasePayloadSize) { - _payloadSize -= headerSize; - } -} - void NLPacket::readSourceID() { if (!NON_SOURCED_PACKETS.contains(_type)) { _sourceID = sourceIDInHeader(*this); diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index cd2168cc4e..11ec40a294 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -65,8 +65,6 @@ protected: NLPacket& operator=(const NLPacket& other); NLPacket& operator=(NLPacket&& other); - void adjustPayloadStartAndCapacity(bool shouldDecreasePayloadSize = false); - // Header writers void writePacketTypeAndVersion(); diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 3746f877ba..335f7e1d17 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -62,8 +62,7 @@ Packet::Packet(qint64 size, bool isReliable, bool isPartOfMessage) : _isReliable(isReliable), _isPartOfMessage(isPartOfMessage) { - _payloadCapacity = size; - _payloadStart = _packet.get() + (_packetSize - _payloadCapacity); + adjustPayloadStartAndCapacity(); // set the UDT header to default values writeSequenceNumber(0); @@ -75,10 +74,8 @@ Packet::Packet(std::unique_ptr data, qint64 size, const HifiSockAddr& send readIsReliable(); readIsPartOfMessage(); readSequenceNumber(); - - _payloadCapacity = _packetSize - localHeaderSize(); - _payloadSize = _payloadCapacity; - _payloadStart = _packet.get() + (_packetSize - _payloadCapacity); + + adjustPayloadStartAndCapacity(_payloadSize > 0); } Packet::Packet(const Packet& other) : @@ -117,6 +114,16 @@ Packet& Packet::operator=(Packet&& other) { return *this; } +void Packet::adjustPayloadStartAndCapacity(bool shouldDecreasePayloadSize) { + qint64 headerSize = localHeaderSize(); + _payloadStart += headerSize; + _payloadCapacity -= headerSize; + + if (shouldDecreasePayloadSize) { + _payloadSize -= headerSize; + } +} + static const uint32_t CONTROL_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 1); static const uint32_t RELIABILITY_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 2); static const uint32_t MESSAGE_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 3); diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index e33a075a1f..39770bb022 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -56,9 +56,12 @@ protected: Packet(qint64 size, bool isReliable = false, bool isPartOfMessage = false); Packet(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); Packet(const Packet& other); - Packet& operator=(const Packet& other); Packet(Packet&& other); + + Packet& operator=(const Packet& other); Packet& operator=(Packet&& other); + + virtual void adjustPayloadStartAndCapacity(bool shouldDecreasePayloadSize = false); // Header readers - these read data to member variables after pulling packet off wire void readIsPartOfMessage(); From 2f030757509a5c72c2197312847f35d4afd6c6ac Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Jul 2015 15:57:31 -0700 Subject: [PATCH 038/549] repairs to type/version header write --- libraries/networking/src/LimitedNodeList.cpp | 8 ++++++-- libraries/networking/src/NLPacket.cpp | 18 ++++++++++++------ libraries/networking/src/NLPacket.h | 2 +- libraries/networking/src/udt/PacketHeaders.cpp | 3 ++- libraries/networking/src/udt/Socket.cpp | 2 +- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 66165a95cc..edfdd682e9 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -624,6 +624,7 @@ void LimitedNodeList::processSTUNResponse(std::unique_ptr packe // enumerate the attributes to find XOR_MAPPED_ADDRESS_TYPE while (attributeStartIndex < packet->getDataSize()) { + if (memcmp(packet->getData() + attributeStartIndex, &XOR_MAPPED_ADDRESS_TYPE, sizeof(XOR_MAPPED_ADDRESS_TYPE)) == 0) { const int NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH = 4; const int NUM_BYTES_FAMILY_ALIGN = 1; @@ -651,8 +652,8 @@ void LimitedNodeList::processSTUNResponse(std::unique_ptr packe uint32_t stunAddress = ntohl(xorMappedAddress) ^ ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER); - QHostAddress newPublicAddress = QHostAddress(stunAddress); - + QHostAddress newPublicAddress(stunAddress); + if (newPublicAddress != _publicSockAddr.getAddress() || newPublicPort != _publicSockAddr.getPort()) { _publicSockAddr = HifiSockAddr(newPublicAddress, newPublicPort); @@ -669,6 +670,9 @@ void LimitedNodeList::processSTUNResponse(std::unique_ptr packe flagTimeForConnectionStep(ConnectionStep::SetPublicSocketFromSTUN); } + + // we're done reading the packet so we can return now + return; } } else { // push forward attributeStartIndex by the length of this attribute diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 3660ac9ba2..47f36792ad 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -95,6 +95,8 @@ NLPacket::NLPacket(PacketType type, qint64 size, bool isReliable, bool isPartOfM Q_ASSERT(size >= 0); adjustPayloadStartAndCapacity(); + + writeTypeAndVersion(); } NLPacket::NLPacket(std::unique_ptr packet) : @@ -146,11 +148,13 @@ NLPacket& NLPacket::operator=(NLPacket&& other) { } PacketType NLPacket::typeInHeader(const udt::Packet& packet) { - return *reinterpret_cast(packet.getData()); + auto headerOffset = packet.Packet::localHeaderSize(); + return *reinterpret_cast(packet.getData() + headerOffset); } PacketVersion NLPacket::versionInHeader(const udt::Packet& packet) { - return *reinterpret_cast(packet.getData() + sizeof(PacketType)); + auto headerOffset = packet.Packet::localHeaderSize(); + return *reinterpret_cast(packet.getData() + headerOffset + sizeof(PacketType)); } QUuid NLPacket::sourceIDInHeader(const udt::Packet& packet) { @@ -177,13 +181,15 @@ QByteArray NLPacket::hashForPacketAndSecret(const udt::Packet& packet, const QUu return hash.result(); } -void NLPacket::writePacketTypeAndVersion() { +void NLPacket::writeTypeAndVersion() { + auto headerOffset = Packet::localHeaderSize(); + // Pack the packet type - memcpy(_packet.get(), &_type, sizeof(PacketType)); + memcpy(_packet.get() + headerOffset, &_type, sizeof(PacketType)); // Pack the packet version auto version = versionForPacketType(_type); - memcpy(_packet.get() + sizeof(PacketType), &version, sizeof(version)); + memcpy(_packet.get() + headerOffset + sizeof(PacketType), &version, sizeof(version)); } void NLPacket::setType(PacketType type) { @@ -192,7 +198,7 @@ void NLPacket::setType(PacketType type) { _type = type; _version = versionForPacketType(_type); - writePacketTypeAndVersion(); + writeTypeAndVersion(); // Setting new packet type with a different header size not currently supported Q_ASSERT(currentHeaderSize == totalHeadersSize()); diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index 11ec40a294..3309032e68 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -66,7 +66,7 @@ protected: NLPacket& operator=(NLPacket&& other); // Header writers - void writePacketTypeAndVersion(); + void writeTypeAndVersion(); // Header readers, used to set member variables after getting a packet from the network void readType(); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index f3d3042b34..50586e1057 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -134,5 +134,6 @@ uint qHash(const PacketType& key, uint seed) { } QDebug operator<<(QDebug debug, const PacketType& type) { - return debug.nospace() << (uint8_t) type << " (" << qPrintable(nameForPacketType(type)) << ")"; + debug.nospace() << (uint8_t) type << " (" << qPrintable(nameForPacketType(type)) << ")"; + return debug.space(); } diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 25afb5424d..aa5085de04 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -83,7 +83,7 @@ void Socket::readPendingDatagrams() { // setup a buffer to read the packet into int packetSizeWithHeader = _udpSocket.pendingDatagramSize(); std::unique_ptr buffer = std::unique_ptr(new char[packetSizeWithHeader]); - + // pull the datagram _udpSocket.readDatagram(buffer.get(), packetSizeWithHeader, senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()); From 069dff0793080734d33bb763227d7d8333637f1a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Jul 2015 16:40:35 -0700 Subject: [PATCH 039/549] fix bugs from movement of type/version to NLPacket --- libraries/networking/src/NLPacket.cpp | 21 ++++++++++++++++----- libraries/networking/src/NodeList.cpp | 3 +-- libraries/networking/src/udt/BasePacket.cpp | 2 ++ libraries/networking/src/udt/Packet.cpp | 2 +- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 47f36792ad..7a2b4af163 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -16,9 +16,9 @@ qint64 NLPacket::maxPayloadSize(PacketType type) { } qint64 NLPacket::localHeaderSize(PacketType type) { - qint64 size = ((NON_SOURCED_PACKETS.contains(type)) ? 0 : NUM_BYTES_RFC4122_UUID) + + qint64 optionalSize = ((NON_SOURCED_PACKETS.contains(type)) ? 0 : NUM_BYTES_RFC4122_UUID) + ((NON_SOURCED_PACKETS.contains(type) || NON_VERIFIED_PACKETS.contains(type)) ? 0 : NUM_BYTES_MD5_HASH); - return size; + return sizeof(PacketType) + sizeof(PacketVersion) + optionalSize; } qint64 NLPacket::maxPayloadSize() const { @@ -85,6 +85,8 @@ NLPacket::NLPacket(PacketType type, bool isReliable, bool isPartOfMessage) : _version(versionForPacketType(type)) { adjustPayloadStartAndCapacity(); + + writeTypeAndVersion(); } NLPacket::NLPacket(PacketType type, qint64 size, bool isReliable, bool isPartOfMessage) : @@ -104,10 +106,14 @@ NLPacket::NLPacket(std::unique_ptr packet) : { adjustPayloadStartAndCapacity(_payloadSize > 0); + readType(); + readVersion(); readSourceID(); } NLPacket::NLPacket(const NLPacket& other) : Packet(other) { + _type = other._type; + _version = other._version; _sourceID = other._sourceID; } @@ -125,14 +131,18 @@ NLPacket::NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& } NLPacket::NLPacket(NLPacket&& other) : - Packet(other) + Packet(std::move(other)) { + _type = other._type; + _version = other._version; _sourceID = std::move(other._sourceID); } NLPacket& NLPacket::operator=(const NLPacket& other) { Packet::operator=(other); + _type = other._type; + _version = other._version; _sourceID = other._sourceID; return *this; @@ -142,6 +152,8 @@ NLPacket& NLPacket::operator=(NLPacket&& other) { Packet::operator=(std::move(other)); + _type = other._type; + _version = other._version; _sourceID = std::move(other._sourceID); return *this; @@ -188,8 +200,7 @@ void NLPacket::writeTypeAndVersion() { memcpy(_packet.get() + headerOffset, &_type, sizeof(PacketType)); // Pack the packet version - auto version = versionForPacketType(_type); - memcpy(_packet.get() + headerOffset + sizeof(PacketType), &version, sizeof(version)); + memcpy(_packet.get() + headerOffset + sizeof(PacketType), &_version, sizeof(_version)); } void NLPacket::setType(PacketType type) { diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 1660312e5d..0864cb9fcd 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -533,8 +533,7 @@ void NodeList::sendAssignment(Assignment& assignment) { QDataStream packetStream(assignmentPacket.get()); packetStream << assignment; - - // TODO: should this be a non sourced packet? + sendPacket(std::move(assignmentPacket), _assignmentServerSocket); } diff --git a/libraries/networking/src/udt/BasePacket.cpp b/libraries/networking/src/udt/BasePacket.cpp index d615f0cc1e..f58cd107cb 100644 --- a/libraries/networking/src/udt/BasePacket.cpp +++ b/libraries/networking/src/udt/BasePacket.cpp @@ -80,6 +80,8 @@ BasePacket& BasePacket::operator=(const BasePacket& other) { _payloadSize = other._payloadSize; + _senderSockAddr = other._senderSockAddr; + if (other.isOpen() && !isOpen()) { open(other.openMode()); } diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 335f7e1d17..47ea6ffef3 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -97,7 +97,7 @@ Packet& Packet::operator=(const Packet& other) { } Packet::Packet(Packet&& other) : - BasePacket(other) + BasePacket(std::move(other)) { _isReliable = other._isReliable; _isPartOfMessage = other._isPartOfMessage; From b68c7fd92aa684744648dc1986daef40a9bd39c7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Jul 2015 16:59:08 -0700 Subject: [PATCH 040/549] first adjustment in NLPacket after type is known --- domain-server/src/DomainServer.cpp | 1 - libraries/networking/src/NLPacket.cpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 4532180ca7..f438972c58 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -580,7 +580,6 @@ void DomainServer::processConnectRequestPacket(QSharedPointer packet) NodeType_t nodeType; HifiSockAddr publicSockAddr, localSockAddr; - if (packet->getPayloadSize() == 0) { return; } diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 7a2b4af163..eb53688a21 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -104,11 +104,11 @@ NLPacket::NLPacket(PacketType type, qint64 size, bool isReliable, bool isPartOfM NLPacket::NLPacket(std::unique_ptr packet) : Packet(std::move(*packet.release())) { - adjustPayloadStartAndCapacity(_payloadSize > 0); - readType(); readVersion(); readSourceID(); + + adjustPayloadStartAndCapacity(_payloadSize > 0); } NLPacket::NLPacket(const NLPacket& other) : Packet(other) { From d938f31fab99035e25dae123b9ef0476a7fe893d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 23 Jul 2015 17:10:40 -0700 Subject: [PATCH 041/549] fix for write of sourceID and verificationHash --- libraries/networking/src/NLPacket.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index eb53688a21..5de7d3065f 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -233,7 +233,7 @@ void NLPacket::readSourceID() { void NLPacket::writeSourceID(const QUuid& sourceID) { Q_ASSERT(!NON_SOURCED_PACKETS.contains(_type)); - auto offset = Packet::localHeaderSize(); + auto offset = Packet::localHeaderSize() + sizeof(PacketType) + sizeof(PacketVersion); memcpy(_packet.get() + offset, sourceID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); _sourceID = sourceID; @@ -242,7 +242,7 @@ void NLPacket::writeSourceID(const QUuid& sourceID) { void NLPacket::writeVerificationHashGivenSecret(const QUuid& connectionSecret) { Q_ASSERT(!NON_SOURCED_PACKETS.contains(_type) && !NON_VERIFIED_PACKETS.contains(_type)); - auto offset = Packet::localHeaderSize() + NUM_BYTES_RFC4122_UUID; + auto offset = Packet::localHeaderSize() + sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID; QByteArray verificationHash = hashForPacketAndSecret(*this, connectionSecret); memcpy(_packet.get() + offset, verificationHash.data(), verificationHash.size()); From 6dba4310844ef59e339634b90d91bdc517c0dec8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Jul 2015 11:38:51 -0700 Subject: [PATCH 042/549] initial version of the control packet class --- .../networking/src/udt/ControlPacket.cpp | 54 ++++++++++++++++++ libraries/networking/src/udt/ControlPacket.h | 55 +++++++++++++++++++ libraries/networking/src/udt/Packet.cpp | 2 +- 3 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 libraries/networking/src/udt/ControlPacket.cpp create mode 100644 libraries/networking/src/udt/ControlPacket.h diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp new file mode 100644 index 0000000000..ee3fef9f3a --- /dev/null +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -0,0 +1,54 @@ +// +// ControlPacket.cpp +// libraries/networking/src/udt +// +// Created by Stephen Birarda on 2015-07-24. +// Copyright 2015 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 "ControlPacket.h" + +using namespace udt; + +std::unique_ptr ControlPacket::create(Type type, const SequenceNumberList& sequenceNumbers) { + return ControlPacket::create(type, sequenceNumbers); +} + +qint64 ControlPacket::localHeaderSize() { + return sizeof(TypeAndSubSequenceNumber); +} + +qint64 ControlPacket::totalHeadersSize() const { + return BasePacket::localHeaderSize() + localHeaderSize(); +} + +ControlPacket::ControlPacket(Type type, const SequenceNumberList& sequenceNumbers) : + BasePacket(localHeaderSize() + (sizeof(Packet::SequenceNumber) * sequenceNumbers.size())) +{ + qint64 headerSize = localHeaderSize(); + + _payloadCapacity -= headerSize; + _payloadStart += headerSize; + + open(QIODevice::ReadWrite); + + // pack in the sequence numbers + for(auto& sequenceNumber : sequenceNumbers) { + writePrimitive(sequenceNumber); + } +} + +ControlPacket::ControlPacket(ControlPacket&& other) : + BasePacket(std::move(other)) +{ + +} + +ControlPacket& ControlPacket::operator=(Packet&& other) { + BasePacket::operator=(std::move(other)); + + return *this; +} diff --git a/libraries/networking/src/udt/ControlPacket.h b/libraries/networking/src/udt/ControlPacket.h new file mode 100644 index 0000000000..2fa7200322 --- /dev/null +++ b/libraries/networking/src/udt/ControlPacket.h @@ -0,0 +1,55 @@ +// +// ControlPacket.h +// libraries/networking/src/udt +// +// Created by Stephen Birarda on 2015-07-24. +// Copyright 2015 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 +// + +#pragma once + +#ifndef hifi_ControlPacket_h +#define hifi_ControlPacket_h + +#include + +#include "BasePacket.h" +#include "Packet.h" + +namespace udt { + +using SequenceNumberList = std::vector; + +class ControlPacket : public BasePacket { + Q_OBJECT +public: + using TypeAndSubSequenceNumber = uint32_t; + + enum class Type : uint16_t { + ACK, + ACK2, + NAK, + PacketPair + }; + + std::unique_ptr create(Type type, const SequenceNumberList& sequenceNumbers); + + static qint64 localHeaderSize(); // Current level's header size + virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers + +private: + ControlPacket(Type type, const SequenceNumberList& sequenceNumbers); + ControlPacket(ControlPacket&& other); + ControlPacket(const Packet& other) = delete; + + ControlPacket& operator=(Packet&& other); + ControlPacket& operator=(const Packet& other) = delete; +}; + +} // namespace udt + + +#endif // hifi_ControlPacket_h diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 47ea6ffef3..c041fec5da 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -50,7 +50,7 @@ qint64 Packet::maxPayloadSize() const { } qint64 Packet::totalHeadersSize() const { - return localHeaderSize(); + return BasePacket::localHeaderSize() + localHeaderSize(); } qint64 Packet::localHeaderSize() const { From aea2fed449d74e1606848694c306e1da78e504ce Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Jul 2015 11:46:11 -0700 Subject: [PATCH 043/549] add a static to create a packet pair --- libraries/networking/src/udt/BasePacket.cpp | 10 +++++++ libraries/networking/src/udt/BasePacket.h | 2 ++ .../networking/src/udt/ControlPacket.cpp | 29 +++++++++++++++---- libraries/networking/src/udt/ControlPacket.h | 5 ++++ libraries/networking/src/udt/Packet.cpp | 10 ------- libraries/networking/src/udt/Packet.h | 2 -- 6 files changed, 40 insertions(+), 18 deletions(-) diff --git a/libraries/networking/src/udt/BasePacket.cpp b/libraries/networking/src/udt/BasePacket.cpp index f58cd107cb..0f940e01e8 100644 --- a/libraries/networking/src/udt/BasePacket.cpp +++ b/libraries/networking/src/udt/BasePacket.cpp @@ -175,3 +175,13 @@ qint64 BasePacket::readData(char* dest, qint64 maxSize) { return numBytesToRead; } + +void BasePacket::adjustPayloadStartAndCapacity(bool shouldDecreasePayloadSize) { + qint64 headerSize = localHeaderSize(); + _payloadStart += headerSize; + _payloadCapacity -= headerSize; + + if (shouldDecreasePayloadSize) { + _payloadSize -= headerSize; + } +} diff --git a/libraries/networking/src/udt/BasePacket.h b/libraries/networking/src/udt/BasePacket.h index cd31240d67..ff5acafaf0 100644 --- a/libraries/networking/src/udt/BasePacket.h +++ b/libraries/networking/src/udt/BasePacket.h @@ -86,6 +86,8 @@ protected: virtual qint64 writeData(const char* data, qint64 maxSize); virtual qint64 readData(char* data, qint64 maxSize); + virtual void adjustPayloadStartAndCapacity(bool shouldDecreasePayloadSize = false); + qint64 _packetSize = 0; // Total size of the allocated memory std::unique_ptr _packet; // Allocated memory diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index ee3fef9f3a..e8e9eff048 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -17,6 +17,13 @@ std::unique_ptr ControlPacket::create(Type type, const SequenceNu return ControlPacket::create(type, sequenceNumbers); } +ControlPacket::ControlPacketPair ControlPacket::createPacketPair(quint64 timestamp) { + // create each of the two packets in the packet pair + ControlPacketPair packetPair { std::unique_ptr(new ControlPacket(timestamp)), + std::unique_ptr(new ControlPacket(timestamp)) }; + return packetPair; +} + qint64 ControlPacket::localHeaderSize() { return sizeof(TypeAndSubSequenceNumber); } @@ -26,21 +33,31 @@ qint64 ControlPacket::totalHeadersSize() const { } ControlPacket::ControlPacket(Type type, const SequenceNumberList& sequenceNumbers) : - BasePacket(localHeaderSize() + (sizeof(Packet::SequenceNumber) * sequenceNumbers.size())) + BasePacket(localHeaderSize() + (sizeof(Packet::SequenceNumber) * sequenceNumbers.size())), + _type(type) { - qint64 headerSize = localHeaderSize(); - - _payloadCapacity -= headerSize; - _payloadStart += headerSize; + adjustPayloadStartAndCapacity(); open(QIODevice::ReadWrite); // pack in the sequence numbers - for(auto& sequenceNumber : sequenceNumbers) { + for (auto& sequenceNumber : sequenceNumbers) { writePrimitive(sequenceNumber); } } +ControlPacket::ControlPacket(quint64 timestamp) : + BasePacket(localHeaderSize() + sizeof(timestamp)), + _type(Type::PacketPair) +{ + adjustPayloadStartAndCapacity(); + + open(QIODevice::ReadWrite); + + // pack in the timestamp + writePrimitive(timestamp); +} + ControlPacket::ControlPacket(ControlPacket&& other) : BasePacket(std::move(other)) { diff --git a/libraries/networking/src/udt/ControlPacket.h b/libraries/networking/src/udt/ControlPacket.h index 2fa7200322..1ebf9009db 100644 --- a/libraries/networking/src/udt/ControlPacket.h +++ b/libraries/networking/src/udt/ControlPacket.h @@ -27,6 +27,7 @@ class ControlPacket : public BasePacket { Q_OBJECT public: using TypeAndSubSequenceNumber = uint32_t; + using ControlPacketPair = std::pair, std::unique_ptr>; enum class Type : uint16_t { ACK, @@ -36,17 +37,21 @@ public: }; std::unique_ptr create(Type type, const SequenceNumberList& sequenceNumbers); + ControlPacketPair createPacketPair(quint64 timestamp); static qint64 localHeaderSize(); // Current level's header size virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers private: ControlPacket(Type type, const SequenceNumberList& sequenceNumbers); + ControlPacket(quint64 timestamp); ControlPacket(ControlPacket&& other); ControlPacket(const Packet& other) = delete; ControlPacket& operator=(Packet&& other); ControlPacket& operator=(const Packet& other) = delete; + + Type _type; }; } // namespace udt diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index c041fec5da..c5e45affd2 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -114,16 +114,6 @@ Packet& Packet::operator=(Packet&& other) { return *this; } -void Packet::adjustPayloadStartAndCapacity(bool shouldDecreasePayloadSize) { - qint64 headerSize = localHeaderSize(); - _payloadStart += headerSize; - _payloadCapacity -= headerSize; - - if (shouldDecreasePayloadSize) { - _payloadSize -= headerSize; - } -} - static const uint32_t CONTROL_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 1); static const uint32_t RELIABILITY_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 2); static const uint32_t MESSAGE_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 3); diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index 39770bb022..bd6e834077 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -60,8 +60,6 @@ protected: Packet& operator=(const Packet& other); Packet& operator=(Packet&& other); - - virtual void adjustPayloadStartAndCapacity(bool shouldDecreasePayloadSize = false); // Header readers - these read data to member variables after pulling packet off wire void readIsPartOfMessage(); From d4504ae6c83cb66c29f9d810cf8a994681ff30bc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 24 Jul 2015 12:21:20 -0700 Subject: [PATCH 044/549] Make SeqNum hash friendly --- libraries/networking/src/udt/SeqNum.h | 31 +++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/udt/SeqNum.h b/libraries/networking/src/udt/SeqNum.h index 058ddcb6cc..ad5a6c7c21 100644 --- a/libraries/networking/src/udt/SeqNum.h +++ b/libraries/networking/src/udt/SeqNum.h @@ -12,6 +12,8 @@ #ifndef hifi_SeqNum_h #define hifi_SeqNum_h +#include + #include namespace udt { @@ -26,9 +28,11 @@ public: static const Type MAX = 0x1FFFFFFF; // maximum sequence number used in UDT SeqNum() : _value(0) {} + SeqNum(const SeqNum& other) : _value(other._value) {} // Only explicit conversions - explicit SeqNum(Type value) { *this = value; } + explicit SeqNum(char* value) { _value = (*reinterpret_cast(value)) & MAX; } + explicit SeqNum(Type value) { _value = (value <= MAX) ? value : MAX; } explicit operator Type() { return _value; } inline SeqNum& operator++() { @@ -50,11 +54,7 @@ public: return before; } - inline SeqNum& operator=(Type value) { - _value = (value <= MAX) ? value : MAX; - return *this; - } - inline SeqNum& operator=(SeqNum& other) { + inline SeqNum& operator=(const SeqNum& other) { _value = other._value; return *this; } @@ -67,18 +67,37 @@ public: return *this; } + inline bool operator==(const SeqNum& other) const { + return _value == other._value; + } + inline bool operator!=(const SeqNum& other) const { + return _value != other._value; + } + friend int seqcmp(const SeqNum& seq1, const SeqNum& seq2); friend int seqlen(const SeqNum& seq1, const SeqNum& seq2); friend int seqoff(const SeqNum& seq1, const SeqNum& seq2); private: Type _value; + + friend struct std::hash; }; int seqcmp(const SeqNum& seq1, const SeqNum& seq2); int seqlen(const SeqNum& seq1, const SeqNum& seq2); int seqoff(const SeqNum& seq1, const SeqNum& seq2); + +} +namespace std { + +template<> struct hash { + size_t operator()(const udt::SeqNum& seqNum) const { + return std::hash()(seqNum._value); + } +}; + } #endif // hifi_SeqNum_h From 797f74f3d94699759bb8f888cb32eb49165ea9f2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 24 Jul 2015 12:27:40 -0700 Subject: [PATCH 045/549] Use SeqNum --- libraries/networking/src/Node.h | 2 +- libraries/networking/src/udt/CongestionControl.cpp | 2 +- libraries/networking/src/udt/Packet.cpp | 13 ++++--------- libraries/networking/src/udt/Packet.h | 6 ++++-- libraries/networking/src/udt/SeqNum.h | 4 ++-- libraries/networking/src/udt/Socket.h | 2 +- 6 files changed, 13 insertions(+), 16 deletions(-) diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 178146c948..411e9982c5 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -85,7 +85,7 @@ private: bool _canAdjustLocks; bool _canRez; - std::map _lastSequenceNumbers; + std::map _lastSequenceNumbers; }; typedef QSharedPointer SharedNodePointer; diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 75ebc0929c..fbb172ecee 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -21,7 +21,7 @@ void UdtCC::init() { setAckTimer(_rcInterval); _lastAck = _sendCurrSeqNum; - _lastDecSeq = SeqNum::MAX; + _lastDecSeq = SeqNum{ SeqNum::MAX }; _congestionWindowSize = 16.0; _packetSendPeriod = 1.0; diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 47ea6ffef3..ebfea3742e 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -65,7 +65,7 @@ Packet::Packet(qint64 size, bool isReliable, bool isPartOfMessage) : adjustPayloadStartAndCapacity(); // set the UDT header to default values - writeSequenceNumber(0); + writeSequenceNumber(SeqNum()); } Packet::Packet(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr) : @@ -142,18 +142,13 @@ void Packet::readIsPartOfMessage() { void Packet::readSequenceNumber() { SequenceNumberAndBitField seqNumBitField = *reinterpret_cast(_packet.get()); - _sequenceNumber = (seqNumBitField & ~BIT_FIELD_MASK); // Remove the bit field + _sequenceNumber = SeqNum{ seqNumBitField & ~BIT_FIELD_MASK }; // Remove the bit field } -static const uint32_t MAX_SEQUENCE_NUMBER = UINT32_MAX >> BIT_FIELD_LENGTH; - -void Packet::writeSequenceNumber(SequenceNumber sequenceNumber) { - // make sure this is a sequence number <= 29 bit unsigned max (536,870,911) - Q_ASSERT(sequenceNumber <= MAX_SEQUENCE_NUMBER); - +void Packet::writeSequenceNumber(SeqNum seqNum) { // grab pointer to current SequenceNumberAndBitField SequenceNumberAndBitField* seqNumBitField = reinterpret_cast(_packet.get()); // write new value by ORing (old value & BIT_FIELD_MASK) with new seqNum - *seqNumBitField = (*seqNumBitField & BIT_FIELD_MASK) | sequenceNumber; + *seqNumBitField = (*seqNumBitField & BIT_FIELD_MASK) | (SeqNum::Type)seqNum; } diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index 39770bb022..51f66e0dab 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -18,6 +18,7 @@ #include "BasePacket.h" #include "PacketHeaders.h" +#include "SeqNum.h" namespace udt { @@ -50,7 +51,8 @@ public: virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers - void writeSequenceNumber(SequenceNumber sequenceNumber); + void writeSequenceNumber(SeqNum seqNum); + SeqNum getSequenceNumber() const { return _sequenceNumber; } protected: Packet(qint64 size, bool isReliable = false, bool isPartOfMessage = false); @@ -70,7 +72,7 @@ protected: bool _isReliable { false }; bool _isPartOfMessage { false }; - SequenceNumber _sequenceNumber { 0 }; + SeqNum _sequenceNumber; }; } // namespace udt diff --git a/libraries/networking/src/udt/SeqNum.h b/libraries/networking/src/udt/SeqNum.h index ad5a6c7c21..b73f5fa23c 100644 --- a/libraries/networking/src/udt/SeqNum.h +++ b/libraries/networking/src/udt/SeqNum.h @@ -27,7 +27,7 @@ public: static const Type THRESHOLD = 0x0FFFFFFF; // threshold for comparing sequence numbers static const Type MAX = 0x1FFFFFFF; // maximum sequence number used in UDT - SeqNum() : _value(0) {} + SeqNum() = default; SeqNum(const SeqNum& other) : _value(other._value) {} // Only explicit conversions @@ -79,7 +79,7 @@ public: friend int seqoff(const SeqNum& seq1, const SeqNum& seq2); private: - Type _value; + Type _value { 0 }; friend struct std::hash; }; diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 68985133ac..8c8b4b4883 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -64,7 +64,7 @@ private: std::unordered_map _unfilteredHandlers; - std::unordered_map _packetSequenceNumbers; + std::unordered_map _packetSequenceNumbers; }; } // namespace udt From da93301ac6d39669f7d7bc0310cd0bce5316b777 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 24 Jul 2015 14:33:40 -0700 Subject: [PATCH 046/549] More work on SendQueue (Threading) --- libraries/networking/src/udt/SendQueue.cpp | 70 +++++++++++++++------- libraries/networking/src/udt/SendQueue.h | 25 +++++--- 2 files changed, 68 insertions(+), 27 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index af19162bb8..9bc306c88f 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -11,18 +11,38 @@ #include "SendQueue.h" +#include + #include #include #include +#include "Packet.h" +#include "Socket.h" + namespace udt { -std::unique_ptr SendQueue::create() { - return std::unique_ptr(new SendQueue()); +std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr dest) { + auto queue = std::unique_ptr(new SendQueue(socket, dest)); + + // Setup queue private thread + QThread* thread = new QThread(queue.get()); + thread->setObjectName("Networking: SendQueue"); // Name thread for easier debug + thread->connect(queue.get(), &QObject::destroyed, thread, &QThread::quit); // Thread auto cleanup + thread->connect(thread, &QThread::finished, thread, &QThread::deleteLater); // Thread auto cleanup + + // Move queue to private thread and start it + queue->moveToThread(thread); + thread->start(); + + return std::move(queue); } -SendQueue::SendQueue() { +SendQueue::SendQueue(Socket* socket, HifiSockAddr dest) : + _socket(socket), + _destination(dest) +{ _sendTimer.reset(new QTimer(this)); _sendTimer->setSingleShot(true); QObject::connect(_sendTimer.get(), &QTimer::timeout, this, &SendQueue::sendNextPacket); @@ -32,8 +52,13 @@ SendQueue::SendQueue() { } void SendQueue::queuePacket(std::unique_ptr packet) { - QWriteLocker locker(&_packetsLock); - _packets.push_back(std::move(packet)); + { + QWriteLocker locker(&_packetsLock); + _packets.push_back(std::move(packet)); + } + if (!_running) { + start(); + } } void SendQueue::start() { @@ -41,28 +66,37 @@ void SendQueue::start() { if (thread() != QThread::currentThread()) { QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection); } + _running = true; + // This will send a packet and fire the send timer sendNextPacket(); } void SendQueue::stop() { - // We need to make sure this is called on the right thread - if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, "stop", Qt::QueuedConnection); - } - // Stopping the timer will stop the sending of packets - _sendTimer->stop(); + _running = false; +} + +void SendQueue::sendPacket(const Packet& packet) { + _socket->writeDatagram(packet.getData(), packet.getDataSize(), _destination); } void SendQueue::sendNextPacket() { + if (!_running) { + return; + } + // Record timing auto sendTime = msecTimestampNow(); // msec _lastSendTimestamp = sendTime; - // TODO send packet - // Insert the packet we have just sent in the sent list - _sentPackets[_nextPacket->readSequenceNumber()].swap(_nextPacket); - Q_ASSERT(!_nextPacket); // There should be no packet where we inserted + if (_nextPacket) { + _nextPacket->writeSequenceNumber(++_currentSeqNum); + sendPacket(*_nextPacket); + + // Insert the packet we have just sent in the sent list + _sentPackets[_nextPacket->getSequenceNumber()].swap(_nextPacket); + Q_ASSERT(!_nextPacket); // There should be no packet where we inserted + } { // Grab next packet to be sent QWriteLocker locker(&_packetsLock); @@ -72,11 +106,7 @@ void SendQueue::sendNextPacket() { // How long before next packet send auto timeToSleep = (sendTime + _packetSendPeriod) - msecTimestampNow(); // msec - if (timeToSleep > 0) { - _sendTimer->start(timeToSleep); - } else { - _sendTimer->start(0); - } + _sendTimer->start(std::max((quint64)0, timeToSleep)); } } diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 9767cfe7aa..3317ead795 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -18,19 +18,24 @@ #include #include -#include "Packet.h" +#include "../HifiSockAddr.h" + +#include "SeqNum.h" class QTimer; namespace udt { +class Socket; +class Packet; + class SendQueue : public QObject { Q_OBJECT public: static const int DEFAULT_SEND_PERIOD = 16; // msec - static std::unique_ptr create(); + static std::unique_ptr create(Socket* socket, HifiSockAddr dest); void queuePacket(std::unique_ptr packet); int getQueueSize() const { return _packets.size(); } @@ -43,24 +48,30 @@ public: public slots: void start(); void stop(); + void sendPacket(const Packet& packet); private slots: void sendNextPacket(); private: - SendQueue(); + SendQueue(Socket* socket, HifiSockAddr dest); SendQueue(SendQueue& other) = delete; SendQueue(SendQueue&& other) = delete; QReadWriteLock _packetsLock; // Protects the packets to be sent list. std::list> _packets; // List of packets to be sent - std::unique_ptr _nextPacket; + std::unique_ptr _nextPacket; // Next packet to be sent + + Socket* _socket { nullptr }; // Socket to send packet on + HifiSockAddr _destination; // Destination addr + SeqNum _currentSeqNum; // Last sequence number sent out std::unique_ptr _sendTimer; // Send timer - std::atomic _packetSendPeriod; // Interval between two packet send envent in msec - std::atomic _lastSendTimestamp; // Record last time of packet departure + std::atomic _packetSendPeriod { 0 }; // Interval between two packet send envent in msec + std::atomic _lastSendTimestamp { 0 }; // Record last time of packet departure + std::atomic _running { false }; - std::unordered_map> _sentPackets; // Packets waiting for ACK. + std::unordered_map> _sentPackets; // Packets waiting for ACK. }; } From e330727e36a65ffd365cf4d46aac4b904dbc574c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 24 Jul 2015 15:24:40 -0700 Subject: [PATCH 047/549] Added NAK resend --- libraries/networking/src/udt/SendQueue.cpp | 43 +++++++++++++++++++--- libraries/networking/src/udt/SendQueue.h | 5 +++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 9bc306c88f..68b47914c2 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -21,7 +21,7 @@ #include "Packet.h" #include "Socket.h" -namespace udt { +using namespace udt; std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr dest) { auto queue = std::unique_ptr(new SendQueue(socket, dest)); @@ -79,6 +79,15 @@ void SendQueue::stop() { void SendQueue::sendPacket(const Packet& packet) { _socket->writeDatagram(packet.getData(), packet.getDataSize(), _destination); } + +void SendQueue::ack(SeqNum ack) { + // TODO Remove acked packet from sent list +} + +void SendQueue::nak(std::list naks) { + QWriteLocker locker(&_naksLock); + _naks.splice(_naks.end(), naks); // Add naks at the end +} void SendQueue::sendNextPacket() { if (!_running) { @@ -95,10 +104,36 @@ void SendQueue::sendNextPacket() { // Insert the packet we have just sent in the sent list _sentPackets[_nextPacket->getSequenceNumber()].swap(_nextPacket); - Q_ASSERT(!_nextPacket); // There should be no packet where we inserted + Q_ASSERT_X(!_nextPacket, + "SendQueue::sendNextPacket()", "Overriden packet in sent list"); } - { // Grab next packet to be sent + bool hasResend = false; + SeqNum seqNum; + { + // Check nak list for packet to resend + QWriteLocker locker(&_naksLock); + if (!_naks.empty()) { + hasResend = true; + seqNum = _naks.front(); + _naks.pop_front(); + } + } + + // Find packet in sent list using SeqNum + if (hasResend) { + auto it = _sentPackets.find(seqNum); + Q_ASSERT_X(it != _sentPackets.end(), + "SendQueue::sendNextPacket()", "Couldn't find NAKed packet to resend"); + + if (it != _sentPackets.end()) { + it->second.swap(_nextPacket); + _sentPackets.erase(it); + } + } + + // If there is no packet to resend, grab the next one in the list + if (!_nextPacket) { QWriteLocker locker(&_packetsLock); _nextPacket.swap(_packets.front()); _packets.pop_front(); @@ -108,5 +143,3 @@ void SendQueue::sendNextPacket() { auto timeToSleep = (sendTime + _packetSendPeriod) - msecTimestampNow(); // msec _sendTimer->start(std::max((quint64)0, timeToSleep)); } - -} diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 3317ead795..56b71eec54 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -50,6 +50,9 @@ public slots: void stop(); void sendPacket(const Packet& packet); + void ack(SeqNum ack); + void nak(std::list naks); + private slots: void sendNextPacket(); @@ -71,6 +74,8 @@ private: std::atomic _lastSendTimestamp { 0 }; // Record last time of packet departure std::atomic _running { false }; + QReadWriteLock _naksLock; // Protects the naks list. + std::list _naks; // Sequence numbers of packets to resend std::unordered_map> _sentPackets; // Packets waiting for ACK. }; From f06d21691d5205508836648a31a74083ea4ab01a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 24 Jul 2015 15:33:42 -0700 Subject: [PATCH 048/549] Added ACKs removal from sent list --- libraries/networking/src/udt/SendQueue.cpp | 13 ++++++++++++- libraries/networking/src/udt/SendQueue.h | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 68b47914c2..9046e05f26 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -81,7 +81,16 @@ void SendQueue::sendPacket(const Packet& packet) { } void SendQueue::ack(SeqNum ack) { - // TODO Remove acked packet from sent list + if (_lastAck == ack) { + return; + } + + QWriteLocker locker(&_sentLock); + for (auto seq = _lastAck; seq != ack; ++seq) { + _sentPackets.erase(seq); + } + + _lastAck = ack; } void SendQueue::nak(std::list naks) { @@ -103,6 +112,7 @@ void SendQueue::sendNextPacket() { sendPacket(*_nextPacket); // Insert the packet we have just sent in the sent list + QWriteLocker locker(&_sentLock); _sentPackets[_nextPacket->getSequenceNumber()].swap(_nextPacket); Q_ASSERT_X(!_nextPacket, "SendQueue::sendNextPacket()", "Overriden packet in sent list"); @@ -122,6 +132,7 @@ void SendQueue::sendNextPacket() { // Find packet in sent list using SeqNum if (hasResend) { + QWriteLocker locker(&_sentLock); auto it = _sentPackets.find(seqNum); Q_ASSERT_X(it != _sentPackets.end(), "SendQueue::sendNextPacket()", "Couldn't find NAKed packet to resend"); diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 56b71eec54..fa73c14578 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -68,6 +68,7 @@ private: Socket* _socket { nullptr }; // Socket to send packet on HifiSockAddr _destination; // Destination addr SeqNum _currentSeqNum; // Last sequence number sent out + SeqNum _lastAck; // ACKed sequence number std::unique_ptr _sendTimer; // Send timer std::atomic _packetSendPeriod { 0 }; // Interval between two packet send envent in msec @@ -76,6 +77,8 @@ private: QReadWriteLock _naksLock; // Protects the naks list. std::list _naks; // Sequence numbers of packets to resend + + QReadWriteLock _sentLock; // Protects the sent packet list std::unordered_map> _sentPackets; // Packets waiting for ACK. }; From 5b0495db8eed1aeac9788005b4adc9abfbdb44fc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Jul 2015 16:02:28 -0700 Subject: [PATCH 049/549] remove unused methods in PacketHeaders --- .../networking/src/udt/PacketHeaders.cpp | 32 ------------------- libraries/networking/src/udt/PacketHeaders.h | 7 ---- 2 files changed, 39 deletions(-) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 50586e1057..f7e34f0671 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -32,34 +32,6 @@ const QSet NON_SOURCED_PACKETS = QSet() const QSet RELIABLE_PACKETS = QSet(); -int arithmeticCodingValueFromBuffer(const char* checkValue) { - if (((uchar) *checkValue) < 255) { - return *checkValue; - } else { - return 255 + arithmeticCodingValueFromBuffer(checkValue + 1); - } -} - -int numBytesArithmeticCodingFromBuffer(const char* checkValue) { - if (((uchar) *checkValue) < 255) { - return 1; - } else { - return 1 + numBytesArithmeticCodingFromBuffer(checkValue + 1); - } -} - -int packArithmeticallyCodedValue(int value, char* destination) { - if (value < 255) { - // less than 255, just pack our value - destination[0] = (uchar) value; - return 1; - } else { - // pack 255 and then recursively pack on - ((unsigned char*)destination)[0] = 255; - return 1 + packArithmeticallyCodedValue(value - 255, destination + 1); - } -} - PacketVersion versionForPacketType(PacketType packetType) { switch (packetType) { case PacketType::EntityAdd: @@ -123,10 +95,6 @@ QString nameForPacketType(PacketType packetType) { return QString("unexpected"); } -int numBytesForArithmeticCodedPacketType(PacketType packetType) { - return (int) ceilf((float) packetType / 255); -} - uint qHash(const PacketType& key, uint seed) { // seems odd that Qt couldn't figure out this cast itself, but this fixes a compile error after switch to // strongly typed enum for PacketType diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 0cb20b2247..394ff01d4a 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -87,13 +87,6 @@ extern const QSet RELIABLE_PACKETS; QString nameForPacketType(PacketType packetType); PacketVersion versionForPacketType(PacketType packetType); -int numBytesForArithmeticCodedPacketType(PacketType packetType); -int numBytesForPacketHeaderGivenPacketType(PacketType packetType); -int packArithmeticallyCodedValue(int value, char* destination); - -int arithmeticCodingValueFromBuffer(const char* checkValue); -int numBytesArithmeticCodingFromBuffer(const char* checkValue); - uint qHash(const PacketType& key, uint seed); QDebug operator<<(QDebug debug, const PacketType& type); From ffb1b9cc935c48c328cdbb7326f812e32fe08ead Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Jul 2015 16:06:05 -0700 Subject: [PATCH 050/549] add a message for PacketHeaders --- libraries/networking/src/udt/PacketHeaders.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 394ff01d4a..155d5e349d 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -23,9 +23,9 @@ #include "UUID.h" -// NOTE: if adding a new packet packetType, you can replace one marked usable or add at the end -// NOTE: if you want the name of the packet packetType to be available for debugging or logging, update nameForPacketType() as well - +// If adding a new packet packetType, you can replace one marked usable or add at the end. +// If you want the name of the packet packetType to be available for debugging or logging, update nameForPacketType() as well +// This enum must hold 256 or fewer packet types (so the value is <= 255) since it is statically typed as a uint8_t enum class PacketType : uint8_t { Unknown, StunResponse, From 49a18be24b74238f0e438cb85f13b2dfaa73b06e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Jul 2015 16:11:22 -0700 Subject: [PATCH 051/549] use totalHeadersSize from Packet in NLPacket --- libraries/networking/src/NLPacket.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 5de7d3065f..5359d6cf2c 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -160,29 +160,29 @@ NLPacket& NLPacket::operator=(NLPacket&& other) { } PacketType NLPacket::typeInHeader(const udt::Packet& packet) { - auto headerOffset = packet.Packet::localHeaderSize(); + auto headerOffset = packet.Packet::totalHeadersSize(); return *reinterpret_cast(packet.getData() + headerOffset); } PacketVersion NLPacket::versionInHeader(const udt::Packet& packet) { - auto headerOffset = packet.Packet::localHeaderSize(); + auto headerOffset = packet.Packet::totalHeadersSize(); return *reinterpret_cast(packet.getData() + headerOffset + sizeof(PacketType)); } QUuid NLPacket::sourceIDInHeader(const udt::Packet& packet) { - int offset = packet.Packet::localHeaderSize() + sizeof(PacketType) + sizeof(PacketVersion); + int offset = packet.Packet::totalHeadersSize() + sizeof(PacketType) + sizeof(PacketVersion); return QUuid::fromRfc4122(QByteArray::fromRawData(packet.getData() + offset, NUM_BYTES_RFC4122_UUID)); } QByteArray NLPacket::verificationHashInHeader(const udt::Packet& packet) { - int offset = packet.Packet::localHeaderSize() + sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID; + int offset = packet.Packet::totalHeadersSize() + sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID; return QByteArray(packet.getData() + offset, NUM_BYTES_MD5_HASH); } QByteArray NLPacket::hashForPacketAndSecret(const udt::Packet& packet, const QUuid& connectionSecret) { QCryptographicHash hash(QCryptographicHash::Md5); - int offset = packet.Packet::localHeaderSize() + sizeof(PacketType) + sizeof(PacketVersion) + int offset = packet.Packet::totalHeadersSize() + sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH; // add the packet payload and the connection UUID @@ -194,7 +194,7 @@ QByteArray NLPacket::hashForPacketAndSecret(const udt::Packet& packet, const QUu } void NLPacket::writeTypeAndVersion() { - auto headerOffset = Packet::localHeaderSize(); + auto headerOffset = Packet::totalHeadersSize(); // Pack the packet type memcpy(_packet.get() + headerOffset, &_type, sizeof(PacketType)); @@ -233,7 +233,7 @@ void NLPacket::readSourceID() { void NLPacket::writeSourceID(const QUuid& sourceID) { Q_ASSERT(!NON_SOURCED_PACKETS.contains(_type)); - auto offset = Packet::localHeaderSize() + sizeof(PacketType) + sizeof(PacketVersion); + auto offset = Packet::totalHeadersSize() + sizeof(PacketType) + sizeof(PacketVersion); memcpy(_packet.get() + offset, sourceID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); _sourceID = sourceID; @@ -242,7 +242,7 @@ void NLPacket::writeSourceID(const QUuid& sourceID) { void NLPacket::writeVerificationHashGivenSecret(const QUuid& connectionSecret) { Q_ASSERT(!NON_SOURCED_PACKETS.contains(_type) && !NON_VERIFIED_PACKETS.contains(_type)); - auto offset = Packet::localHeaderSize() + sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID; + auto offset = Packet::totalHeadersSize() + sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID; QByteArray verificationHash = hashForPacketAndSecret(*this, connectionSecret); memcpy(_packet.get() + offset, verificationHash.data(), verificationHash.size()); From f4ade0ee8e0e0ce150465a7b4c61ed74ebb2bc87 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Jul 2015 16:13:05 -0700 Subject: [PATCH 052/549] remove lastSequenceNumbers from Node --- libraries/networking/src/Node.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 178146c948..53a2aced8c 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -24,7 +24,6 @@ #include "NetworkPeer.h" #include "NodeData.h" #include "NodeType.h" -#include "udt/Packet.h" #include "SimpleMovingAverage.h" #include "MovingPercentile.h" @@ -84,8 +83,6 @@ private: MovingPercentile _clockSkewMovingPercentile; bool _canAdjustLocks; bool _canRez; - - std::map _lastSequenceNumbers; }; typedef QSharedPointer SharedNodePointer; From 47a05bd3ecdb4b36db4f45ceedce13361a145f25 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Jul 2015 16:17:06 -0700 Subject: [PATCH 053/549] repairs for dead listener checks --- libraries/networking/src/PacketReceiver.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index cb35b9b5c9..e62fcd072a 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -230,7 +230,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { auto listener = it.value(); - if (listener.first && it->second.isValid()) { + if (listener.first) { bool success = false; @@ -273,12 +273,21 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { Q_ARG(QSharedPointer, QSharedPointer(nlPacket.release()))); } + } else { + listenerIsDead = true; } } else { emit dataReceived(NodeType::Unassigned, nlPacket->getDataSize()); - success = listener.second.invoke(listener.first, - Q_ARG(QSharedPointer, QSharedPointer(nlPacket.release()))); + // one final check on the QPointer before we invoke + if (listener.first) { + success = listener.second.invoke(listener.first, + Q_ARG(QSharedPointer, + QSharedPointer(nlPacket.release()))); + } else { + listenerIsDead = true; + } + } if (!success) { From ff3cca1c20541575fa76ffeb04c6e051b5b24b73 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Jul 2015 16:17:49 -0700 Subject: [PATCH 054/549] fix indentation in BasePacket --- libraries/networking/src/udt/BasePacket.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/BasePacket.cpp b/libraries/networking/src/udt/BasePacket.cpp index 0f940e01e8..0f1cc72d98 100644 --- a/libraries/networking/src/udt/BasePacket.cpp +++ b/libraries/networking/src/udt/BasePacket.cpp @@ -24,8 +24,7 @@ std::unique_ptr BasePacket::create(qint64 size) { } std::unique_ptr BasePacket::fromReceivedPacket(std::unique_ptr data, - qint64 size, - const HifiSockAddr& senderSockAddr) { + qint64 size, const HifiSockAddr& senderSockAddr) { // Fail with invalid size Q_ASSERT(size >= 0); From 78688ebaca3032e530dda681f6e7262f0c4696a7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Jul 2015 16:18:58 -0700 Subject: [PATCH 055/549] add construction of QIODevice for BasePacket copy --- libraries/networking/src/udt/BasePacket.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/BasePacket.cpp b/libraries/networking/src/udt/BasePacket.cpp index 0f1cc72d98..083a62b155 100644 --- a/libraries/networking/src/udt/BasePacket.cpp +++ b/libraries/networking/src/udt/BasePacket.cpp @@ -65,7 +65,9 @@ BasePacket::BasePacket(std::unique_ptr data, qint64 size, const HifiSockAd } -BasePacket::BasePacket(const BasePacket& other) { +BasePacket::BasePacket(const BasePacket& other) : + QIODevice() +{ *this = other; } From b3d33bc59f10b29e3b792aa96dbd725990d27939 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Jul 2015 16:20:49 -0700 Subject: [PATCH 056/549] copy the ControlPacket type when moving ControlPacket --- libraries/networking/src/udt/ControlPacket.cpp | 6 ++++-- libraries/networking/src/udt/ControlPacket.h | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index e8e9eff048..73fca9ed8a 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -61,11 +61,13 @@ ControlPacket::ControlPacket(quint64 timestamp) : ControlPacket::ControlPacket(ControlPacket&& other) : BasePacket(std::move(other)) { - + _type = other._type; } -ControlPacket& ControlPacket::operator=(Packet&& other) { +ControlPacket& ControlPacket::operator=(ControlPacket&& other) { BasePacket::operator=(std::move(other)); + _type = other._type; + return *this; } diff --git a/libraries/networking/src/udt/ControlPacket.h b/libraries/networking/src/udt/ControlPacket.h index 1ebf9009db..04357ab307 100644 --- a/libraries/networking/src/udt/ControlPacket.h +++ b/libraries/networking/src/udt/ControlPacket.h @@ -46,10 +46,10 @@ private: ControlPacket(Type type, const SequenceNumberList& sequenceNumbers); ControlPacket(quint64 timestamp); ControlPacket(ControlPacket&& other); - ControlPacket(const Packet& other) = delete; + ControlPacket(const ControlPacket& other) = delete; - ControlPacket& operator=(Packet&& other); - ControlPacket& operator=(const Packet& other) = delete; + ControlPacket& operator=(ControlPacket&& other); + ControlPacket& operator=(const ControlPacket& other) = delete; Type _type; }; From f50154551b05904c787d0a2a5e8644f6cd6e900e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Jul 2015 16:23:35 -0700 Subject: [PATCH 057/549] fix comment for sequence number write --- libraries/networking/src/udt/Socket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index aa5085de04..7eb53f5a28 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -65,7 +65,7 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc qint64 bytesWritten = _udpSocket.writeDatagram(datagram, sockAddr.getAddress(), sockAddr.getPort()); - // TODO:: + // TODO: write the correct sequence number to the Packet here // const_cast(packet).writeSequenceNumber(sequenceNumber); if (bytesWritten < 0) { From 2cf4a1f3e1db3cc263f847b3280f56016c6f0c72 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Jul 2015 16:29:44 -0700 Subject: [PATCH 058/549] move MAX_PACKET_HEADER_SIZE to NLPacket --- libraries/networking/src/NLPacket.h | 6 ++++++ libraries/networking/src/udt/PacketHeaders.h | 1 - libraries/octree/src/OctreePacketData.h | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index 3309032e68..896fbaa66d 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -19,6 +19,12 @@ class NLPacket : public udt::Packet { Q_OBJECT public: + + // this is used by the Octree classes - must be known at compile time + static const int MAX_PACKET_HEADER_SIZE = + sizeof(udt::Packet::SequenceNumberAndBitField) + sizeof(udt::Packet::MessageNumberAndBitField) + + sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH; + static std::unique_ptr create(PacketType type, qint64 size = -1, bool isReliable = false, bool isPartOfMessage = false); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 155d5e349d..d8bc1d52e6 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -76,7 +76,6 @@ enum class PacketType : uint8_t { }; const int NUM_BYTES_MD5_HASH = 16; -const int MAX_PACKET_HEADER_BYTES = 4 + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH; typedef char PacketVersion; diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index a242f9117f..da4ca7164d 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include "OctreeConstants.h" @@ -46,7 +46,7 @@ const unsigned int OCTREE_PACKET_EXTRA_HEADERS_SIZE = sizeof(OCTREE_PACKET_FLAGS + sizeof(OCTREE_PACKET_SEQUENCE) + sizeof(OCTREE_PACKET_SENT_TIME); const unsigned int MAX_OCTREE_PACKET_DATA_SIZE = - udt::MAX_PACKET_SIZE - (MAX_PACKET_HEADER_BYTES + OCTREE_PACKET_EXTRA_HEADERS_SIZE); + udt::MAX_PACKET_SIZE - (NLPacket::MAX_PACKET_HEADER_SIZE + OCTREE_PACKET_EXTRA_HEADERS_SIZE); const unsigned int MAX_OCTREE_UNCOMRESSED_PACKET_SIZE = MAX_OCTREE_PACKET_DATA_SIZE; const unsigned int MINIMUM_ATTEMPT_MORE_PACKING = sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) + 40; From dce63c84a3d7170be1ed92d09b9738689763fd2a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Jul 2015 16:33:03 -0700 Subject: [PATCH 059/549] read and write uin8_t PacketType into SVO as int --- libraries/octree/src/Octree.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index a8a3f28f9a..c616ace9f9 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1902,7 +1902,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr if (getWantSVOfileVersions()) { // read just enough of the file to parse the header... - const unsigned long HEADER_LENGTH = sizeof(PacketType) + sizeof(PacketVersion); + const unsigned long HEADER_LENGTH = sizeof(int) + sizeof(PacketVersion); unsigned char fileHeader[HEADER_LENGTH]; inputStream.readRawData((char*)&fileHeader, HEADER_LENGTH); @@ -1912,8 +1912,9 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr unsigned long dataLength = HEADER_LENGTH; // if so, read the first byte of the file and see if it matches the expected version code - PacketType gotType; - memcpy(&gotType, dataAt, sizeof(gotType)); + int intPacketType; + memcpy(&intPacketType, dataAt, sizeof(intPacketType)); + PacketType gotType = (PacketType) intPacketType; dataAt += sizeof(expectedType); dataLength -= sizeof(expectedType); @@ -2076,16 +2077,17 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* element) { if(file.is_open()) { qCDebug(octree, "Saving binary SVO to file %s...", fileName); - PacketType expectedType = expectedDataPacketType(); - PacketVersion expectedVersion = versionForPacketType(expectedType); + PacketType expectedPacketType = expectedDataPacketType(); + int expectedIntType = (int) expectedPacketType; + PacketVersion expectedVersion = versionForPacketType(expectedPacketType); bool hasBufferBreaks = versionHasSVOfileBreaks(expectedVersion); // before reading the file, check to see if this version of the Octree supports file versions if (getWantSVOfileVersions()) { // if so, read the first byte of the file and see if it matches the expected version code - file.write(reinterpret_cast(&expectedType), sizeof(expectedType)); + file.write(reinterpret_cast(&expectedIntType), sizeof(expectedIntType)); file.write(&expectedVersion, sizeof(expectedVersion)); - qCDebug(octree) << "SVO file type: " << nameForPacketType(expectedType) << " version: " << (int)expectedVersion; + qCDebug(octree) << "SVO file type: " << expectedPacketType << " version: " << (int)expectedVersion; hasBufferBreaks = versionHasSVOfileBreaks(expectedVersion); } From 65ec50b01f0bb075f205bca953c5b162d77670c0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Jul 2015 16:42:07 -0700 Subject: [PATCH 060/549] remove an extra space --- libraries/networking/src/udt/BasePacket.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/BasePacket.h b/libraries/networking/src/udt/BasePacket.h index ff5acafaf0..d943e05204 100644 --- a/libraries/networking/src/udt/BasePacket.h +++ b/libraries/networking/src/udt/BasePacket.h @@ -30,7 +30,7 @@ public: static std::unique_ptr create(qint64 size = -1); static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); - static qint64 maxPayloadSize() { return MAX_PACKET_SIZE; } // The maximum payload size this packet can use to fit in MTU + static qint64 maxPayloadSize() { return MAX_PACKET_SIZE; } // The maximum payload size this packet can use to fit in MTU static qint64 localHeaderSize() { return 0; } // Current level's header size virtual qint64 totalHeadersSize() const { return 0; } // Cumulated size of all the headers From b0d96cdb885ed7bb2a3580827cb8920d846be105 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Jul 2015 16:43:17 -0700 Subject: [PATCH 061/549] use BasePacket::totalHeadersSize in ControlPacket --- libraries/networking/src/udt/ControlPacket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index 73fca9ed8a..a8688f2cdf 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -29,7 +29,7 @@ qint64 ControlPacket::localHeaderSize() { } qint64 ControlPacket::totalHeadersSize() const { - return BasePacket::localHeaderSize() + localHeaderSize(); + return BasePacket::totalHeadersSize() + localHeaderSize(); } ControlPacket::ControlPacket(Type type, const SequenceNumberList& sequenceNumbers) : From f4a9f21869886d0fca5ad1b2b4f3c3c5bd01f506 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 27 Jul 2015 11:28:48 -0700 Subject: [PATCH 062/549] Use udt instead declaring namespace in cpp --- libraries/networking/src/udt/CongestionControl.cpp | 4 +--- libraries/networking/src/udt/SeqNum.cpp | 10 +++------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index fbb172ecee..ebbf86ecd8 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -13,7 +13,7 @@ #include -namespace udt { +using namespace udt; void UdtCC::init() { _rcInterval = _synInterval; @@ -144,5 +144,3 @@ void UdtCC::onTimeout() { */ } } - -} \ No newline at end of file diff --git a/libraries/networking/src/udt/SeqNum.cpp b/libraries/networking/src/udt/SeqNum.cpp index 29347a9249..3ab4b23606 100644 --- a/libraries/networking/src/udt/SeqNum.cpp +++ b/libraries/networking/src/udt/SeqNum.cpp @@ -11,19 +11,17 @@ #include "SeqNum.h" -namespace udt { - -int seqcmp(const SeqNum& seq1, const SeqNum& seq2) { +int udt::seqcmp(const SeqNum& seq1, const SeqNum& seq2) { return (glm::abs(seq1._value - seq2._value) < SeqNum::THRESHOLD) ? (seq1._value - seq2._value) : (seq2._value - seq1._value); } -int seqlen(const SeqNum& seq1, const SeqNum& seq2) { +int udt::seqlen(const SeqNum& seq1, const SeqNum& seq2) { return (seq1._value <= seq2._value) ? (seq2._value - seq1._value + 1) : (seq2._value - seq1._value + SeqNum::MAX + 2); } -int seqoff(const SeqNum& seq1, const SeqNum& seq2) { +int udt::seqoff(const SeqNum& seq1, const SeqNum& seq2) { if (glm::abs(seq1._value - seq2._value) < SeqNum::THRESHOLD) { return seq2._value - seq1._value; } @@ -34,5 +32,3 @@ int seqoff(const SeqNum& seq1, const SeqNum& seq2) { return seq2._value - seq1._value + SeqNum::MAX + 1; } - -} From 1e766faa881f4e042a508708cc1cb9d735957db5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 27 Jul 2015 11:29:15 -0700 Subject: [PATCH 063/549] Remove unecessary headers --- libraries/networking/src/udt/Socket.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 8c8b4b4883..882ebe5841 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -20,10 +20,10 @@ #include #include -#include "../HifiSockAddr.h" -#include "Packet.h" - namespace udt { + +class Packet; +class HifiSockAddr; using PacketFilterOperator = std::function; From 3e8bb371d67224ce73c7ca24dba45c23f2752939 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 11:32:17 -0700 Subject: [PATCH 064/549] declare BasePacket in Socket --- libraries/networking/src/udt/Socket.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 882ebe5841..b97dce45fa 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -22,6 +22,7 @@ namespace udt { +class BasePacket; class Packet; class HifiSockAddr; From d0c3274b5f42fa5a191d402879ed5000fc31eddc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 11:36:09 -0700 Subject: [PATCH 065/549] include Packet for udt::Socket --- libraries/networking/src/udt/Socket.cpp | 1 + libraries/networking/src/udt/Socket.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 7eb53f5a28..8bf7f973ae 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -12,6 +12,7 @@ #include "Socket.h" #include "../NetworkLogging.h" +#include "Packet.h" using namespace udt; diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index b97dce45fa..184d8716fe 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -20,11 +20,13 @@ #include #include +#include "../HifiSockAddr.h" +#include "SeqNum.h" + namespace udt { class BasePacket; class Packet; -class HifiSockAddr; using PacketFilterOperator = std::function; From 6db401f6d347ba579db211e1c8796712076350c4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 27 Jul 2015 11:38:49 -0700 Subject: [PATCH 066/549] Foreward declare SeqNum --- libraries/networking/src/udt/Socket.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 184d8716fe..b23903501e 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -21,12 +21,12 @@ #include #include "../HifiSockAddr.h" -#include "SeqNum.h" namespace udt { class BasePacket; class Packet; +class SeqNum; using PacketFilterOperator = std::function; From 507592b08868fe75f1ca2c7cfa4a7735e9c0c1f2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 11:40:05 -0700 Subject: [PATCH 067/549] add paths to CongestionControl files --- libraries/networking/src/udt/CongestionControl.cpp | 2 +- libraries/networking/src/udt/CongestionControl.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index ebbf86ecd8..4f32be0d06 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -1,6 +1,6 @@ // // CongestionControl.cpp -// +// libraries/networking/src/udt // // Created by Clement on 7/23/15. // Copyright 2015 High Fidelity, Inc. diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index fdf8803ec0..fe7f4a15fc 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -1,6 +1,6 @@ // // CongestionControl.h -// +// libraries/networking/src/udt // // Created by Clement on 7/23/15. // Copyright 2015 High Fidelity, Inc. From f520caa5fe47440bad330b3b0c800aab6b6b6cfe Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 27 Jul 2015 12:06:27 -0700 Subject: [PATCH 068/549] Connection class draft --- libraries/networking/src/udt/Connection.cpp | 31 ++++++++++++++++ libraries/networking/src/udt/Connection.h | 41 +++++++++++++++++++++ libraries/networking/src/udt/SendQueue.cpp | 1 - libraries/networking/src/udt/SendQueue.h | 7 ++-- 4 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 libraries/networking/src/udt/Connection.cpp create mode 100644 libraries/networking/src/udt/Connection.h diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp new file mode 100644 index 0000000000..c28a5f6ed0 --- /dev/null +++ b/libraries/networking/src/udt/Connection.cpp @@ -0,0 +1,31 @@ +// +// Connection.cpp +// +// +// Created by Clement on 7/27/15. +// Copyright 2015 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 "Connection.h" + +#include "../HifiSockAddr.h" +#include "ControlPacket.h" +#include "Packet.h" +#include "Socket.h" + +using namespace udt; + +Connection::Connection(Socket* parentSocket, HifiSockAddr destination) { + +} + +void Connection::send(std::unique_ptr packet) { + +} + +void Connection::processControl(std::unique_ptr controlPacket) { + +} diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h new file mode 100644 index 0000000000..ea49edd1e7 --- /dev/null +++ b/libraries/networking/src/udt/Connection.h @@ -0,0 +1,41 @@ +// +// Connection.h +// +// +// Created by Clement on 7/27/15. +// Copyright 2015 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 +// + +#ifndef hifi_Connection_h +#define hifi_Connection_h + +#include + +#include "SendQueue.h" + +class HifiSockAddr; + +namespace udt { + +class ControlPacket; +class Packet; +class Socket; + +class Connection { + +public: + Connection(Socket* parentSocket, HifiSockAddr destination); + + void send(std::unique_ptr packet); + void processControl(std::unique_ptr controlPacket); + +private: + std::unique_ptr _sendQueue; +}; + +} + +#endif // hifi_Connection_h diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 9046e05f26..c52621dccd 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -14,7 +14,6 @@ #include #include -#include #include diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index fa73c14578..9a46f0f119 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -15,15 +15,14 @@ #include #include -#include -#include +#include +#include +#include #include "../HifiSockAddr.h" #include "SeqNum.h" -class QTimer; - namespace udt { class Socket; From b0e7c208ac289d9a87d5bcbb704cdb51ea72ea81 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 12:21:27 -0700 Subject: [PATCH 069/549] initial version of the sleeping ControlSender --- .../networking/src/udt/ControlSender.cpp | 40 +++++++++++++++++++ libraries/networking/src/udt/ControlSender.h | 39 ++++++++++++++++++ libraries/networking/src/udt/Socket.cpp | 35 ++++++++++++++++ libraries/networking/src/udt/Socket.h | 6 ++- 4 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 libraries/networking/src/udt/ControlSender.cpp create mode 100644 libraries/networking/src/udt/ControlSender.h diff --git a/libraries/networking/src/udt/ControlSender.cpp b/libraries/networking/src/udt/ControlSender.cpp new file mode 100644 index 0000000000..dd9948502a --- /dev/null +++ b/libraries/networking/src/udt/ControlSender.cpp @@ -0,0 +1,40 @@ +// +// ControlSender.cpp +// libraries/networking/src/udt +// +// Created by Stephen Birarda on 2015-07-27. +// Copyright 2015 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 +#include + +#include +#include + +#include "ControlSender.h" + +using namespace udt; + +void ControlSender::loop() { + while (!_isStopped) { + // grab the time now + auto start = std::chrono::high_resolution_clock::now(); + + // for each of the connections managed by the udt::Socket, we need to ask for the ACK value to send + + // since we're infinitely looping, give the thread a chance to process events + QCoreApplication::processEvents(); + + auto end = std::chrono::high_resolution_clock::now(); + + std::chrono::duration elapsed = end - start; + int timeToSleep = _synInterval - (int) elapsed.count(); + + // based on how much time it took us to process, let's figure out how much time we have need to sleep + std::this_thread::sleep_for(std::chrono::microseconds(timeToSleep)); + } +} diff --git a/libraries/networking/src/udt/ControlSender.h b/libraries/networking/src/udt/ControlSender.h new file mode 100644 index 0000000000..040c6a70db --- /dev/null +++ b/libraries/networking/src/udt/ControlSender.h @@ -0,0 +1,39 @@ +// +// ControlSender.h +// libraries/networking/src/udt +// +// Created by Stephen Birarda on 2015-07-27. +// Copyright 2015 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 +// + +#pragma once + +#ifndef hifi_ControlSender_h +#define hifi_ControlSender_h + +#include + +namespace udt { + +// Handles the sending of periodic control packets for all active UDT reliable connections +// Currently the interval for all connections is the same, so one thread is sufficient to manage all +class ControlSender : public QObject { + Q_OBJECT +public: + ControlSender(QObject* parent = 0) : QObject(parent) {}; + +public slots: + void loop(); // infinitely loops and sleeps to manage rate of control packet sending + void stop() { _isStopped = true; } // stops the loop + +private: + int _synInterval = 10 * 1000; + bool _isStopped { false }; +}; + +} + +#endif // hifi_ControlSender_h diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 8bf7f973ae..57c4b75b12 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -11,7 +11,10 @@ #include "Socket.h" +#include + #include "../NetworkLogging.h" +#include "ControlSender.h" #include "Packet.h" using namespace udt; @@ -20,6 +23,38 @@ Socket::Socket(QObject* parent) : QObject(parent) { connect(&_udpSocket, &QUdpSocket::readyRead, this, &Socket::readPendingDatagrams); + + // make a QThread for the ControlSender to live on + QThread* controlThread = new QThread(this); + + // setup the ControlSender and parent it + _controlSender = new ControlSender; + + // move the ControlSender to its thread + _controlSender->moveToThread(controlThread); + + // start the ControlSender once the thread is started + connect(controlThread, &QThread::started, _controlSender, &ControlSender::loop); + + // make sure the control thread is named so we can identify it + controlThread->setObjectName("UDT Control Thread"); + + // start the control thread + controlThread->start(); +} + +Socket::~Socket() { + if (_controlSender) { + QThread* controlThread = _controlSender->thread(); + + // tell the control sender to stop and be deleted so we can wait on its thread + QMetaObject::invokeMethod(_controlSender, "stop"); + _controlSender->deleteLater(); + + // make sure the control thread goes down + controlThread->quit(); + controlThread->wait(); + } } void Socket::rebind() { diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 184d8716fe..be6ef982af 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -24,8 +24,9 @@ #include "SeqNum.h" namespace udt { - + class BasePacket; +class ControlSender; class Packet; using PacketFilterOperator = std::function; @@ -37,6 +38,7 @@ class Socket : public QObject { Q_OBJECT public: Socket(QObject* object = 0); + ~Socket(); quint16 localPort() const { return _udpSocket.localPort(); } @@ -68,6 +70,8 @@ private: std::unordered_map _unfilteredHandlers; std::unordered_map _packetSequenceNumbers; + + ControlSender* _controlSender { nullptr }; }; } // namespace udt From 594b4f4814819de64d513799f78f06ee94821822 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 12:25:46 -0700 Subject: [PATCH 070/549] fix the shutdown of the ControlSender --- libraries/networking/src/udt/Socket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 57c4b75b12..9078ac0f6d 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -48,7 +48,7 @@ Socket::~Socket() { QThread* controlThread = _controlSender->thread(); // tell the control sender to stop and be deleted so we can wait on its thread - QMetaObject::invokeMethod(_controlSender, "stop"); + _controlSender->stop(); _controlSender->deleteLater(); // make sure the control thread goes down From a31053d4508c0b0491db89806af6d39fe7fe2c11 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 13:02:11 -0700 Subject: [PATCH 071/549] small spacing change --- libraries/networking/src/udt/ControlSender.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/ControlSender.cpp b/libraries/networking/src/udt/ControlSender.cpp index dd9948502a..1b955d0254 100644 --- a/libraries/networking/src/udt/ControlSender.cpp +++ b/libraries/networking/src/udt/ControlSender.cpp @@ -25,7 +25,7 @@ void ControlSender::loop() { auto start = std::chrono::high_resolution_clock::now(); // for each of the connections managed by the udt::Socket, we need to ask for the ACK value to send - + // since we're infinitely looping, give the thread a chance to process events QCoreApplication::processEvents(); From 41a0f6b9809939022b48a47c4dc868e258861f9f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 27 Jul 2015 14:18:18 -0700 Subject: [PATCH 072/549] Added +/- operator to SeqNum --- libraries/networking/src/udt/SeqNum.cpp | 4 ++-- libraries/networking/src/udt/SeqNum.h | 31 +++++++++++++++++++++---- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/udt/SeqNum.cpp b/libraries/networking/src/udt/SeqNum.cpp index 3ab4b23606..506b8bf3c9 100644 --- a/libraries/networking/src/udt/SeqNum.cpp +++ b/libraries/networking/src/udt/SeqNum.cpp @@ -13,12 +13,12 @@ int udt::seqcmp(const SeqNum& seq1, const SeqNum& seq2) { return (glm::abs(seq1._value - seq2._value) < SeqNum::THRESHOLD) ? (seq1._value - seq2._value) - : (seq2._value - seq1._value); + : (seq2._value - seq1._value); } int udt::seqlen(const SeqNum& seq1, const SeqNum& seq2) { return (seq1._value <= seq2._value) ? (seq2._value - seq1._value + 1) - : (seq2._value - seq1._value + SeqNum::MAX + 2); + : (seq2._value - seq1._value + SeqNum::MAX + 2); } int udt::seqoff(const SeqNum& seq1, const SeqNum& seq2) { diff --git a/libraries/networking/src/udt/SeqNum.h b/libraries/networking/src/udt/SeqNum.h index b73f5fa23c..a57ad01e11 100644 --- a/libraries/networking/src/udt/SeqNum.h +++ b/libraries/networking/src/udt/SeqNum.h @@ -74,6 +74,11 @@ public: return _value != other._value; } + friend SeqNum operator+(const SeqNum a, const Type& b); + friend SeqNum operator+(const Type& a, const SeqNum b); + friend SeqNum operator-(const SeqNum a, const Type& b); + friend SeqNum operator-(const Type& a, const SeqNum b); + friend int seqcmp(const SeqNum& seq1, const SeqNum& seq2); friend int seqlen(const SeqNum& seq1, const SeqNum& seq2); friend int seqoff(const SeqNum& seq1, const SeqNum& seq2); @@ -84,20 +89,36 @@ private: friend struct std::hash; }; +SeqNum operator+(SeqNum a, const SeqNum::Type& b) { + a += b; + return a; +} + +SeqNum operator+(const SeqNum::Type& a, SeqNum b) { + b += a; + return b; +} + +SeqNum operator-(SeqNum a, const SeqNum::Type& b) { + a -= b; + return a; +} + +SeqNum operator-(const SeqNum::Type& a, SeqNum b) { + b -= a; + return b; +} + int seqcmp(const SeqNum& seq1, const SeqNum& seq2); int seqlen(const SeqNum& seq1, const SeqNum& seq2); int seqoff(const SeqNum& seq1, const SeqNum& seq2); } -namespace std { - -template<> struct hash { +template<> struct std::hash { size_t operator()(const udt::SeqNum& seqNum) const { return std::hash()(seqNum._value); } }; - -} #endif // hifi_SeqNum_h From 2b29f5c1301552a2c78d8a02f734ced25f621f3d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 27 Jul 2015 15:57:41 -0700 Subject: [PATCH 073/549] More work on Connnections --- libraries/networking/src/udt/Connection.cpp | 27 ++++++++++++++++- libraries/networking/src/udt/Connection.h | 4 +++ libraries/networking/src/udt/ControlPacket.h | 2 ++ libraries/networking/src/udt/SendQueue.cpp | 9 ++++-- libraries/networking/src/udt/SendQueue.h | 11 ++++--- libraries/networking/src/udt/SeqNum.h | 31 +++++++++++++++++--- 6 files changed, 73 insertions(+), 11 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index c28a5f6ed0..7fd643cd5c 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -23,9 +23,34 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination) { } void Connection::send(std::unique_ptr packet) { + if (_sendQueue) { + _sendQueue->queuePacket(std::move(packet)); + } +} +void Connection::processReceivedSeqNum(SeqNum seq) { + if (udt::seqcmp(seq, _largestRecievedSeqNum + 1) > 0) { + // TODO: Add range to loss list + + // TODO: Send loss report + } + + if (seq > _largestRecievedSeqNum) { + _largestRecievedSeqNum = seq; + } else { + // TODO: Remove seq from loss list + } } void Connection::processControl(std::unique_ptr controlPacket) { - + switch (controlPacket->getType()) { + case ControlPacket::Type::ACK: + break; + case ControlPacket::Type::ACK2: + break; + case ControlPacket::Type::NAK: + break; + case ControlPacket::Type::PacketPair: + break; + } } diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index ea49edd1e7..3f3b39524b 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -30,9 +30,13 @@ public: Connection(Socket* parentSocket, HifiSockAddr destination); void send(std::unique_ptr packet); + + void processReceivedSeqNum(SeqNum seq); void processControl(std::unique_ptr controlPacket); private: + + SeqNum _largestRecievedSeqNum; std::unique_ptr _sendQueue; }; diff --git a/libraries/networking/src/udt/ControlPacket.h b/libraries/networking/src/udt/ControlPacket.h index 04357ab307..8b9ccbf073 100644 --- a/libraries/networking/src/udt/ControlPacket.h +++ b/libraries/networking/src/udt/ControlPacket.h @@ -42,6 +42,8 @@ public: static qint64 localHeaderSize(); // Current level's header size virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers + Type getType() const { return _type; } + private: ControlPacket(Type type, const SequenceNumberList& sequenceNumbers); ControlPacket(quint64 timestamp); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index c52621dccd..7561a7042d 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -28,8 +28,8 @@ std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr dest) // Setup queue private thread QThread* thread = new QThread(queue.get()); thread->setObjectName("Networking: SendQueue"); // Name thread for easier debug - thread->connect(queue.get(), &QObject::destroyed, thread, &QThread::quit); // Thread auto cleanup - thread->connect(thread, &QThread::finished, thread, &QThread::deleteLater); // Thread auto cleanup + connect(queue.get(), &QObject::destroyed, thread, &QThread::quit); // Thread auto cleanup + connect(thread, &QThread::finished, thread, &QThread::deleteLater); // Thread auto cleanup // Move queue to private thread and start it queue->moveToThread(thread); @@ -50,6 +50,11 @@ SendQueue::SendQueue(Socket* socket, HifiSockAddr dest) : _lastSendTimestamp = 0; } +SendQueue::~SendQueue() { + assert(thread() == QThread::currentThread()); + _sendTimer->stop(); +} + void SendQueue::queuePacket(std::unique_ptr packet) { { QWriteLocker locker(&_packetsLock); diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 9a46f0f119..1a1a2fc90d 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -37,7 +37,7 @@ public: static std::unique_ptr create(Socket* socket, HifiSockAddr dest); void queuePacket(std::unique_ptr packet); - int getQueueSize() const { return _packets.size(); } + int getQueueSize() const { QReadLocker locker(&_packetsLock); return _packets.size(); } quint64 getLastSendTimestamp() const { return _lastSendTimestamp; } @@ -56,11 +56,14 @@ private slots: void sendNextPacket(); private: + friend struct std::default_delete; + SendQueue(Socket* socket, HifiSockAddr dest); SendQueue(SendQueue& other) = delete; SendQueue(SendQueue&& other) = delete; + ~SendQueue(); - QReadWriteLock _packetsLock; // Protects the packets to be sent list. + mutable QReadWriteLock _packetsLock; // Protects the packets to be sent list. std::list> _packets; // List of packets to be sent std::unique_ptr _nextPacket; // Next packet to be sent @@ -74,10 +77,10 @@ private: std::atomic _lastSendTimestamp { 0 }; // Record last time of packet departure std::atomic _running { false }; - QReadWriteLock _naksLock; // Protects the naks list. + mutable QReadWriteLock _naksLock; // Protects the naks list. std::list _naks; // Sequence numbers of packets to resend - QReadWriteLock _sentLock; // Protects the sent packet list + mutable QReadWriteLock _sentLock; // Protects the sent packet list std::unordered_map> _sentPackets; // Packets waiting for ACK. }; diff --git a/libraries/networking/src/udt/SeqNum.h b/libraries/networking/src/udt/SeqNum.h index a57ad01e11..5f541b0c36 100644 --- a/libraries/networking/src/udt/SeqNum.h +++ b/libraries/networking/src/udt/SeqNum.h @@ -74,6 +74,11 @@ public: return _value != other._value; } + friend bool operator<(const SeqNum& a, const SeqNum& b); + friend bool operator>(const SeqNum& a, const SeqNum& b); + friend bool operator<=(const SeqNum& a, const SeqNum& b); + friend bool operator>=(const SeqNum& a, const SeqNum& b); + friend SeqNum operator+(const SeqNum a, const Type& b); friend SeqNum operator+(const Type& a, const SeqNum b); friend SeqNum operator-(const SeqNum a, const Type& b); @@ -89,22 +94,40 @@ private: friend struct std::hash; }; -SeqNum operator+(SeqNum a, const SeqNum::Type& b) { + +inline bool operator<(const SeqNum& a, const SeqNum& b) { + +} + +inline bool operator>(const SeqNum& a, const SeqNum& b) { + +} + +inline bool operator<=(const SeqNum& a, const SeqNum& b) { + +} + +inline bool operator>=(const SeqNum& a, const SeqNum& b) { + +} + + +inline SeqNum operator+(SeqNum a, const SeqNum::Type& b) { a += b; return a; } -SeqNum operator+(const SeqNum::Type& a, SeqNum b) { +inline SeqNum operator+(const SeqNum::Type& a, SeqNum b) { b += a; return b; } -SeqNum operator-(SeqNum a, const SeqNum::Type& b) { +inline SeqNum operator-(SeqNum a, const SeqNum::Type& b) { a -= b; return a; } -SeqNum operator-(const SeqNum::Type& a, SeqNum b) { +inline SeqNum operator-(const SeqNum::Type& a, SeqNum b) { b -= a; return b; } From 50a7ef7c2024ed07f7fbf879fa6acbc013eb99fd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 15:59:04 -0700 Subject: [PATCH 074/549] remove the ControlSender and perform sync in Socket --- .../networking/src/udt/ControlSender.cpp | 40 ----------------- libraries/networking/src/udt/ControlSender.h | 39 ---------------- libraries/networking/src/udt/Socket.cpp | 45 +++++++------------ libraries/networking/src/udt/Socket.h | 5 ++- 4 files changed, 19 insertions(+), 110 deletions(-) delete mode 100644 libraries/networking/src/udt/ControlSender.cpp delete mode 100644 libraries/networking/src/udt/ControlSender.h diff --git a/libraries/networking/src/udt/ControlSender.cpp b/libraries/networking/src/udt/ControlSender.cpp deleted file mode 100644 index 1b955d0254..0000000000 --- a/libraries/networking/src/udt/ControlSender.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// -// ControlSender.cpp -// libraries/networking/src/udt -// -// Created by Stephen Birarda on 2015-07-27. -// Copyright 2015 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 -#include - -#include -#include - -#include "ControlSender.h" - -using namespace udt; - -void ControlSender::loop() { - while (!_isStopped) { - // grab the time now - auto start = std::chrono::high_resolution_clock::now(); - - // for each of the connections managed by the udt::Socket, we need to ask for the ACK value to send - - // since we're infinitely looping, give the thread a chance to process events - QCoreApplication::processEvents(); - - auto end = std::chrono::high_resolution_clock::now(); - - std::chrono::duration elapsed = end - start; - int timeToSleep = _synInterval - (int) elapsed.count(); - - // based on how much time it took us to process, let's figure out how much time we have need to sleep - std::this_thread::sleep_for(std::chrono::microseconds(timeToSleep)); - } -} diff --git a/libraries/networking/src/udt/ControlSender.h b/libraries/networking/src/udt/ControlSender.h deleted file mode 100644 index 040c6a70db..0000000000 --- a/libraries/networking/src/udt/ControlSender.h +++ /dev/null @@ -1,39 +0,0 @@ -// -// ControlSender.h -// libraries/networking/src/udt -// -// Created by Stephen Birarda on 2015-07-27. -// Copyright 2015 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 -// - -#pragma once - -#ifndef hifi_ControlSender_h -#define hifi_ControlSender_h - -#include - -namespace udt { - -// Handles the sending of periodic control packets for all active UDT reliable connections -// Currently the interval for all connections is the same, so one thread is sufficient to manage all -class ControlSender : public QObject { - Q_OBJECT -public: - ControlSender(QObject* parent = 0) : QObject(parent) {}; - -public slots: - void loop(); // infinitely loops and sleeps to manage rate of control packet sending - void stop() { _isStopped = true; } // stops the loop - -private: - int _synInterval = 10 * 1000; - bool _isStopped { false }; -}; - -} - -#endif // hifi_ControlSender_h diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 9078ac0f6d..a110a4f649 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -24,37 +24,11 @@ Socket::Socket(QObject* parent) : { connect(&_udpSocket, &QUdpSocket::readyRead, this, &Socket::readPendingDatagrams); - // make a QThread for the ControlSender to live on - QThread* controlThread = new QThread(this); + // make sure our synchronization method is called every SYN interval + connect(&_synTimer, &QTimer::timeout, this, &Socket::rateControlSync); - // setup the ControlSender and parent it - _controlSender = new ControlSender; - - // move the ControlSender to its thread - _controlSender->moveToThread(controlThread); - - // start the ControlSender once the thread is started - connect(controlThread, &QThread::started, _controlSender, &ControlSender::loop); - - // make sure the control thread is named so we can identify it - controlThread->setObjectName("UDT Control Thread"); - - // start the control thread - controlThread->start(); -} - -Socket::~Socket() { - if (_controlSender) { - QThread* controlThread = _controlSender->thread(); - - // tell the control sender to stop and be deleted so we can wait on its thread - _controlSender->stop(); - _controlSender->deleteLater(); - - // make sure the control thread goes down - controlThread->quit(); - controlThread->wait(); - } + // start our timer for the synchronization time interval + _synTimer->start(_synInterval); } void Socket::rebind() { @@ -148,3 +122,14 @@ void Socket::readPendingDatagrams() { } } } + +void Socket::rateControlSync() { + + + + if (_synTimer.interval() != _synInterval) { + // if the _synTimer interval doesn't match the current _synInterval (changes when the CC factory is changed) + // then restart it now with the right interval + _synTimer.start(_synInterval); + } +} diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index be6ef982af..35f8991634 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -18,6 +18,7 @@ #include #include +#include #include #include "../HifiSockAddr.h" @@ -61,6 +62,7 @@ public: private slots: void readPendingDatagrams(); + void rateControlSync(); private: QUdpSocket _udpSocket { this }; @@ -71,7 +73,8 @@ private: std::unordered_map _packetSequenceNumbers; - ControlSender* _controlSender { nullptr }; + int32_t _synInterval; + QTimer _synTimer; }; } // namespace udt From 10d6520098beb0c74039184c63f5b3c24f46cd04 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 16:00:00 -0700 Subject: [PATCH 075/549] add a TODO message to Socket::rateControlSync --- libraries/networking/src/udt/Socket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index a110a4f649..75924b791a 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -125,7 +125,7 @@ void Socket::readPendingDatagrams() { void Socket::rateControlSync() { - + // TODO: enumerate our list of connections and ask each of them to send off periodic ACK packet for rate control if (_synTimer.interval() != _synInterval) { // if the _synTimer interval doesn't match the current _synInterval (changes when the CC factory is changed) From d6487dcb81c6a2bf1f08cc6ea10889b4023b9a49 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 27 Jul 2015 16:01:07 -0700 Subject: [PATCH 076/549] Comparaison operators for seq nums --- libraries/networking/src/udt/SeqNum.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/SeqNum.h b/libraries/networking/src/udt/SeqNum.h index 5f541b0c36..5ae85f3dcf 100644 --- a/libraries/networking/src/udt/SeqNum.h +++ b/libraries/networking/src/udt/SeqNum.h @@ -96,19 +96,19 @@ private: inline bool operator<(const SeqNum& a, const SeqNum& b) { - + return (glm::abs(a._value - b._value) < SeqNum::THRESHOLD) ? a._value < b._value : b._value < a._value; } inline bool operator>(const SeqNum& a, const SeqNum& b) { - + return (glm::abs(a._value - b._value) < SeqNum::THRESHOLD) ? a._value > b._value : b._value > a._value; } inline bool operator<=(const SeqNum& a, const SeqNum& b) { - + return (glm::abs(a._value - b._value) < SeqNum::THRESHOLD) ? a._value <= b._value : b._value <= a._value; } inline bool operator>=(const SeqNum& a, const SeqNum& b) { - + return (glm::abs(a._value - b._value) < SeqNum::THRESHOLD) ? a._value >= b._value : b._value >= a._value; } From d787e086327bc1e78a31eff197580936dd5553f9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 16:10:52 -0700 Subject: [PATCH 077/549] fix for rate control sync in Socket --- libraries/networking/src/udt/Socket.cpp | 7 +++---- libraries/networking/src/udt/Socket.h | 3 +-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 75924b791a..c258283c61 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -14,7 +14,6 @@ #include #include "../NetworkLogging.h" -#include "ControlSender.h" #include "Packet.h" using namespace udt; @@ -28,7 +27,7 @@ Socket::Socket(QObject* parent) : connect(&_synTimer, &QTimer::timeout, this, &Socket::rateControlSync); // start our timer for the synchronization time interval - _synTimer->start(_synInterval); + _synTimer.start(_synInterval); } void Socket::rebind() { @@ -124,8 +123,8 @@ void Socket::readPendingDatagrams() { } void Socket::rateControlSync() { - - // TODO: enumerate our list of connections and ask each of them to send off periodic ACK packet for rate control + + // TODO: enumerate our list of connections and ask each of them to send off periodic ACK packet for rate control if (_synTimer.interval() != _synInterval) { // if the _synTimer interval doesn't match the current _synInterval (changes when the CC factory is changed) diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 2f49b9caf7..4feafa6c4c 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -39,7 +39,6 @@ class Socket : public QObject { Q_OBJECT public: Socket(QObject* object = 0); - ~Socket(); quint16 localPort() const { return _udpSocket.localPort(); } @@ -73,7 +72,7 @@ private: std::unordered_map _packetSequenceNumbers; - int32_t _synInterval; + int32_t _synInterval = 10; // 10ms QTimer _synTimer; }; From 75a722f63c8eed010211d858c30fffd0e6d7280c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 16:12:14 -0700 Subject: [PATCH 078/549] remove a couple of unused variables --- libraries/networking/src/udt/Packet.cpp | 1 - libraries/networking/src/udt/Packet.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index e9a5636172..a70c3bfbef 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -117,7 +117,6 @@ Packet& Packet::operator=(Packet&& other) { static const uint32_t CONTROL_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 1); static const uint32_t RELIABILITY_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 2); static const uint32_t MESSAGE_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 3); -static const int BIT_FIELD_LENGTH = 3; static const uint32_t BIT_FIELD_MASK = CONTROL_BIT_MASK | RELIABILITY_BIT_MASK | MESSAGE_BIT_MASK; void Packet::readIsReliable() { diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index 905af15ded..6189be0ef1 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -33,8 +33,6 @@ public: using MessageNumber = uint32_t; using MessageNumberAndBitField = uint32_t; - static const uint32_t DEFAULT_SEQUENCE_NUMBER = 0; - static std::unique_ptr create(qint64 size = -1, bool isReliable = false, bool isPartOfMessage = false); static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); From 90d25156741c78d6bfcc5a63aed40c5f22a250e0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 16:43:49 -0700 Subject: [PATCH 079/549] add methods to send ACKs from Connection --- libraries/networking/src/udt/Connection.cpp | 46 ++++++++++++++++--- libraries/networking/src/udt/Connection.h | 9 +++- .../networking/src/udt/ControlPacket.cpp | 36 ++++++++++----- libraries/networking/src/udt/ControlPacket.h | 11 ++--- libraries/networking/src/udt/SendQueue.cpp | 4 +- libraries/networking/src/udt/SendQueue.h | 3 +- libraries/networking/src/udt/Socket.cpp | 2 +- libraries/networking/src/udt/Socket.h | 2 +- 8 files changed, 82 insertions(+), 31 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 7fd643cd5c..4f309249ff 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -28,15 +28,47 @@ void Connection::send(std::unique_ptr packet) { } } +void Connection::sendACK() { + static const int ACK_PACKET_PAYLOAD_BYTES = 8; + + // setup the ACK packet, make it static so we can re-use it + static auto ackPacket = ControlPacket::create(ControlPacket::ACK, ACK_PACKET_PAYLOAD_BYTES); + + // have the send queue send off our packet + _sendQueue->sendPacket(*ackPacket); +} + +void Connection::sendLightACK() const { + static const int LIGHT_ACK_PACKET_PAYLOAD_BYTES = 4; + + // create the light ACK packet, make it static so we can re-use it + static auto lightACKPacket = ControlPacket::create(ControlPacket::ACK, LIGHT_ACK_PACKET_PAYLOAD_BYTES); + + SeqNum nextACKNumber = nextACK(); + + if (nextACKNumber != _lastReceivedAcknowledgedACK) { + // pack in the ACK + memcpy(lightACKPacket->getPayload(), &nextACKNumber, sizeof(nextACKNumber)); + + // have the send queue send off our packet + _sendQueue->sendPacket(*lightACKPacket); + } +} + +SeqNum Connection::nextACK() const { + // TODO: check if we have a loss list + return _largestReceivedSeqNum + 1; +} + void Connection::processReceivedSeqNum(SeqNum seq) { - if (udt::seqcmp(seq, _largestRecievedSeqNum + 1) > 0) { + if (udt::seqcmp(seq, _largestReceivedSeqNum + 1) > 0) { // TODO: Add range to loss list // TODO: Send loss report } - if (seq > _largestRecievedSeqNum) { - _largestRecievedSeqNum = seq; + if (seq > _largestReceivedSeqNum) { + _largestReceivedSeqNum = seq; } else { // TODO: Remove seq from loss list } @@ -44,13 +76,13 @@ void Connection::processReceivedSeqNum(SeqNum seq) { void Connection::processControl(std::unique_ptr controlPacket) { switch (controlPacket->getType()) { - case ControlPacket::Type::ACK: + case ControlPacket::ACK: break; - case ControlPacket::Type::ACK2: + case ControlPacket::ACK2: break; - case ControlPacket::Type::NAK: + case ControlPacket::NAK: break; - case ControlPacket::Type::PacketPair: + case ControlPacket::PacketPair: break; } } diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 3f3b39524b..8bfc2a3d31 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -31,12 +31,17 @@ public: void send(std::unique_ptr packet); + void sendACK(); + void sendLightACK() const; + + SeqNum nextACK() const; + void processReceivedSeqNum(SeqNum seq); void processControl(std::unique_ptr controlPacket); private: - - SeqNum _largestRecievedSeqNum; + SeqNum _largestReceivedSeqNum; + SeqNum _lastReceivedAcknowledgedACK; // The last sent ACK that has been acknowledged via an ACK2 from the peer std::unique_ptr _sendQueue; }; diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index a8688f2cdf..8d3a1561fc 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -13,8 +13,22 @@ using namespace udt; -std::unique_ptr ControlPacket::create(Type type, const SequenceNumberList& sequenceNumbers) { - return ControlPacket::create(type, sequenceNumbers); +std::unique_ptr ControlPacket::create(Type type, qint64 size) { + + std::unique_ptr controlPacket; + + if (size == -1) { + controlPacket = ControlPacket::create(type); + } else { + // Fail with invalid size + Q_ASSERT(size >= 0); + + controlPacket = ControlPacket::create(type, size); + } + + controlPacket->open(QIODevice::ReadWrite); + + return controlPacket; } ControlPacket::ControlPacketPair ControlPacket::createPacketPair(quint64 timestamp) { @@ -32,18 +46,18 @@ qint64 ControlPacket::totalHeadersSize() const { return BasePacket::totalHeadersSize() + localHeaderSize(); } -ControlPacket::ControlPacket(Type type, const SequenceNumberList& sequenceNumbers) : - BasePacket(localHeaderSize() + (sizeof(Packet::SequenceNumber) * sequenceNumbers.size())), +ControlPacket::ControlPacket(Type type) : + BasePacket(-1), + _type(type) +{ + adjustPayloadStartAndCapacity(); +} + +ControlPacket::ControlPacket(Type type, qint64 size) : + BasePacket(localHeaderSize() + size), _type(type) { adjustPayloadStartAndCapacity(); - - open(QIODevice::ReadWrite); - - // pack in the sequence numbers - for (auto& sequenceNumber : sequenceNumbers) { - writePrimitive(sequenceNumber); - } } ControlPacket::ControlPacket(quint64 timestamp) : diff --git a/libraries/networking/src/udt/ControlPacket.h b/libraries/networking/src/udt/ControlPacket.h index 8b9ccbf073..2eab8a2192 100644 --- a/libraries/networking/src/udt/ControlPacket.h +++ b/libraries/networking/src/udt/ControlPacket.h @@ -21,23 +21,21 @@ namespace udt { -using SequenceNumberList = std::vector; - class ControlPacket : public BasePacket { Q_OBJECT public: using TypeAndSubSequenceNumber = uint32_t; using ControlPacketPair = std::pair, std::unique_ptr>; - enum class Type : uint16_t { + enum Type : uint16_t { ACK, ACK2, NAK, PacketPair }; - std::unique_ptr create(Type type, const SequenceNumberList& sequenceNumbers); - ControlPacketPair createPacketPair(quint64 timestamp); + static std::unique_ptr create(Type type, qint64 size = -1); + static ControlPacketPair createPacketPair(quint64 timestamp); static qint64 localHeaderSize(); // Current level's header size virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers @@ -45,7 +43,8 @@ public: Type getType() const { return _type; } private: - ControlPacket(Type type, const SequenceNumberList& sequenceNumbers); + ControlPacket(Type type); + ControlPacket(Type type, qint64 size); ControlPacket(quint64 timestamp); ControlPacket(ControlPacket&& other); ControlPacket(const ControlPacket& other) = delete; diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 7561a7042d..65c1807d19 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -80,8 +80,8 @@ void SendQueue::stop() { _running = false; } -void SendQueue::sendPacket(const Packet& packet) { - _socket->writeDatagram(packet.getData(), packet.getDataSize(), _destination); +void SendQueue::sendPacket(const BasePacket& packet) { + _socket->writeUnreliablePacket(packet, _destination); } void SendQueue::ack(SeqNum ack) { diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 1a1a2fc90d..9c14c19ede 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -26,6 +26,7 @@ namespace udt { class Socket; +class BasePacket; class Packet; class SendQueue : public QObject { @@ -47,7 +48,7 @@ public: public slots: void start(); void stop(); - void sendPacket(const Packet& packet); + void sendPacket(const BasePacket& packet); void ack(SeqNum ack); void nak(std::list naks); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index c258283c61..6923879201 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -66,7 +66,7 @@ void Socket::setBufferSizes(int numBytes) { } } -qint64 Socket::writeUnreliablePacket(const Packet& packet, const HifiSockAddr& sockAddr) { +qint64 Socket::writeUnreliablePacket(const BasePacket& packet, const HifiSockAddr& sockAddr) { return writeDatagram(packet.getData(), packet.getDataSize(), sockAddr); } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 4feafa6c4c..f74ea49f0b 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -42,7 +42,7 @@ public: quint16 localPort() const { return _udpSocket.localPort(); } - qint64 writeUnreliablePacket(const Packet& packet, const HifiSockAddr& sockAddr); + qint64 writeUnreliablePacket(const BasePacket& packet, const HifiSockAddr& sockAddr); qint64 writeDatagram(const char* data, qint64 size, const HifiSockAddr& sockAddr) { return writeDatagram(QByteArray::fromRawData(data, size), sockAddr); } From f6fb421bf297c09c234b9e3dbd198b6a81a802ce Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 17:15:26 -0700 Subject: [PATCH 080/549] write out more packing of ACK packet in Connection --- libraries/networking/src/udt/Connection.cpp | 67 ++++++++++++++++++--- libraries/networking/src/udt/Connection.h | 12 +++- 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 4f309249ff..ae0ea6e065 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -17,6 +17,7 @@ #include "Socket.h" using namespace udt; +using namespace std::chrono; Connection::Connection(Socket* parentSocket, HifiSockAddr destination) { @@ -28,12 +29,57 @@ void Connection::send(std::unique_ptr packet) { } } -void Connection::sendACK() { - static const int ACK_PACKET_PAYLOAD_BYTES = 8; +void Connection::sendACK(bool wasCausedBySyncTimeout) { + static const int ACK_PACKET_PAYLOAD_BYTES = sizeof(SeqNum); // setup the ACK packet, make it static so we can re-use it static auto ackPacket = ControlPacket::create(ControlPacket::ACK, ACK_PACKET_PAYLOAD_BYTES); - + + auto currentTime = high_resolution_clock::now(); + + SeqNum nextACKNumber = nextACK(); + + if (nextACKNumber <= _lastReceivedAcknowledgedACK) { + // we already got an ACK2 for this ACK we would be sending, don't bother + return; + } + + if (nextACKNumber >= _lastSentACK) { + // we have received new packets since the last sent ACK + + // update the last sent ACK + _lastSentACK = nextACKNumber; + + // remove the ACKed packets from the receive queue + + } else if (nextACKNumber == _lastSentACK) { + // We already sent this ACK, but check if we should re-send it. + // We will re-send if it has been more than RTT + (4 * RTT variance) since the last ACK + milliseconds sinceLastACK = duration_cast(currentTime - _lastACKTime); + if (sinceLastACK.count() < (_rtt + (4 * _rttVariance))) { + return; + } + } + + // reset the ACK packet so we can fill it up and have it figure out what size it is + ackPacket->reset(); + + // pack in the ACK + ackPacket->writePrimitive(nextACKNumber); + + // pack in the RTT and variance + ackPacket->writePrimitive(_rtt); + ackPacket->writePrimitive(_rttVariance); + + // pack the available buffer size - must be a minimum of 2 + + if (wasCausedBySyncTimeout) { + // pack in the receive speed and bandwidth + + // record this as the last ACK send time + _lastACKTime = high_resolution_clock::now(); + } + // have the send queue send off our packet _sendQueue->sendPacket(*ackPacket); } @@ -46,13 +92,16 @@ void Connection::sendLightACK() const { SeqNum nextACKNumber = nextACK(); - if (nextACKNumber != _lastReceivedAcknowledgedACK) { - // pack in the ACK - memcpy(lightACKPacket->getPayload(), &nextACKNumber, sizeof(nextACKNumber)); - - // have the send queue send off our packet - _sendQueue->sendPacket(*lightACKPacket); + if (nextACKNumber == _lastReceivedAcknowledgedACK) { + // we already got an ACK2 for this ACK we would be sending, don't bother + return; } + + // pack in the ACK + memcpy(lightACKPacket->getPayload(), &nextACKNumber, sizeof(nextACKNumber)); + + // have the send queue send off our packet + _sendQueue->sendPacket(*lightACKPacket); } SeqNum Connection::nextACK() const { diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 8bfc2a3d31..882de3b79f 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -12,6 +12,7 @@ #ifndef hifi_Connection_h #define hifi_Connection_h +#include #include #include "SendQueue.h" @@ -31,7 +32,7 @@ public: void send(std::unique_ptr packet); - void sendACK(); + void sendACK(bool wasCausedBySyncTimeout = true); void sendLightACK() const; SeqNum nextACK() const; @@ -40,8 +41,15 @@ public: void processControl(std::unique_ptr controlPacket); private: - SeqNum _largestReceivedSeqNum; + SeqNum _largestReceivedSeqNum; // The largest sequence number received from the peer + SeqNum _lastSentACK; // The last sent ACK SeqNum _lastReceivedAcknowledgedACK; // The last sent ACK that has been acknowledged via an ACK2 from the peer + + int32_t _rtt; // RTT, in milliseconds + int32_t _rttVariance; // RTT variance + + std::chrono::high_resolution_clock::time_point _lastACKTime; + std::unique_ptr _sendQueue; }; From 52411bb8bac7ecd18515782761a56194ddddeade Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 17:23:39 -0700 Subject: [PATCH 081/549] pack ACK sub sequence number manually for control --- libraries/networking/src/udt/Connection.cpp | 5 ++++- libraries/networking/src/udt/Connection.h | 1 + libraries/networking/src/udt/ControlPacket.cpp | 2 +- libraries/networking/src/udt/ControlPacket.h | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index ae0ea6e065..4b249bc91e 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -64,7 +64,10 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { // reset the ACK packet so we can fill it up and have it figure out what size it is ackPacket->reset(); - // pack in the ACK + // pack in the ACK sub-sequence number + ackPacket->writePrimitive(_currentACKSubSequenceNumber++); + + // pack in the ACK number ackPacket->writePrimitive(nextACKNumber); // pack in the RTT and variance diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 882de3b79f..a9c73ce74a 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -44,6 +44,7 @@ private: SeqNum _largestReceivedSeqNum; // The largest sequence number received from the peer SeqNum _lastSentACK; // The last sent ACK SeqNum _lastReceivedAcknowledgedACK; // The last sent ACK that has been acknowledged via an ACK2 from the peer + SeqNum _currentACKSubSequenceNumber; // The current ACK sub-sequence number (used for Acknowledgment of ACKs) int32_t _rtt; // RTT, in milliseconds int32_t _rttVariance; // RTT variance diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index 8d3a1561fc..f62c7a6454 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -39,7 +39,7 @@ ControlPacket::ControlPacketPair ControlPacket::createPacketPair(quint64 timesta } qint64 ControlPacket::localHeaderSize() { - return sizeof(TypeAndSubSequenceNumber); + return sizeof(BitFieldAndControlType); } qint64 ControlPacket::totalHeadersSize() const { diff --git a/libraries/networking/src/udt/ControlPacket.h b/libraries/networking/src/udt/ControlPacket.h index 2eab8a2192..049f95cf59 100644 --- a/libraries/networking/src/udt/ControlPacket.h +++ b/libraries/networking/src/udt/ControlPacket.h @@ -24,7 +24,7 @@ namespace udt { class ControlPacket : public BasePacket { Q_OBJECT public: - using TypeAndSubSequenceNumber = uint32_t; + using BitFieldAndControlType = uint32_t; using ControlPacketPair = std::pair, std::unique_ptr>; enum Type : uint16_t { From d2c5e79ac2e0d26c1fcde50987ecc2e37f3cd5b9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 17:38:10 -0700 Subject: [PATCH 082/549] add writing of control bit and type to ControlPacket --- .../networking/src/udt/ControlPacket.cpp | 32 +++++++++++++++---- libraries/networking/src/udt/ControlPacket.h | 5 ++- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index f62c7a6454..8b863c5a21 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -18,17 +18,13 @@ std::unique_ptr ControlPacket::create(Type type, qint64 size) { std::unique_ptr controlPacket; if (size == -1) { - controlPacket = ControlPacket::create(type); + return ControlPacket::create(type); } else { // Fail with invalid size Q_ASSERT(size >= 0); - controlPacket = ControlPacket::create(type, size); + return ControlPacket::create(type, size); } - - controlPacket->open(QIODevice::ReadWrite); - - return controlPacket; } ControlPacket::ControlPacketPair ControlPacket::createPacketPair(quint64 timestamp) { @@ -39,7 +35,7 @@ ControlPacket::ControlPacketPair ControlPacket::createPacketPair(quint64 timesta } qint64 ControlPacket::localHeaderSize() { - return sizeof(BitFieldAndControlType); + return sizeof(ControlBitAndType); } qint64 ControlPacket::totalHeadersSize() const { @@ -51,6 +47,10 @@ ControlPacket::ControlPacket(Type type) : _type(type) { adjustPayloadStartAndCapacity(); + + open(QIODevice::ReadWrite); + + writeControlBitAndType(); } ControlPacket::ControlPacket(Type type, qint64 size) : @@ -58,6 +58,10 @@ ControlPacket::ControlPacket(Type type, qint64 size) : _type(type) { adjustPayloadStartAndCapacity(); + + open(QIODevice::ReadWrite); + + writeControlBitAndType(); } ControlPacket::ControlPacket(quint64 timestamp) : @@ -68,6 +72,8 @@ ControlPacket::ControlPacket(quint64 timestamp) : open(QIODevice::ReadWrite); + writeControlBitAndType(); + // pack in the timestamp writePrimitive(timestamp); } @@ -85,3 +91,15 @@ ControlPacket& ControlPacket::operator=(ControlPacket&& other) { return *this; } + +static const uint32_t CONTROL_BIT_MASK = 1 << (sizeof(ControlPacket::ControlBitAndType) - 1); + +void ControlPacket::writeControlBitAndType() { + ControlBitAndType* bitAndType = reinterpret_cast(_packet.get()); + + // write the control bit by OR'ing the current value with the CONTROL_BIT_MASK + *bitAndType = (*bitAndType | CONTROL_BIT_MASK); + + // write the type by OR'ing the type with the current value & CONTROL_BIT_MASK + *bitAndType = (*bitAndType & CONTROL_BIT_MASK) | (_type << sizeof((ControlPacket::Type) - 1)); +} diff --git a/libraries/networking/src/udt/ControlPacket.h b/libraries/networking/src/udt/ControlPacket.h index 049f95cf59..6d1b7eb5d3 100644 --- a/libraries/networking/src/udt/ControlPacket.h +++ b/libraries/networking/src/udt/ControlPacket.h @@ -24,7 +24,7 @@ namespace udt { class ControlPacket : public BasePacket { Q_OBJECT public: - using BitFieldAndControlType = uint32_t; + using ControlBitAndType = uint32_t; using ControlPacketPair = std::pair, std::unique_ptr>; enum Type : uint16_t { @@ -52,6 +52,9 @@ private: ControlPacket& operator=(ControlPacket&& other); ControlPacket& operator=(const ControlPacket& other) = delete; + // Header writers + void writeControlBitAndType(); + Type _type; }; From 75765d02e4ba3d073aa74758a11d163989538514 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 17:40:32 -0700 Subject: [PATCH 083/549] correct sizeof ACK_PACKET_PAYLOAD_BYTES in Connection --- libraries/networking/src/udt/Connection.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 4b249bc91e..3753729123 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -30,7 +30,8 @@ void Connection::send(std::unique_ptr packet) { } void Connection::sendACK(bool wasCausedBySyncTimeout) { - static const int ACK_PACKET_PAYLOAD_BYTES = sizeof(SeqNum); + static const int ACK_PACKET_PAYLOAD_BYTES = sizeof(_lastSentACK) + sizeof(_currentACKSubSequenceNumber) + + sizeof(_rtt) + sizeof(_rttVariance) + sizeof(int32_t) + sizeof(int32_t); // setup the ACK packet, make it static so we can re-use it static auto ackPacket = ControlPacket::create(ControlPacket::ACK, ACK_PACKET_PAYLOAD_BYTES); From c4f88a0f537f5761eb57515c49e91cd5e158a32a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 27 Jul 2015 17:41:15 -0700 Subject: [PATCH 084/549] Added loss list to connections --- libraries/networking/src/udt/Connection.cpp | 20 +++-- libraries/networking/src/udt/Connection.h | 2 + libraries/networking/src/udt/LossList.cpp | 99 +++++++++++++++++++++ libraries/networking/src/udt/LossList.h | 42 +++++++++ 4 files changed, 157 insertions(+), 6 deletions(-) create mode 100644 libraries/networking/src/udt/LossList.cpp create mode 100644 libraries/networking/src/udt/LossList.h diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 7fd643cd5c..d3b521e054 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -17,32 +17,40 @@ #include "Socket.h" using namespace udt; +using namespace std; Connection::Connection(Socket* parentSocket, HifiSockAddr destination) { } -void Connection::send(std::unique_ptr packet) { +void Connection::send(unique_ptr packet) { if (_sendQueue) { - _sendQueue->queuePacket(std::move(packet)); + _sendQueue->queuePacket(move(packet)); } } void Connection::processReceivedSeqNum(SeqNum seq) { - if (udt::seqcmp(seq, _largestRecievedSeqNum + 1) > 0) { - // TODO: Add range to loss list + // If this is not the next sequence number, report loss + if (seq > _largestRecievedSeqNum + 1) { + if (_largestRecievedSeqNum + 1 == seq - 1) { + _lossList.append(_largestRecievedSeqNum + 1); + } else { + _lossList.append(_largestRecievedSeqNum + 1, seq - 1); + } // TODO: Send loss report } if (seq > _largestRecievedSeqNum) { + // Update largest recieved sequence number _largestRecievedSeqNum = seq; } else { - // TODO: Remove seq from loss list + // Otherwise, it's a resend, remove it from the loss list + _lossList.remove(seq); } } -void Connection::processControl(std::unique_ptr controlPacket) { +void Connection::processControl(unique_ptr controlPacket) { switch (controlPacket->getType()) { case ControlPacket::Type::ACK: break; diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 3f3b39524b..3b25c7f1b1 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -14,6 +14,7 @@ #include +#include "LossList.h" #include "SendQueue.h" class HifiSockAddr; @@ -36,6 +37,7 @@ public: private: + LossList _lossList; SeqNum _largestRecievedSeqNum; std::unique_ptr _sendQueue; }; diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp new file mode 100644 index 0000000000..0a3eb5b4fb --- /dev/null +++ b/libraries/networking/src/udt/LossList.cpp @@ -0,0 +1,99 @@ +// +// LossList.cpp +// +// +// Created by Clement on 7/27/15. +// Copyright 2015 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 "LossList.h" + +using namespace udt; +using namespace std; + +void LossList::append(SeqNum seq) { + assert(_lossList.back().second < seq); + + if (getLength() > 0 && _lossList.back().second + 1 == seq) { + ++_lossList.back().second; + } else { + _lossList.push_back(make_pair(seq, seq)); + } + _length += 1; +} + +void LossList::append(SeqNum start, SeqNum end) { + if (getLength() > 0 && _lossList.back().second + 1 == start) { + _lossList.back().second = end; + } else { + _lossList.push_back(make_pair(start, end)); + } + _length += seqlen(start, end); +} + +void LossList::remove(SeqNum seq) { + auto it = find_if(_lossList.begin(), _lossList.end(), [&seq](pair pair) { + return pair.first <= seq && seq <= pair.second; + }); + + if (it != end(_lossList)) { + if (it->first == it->second) { + _lossList.erase(it); + } else if (seq == it->first) { + ++it->first; + } else if (seq == it->second) { + --it->second; + } else { + auto temp = it->second; + it->second = seq - 1; + _lossList.insert(it, make_pair(seq + 1, temp)); + } + } +} + +void LossList::remove(SeqNum start, SeqNum end) { + // Find the first segment sharing sequence numbers + auto it = find_if(_lossList.begin(), _lossList.end(), [&start, &end](pair pair) { + return (pair.first <= start && start <= pair.second) || + (start <= pair.first && pair.first <= end); + }); + + // If we found one + if (it != _lossList.end()) { + + // While the end of the current segment is contained, either shorten it (first one only - sometimes) + // or remove it altogether since it is fully contained it the range + while (it != _lossList.end() && end >= it->second) { + if (start <= it->first) { + // Segment is contained, erase it. + it = _lossList.erase(it); + } else { + // Beginning of segment not contained, modify end of segment. + // Will only occur sometimes one the first loop + it->second = start - 1; + ++it; + } + } + + // There might be more to remove + if (it != _lossList.end() && it->first <= end) { + if (start <= it->first) { + // Truncate beginning of segment + it->first = end + 1; + } else { + // Cut it in half if the range we are removing is contained within one segment + auto temp = it->second; + it->second = start - 1; + _lossList.insert(it, make_pair(end + 1, temp)); + } + } + } +} + +SeqNum LossList::getFirstSeqNum() { + assert(getLength() > 0); + return _lossList.front().first; +} \ No newline at end of file diff --git a/libraries/networking/src/udt/LossList.h b/libraries/networking/src/udt/LossList.h new file mode 100644 index 0000000000..ee20104b4d --- /dev/null +++ b/libraries/networking/src/udt/LossList.h @@ -0,0 +1,42 @@ +// +// LossList.h +// +// +// Created by Clement on 7/27/15. +// Copyright 2015 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 +// + +#ifndef hifi_LossList_h +#define hifi_LossList_h + +#include + +#include "SeqNum.h" + +namespace udt { + +class LossList { +public: + LossList() {} + + // Should always add at the end + void append(SeqNum seq); + void append(SeqNum start, SeqNum end); + + void remove(SeqNum seq); + void remove(SeqNum start, SeqNum end); + + int getLength() const { return _length; } + SeqNum getFirstSeqNum(); + +private: + std::list> _lossList; + int _length { 0 }; +}; + +} + +#endif // hifi_LossList_h \ No newline at end of file From f176c45a619c8ce97efb31c86ca954442bd1f001 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 17:48:38 -0700 Subject: [PATCH 085/549] return an ACK2 from processControl --- libraries/networking/src/udt/Connection.cpp | 4 ++++ libraries/networking/src/udt/ControlPacket.cpp | 14 +++++++++++++- libraries/networking/src/udt/ControlPacket.h | 2 ++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 3753729123..b0c35d4678 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -132,6 +132,10 @@ void Connection::processControl(std::unique_ptr controlPacket) { case ControlPacket::ACK: break; case ControlPacket::ACK2: + // change the type of the packet to an ACK2 and send it back + controlPacket->setType(ControlPacket::ACK2); + _sendQueue->sendPacket(*controlPacket); + break; case ControlPacket::NAK: break; diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index 8b863c5a21..5f28b96750 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -94,12 +94,24 @@ ControlPacket& ControlPacket::operator=(ControlPacket&& other) { static const uint32_t CONTROL_BIT_MASK = 1 << (sizeof(ControlPacket::ControlBitAndType) - 1); +void ControlPacket::setType(udt::ControlPacket::Type type) { + _type = type; + + writeType(); +} + void ControlPacket::writeControlBitAndType() { ControlBitAndType* bitAndType = reinterpret_cast(_packet.get()); // write the control bit by OR'ing the current value with the CONTROL_BIT_MASK *bitAndType = (*bitAndType | CONTROL_BIT_MASK); - // write the type by OR'ing the type with the current value & CONTROL_BIT_MASK + writeType(); +} + +void ControlPacket::writeType() { + ControlBitAndType* bitAndType = reinterpret_cast(_packet.get()); + + // write the type by OR'ing the new type with the current value & CONTROL_BIT_MASK *bitAndType = (*bitAndType & CONTROL_BIT_MASK) | (_type << sizeof((ControlPacket::Type) - 1)); } diff --git a/libraries/networking/src/udt/ControlPacket.h b/libraries/networking/src/udt/ControlPacket.h index 6d1b7eb5d3..d17e12e182 100644 --- a/libraries/networking/src/udt/ControlPacket.h +++ b/libraries/networking/src/udt/ControlPacket.h @@ -41,6 +41,7 @@ public: virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers Type getType() const { return _type; } + void setType(Type type); private: ControlPacket(Type type); @@ -54,6 +55,7 @@ private: // Header writers void writeControlBitAndType(); + void writeType(); Type _type; }; From 5833cea29deca7ebfe500660fba175fba469dad9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 27 Jul 2015 18:51:17 -0700 Subject: [PATCH 086/549] Send out NAK packets --- libraries/networking/src/udt/Connection.cpp | 29 ++++++++++++++++----- libraries/networking/src/udt/Connection.h | 2 +- libraries/networking/src/udt/LossList.cpp | 2 +- libraries/networking/src/udt/LossList.h | 2 +- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 20d8a9cb92..b66110979b 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -90,10 +90,10 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { } void Connection::sendLightACK() const { - static const int LIGHT_ACK_PACKET_PAYLOAD_BYTES = 4; - // create the light ACK packet, make it static so we can re-use it + static const int LIGHT_ACK_PACKET_PAYLOAD_BYTES = sizeof(SeqNum); static auto lightACKPacket = ControlPacket::create(ControlPacket::ACK, LIGHT_ACK_PACKET_PAYLOAD_BYTES); + lightACKPacket->reset(); // We need to reset it every time. SeqNum nextACKNumber = nextACK(); @@ -103,15 +103,18 @@ void Connection::sendLightACK() const { } // pack in the ACK - memcpy(lightACKPacket->getPayload(), &nextACKNumber, sizeof(nextACKNumber)); + lightACKPacket->writePrimitive(nextACKNumber); - // have the send queue send off our packet + // have the send queue send off our packet immediately _sendQueue->sendPacket(*lightACKPacket); } SeqNum Connection::nextACK() const { - // TODO: check if we have a loss list - return _largestReceivedSeqNum + 1; + if (_lossList.getLength() > 0) { + return _lossList.getFirstSeqNum(); + } else { + return _largestReceivedSeqNum + 1; + } } void Connection::processReceivedSeqNum(SeqNum seq) { @@ -123,7 +126,19 @@ void Connection::processReceivedSeqNum(SeqNum seq) { _lossList.append(_largestReceivedSeqNum + 1, seq - 1); } - // TODO: Send loss report + // create the loss report packet, make it static so we can re-use it + static const int NAK_PACKET_PAYLOAD_BYTES = 2 * sizeof(SeqNum); + static auto lossReport = ControlPacket::create(ControlPacket::NAK, NAK_PACKET_PAYLOAD_BYTES); + lossReport->reset(); // We need to reset it every time. + + // pack in the loss report + lossReport->writePrimitive(_largestReceivedSeqNum + 1); + if (_largestReceivedSeqNum + 1 != seq - 1) { + lossReport->writePrimitive(seq - 1); + } + + // have the send queue send off our packet immediately + _sendQueue->sendPacket(*lossReport); } if (seq > _largestReceivedSeqNum) { diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index f67404a16b..5d8d309d94 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -42,7 +42,7 @@ public: void processControl(std::unique_ptr controlPacket); private: - LossList _lossList; + LossList _lossList; // List of all missing packets SeqNum _largestReceivedSeqNum; // The largest sequence number received from the peer SeqNum _lastSentACK; // The last sent ACK SeqNum _lastReceivedAcknowledgedACK; // The last sent ACK that has been acknowledged via an ACK2 from the peer diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp index 0a3eb5b4fb..a8fe0912d5 100644 --- a/libraries/networking/src/udt/LossList.cpp +++ b/libraries/networking/src/udt/LossList.cpp @@ -93,7 +93,7 @@ void LossList::remove(SeqNum start, SeqNum end) { } } -SeqNum LossList::getFirstSeqNum() { +SeqNum LossList::getFirstSeqNum() const { assert(getLength() > 0); return _lossList.front().first; } \ No newline at end of file diff --git a/libraries/networking/src/udt/LossList.h b/libraries/networking/src/udt/LossList.h index ee20104b4d..dd7f1de2ff 100644 --- a/libraries/networking/src/udt/LossList.h +++ b/libraries/networking/src/udt/LossList.h @@ -30,7 +30,7 @@ public: void remove(SeqNum start, SeqNum end); int getLength() const { return _length; } - SeqNum getFirstSeqNum(); + SeqNum getFirstSeqNum() const; private: std::list> _lossList; From 89a53886cb828e766b50dc8eb8e59c2e33b053ff Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 27 Jul 2015 20:44:12 -0700 Subject: [PATCH 087/549] Read ACK, NAK control packet --- libraries/networking/src/udt/Connection.cpp | 37 +++++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index b66110979b..2f901d6540 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -36,6 +36,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { // setup the ACK packet, make it static so we can re-use it static auto ackPacket = ControlPacket::create(ControlPacket::ACK, ACK_PACKET_PAYLOAD_BYTES); + ackPacket->reset(); // We need to reset it every time. auto currentTime = high_resolution_clock::now(); @@ -63,9 +64,6 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { } } - // reset the ACK packet so we can fill it up and have it figure out what size it is - ackPacket->reset(); - // pack in the ACK sub-sequence number ackPacket->writePrimitive(_currentACKSubSequenceNumber++); @@ -152,13 +150,38 @@ void Connection::processReceivedSeqNum(SeqNum seq) { void Connection::processControl(unique_ptr controlPacket) { switch (controlPacket->getType()) { - case ControlPacket::ACK: + case ControlPacket::ACK: { + // read the ACK sub-sequence number + SeqNum currentACKSubSequenceNumber; + controlPacket->readPrimitive(¤tACKSubSequenceNumber); + + // read the ACK number + SeqNum nextACKNumber; + controlPacket->readPrimitive(&nextACKNumber); + + // read the RTT and variance + int32_t rtt{ 0 }, rttVariance{ 0 }; + controlPacket->readPrimitive(&rtt); + controlPacket->readPrimitive(&rttVariance); + break; - case ControlPacket::ACK2: + } + case ControlPacket::ACK2: { + break; - case ControlPacket::NAK: + } + case ControlPacket::NAK: { + // read the loss report + SeqNum start, end; + controlPacket->readPrimitive(&start); + if (controlPacket->bytesLeftToRead() >= (qint64)sizeof(SeqNum)) { + controlPacket->readPrimitive(&end); + } break; - case ControlPacket::PacketPair: + } + case ControlPacket::PacketPair: { + break; + } } } From 3efd1be3d656347a1ad3abe345604eb35a85f0d5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 09:54:46 -0700 Subject: [PATCH 088/549] resolve conflicts for removal of ACK2 process --- libraries/networking/src/udt/Connection.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 2a482ec4ec..18d3658270 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -167,10 +167,6 @@ void Connection::processControl(unique_ptr controlPacket) { break; } case ControlPacket::ACK2: { - // change the type of the packet to an ACK2 and send it back - controlPacket->setType(ControlPacket::ACK2); - _sendQueue->sendPacket(*controlPacket); - break; } case ControlPacket::NAK: { From c14fee2ee8d1fa316ea4a547e8b8695830e50247 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 09:56:31 -0700 Subject: [PATCH 089/549] remove initialization of rtt and rttVariance --- libraries/networking/src/udt/Connection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 18d3658270..abe0ef8986 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -160,7 +160,7 @@ void Connection::processControl(unique_ptr controlPacket) { controlPacket->readPrimitive(&nextACKNumber); // read the RTT and variance - int32_t rtt{ 0 }, rttVariance{ 0 }; + int32_t rtt, rttVariance; controlPacket->readPrimitive(&rtt); controlPacket->readPrimitive(&rttVariance); From 17d8085ab58fb42d02c54a377f19879836d9b218 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 10:01:38 -0700 Subject: [PATCH 090/549] add process methods for control packet types --- libraries/networking/src/udt/Connection.cpp | 54 +++++++++++++-------- libraries/networking/src/udt/Connection.h | 4 ++ 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index abe0ef8986..d12f2b9fdb 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -91,7 +91,6 @@ void Connection::sendLightACK() const { // create the light ACK packet, make it static so we can re-use it static const int LIGHT_ACK_PACKET_PAYLOAD_BYTES = sizeof(SeqNum); static auto lightACKPacket = ControlPacket::create(ControlPacket::ACK, LIGHT_ACK_PACKET_PAYLOAD_BYTES); - lightACKPacket->reset(); // We need to reset it every time. SeqNum nextACKNumber = nextACK(); @@ -100,6 +99,9 @@ void Connection::sendLightACK() const { return; } + // reset the lightACKPacket before we go to write the ACK to it + lightACKPacket->reset(); + // pack in the ACK lightACKPacket->writePrimitive(nextACKNumber); @@ -151,31 +153,15 @@ void Connection::processReceivedSeqNum(SeqNum seq) { void Connection::processControl(unique_ptr controlPacket) { switch (controlPacket->getType()) { case ControlPacket::ACK: { - // read the ACK sub-sequence number - SeqNum currentACKSubSequenceNumber; - controlPacket->readPrimitive(¤tACKSubSequenceNumber); - - // read the ACK number - SeqNum nextACKNumber; - controlPacket->readPrimitive(&nextACKNumber); - - // read the RTT and variance - int32_t rtt, rttVariance; - controlPacket->readPrimitive(&rtt); - controlPacket->readPrimitive(&rttVariance); - + processACK(move(controlPacket)); break; } case ControlPacket::ACK2: { + processACK2(move(controlPacket)); break; } case ControlPacket::NAK: { - // read the loss report - SeqNum start, end; - controlPacket->readPrimitive(&start); - if (controlPacket->bytesLeftToRead() >= (qint64)sizeof(SeqNum)) { - controlPacket->readPrimitive(&end); - } + processNAK(move(controlPacket)); break; } case ControlPacket::PacketPair: { @@ -184,3 +170,31 @@ void Connection::processControl(unique_ptr controlPacket) { } } } + +void Connection::processACK(std::unique_ptr controlPacket) { + // read the ACK sub-sequence number + SeqNum currentACKSubSequenceNumber; + controlPacket->readPrimitive(¤tACKSubSequenceNumber); + + // read the ACK number + SeqNum nextACKNumber; + controlPacket->readPrimitive(&nextACKNumber); + + // read the RTT and variance + int32_t rtt, rttVariance; + controlPacket->readPrimitive(&rtt); + controlPacket->readPrimitive(&rttVariance); +} + +void Connection::processACK2(std::unique_ptr controlPacket) { + +} + +void Connection::processNAK(std::unique_ptr controlPacket) { + // read the loss report + SeqNum start, end; + controlPacket->readPrimitive(&start); + if (controlPacket->bytesLeftToRead() >= (qint64)sizeof(SeqNum)) { + controlPacket->readPrimitive(&end); + } +} diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 5d8d309d94..f96a571de4 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -42,6 +42,10 @@ public: void processControl(std::unique_ptr controlPacket); private: + void processACK(std::unique_ptr controlPacket); + void processACK2(std::unique_ptr controlPacket); + void processNAK(std::unique_ptr controlPacket); + LossList _lossList; // List of all missing packets SeqNum _largestReceivedSeqNum; // The largest sequence number received from the peer SeqNum _lastSentACK; // The last sent ACK From 1c6b14d17c439de9e8dbb8944dc5ac8f6db195b8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 10:24:56 -0700 Subject: [PATCH 091/549] add file path to clement's header --- libraries/networking/src/udt/SeqNum.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/SeqNum.cpp b/libraries/networking/src/udt/SeqNum.cpp index 506b8bf3c9..668c1f131a 100644 --- a/libraries/networking/src/udt/SeqNum.cpp +++ b/libraries/networking/src/udt/SeqNum.cpp @@ -1,6 +1,6 @@ // // SeqNum.cpp -// +// libraries/networking/src/udt // // Created by Clement on 7/23/15. // Copyright 2015 High Fidelity, Inc. From c32c95c707adf8ffbe4bb7ab5872f6d6a6509f17 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 10:33:07 -0700 Subject: [PATCH 092/549] complete implementation of processLightACK --- libraries/networking/src/udt/Connection.cpp | 22 ++++++++++++++++++++- libraries/networking/src/udt/Connection.h | 3 +++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index d12f2b9fdb..184597004e 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -153,7 +153,12 @@ void Connection::processReceivedSeqNum(SeqNum seq) { void Connection::processControl(unique_ptr controlPacket) { switch (controlPacket->getType()) { case ControlPacket::ACK: { - processACK(move(controlPacket)); + if (controlPacket->getPayloadSize() == sizeof(SeqNum)) { + processLightACK(move(controlPacket)); + } else { + processACK(move(controlPacket)); + } + break; } case ControlPacket::ACK2: { @@ -186,6 +191,21 @@ void Connection::processACK(std::unique_ptr controlPacket) { controlPacket->readPrimitive(&rttVariance); } +void Connection::processLightACK(std::unique_ptr controlPacket) { + // read the ACKed sequence number + SeqNum ack; + controlPacket->readPrimitive(&ack); + + // must be larger than the last received ACK to be processed + if (ack > _lastReceivedACK) { + // decrease the flow window size by the offset between the last received ACK and this ACK + _flowWindowSize -= seqoff(_lastReceivedACK, ack); + + // update the last received ACK to the this one + _lastReceivedACK = ack; + } +} + void Connection::processACK2(std::unique_ptr controlPacket) { } diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index f96a571de4..f1d2210b2f 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -43,17 +43,20 @@ public: private: void processACK(std::unique_ptr controlPacket); + void processLightACK(std::unique_ptr controlPacket); void processACK2(std::unique_ptr controlPacket); void processNAK(std::unique_ptr controlPacket); LossList _lossList; // List of all missing packets SeqNum _largestReceivedSeqNum; // The largest sequence number received from the peer SeqNum _lastSentACK; // The last sent ACK + SeqNum _lastReceivedACK; // The last ACK received SeqNum _lastReceivedAcknowledgedACK; // The last sent ACK that has been acknowledged via an ACK2 from the peer SeqNum _currentACKSubSequenceNumber; // The current ACK sub-sequence number (used for Acknowledgment of ACKs) int32_t _rtt; // RTT, in milliseconds int32_t _rttVariance; // RTT variance + int _flowWindowSize; // Flow control window size std::chrono::high_resolution_clock::time_point _lastACKTime; From 8b71462dc14c499f2a33c9d95b96f13d1c6d3476 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Jul 2015 10:36:00 -0700 Subject: [PATCH 093/549] Remove unnecessary headers --- libraries/gpu/src/gpu/State.h | 1 - libraries/networking/src/udt/Connection.cpp | 9 +++------ libraries/octree/src/OctreeEditPacketSender.h | 10 +++++----- tests/render-utils/src/main.cpp | 1 - tests/ui/src/main.cpp | 1 - 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index 39cad1445f..ac350b0f5f 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -15,7 +15,6 @@ #include #include -#include #include // Why a macro and not a fancy template you will ask me ? diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index d12f2b9fdb..386ad13bb6 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -152,18 +152,15 @@ void Connection::processReceivedSeqNum(SeqNum seq) { void Connection::processControl(unique_ptr controlPacket) { switch (controlPacket->getType()) { - case ControlPacket::ACK: { + case ControlPacket::ACK: processACK(move(controlPacket)); break; - } - case ControlPacket::ACK2: { + case ControlPacket::ACK2: processACK2(move(controlPacket)); break; - } - case ControlPacket::NAK: { + case ControlPacket::NAK: processNAK(move(controlPacket)); break; - } case ControlPacket::PacketPair: { break; diff --git a/libraries/octree/src/OctreeEditPacketSender.h b/libraries/octree/src/OctreeEditPacketSender.h index be44aec88d..d10870a221 100644 --- a/libraries/octree/src/OctreeEditPacketSender.h +++ b/libraries/octree/src/OctreeEditPacketSender.h @@ -12,19 +12,19 @@ #ifndef hifi_OctreeEditPacketSender_h #define hifi_OctreeEditPacketSender_h +#include + #include #include #include "JurisdictionMap.h" #include "SentPacketHistory.h" -namespace std { - template <> struct hash { +template <> struct std::hash { size_t operator()(const QUuid& uuid) const { - return qHash(uuid); + return qHash(uuid); } - }; -} +}; /// Utility for processing, packing, queueing and sending of outbound edit messages. class OctreeEditPacketSender : public PacketSender { diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 3b7eb18368..0806e0b6df 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -26,7 +26,6 @@ #include #include -#include #include #include diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index f5647bd176..fa45e807ae 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include From b25d860be4025dec88df8f1c1cf2032eb64ff9fe Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Jul 2015 10:36:19 -0700 Subject: [PATCH 094/549] Remove seqcmp --- libraries/networking/src/udt/CongestionControl.cpp | 2 +- libraries/networking/src/udt/SeqNum.cpp | 5 ----- libraries/networking/src/udt/SeqNum.h | 2 -- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 4f32be0d06..a75f62bb5f 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -106,7 +106,7 @@ void UdtCC::onLoss(const std::vector& losslist) { _loss = true; - if (seqcmp(losslist[0], _lastDecSeq) > 0) { + if (losslist[0] > _lastDecSeq) { _lastDecPeriod = _packetSendPeriod; _packetSendPeriod = ceil(_packetSendPeriod * 1.125); diff --git a/libraries/networking/src/udt/SeqNum.cpp b/libraries/networking/src/udt/SeqNum.cpp index 506b8bf3c9..1e853bf4f3 100644 --- a/libraries/networking/src/udt/SeqNum.cpp +++ b/libraries/networking/src/udt/SeqNum.cpp @@ -11,11 +11,6 @@ #include "SeqNum.h" -int udt::seqcmp(const SeqNum& seq1, const SeqNum& seq2) { - return (glm::abs(seq1._value - seq2._value) < SeqNum::THRESHOLD) ? (seq1._value - seq2._value) - : (seq2._value - seq1._value); -} - int udt::seqlen(const SeqNum& seq1, const SeqNum& seq2) { return (seq1._value <= seq2._value) ? (seq2._value - seq1._value + 1) : (seq2._value - seq1._value + SeqNum::MAX + 2); diff --git a/libraries/networking/src/udt/SeqNum.h b/libraries/networking/src/udt/SeqNum.h index 5ae85f3dcf..90b327e4c9 100644 --- a/libraries/networking/src/udt/SeqNum.h +++ b/libraries/networking/src/udt/SeqNum.h @@ -84,7 +84,6 @@ public: friend SeqNum operator-(const SeqNum a, const Type& b); friend SeqNum operator-(const Type& a, const SeqNum b); - friend int seqcmp(const SeqNum& seq1, const SeqNum& seq2); friend int seqlen(const SeqNum& seq1, const SeqNum& seq2); friend int seqoff(const SeqNum& seq1, const SeqNum& seq2); @@ -132,7 +131,6 @@ inline SeqNum operator-(const SeqNum::Type& a, SeqNum b) { return b; } -int seqcmp(const SeqNum& seq1, const SeqNum& seq2); int seqlen(const SeqNum& seq1, const SeqNum& seq2); int seqoff(const SeqNum& seq1, const SeqNum& seq2); From c3995a6e235e247ed5cb7cc4ee7799c96d3856eb Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Jul 2015 11:30:50 -0700 Subject: [PATCH 095/549] Fix LossList length not cumputed --- libraries/networking/src/udt/LossList.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp index a8fe0912d5..b1d3165f34 100644 --- a/libraries/networking/src/udt/LossList.cpp +++ b/libraries/networking/src/udt/LossList.cpp @@ -51,6 +51,7 @@ void LossList::remove(SeqNum seq) { it->second = seq - 1; _lossList.insert(it, make_pair(seq + 1, temp)); } + _length -= 1; } } @@ -68,11 +69,13 @@ void LossList::remove(SeqNum start, SeqNum end) { // or remove it altogether since it is fully contained it the range while (it != _lossList.end() && end >= it->second) { if (start <= it->first) { - // Segment is contained, erase it. + // Segment is contained, update new length and erase it. + _length -= seqlen(it->first, it->second); it = _lossList.erase(it); } else { // Beginning of segment not contained, modify end of segment. // Will only occur sometimes one the first loop + _length -= seqlen(start, it->second); it->second = start - 1; ++it; } @@ -82,9 +85,11 @@ void LossList::remove(SeqNum start, SeqNum end) { if (it != _lossList.end() && it->first <= end) { if (start <= it->first) { // Truncate beginning of segment + _length -= seqlen(it->first, end); it->first = end + 1; } else { // Cut it in half if the range we are removing is contained within one segment + _length -= seqlen(start, end); auto temp = it->second; it->second = start - 1; _lossList.insert(it, make_pair(end + 1, temp)); From c7ae4d5e59a2d5746647162f04ea8e96b0a6ab4e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 11:47:57 -0700 Subject: [PATCH 096/549] implement more of processACK in Connection --- libraries/networking/src/udt/Connection.cpp | 82 +++++++++++++++++++-- libraries/networking/src/udt/Connection.h | 13 +++- libraries/networking/src/udt/SendQueue.cpp | 1 + libraries/networking/src/udt/SendQueue.h | 4 + 4 files changed, 92 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 184597004e..abdfcbcdb8 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -39,6 +39,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { ackPacket->reset(); // We need to reset it every time. auto currentTime = high_resolution_clock::now(); + static high_resolution_clock::time_point lastACKSendTime; SeqNum nextACKNumber = nextACK(); @@ -58,7 +59,8 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { } else if (nextACKNumber == _lastSentACK) { // We already sent this ACK, but check if we should re-send it. // We will re-send if it has been more than RTT + (4 * RTT variance) since the last ACK - milliseconds sinceLastACK = duration_cast(currentTime - _lastACKTime); + milliseconds sinceLastACK = duration_cast(currentTime - lastACKSendTime); + if (sinceLastACK.count() < (_rtt + (4 * _rttVariance))) { return; } @@ -80,7 +82,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { // pack in the receive speed and bandwidth // record this as the last ACK send time - _lastACKTime = high_resolution_clock::now(); + lastACKSendTime = high_resolution_clock::now(); } // have the send queue send off our packet @@ -181,14 +183,84 @@ void Connection::processACK(std::unique_ptr controlPacket) { SeqNum currentACKSubSequenceNumber; controlPacket->readPrimitive(¤tACKSubSequenceNumber); - // read the ACK number - SeqNum nextACKNumber; - controlPacket->readPrimitive(&nextACKNumber); + // check if we need send an ACK2 for this ACK + auto currentTime = high_resolution_clock::now(); + static high_resolution_clock::time_point lastACK2SendTime; + + milliseconds sinceLastACK2 = duration_cast(currentTime - lastACK2SendTime); + + if (sinceLastACK2.count() > _synInterval || currentACKSubSequenceNumber == _lastSentACK2) { + // setup a static ACK2 packet we will re-use + static const int ACK2_PAYLOAD_BYTES = sizeof(SeqNum); + static auto ack2Packet = ControlPacket::create(ControlPacket::ACK2, ACK2_PAYLOAD_BYTES); + + // reset the ACK2 Packet before writing the sub-sequence number to it + ack2Packet->reset(); + + // write the sub sequence number for this ACK2 + ack2Packet->writePrimitive(currentACKSubSequenceNumber); + + // update the last sent ACK2 and the last ACK2 send time + _lastSentACK2 = currentACKSubSequenceNumber; + lastACK2SendTime = high_resolution_clock::now(); + } + + // read the ACKed sequence number + SeqNum ack; + controlPacket->readPrimitive(&ack); + + // validate that this isn't a BS ACK + if (ack > (_sendQueue->getCurrentSeqNum() + 1)) { + // in UDT they specifically break the connection here - do we want to do anything? + return; + } // read the RTT and variance int32_t rtt, rttVariance; controlPacket->readPrimitive(&rtt); controlPacket->readPrimitive(&rttVariance); + + // read the desired flow window size + int flowWindowSize; + controlPacket->readPrimitive(&flowWindowSize); + + if (ack <= _lastReceivedACK) { + // this is a valid ACKed sequence number - update the flow window size and the last received ACK + _flowWindowSize = flowWindowSize; + _lastReceivedACK = ack; + } + + // make sure this isn't a repeated ACK + if (ack <= SeqNum(_atomicLastReceivedACK)) { + return; + } + + // ACK the send queue so it knows what was received + _sendQueue->ack(ack); + + // update the atomic for last received ACK, the send queue uses this to re-transmit + _atomicLastReceivedACK.store((uint32_t) _lastReceivedACK); + + // remove everything up to this ACK from the sender loss list + + // update the RTT + _rttVariance = (_rttVariance * 3 + abs(rtt - _rtt)) >> 2; + _rtt = (_rtt * 7 + rtt) >> 3; + + // set the RTT for congestion control + + if (controlPacket->getPayloadSize() > (qint64) (sizeof(SeqNum) + sizeof(SeqNum) + sizeof(rtt) + sizeof(rttVariance))) { + int32_t deliveryRate, bandwidth; + controlPacket->readPrimitive(&deliveryRate); + controlPacket->readPrimitive(&bandwidth); + + // set the delivery rate and bandwidth for congestion control + } + + // fire the onACK callback for congestion control + + // update the total count of received ACKs + ++_totalReceivedACKs; } void Connection::processLightACK(std::unique_ptr controlPacket) { diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index f1d2210b2f..de60b88b37 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -38,6 +38,8 @@ public: SeqNum nextACK() const; + SeqNum getLastReceivedACK() const { return SeqNum(_atomicLastReceivedACK); } + void processReceivedSeqNum(SeqNum seq); void processControl(std::unique_ptr controlPacket); @@ -47,19 +49,24 @@ private: void processACK2(std::unique_ptr controlPacket); void processNAK(std::unique_ptr controlPacket); + int _synInterval; // Periodical Rate Control Interval, defaults to 10ms + LossList _lossList; // List of all missing packets SeqNum _largestReceivedSeqNum; // The largest sequence number received from the peer - SeqNum _lastSentACK; // The last sent ACK SeqNum _lastReceivedACK; // The last ACK received + std::atomic _atomicLastReceivedACK; // Atomic for thread-safe get of last ACK received SeqNum _lastReceivedAcknowledgedACK; // The last sent ACK that has been acknowledged via an ACK2 from the peer SeqNum _currentACKSubSequenceNumber; // The current ACK sub-sequence number (used for Acknowledgment of ACKs) + SeqNum _lastSentACK; // The last sent ACK + SeqNum _lastSentACK2; // The last sent ACK sub-sequence number in an ACK2 + + int _totalReceivedACKs { 0 }; + int32_t _rtt; // RTT, in milliseconds int32_t _rttVariance; // RTT variance int _flowWindowSize; // Flow control window size - std::chrono::high_resolution_clock::time_point _lastACKTime; - std::unique_ptr _sendQueue; }; diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 65c1807d19..93b90379c7 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -114,6 +114,7 @@ void SendQueue::sendNextPacket() { if (_nextPacket) { _nextPacket->writeSequenceNumber(++_currentSeqNum); sendPacket(*_nextPacket); + _atomicCurrentSeqNum.store((uint32_t) _currentSeqNum); // Insert the packet we have just sent in the sent list QWriteLocker locker(&_sentLock); diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 9c14c19ede..729ed9e305 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -42,6 +42,8 @@ public: quint64 getLastSendTimestamp() const { return _lastSendTimestamp; } + SeqNum getCurrentSeqNum() const { return SeqNum(_atomicCurrentSeqNum); } + int getPacketSendPeriod() const { return _packetSendPeriod; } void setPacketSendPeriod(int newPeriod) { _packetSendPeriod = newPeriod; } @@ -73,6 +75,8 @@ private: SeqNum _currentSeqNum; // Last sequence number sent out SeqNum _lastAck; // ACKed sequence number + std::atomic _atomicCurrentSeqNum; // Atomic for last sequence number sent out + std::unique_ptr _sendTimer; // Send timer std::atomic _packetSendPeriod { 0 }; // Interval between two packet send envent in msec std::atomic _lastSendTimestamp { 0 }; // Record last time of packet departure From 155d339c2f47118a0b1214849af77650082fa17d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 11:53:40 -0700 Subject: [PATCH 097/549] remove RTT variance that isn't handled --- libraries/networking/src/udt/Connection.cpp | 21 ++++++++++++--------- libraries/networking/src/udt/Connection.h | 2 ++ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index abdfcbcdb8..dc8e3c9c11 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -32,7 +32,7 @@ void Connection::send(unique_ptr packet) { void Connection::sendACK(bool wasCausedBySyncTimeout) { static const int ACK_PACKET_PAYLOAD_BYTES = sizeof(_lastSentACK) + sizeof(_currentACKSubSequenceNumber) - + sizeof(_rtt) + sizeof(_rttVariance) + sizeof(int32_t) + sizeof(int32_t); + + sizeof(_rtt) + sizeof(int32_t) + sizeof(int32_t); // setup the ACK packet, make it static so we can re-use it static auto ackPacket = ControlPacket::create(ControlPacket::ACK, ACK_PACKET_PAYLOAD_BYTES); @@ -74,7 +74,6 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { // pack in the RTT and variance ackPacket->writePrimitive(_rtt); - ackPacket->writePrimitive(_rttVariance); // pack the available buffer size - must be a minimum of 2 @@ -215,10 +214,9 @@ void Connection::processACK(std::unique_ptr controlPacket) { return; } - // read the RTT and variance - int32_t rtt, rttVariance; + // read the RTT + int32_t rtt; controlPacket->readPrimitive(&rtt); - controlPacket->readPrimitive(&rttVariance); // read the desired flow window size int flowWindowSize; @@ -244,12 +242,11 @@ void Connection::processACK(std::unique_ptr controlPacket) { // remove everything up to this ACK from the sender loss list // update the RTT - _rttVariance = (_rttVariance * 3 + abs(rtt - _rtt)) >> 2; - _rtt = (_rtt * 7 + rtt) >> 3; + updateRTT(rtt); // set the RTT for congestion control - if (controlPacket->getPayloadSize() > (qint64) (sizeof(SeqNum) + sizeof(SeqNum) + sizeof(rtt) + sizeof(rttVariance))) { + if (controlPacket->getPayloadSize() > (qint64) (sizeof(SeqNum) + sizeof(SeqNum) + sizeof(rtt))) { int32_t deliveryRate, bandwidth; controlPacket->readPrimitive(&deliveryRate); controlPacket->readPrimitive(&bandwidth); @@ -260,7 +257,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { // fire the onACK callback for congestion control // update the total count of received ACKs - ++_totalReceivedACKs; + ++_totalReceivedACKs; } void Connection::processLightACK(std::unique_ptr controlPacket) { @@ -290,3 +287,9 @@ void Connection::processNAK(std::unique_ptr controlPacket) { controlPacket->readPrimitive(&end); } } + +void Connection::updateRTT(int32_t rtt) { + // this updates the RTT using exponential weighted moving average + _rttVariance = (_rttVariance * 3 + abs(rtt - _rtt)) >> 2; + _rtt = (_rtt * 7 + rtt) >> 3; +} diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index de60b88b37..d58cd21cff 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -49,6 +49,8 @@ private: void processACK2(std::unique_ptr controlPacket); void processNAK(std::unique_ptr controlPacket); + void updateRTT(int32_t rtt); + int _synInterval; // Periodical Rate Control Interval, defaults to 10ms LossList _lossList; // List of all missing packets From 0b8feed327ece8df87f2afc3d85f68a2a503659b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 13:01:35 -0700 Subject: [PATCH 098/549] add a map of sentACKs for ACK2 processing --- libraries/networking/src/udt/Connection.cpp | 27 ++++++++++++++++++++- libraries/networking/src/udt/Connection.h | 5 ++++ libraries/networking/src/udt/SendQueue.h | 2 +- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index dc8e3c9c11..0e6300b020 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -86,6 +86,9 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { // have the send queue send off our packet _sendQueue->sendPacket(*ackPacket); + + // write this ACK to the map of sent ACKs + _sentACKs[_currentACKSubSequenceNumber] = { nextACKNumber, high_resolution_clock::now() }; } void Connection::sendLightACK() const { @@ -276,7 +279,29 @@ void Connection::processLightACK(std::unique_ptr controlPacket) { } void Connection::processACK2(std::unique_ptr controlPacket) { - + // pull the sub sequence number from the packet + SeqNum subSequenceNumber; + controlPacket->readPrimitive(&subSequenceNumber); + + // check if we had that subsequence number in our map + auto it = _sentACKs.find(subSequenceNumber); + if (it != _sentACKs.end()) { + // update the RTT using the ACK window + SequenceNumberTimePair& pair = it->second; + + // calculate the RTT (time now - time ACK sent) + auto now = high_resolution_clock::now(); + int rtt = duration_cast(now - pair.second).count(); + + updateRTT(rtt); + + // set the RTT for congestion control + + // update the last ACKed ACK + if (pair.first > _lastReceivedAcknowledgedACK) { + _lastReceivedAcknowledgedACK = pair.first; + } + } } void Connection::processNAK(std::unique_ptr controlPacket) { diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index d58cd21cff..2643e06a43 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -29,6 +29,9 @@ class Socket; class Connection { public: + using SequenceNumberTimePair = std::pair>; + using SentACKMap = std::unordered_map; + Connection(Socket* parentSocket, HifiSockAddr destination); void send(std::unique_ptr packet); @@ -69,6 +72,8 @@ private: int32_t _rttVariance; // RTT variance int _flowWindowSize; // Flow control window size + SentACKMap _sentACKs; // Map of ACK sub-sequence numbers to ACKed sequence number and sent time + std::unique_ptr _sendQueue; }; diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 729ed9e305..b30a7a0cbb 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -73,7 +73,7 @@ private: Socket* _socket { nullptr }; // Socket to send packet on HifiSockAddr _destination; // Destination addr SeqNum _currentSeqNum; // Last sequence number sent out - SeqNum _lastAck; // ACKed sequence number + SeqNum _lastAck; // Last ACKed sequence number std::atomic _atomicCurrentSeqNum; // Atomic for last sequence number sent out From a8371cc3ed1b6ff7b2f87ca2457e74eea8a33989 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 13:28:01 -0700 Subject: [PATCH 099/549] send the actual sequence number being ACKed --- libraries/networking/src/udt/Connection.cpp | 6 +++--- libraries/networking/src/udt/Connection.h | 14 +++++++------- libraries/networking/src/udt/SendQueue.cpp | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 0e6300b020..dfe25176a2 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -1,6 +1,6 @@ // // Connection.cpp -// +// libraries/networking/src/udt // // Created by Clement on 7/27/15. // Copyright 2015 High Fidelity, Inc. @@ -117,7 +117,7 @@ SeqNum Connection::nextACK() const { if (_lossList.getLength() > 0) { return _lossList.getFirstSeqNum(); } else { - return _largestReceivedSeqNum + 1; + return _largestReceivedSeqNum; } } @@ -212,7 +212,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { controlPacket->readPrimitive(&ack); // validate that this isn't a BS ACK - if (ack > (_sendQueue->getCurrentSeqNum() + 1)) { + if (ack > _sendQueue->getCurrentSeqNum()) { // in UDT they specifically break the connection here - do we want to do anything? return; } diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 2643e06a43..ec2736ae8d 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -1,6 +1,6 @@ // // Connection.h -// +// libraries/networking/src/udt // // Created by Clement on 7/27/15. // Copyright 2015 High Fidelity, Inc. @@ -29,7 +29,7 @@ class Socket; class Connection { public: - using SequenceNumberTimePair = std::pair>; + using SequenceNumberTimePair = std::pair; using SentACKMap = std::unordered_map; Connection(Socket* parentSocket, HifiSockAddr destination); @@ -57,13 +57,13 @@ private: int _synInterval; // Periodical Rate Control Interval, defaults to 10ms LossList _lossList; // List of all missing packets - SeqNum _largestReceivedSeqNum; // The largest sequence number received from the peer - SeqNum _lastReceivedACK; // The last ACK received - std::atomic _atomicLastReceivedACK; // Atomic for thread-safe get of last ACK received - SeqNum _lastReceivedAcknowledgedACK; // The last sent ACK that has been acknowledged via an ACK2 from the peer + SeqNum _largestReceivedSeqNum { SeqNum::MAX }; // The largest sequence number received from the peer + SeqNum _lastReceivedACK { SeqNum::MAX }; // The last ACK received + std::atomic _atomicLastReceivedACK { (uint32_t) SeqNum::MAX }; // Atomic for thread-safe get of last ACK received + SeqNum _lastReceivedAcknowledgedACK { SeqNum::MAX }; // The last sent ACK that has been acknowledged via an ACK2 from the peer SeqNum _currentACKSubSequenceNumber; // The current ACK sub-sequence number (used for Acknowledgment of ACKs) - SeqNum _lastSentACK; // The last sent ACK + SeqNum _lastSentACK { SeqNum::MAX }; // The last sent ACK SeqNum _lastSentACK2; // The last sent ACK sub-sequence number in an ACK2 int _totalReceivedACKs { 0 }; diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 93b90379c7..bc88c646df 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -90,7 +90,7 @@ void SendQueue::ack(SeqNum ack) { } QWriteLocker locker(&_sentLock); - for (auto seq = _lastAck; seq != ack; ++seq) { + for (auto seq = _lastAck; seq <= ack; ++seq) { _sentPackets.erase(seq); } From 45f6a984af806d973ee8bedf575fe33658411684 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 13:28:58 -0700 Subject: [PATCH 100/549] add a comment to SendQueue ack --- libraries/networking/src/udt/SendQueue.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index bc88c646df..0648ef0292 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -89,6 +89,7 @@ void SendQueue::ack(SeqNum ack) { return; } + // remove any ACKed packets from the map of sent packets QWriteLocker locker(&_sentLock); for (auto seq = _lastAck; seq <= ack; ++seq) { _sentPackets.erase(seq); From 606356cdcfec6c62c96d3e0a756afa222d1cf412 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 13:39:19 -0700 Subject: [PATCH 101/549] rename SeqNum to SequenceNumber --- .../networking/src/udt/CongestionControl.cpp | 6 +- .../networking/src/udt/CongestionControl.h | 18 +-- libraries/networking/src/udt/Connection.cpp | 54 +++---- libraries/networking/src/udt/Connection.h | 24 +-- libraries/networking/src/udt/LossList.cpp | 14 +- libraries/networking/src/udt/LossList.h | 16 +- libraries/networking/src/udt/Packet.cpp | 8 +- libraries/networking/src/udt/Packet.h | 9 +- libraries/networking/src/udt/SendQueue.cpp | 10 +- libraries/networking/src/udt/SendQueue.h | 18 +-- libraries/networking/src/udt/SeqNum.cpp | 34 ---- libraries/networking/src/udt/SeqNum.h | 147 ------------------ .../networking/src/udt/SequenceNumber.cpp | 34 ++++ libraries/networking/src/udt/SequenceNumber.h | 147 ++++++++++++++++++ libraries/networking/src/udt/Socket.h | 4 +- 15 files changed, 271 insertions(+), 272 deletions(-) delete mode 100644 libraries/networking/src/udt/SeqNum.cpp delete mode 100644 libraries/networking/src/udt/SeqNum.h create mode 100644 libraries/networking/src/udt/SequenceNumber.cpp create mode 100644 libraries/networking/src/udt/SequenceNumber.h diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 4f32be0d06..070e946c92 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -21,13 +21,13 @@ void UdtCC::init() { setAckTimer(_rcInterval); _lastAck = _sendCurrSeqNum; - _lastDecSeq = SeqNum{ SeqNum::MAX }; + _lastDecSeq = SequenceNumber{ SequenceNumber::MAX }; _congestionWindowSize = 16.0; _packetSendPeriod = 1.0; } -void UdtCC::onACK(SeqNum ackNum) { +void UdtCC::onACK(SequenceNumber ackNum) { int64_t B = 0; double inc = 0; // Note: 1/24/2012 @@ -89,7 +89,7 @@ void UdtCC::onACK(SeqNum ackNum) { _packetSendPeriod = (_packetSendPeriod * _rcInterval) / (_packetSendPeriod * inc + _rcInterval); } -void UdtCC::onLoss(const std::vector& losslist) { +void UdtCC::onLoss(const std::vector& losslist) { //Slow Start stopped, if it hasn't yet if (_slowStart) { _slowStart = false; diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index fe7f4a15fc..9f61c7944f 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -14,7 +14,7 @@ #include -#include "SeqNum.h" +#include "SequenceNumber.h" namespace udt { @@ -29,8 +29,8 @@ public: virtual void init() {} virtual void close() {} - virtual void onAck(SeqNum ackNum) {} - virtual void onLoss(const std::vector& lossList) {} + virtual void onAck(SequenceNumber ackNum) {} + virtual void onLoss(const std::vector& lossList) {} virtual void onPacketSent(const Packet& packet) {} virtual void onPacketReceived(const Packet& packet) {} @@ -48,7 +48,7 @@ protected: double _maxCongestionWindowSize = 0.0; // maximum cwnd size, in packets int _mss = 0; // Maximum Packet Size, including all packet headers - SeqNum _sendCurrSeqNum; // current maximum seq num sent out + SequenceNumber _sendCurrSeqNum; // current maximum seq num sent out int _recvieveRate = 0; // packet arrive rate at receiver side, packets per second int _rtt = 0; // current estimated RTT, microsecond @@ -59,7 +59,7 @@ private: void setMss(int mss) { _mss = mss; } void setMaxCongestionWindowSize(int window) { _maxCongestionWindowSize = window; } void setBandwidth(int bandwidth) { _bandwidth = bandwidth; } - void setSndCurrSeqNum(SeqNum seqNum) { _sendCurrSeqNum = seqNum; } + void setSndCurrSeqNum(SequenceNumber seqNum) { _sendCurrSeqNum = seqNum; } void setRcvRate(int rate) { _recvieveRate = rate; } void setRtt(int rtt) { _rtt = rtt; } @@ -92,17 +92,17 @@ public: public: virtual void init(); - virtual void onACK(SeqNum ackNum); - virtual void onLoss(const std::vector& lossList); + virtual void onACK(SequenceNumber ackNum); + virtual void onLoss(const std::vector& lossList); virtual void onTimeout(); private: int _rcInterval = 0; // UDT Rate control interval uint64_t _lastRCTime = 0; // last rate increase time bool _slowStart = true; // if in slow start phase - SeqNum _lastAck; // last ACKed seq num + SequenceNumber _lastAck; // last ACKed seq num bool _loss = false; // if loss happened since last rate increase - SeqNum _lastDecSeq; // max pkt seq num sent out when last decrease happened + SequenceNumber _lastDecSeq; // max pkt seq num sent out when last decrease happened double _lastDecPeriod = 1; // value of pktsndperiod when last decrease happened int _nakCount = 0; // NAK counter int _decRandom = 1; // random threshold on decrease by number of loss events diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index dfe25176a2..9ecba087a5 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -41,7 +41,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { auto currentTime = high_resolution_clock::now(); static high_resolution_clock::time_point lastACKSendTime; - SeqNum nextACKNumber = nextACK(); + SequenceNumber nextACKNumber = nextACK(); if (nextACKNumber <= _lastReceivedAcknowledgedACK) { // we already got an ACK2 for this ACK we would be sending, don't bother @@ -93,10 +93,10 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { void Connection::sendLightACK() const { // create the light ACK packet, make it static so we can re-use it - static const int LIGHT_ACK_PACKET_PAYLOAD_BYTES = sizeof(SeqNum); + static const int LIGHT_ACK_PACKET_PAYLOAD_BYTES = sizeof(SequenceNumber); static auto lightACKPacket = ControlPacket::create(ControlPacket::ACK, LIGHT_ACK_PACKET_PAYLOAD_BYTES); - SeqNum nextACKNumber = nextACK(); + SequenceNumber nextACKNumber = nextACK(); if (nextACKNumber == _lastReceivedAcknowledgedACK) { // we already got an ACK2 for this ACK we would be sending, don't bother @@ -113,31 +113,31 @@ void Connection::sendLightACK() const { _sendQueue->sendPacket(*lightACKPacket); } -SeqNum Connection::nextACK() const { +SequenceNumber Connection::nextACK() const { if (_lossList.getLength() > 0) { - return _lossList.getFirstSeqNum(); + return _lossList.getFirstSequenceNumber(); } else { - return _largestReceivedSeqNum; + return _lastReceivedSequenceNumber; } } -void Connection::processReceivedSeqNum(SeqNum seq) { +void Connection::processReceivedSequenceNumber(SequenceNumber seq) { // If this is not the next sequence number, report loss - if (seq > _largestReceivedSeqNum + 1) { - if (_largestReceivedSeqNum + 1 == seq - 1) { - _lossList.append(_largestReceivedSeqNum + 1); + if (seq > _lastReceivedSequenceNumber + 1) { + if (_lastReceivedSequenceNumber + 1 == seq - 1) { + _lossList.append(_lastReceivedSequenceNumber + 1); } else { - _lossList.append(_largestReceivedSeqNum + 1, seq - 1); + _lossList.append(_lastReceivedSequenceNumber + 1, seq - 1); } // create the loss report packet, make it static so we can re-use it - static const int NAK_PACKET_PAYLOAD_BYTES = 2 * sizeof(SeqNum); + static const int NAK_PACKET_PAYLOAD_BYTES = 2 * sizeof(SequenceNumber); static auto lossReport = ControlPacket::create(ControlPacket::NAK, NAK_PACKET_PAYLOAD_BYTES); lossReport->reset(); // We need to reset it every time. // pack in the loss report - lossReport->writePrimitive(_largestReceivedSeqNum + 1); - if (_largestReceivedSeqNum + 1 != seq - 1) { + lossReport->writePrimitive(_lastReceivedSequenceNumber + 1); + if (_lastReceivedSequenceNumber + 1 != seq - 1) { lossReport->writePrimitive(seq - 1); } @@ -145,9 +145,9 @@ void Connection::processReceivedSeqNum(SeqNum seq) { _sendQueue->sendPacket(*lossReport); } - if (seq > _largestReceivedSeqNum) { + if (seq > _lastReceivedSequenceNumber) { // Update largest recieved sequence number - _largestReceivedSeqNum = seq; + _lastReceivedSequenceNumber = seq; } else { // Otherwise, it's a resend, remove it from the loss list _lossList.remove(seq); @@ -157,7 +157,7 @@ void Connection::processReceivedSeqNum(SeqNum seq) { void Connection::processControl(unique_ptr controlPacket) { switch (controlPacket->getType()) { case ControlPacket::ACK: { - if (controlPacket->getPayloadSize() == sizeof(SeqNum)) { + if (controlPacket->getPayloadSize() == sizeof(SequenceNumber)) { processLightACK(move(controlPacket)); } else { processACK(move(controlPacket)); @@ -182,7 +182,7 @@ void Connection::processControl(unique_ptr controlPacket) { void Connection::processACK(std::unique_ptr controlPacket) { // read the ACK sub-sequence number - SeqNum currentACKSubSequenceNumber; + SequenceNumber currentACKSubSequenceNumber; controlPacket->readPrimitive(¤tACKSubSequenceNumber); // check if we need send an ACK2 for this ACK @@ -193,7 +193,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { if (sinceLastACK2.count() > _synInterval || currentACKSubSequenceNumber == _lastSentACK2) { // setup a static ACK2 packet we will re-use - static const int ACK2_PAYLOAD_BYTES = sizeof(SeqNum); + static const int ACK2_PAYLOAD_BYTES = sizeof(SequenceNumber); static auto ack2Packet = ControlPacket::create(ControlPacket::ACK2, ACK2_PAYLOAD_BYTES); // reset the ACK2 Packet before writing the sub-sequence number to it @@ -208,11 +208,11 @@ void Connection::processACK(std::unique_ptr controlPacket) { } // read the ACKed sequence number - SeqNum ack; + SequenceNumber ack; controlPacket->readPrimitive(&ack); // validate that this isn't a BS ACK - if (ack > _sendQueue->getCurrentSeqNum()) { + if (ack > _sendQueue->getCurrentSequenceNumber()) { // in UDT they specifically break the connection here - do we want to do anything? return; } @@ -232,7 +232,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { } // make sure this isn't a repeated ACK - if (ack <= SeqNum(_atomicLastReceivedACK)) { + if (ack <= SequenceNumber(_atomicLastReceivedACK)) { return; } @@ -249,7 +249,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { // set the RTT for congestion control - if (controlPacket->getPayloadSize() > (qint64) (sizeof(SeqNum) + sizeof(SeqNum) + sizeof(rtt))) { + if (controlPacket->getPayloadSize() > (qint64) (sizeof(SequenceNumber) + sizeof(SequenceNumber) + sizeof(rtt))) { int32_t deliveryRate, bandwidth; controlPacket->readPrimitive(&deliveryRate); controlPacket->readPrimitive(&bandwidth); @@ -265,7 +265,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { void Connection::processLightACK(std::unique_ptr controlPacket) { // read the ACKed sequence number - SeqNum ack; + SequenceNumber ack; controlPacket->readPrimitive(&ack); // must be larger than the last received ACK to be processed @@ -280,7 +280,7 @@ void Connection::processLightACK(std::unique_ptr controlPacket) { void Connection::processACK2(std::unique_ptr controlPacket) { // pull the sub sequence number from the packet - SeqNum subSequenceNumber; + SequenceNumber subSequenceNumber; controlPacket->readPrimitive(&subSequenceNumber); // check if we had that subsequence number in our map @@ -306,9 +306,9 @@ void Connection::processACK2(std::unique_ptr controlPacket) { void Connection::processNAK(std::unique_ptr controlPacket) { // read the loss report - SeqNum start, end; + SequenceNumber start, end; controlPacket->readPrimitive(&start); - if (controlPacket->bytesLeftToRead() >= (qint64)sizeof(SeqNum)) { + if (controlPacket->bytesLeftToRead() >= (qint64)sizeof(SequenceNumber)) { controlPacket->readPrimitive(&end); } } diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index ec2736ae8d..5bf15f3031 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -29,8 +29,8 @@ class Socket; class Connection { public: - using SequenceNumberTimePair = std::pair; - using SentACKMap = std::unordered_map; + using SequenceNumberTimePair = std::pair; + using SentACKMap = std::unordered_map; Connection(Socket* parentSocket, HifiSockAddr destination); @@ -39,11 +39,11 @@ public: void sendACK(bool wasCausedBySyncTimeout = true); void sendLightACK() const; - SeqNum nextACK() const; + SequenceNumber nextACK() const; - SeqNum getLastReceivedACK() const { return SeqNum(_atomicLastReceivedACK); } + SequenceNumber getLastReceivedACK() const { return SequenceNumber(_atomicLastReceivedACK); } - void processReceivedSeqNum(SeqNum seq); + void processReceivedSequenceNumber(SequenceNumber seq); void processControl(std::unique_ptr controlPacket); private: @@ -57,14 +57,14 @@ private: int _synInterval; // Periodical Rate Control Interval, defaults to 10ms LossList _lossList; // List of all missing packets - SeqNum _largestReceivedSeqNum { SeqNum::MAX }; // The largest sequence number received from the peer - SeqNum _lastReceivedACK { SeqNum::MAX }; // The last ACK received - std::atomic _atomicLastReceivedACK { (uint32_t) SeqNum::MAX }; // Atomic for thread-safe get of last ACK received - SeqNum _lastReceivedAcknowledgedACK { SeqNum::MAX }; // The last sent ACK that has been acknowledged via an ACK2 from the peer - SeqNum _currentACKSubSequenceNumber; // The current ACK sub-sequence number (used for Acknowledgment of ACKs) + SequenceNumber _lastReceivedSequenceNumber { SequenceNumber::MAX }; // The largest sequence number received from the peer + SequenceNumber _lastReceivedACK { SequenceNumber::MAX }; // The last ACK received + std::atomic _atomicLastReceivedACK { (uint32_t) SequenceNumber::MAX }; // Atomic for thread-safe get of last ACK received + SequenceNumber _lastReceivedAcknowledgedACK { SequenceNumber::MAX }; // The last sent ACK that has been acknowledged via an ACK2 from the peer + SequenceNumber _currentACKSubSequenceNumber; // The current ACK sub-sequence number (used for Acknowledgment of ACKs) - SeqNum _lastSentACK { SeqNum::MAX }; // The last sent ACK - SeqNum _lastSentACK2; // The last sent ACK sub-sequence number in an ACK2 + SequenceNumber _lastSentACK { SequenceNumber::MAX }; // The last sent ACK + SequenceNumber _lastSentACK2; // The last sent ACK sub-sequence number in an ACK2 int _totalReceivedACKs { 0 }; diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp index a8fe0912d5..2b4943b08b 100644 --- a/libraries/networking/src/udt/LossList.cpp +++ b/libraries/networking/src/udt/LossList.cpp @@ -14,7 +14,7 @@ using namespace udt; using namespace std; -void LossList::append(SeqNum seq) { +void LossList::append(SequenceNumber seq) { assert(_lossList.back().second < seq); if (getLength() > 0 && _lossList.back().second + 1 == seq) { @@ -25,7 +25,7 @@ void LossList::append(SeqNum seq) { _length += 1; } -void LossList::append(SeqNum start, SeqNum end) { +void LossList::append(SequenceNumber start, SequenceNumber end) { if (getLength() > 0 && _lossList.back().second + 1 == start) { _lossList.back().second = end; } else { @@ -34,8 +34,8 @@ void LossList::append(SeqNum start, SeqNum end) { _length += seqlen(start, end); } -void LossList::remove(SeqNum seq) { - auto it = find_if(_lossList.begin(), _lossList.end(), [&seq](pair pair) { +void LossList::remove(SequenceNumber seq) { + auto it = find_if(_lossList.begin(), _lossList.end(), [&seq](pair pair) { return pair.first <= seq && seq <= pair.second; }); @@ -54,9 +54,9 @@ void LossList::remove(SeqNum seq) { } } -void LossList::remove(SeqNum start, SeqNum end) { +void LossList::remove(SequenceNumber start, SequenceNumber end) { // Find the first segment sharing sequence numbers - auto it = find_if(_lossList.begin(), _lossList.end(), [&start, &end](pair pair) { + auto it = find_if(_lossList.begin(), _lossList.end(), [&start, &end](pair pair) { return (pair.first <= start && start <= pair.second) || (start <= pair.first && pair.first <= end); }); @@ -93,7 +93,7 @@ void LossList::remove(SeqNum start, SeqNum end) { } } -SeqNum LossList::getFirstSeqNum() const { +SequenceNumber LossList::getFirstSequenceNumber() const { assert(getLength() > 0); return _lossList.front().first; } \ No newline at end of file diff --git a/libraries/networking/src/udt/LossList.h b/libraries/networking/src/udt/LossList.h index dd7f1de2ff..ec26947dfc 100644 --- a/libraries/networking/src/udt/LossList.h +++ b/libraries/networking/src/udt/LossList.h @@ -14,7 +14,7 @@ #include -#include "SeqNum.h" +#include "SequenceNumber.h" namespace udt { @@ -23,20 +23,20 @@ public: LossList() {} // Should always add at the end - void append(SeqNum seq); - void append(SeqNum start, SeqNum end); + void append(SequenceNumber seq); + void append(SequenceNumber start, SequenceNumber end); - void remove(SeqNum seq); - void remove(SeqNum start, SeqNum end); + void remove(SequenceNumber seq); + void remove(SequenceNumber start, SequenceNumber end); int getLength() const { return _length; } - SeqNum getFirstSeqNum() const; + SequenceNumber getFirstSequenceNumber() const; private: - std::list> _lossList; + std::list> _lossList; int _length { 0 }; }; } -#endif // hifi_LossList_h \ No newline at end of file +#endif // hifi_LossList_h diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index a70c3bfbef..6bbb5a8972 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -65,7 +65,7 @@ Packet::Packet(qint64 size, bool isReliable, bool isPartOfMessage) : adjustPayloadStartAndCapacity(); // set the UDT header to default values - writeSequenceNumber(SeqNum()); + writeSequenceNumber(SequenceNumber()); } Packet::Packet(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr) : @@ -131,13 +131,13 @@ void Packet::readIsPartOfMessage() { void Packet::readSequenceNumber() { SequenceNumberAndBitField seqNumBitField = *reinterpret_cast(_packet.get()); - _sequenceNumber = SeqNum{ seqNumBitField & ~BIT_FIELD_MASK }; // Remove the bit field + _sequenceNumber = SequenceNumber{ seqNumBitField & ~BIT_FIELD_MASK }; // Remove the bit field } -void Packet::writeSequenceNumber(SeqNum seqNum) { +void Packet::writeSequenceNumber(SequenceNumber seqNum) { // grab pointer to current SequenceNumberAndBitField SequenceNumberAndBitField* seqNumBitField = reinterpret_cast(_packet.get()); // write new value by ORing (old value & BIT_FIELD_MASK) with new seqNum - *seqNumBitField = (*seqNumBitField & BIT_FIELD_MASK) | (SeqNum::Type)seqNum; + *seqNumBitField = (*seqNumBitField & BIT_FIELD_MASK) | (SequenceNumber::Type) seqNum; } diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index 6189be0ef1..343b89107c 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -18,7 +18,7 @@ #include "BasePacket.h" #include "PacketHeaders.h" -#include "SeqNum.h" +#include "SequenceNumber.h" namespace udt { @@ -26,7 +26,6 @@ class Packet : public BasePacket { Q_OBJECT public: // NOTE: The SequenceNumber is only actually 29 bits to leave room for a bit field - using SequenceNumber = uint32_t; using SequenceNumberAndBitField = uint32_t; // NOTE: The MessageNumber is only actually 29 bits to leave room for a bit field @@ -49,8 +48,8 @@ public: virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers - void writeSequenceNumber(SeqNum seqNum); - SeqNum getSequenceNumber() const { return _sequenceNumber; } + void writeSequenceNumber(SequenceNumber seqNum); + SequenceNumber getSequenceNumber() const { return _sequenceNumber; } protected: Packet(qint64 size, bool isReliable = false, bool isPartOfMessage = false); @@ -68,7 +67,7 @@ protected: bool _isReliable { false }; bool _isPartOfMessage { false }; - SeqNum _sequenceNumber; + SequenceNumber _sequenceNumber; }; } // namespace udt diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 0648ef0292..2fe1603200 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -84,7 +84,7 @@ void SendQueue::sendPacket(const BasePacket& packet) { _socket->writeUnreliablePacket(packet, _destination); } -void SendQueue::ack(SeqNum ack) { +void SendQueue::ack(SequenceNumber ack) { if (_lastAck == ack) { return; } @@ -98,7 +98,7 @@ void SendQueue::ack(SeqNum ack) { _lastAck = ack; } -void SendQueue::nak(std::list naks) { +void SendQueue::nak(std::list naks) { QWriteLocker locker(&_naksLock); _naks.splice(_naks.end(), naks); // Add naks at the end } @@ -113,9 +113,9 @@ void SendQueue::sendNextPacket() { _lastSendTimestamp = sendTime; if (_nextPacket) { - _nextPacket->writeSequenceNumber(++_currentSeqNum); + _nextPacket->writeSequenceNumber(++_currentSequenceNumber); sendPacket(*_nextPacket); - _atomicCurrentSeqNum.store((uint32_t) _currentSeqNum); + _atomicCurrentSequenceNumber.store((uint32_t) _currentSequenceNumber); // Insert the packet we have just sent in the sent list QWriteLocker locker(&_sentLock); @@ -125,7 +125,7 @@ void SendQueue::sendNextPacket() { } bool hasResend = false; - SeqNum seqNum; + SequenceNumber seqNum; { // Check nak list for packet to resend QWriteLocker locker(&_naksLock); diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index b30a7a0cbb..60ad1d0101 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -21,7 +21,7 @@ #include "../HifiSockAddr.h" -#include "SeqNum.h" +#include "SequenceNumber.h" namespace udt { @@ -42,7 +42,7 @@ public: quint64 getLastSendTimestamp() const { return _lastSendTimestamp; } - SeqNum getCurrentSeqNum() const { return SeqNum(_atomicCurrentSeqNum); } + SequenceNumber getCurrentSequenceNumber() const { return SequenceNumber(_atomicCurrentSequenceNumber); } int getPacketSendPeriod() const { return _packetSendPeriod; } void setPacketSendPeriod(int newPeriod) { _packetSendPeriod = newPeriod; } @@ -52,8 +52,8 @@ public slots: void stop(); void sendPacket(const BasePacket& packet); - void ack(SeqNum ack); - void nak(std::list naks); + void ack(SequenceNumber ack); + void nak(std::list naks); private slots: void sendNextPacket(); @@ -72,10 +72,10 @@ private: Socket* _socket { nullptr }; // Socket to send packet on HifiSockAddr _destination; // Destination addr - SeqNum _currentSeqNum; // Last sequence number sent out - SeqNum _lastAck; // Last ACKed sequence number + SequenceNumber _currentSequenceNumber; // Last sequence number sent out + SequenceNumber _lastAck; // Last ACKed sequence number - std::atomic _atomicCurrentSeqNum; // Atomic for last sequence number sent out + std::atomic _atomicCurrentSequenceNumber; // Atomic for last sequence number sent out std::unique_ptr _sendTimer; // Send timer std::atomic _packetSendPeriod { 0 }; // Interval between two packet send envent in msec @@ -83,10 +83,10 @@ private: std::atomic _running { false }; mutable QReadWriteLock _naksLock; // Protects the naks list. - std::list _naks; // Sequence numbers of packets to resend + std::list _naks; // Sequence numbers of packets to resend mutable QReadWriteLock _sentLock; // Protects the sent packet list - std::unordered_map> _sentPackets; // Packets waiting for ACK. + std::unordered_map> _sentPackets; // Packets waiting for ACK. }; } diff --git a/libraries/networking/src/udt/SeqNum.cpp b/libraries/networking/src/udt/SeqNum.cpp deleted file mode 100644 index 668c1f131a..0000000000 --- a/libraries/networking/src/udt/SeqNum.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// -// SeqNum.cpp -// libraries/networking/src/udt -// -// Created by Clement on 7/23/15. -// Copyright 2015 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 "SeqNum.h" - -int udt::seqcmp(const SeqNum& seq1, const SeqNum& seq2) { - return (glm::abs(seq1._value - seq2._value) < SeqNum::THRESHOLD) ? (seq1._value - seq2._value) - : (seq2._value - seq1._value); -} - -int udt::seqlen(const SeqNum& seq1, const SeqNum& seq2) { - return (seq1._value <= seq2._value) ? (seq2._value - seq1._value + 1) - : (seq2._value - seq1._value + SeqNum::MAX + 2); -} - -int udt::seqoff(const SeqNum& seq1, const SeqNum& seq2) { - if (glm::abs(seq1._value - seq2._value) < SeqNum::THRESHOLD) { - return seq2._value - seq1._value; - } - - if (seq1._value < seq2._value) { - return seq2._value - seq1._value - SeqNum::MAX - 1; - } - - return seq2._value - seq1._value + SeqNum::MAX + 1; -} diff --git a/libraries/networking/src/udt/SeqNum.h b/libraries/networking/src/udt/SeqNum.h deleted file mode 100644 index 5ae85f3dcf..0000000000 --- a/libraries/networking/src/udt/SeqNum.h +++ /dev/null @@ -1,147 +0,0 @@ -// -// SeqNum.h -// libraries/networking/src/udt -// -// Created by Clement on 7/23/15. -// Copyright 2015 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 -// - -#ifndef hifi_SeqNum_h -#define hifi_SeqNum_h - -#include - -#include - -namespace udt { - -class SeqNum { -public: - // Base type of sequence numbers - using Type = uint32_t; - - // Values are for 29 bit SeqNum - static const Type THRESHOLD = 0x0FFFFFFF; // threshold for comparing sequence numbers - static const Type MAX = 0x1FFFFFFF; // maximum sequence number used in UDT - - SeqNum() = default; - SeqNum(const SeqNum& other) : _value(other._value) {} - - // Only explicit conversions - explicit SeqNum(char* value) { _value = (*reinterpret_cast(value)) & MAX; } - explicit SeqNum(Type value) { _value = (value <= MAX) ? value : MAX; } - explicit operator Type() { return _value; } - - inline SeqNum& operator++() { - _value = (_value == MAX) ? 0 : ++_value; - return *this; - } - inline SeqNum& operator--() { - _value = (_value == 0) ? MAX : --_value; - return *this; - } - inline SeqNum operator++(int) { - SeqNum before = *this; - (*this)++; - return before; - } - inline SeqNum operator--(int) { - SeqNum before = *this; - (*this)--; - return before; - } - - inline SeqNum& operator=(const SeqNum& other) { - _value = other._value; - return *this; - } - inline SeqNum& operator+=(Type inc) { - _value = (_value + inc > MAX) ? _value + inc - (MAX + 1) : _value + inc; - return *this; - } - inline SeqNum& operator-=(Type dec) { - _value = (_value < dec) ? MAX - (dec - _value + 1) : _value - dec; - return *this; - } - - inline bool operator==(const SeqNum& other) const { - return _value == other._value; - } - inline bool operator!=(const SeqNum& other) const { - return _value != other._value; - } - - friend bool operator<(const SeqNum& a, const SeqNum& b); - friend bool operator>(const SeqNum& a, const SeqNum& b); - friend bool operator<=(const SeqNum& a, const SeqNum& b); - friend bool operator>=(const SeqNum& a, const SeqNum& b); - - friend SeqNum operator+(const SeqNum a, const Type& b); - friend SeqNum operator+(const Type& a, const SeqNum b); - friend SeqNum operator-(const SeqNum a, const Type& b); - friend SeqNum operator-(const Type& a, const SeqNum b); - - friend int seqcmp(const SeqNum& seq1, const SeqNum& seq2); - friend int seqlen(const SeqNum& seq1, const SeqNum& seq2); - friend int seqoff(const SeqNum& seq1, const SeqNum& seq2); - -private: - Type _value { 0 }; - - friend struct std::hash; -}; - - -inline bool operator<(const SeqNum& a, const SeqNum& b) { - return (glm::abs(a._value - b._value) < SeqNum::THRESHOLD) ? a._value < b._value : b._value < a._value; -} - -inline bool operator>(const SeqNum& a, const SeqNum& b) { - return (glm::abs(a._value - b._value) < SeqNum::THRESHOLD) ? a._value > b._value : b._value > a._value; -} - -inline bool operator<=(const SeqNum& a, const SeqNum& b) { - return (glm::abs(a._value - b._value) < SeqNum::THRESHOLD) ? a._value <= b._value : b._value <= a._value; -} - -inline bool operator>=(const SeqNum& a, const SeqNum& b) { - return (glm::abs(a._value - b._value) < SeqNum::THRESHOLD) ? a._value >= b._value : b._value >= a._value; -} - - -inline SeqNum operator+(SeqNum a, const SeqNum::Type& b) { - a += b; - return a; -} - -inline SeqNum operator+(const SeqNum::Type& a, SeqNum b) { - b += a; - return b; -} - -inline SeqNum operator-(SeqNum a, const SeqNum::Type& b) { - a -= b; - return a; -} - -inline SeqNum operator-(const SeqNum::Type& a, SeqNum b) { - b -= a; - return b; -} - -int seqcmp(const SeqNum& seq1, const SeqNum& seq2); -int seqlen(const SeqNum& seq1, const SeqNum& seq2); -int seqoff(const SeqNum& seq1, const SeqNum& seq2); - -} - -template<> struct std::hash { - size_t operator()(const udt::SeqNum& seqNum) const { - return std::hash()(seqNum._value); - } -}; - -#endif // hifi_SeqNum_h diff --git a/libraries/networking/src/udt/SequenceNumber.cpp b/libraries/networking/src/udt/SequenceNumber.cpp new file mode 100644 index 0000000000..cd7a467d23 --- /dev/null +++ b/libraries/networking/src/udt/SequenceNumber.cpp @@ -0,0 +1,34 @@ +// +// SequenceNumber.cpp +// libraries/networking/src/udt +// +// Created by Clement on 7/23/15. +// Copyright 2015 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 "SequenceNumber.h" + +int udt::seqcmp(const SequenceNumber& seq1, const SequenceNumber& seq2) { + return (glm::abs(seq1._value - seq2._value) < SequenceNumber::THRESHOLD) ? (seq1._value - seq2._value) + : (seq2._value - seq1._value); +} + +int udt::seqlen(const SequenceNumber& seq1, const SequenceNumber& seq2) { + return (seq1._value <= seq2._value) ? (seq2._value - seq1._value + 1) + : (seq2._value - seq1._value + SequenceNumber::MAX + 2); +} + +int udt::seqoff(const SequenceNumber& seq1, const SequenceNumber& seq2) { + if (glm::abs(seq1._value - seq2._value) < SequenceNumber::THRESHOLD) { + return seq2._value - seq1._value; + } + + if (seq1._value < seq2._value) { + return seq2._value - seq1._value - SequenceNumber::MAX - 1; + } + + return seq2._value - seq1._value + SequenceNumber::MAX + 1; +} diff --git a/libraries/networking/src/udt/SequenceNumber.h b/libraries/networking/src/udt/SequenceNumber.h new file mode 100644 index 0000000000..28d94d70fb --- /dev/null +++ b/libraries/networking/src/udt/SequenceNumber.h @@ -0,0 +1,147 @@ +// +// SequenceNumber.h +// libraries/networking/src/udt +// +// Created by Clement on 7/23/15. +// Copyright 2015 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 +// + +#ifndef hifi_SequenceNumber_h +#define hifi_SequenceNumber_h + +#include + +#include + +namespace udt { + +class SequenceNumber { +public: + // Base type of sequence numbers + using Type = uint32_t; + + // Values are for 29 bit SequenceNumber + static const Type THRESHOLD = 0x0FFFFFFF; // threshold for comparing sequence numbers + static const Type MAX = 0x1FFFFFFF; // maximum sequence number used in UDT + + SequenceNumber() = default; + SequenceNumber(const SequenceNumber& other) : _value(other._value) {} + + // Only explicit conversions + explicit SequenceNumber(char* value) { _value = (*reinterpret_cast(value)) & MAX; } + explicit SequenceNumber(Type value) { _value = (value <= MAX) ? value : MAX; } + explicit operator Type() { return _value; } + + inline SequenceNumber& operator++() { + _value = (_value == MAX) ? 0 : ++_value; + return *this; + } + inline SequenceNumber& operator--() { + _value = (_value == 0) ? MAX : --_value; + return *this; + } + inline SequenceNumber operator++(int) { + SequenceNumber before = *this; + (*this)++; + return before; + } + inline SequenceNumber operator--(int) { + SequenceNumber before = *this; + (*this)--; + return before; + } + + inline SequenceNumber& operator=(const SequenceNumber& other) { + _value = other._value; + return *this; + } + inline SequenceNumber& operator+=(Type inc) { + _value = (_value + inc > MAX) ? _value + inc - (MAX + 1) : _value + inc; + return *this; + } + inline SequenceNumber& operator-=(Type dec) { + _value = (_value < dec) ? MAX - (dec - _value + 1) : _value - dec; + return *this; + } + + inline bool operator==(const SequenceNumber& other) const { + return _value == other._value; + } + inline bool operator!=(const SequenceNumber& other) const { + return _value != other._value; + } + + friend bool operator<(const SequenceNumber& a, const SequenceNumber& b); + friend bool operator>(const SequenceNumber& a, const SequenceNumber& b); + friend bool operator<=(const SequenceNumber& a, const SequenceNumber& b); + friend bool operator>=(const SequenceNumber& a, const SequenceNumber& b); + + friend SequenceNumber operator+(const SequenceNumber a, const Type& b); + friend SequenceNumber operator+(const Type& a, const SequenceNumber b); + friend SequenceNumber operator-(const SequenceNumber a, const Type& b); + friend SequenceNumber operator-(const Type& a, const SequenceNumber b); + + friend int seqcmp(const SequenceNumber& seq1, const SequenceNumber& seq2); + friend int seqlen(const SequenceNumber& seq1, const SequenceNumber& seq2); + friend int seqoff(const SequenceNumber& seq1, const SequenceNumber& seq2); + +private: + Type _value { 0 }; + + friend struct std::hash; +}; + + +inline bool operator<(const SequenceNumber& a, const SequenceNumber& b) { + return (glm::abs(a._value - b._value) < SequenceNumber::THRESHOLD) ? a._value < b._value : b._value < a._value; +} + +inline bool operator>(const SequenceNumber& a, const SequenceNumber& b) { + return (glm::abs(a._value - b._value) < SequenceNumber::THRESHOLD) ? a._value > b._value : b._value > a._value; +} + +inline bool operator<=(const SequenceNumber& a, const SequenceNumber& b) { + return (glm::abs(a._value - b._value) < SequenceNumber::THRESHOLD) ? a._value <= b._value : b._value <= a._value; +} + +inline bool operator>=(const SequenceNumber& a, const SequenceNumber& b) { + return (glm::abs(a._value - b._value) < SequenceNumber::THRESHOLD) ? a._value >= b._value : b._value >= a._value; +} + + +inline SequenceNumber operator+(SequenceNumber a, const SequenceNumber::Type& b) { + a += b; + return a; +} + +inline SequenceNumber operator+(const SequenceNumber::Type& a, SequenceNumber b) { + b += a; + return b; +} + +inline SequenceNumber operator-(SequenceNumber a, const SequenceNumber::Type& b) { + a -= b; + return a; +} + +inline SequenceNumber operator-(const SequenceNumber::Type& a, SequenceNumber b) { + b -= a; + return b; +} + +int seqcmp(const SequenceNumber& seq1, const SequenceNumber& seq2); +int seqlen(const SequenceNumber& seq1, const SequenceNumber& seq2); +int seqoff(const SequenceNumber& seq1, const SequenceNumber& seq2); + +} + +template<> struct std::hash { + size_t operator()(const udt::SequenceNumber& SequenceNumber) const { + return std::hash()(SequenceNumber._value); + } +}; + +#endif // hifi_SequenceNumber_h diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index f74ea49f0b..5b8ebb5d0f 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -28,7 +28,7 @@ namespace udt { class BasePacket; class ControlSender; class Packet; -class SeqNum; +class SequenceNumber; using PacketFilterOperator = std::function; @@ -70,7 +70,7 @@ private: std::unordered_map _unfilteredHandlers; - std::unordered_map _packetSequenceNumbers; + std::unordered_map _packetSequenceNumbers; int32_t _synInterval = 10; // 10ms QTimer _synTimer; From 00fdcf3133c87bb87ca92bd26f46837340b1e900 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 13:44:26 -0700 Subject: [PATCH 102/549] fix a comment that reference SequenceNumber --- libraries/networking/src/udt/SendQueue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 2fe1603200..34761d57f6 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -136,7 +136,7 @@ void SendQueue::sendNextPacket() { } } - // Find packet in sent list using SeqNum + // Find packet in sent list using SequenceNumber if (hasResend) { QWriteLocker locker(&_sentLock); auto it = _sentPackets.find(seqNum); From f0bb71b5196ae7eb674c2f1e0338c66c52c2d500 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Jul 2015 13:48:20 -0700 Subject: [PATCH 103/549] Change Packet read/write fcts --- libraries/networking/src/udt/Connection.cpp | 6 ++-- libraries/networking/src/udt/Packet.cpp | 38 ++++++++++++--------- libraries/networking/src/udt/Packet.h | 12 ++++--- 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 6826b4b109..b1b298c0ff 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -156,7 +156,7 @@ void Connection::processReceivedSequenceNumber(SequenceNumber seq) { void Connection::processControl(unique_ptr controlPacket) { switch (controlPacket->getType()) { - case ControlPacket::ACK: { + case ControlPacket::ACK: if (controlPacket->getPayloadSize() == sizeof(SequenceNumber)) { processLightACK(move(controlPacket)); } else { @@ -169,10 +169,8 @@ void Connection::processControl(unique_ptr controlPacket) { case ControlPacket::NAK: processNAK(move(controlPacket)); break; - case ControlPacket::PacketPair: { - + case ControlPacket::PacketPair: break; - } } } diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 6bbb5a8972..5f1aa88937 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -65,15 +65,13 @@ Packet::Packet(qint64 size, bool isReliable, bool isPartOfMessage) : adjustPayloadStartAndCapacity(); // set the UDT header to default values - writeSequenceNumber(SequenceNumber()); + writeHeader(); } Packet::Packet(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr) : BasePacket(std::move(data), size, senderSockAddr) { - readIsReliable(); - readIsPartOfMessage(); - readSequenceNumber(); + readHeader(); adjustPayloadStartAndCapacity(_payloadSize > 0); } @@ -119,25 +117,33 @@ static const uint32_t RELIABILITY_BIT_MASK = 1 << (sizeof(Packet::SequenceNumber static const uint32_t MESSAGE_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 3); static const uint32_t BIT_FIELD_MASK = CONTROL_BIT_MASK | RELIABILITY_BIT_MASK | MESSAGE_BIT_MASK; -void Packet::readIsReliable() { +void Packet::readHeader() { SequenceNumberAndBitField seqNumBitField = *reinterpret_cast(_packet.get()); + Q_ASSERT_X((bool) (seqNumBitField & CONTROL_BIT_MASK), + "Packet::readHeader()", "This should be a data packet"); _isReliable = (bool) (seqNumBitField & RELIABILITY_BIT_MASK); // Only keep reliability bit -} - -void Packet::readIsPartOfMessage() { - SequenceNumberAndBitField seqNumBitField = *reinterpret_cast(_packet.get()); - _isReliable = (bool) (seqNumBitField & MESSAGE_BIT_MASK); // Only keep message bit -} - -void Packet::readSequenceNumber() { - SequenceNumberAndBitField seqNumBitField = *reinterpret_cast(_packet.get()); + _isPartOfMessage = (bool) (seqNumBitField & MESSAGE_BIT_MASK); // Only keep message bit _sequenceNumber = SequenceNumber{ seqNumBitField & ~BIT_FIELD_MASK }; // Remove the bit field } -void Packet::writeSequenceNumber(SequenceNumber seqNum) { +void Packet::writeHeader() { // grab pointer to current SequenceNumberAndBitField SequenceNumberAndBitField* seqNumBitField = reinterpret_cast(_packet.get()); + *seqNumBitField &= ~CONTROL_BIT_MASK; + + if (_isPartOfMessage) { + *seqNumBitField |= MESSAGE_BIT_MASK; + } else { + *seqNumBitField &= ~MESSAGE_BIT_MASK; + } + + if (_isReliable) { + *seqNumBitField |= RELIABILITY_BIT_MASK; + } else { + *seqNumBitField &= ~RELIABILITY_BIT_MASK; + } + // write new value by ORing (old value & BIT_FIELD_MASK) with new seqNum - *seqNumBitField = (*seqNumBitField & BIT_FIELD_MASK) | (SequenceNumber::Type) seqNum; + *seqNumBitField = (*seqNumBitField & BIT_FIELD_MASK) | (SequenceNumber::Type)_sequenceNumber; } diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index 343b89107c..94bd1be4fa 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -47,9 +47,12 @@ public: virtual qint64 localHeaderSize() const; virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers - - void writeSequenceNumber(SequenceNumber seqNum); + + bool isPartOfMessage() const { return _isPartOfMessage; } + bool isReliable() const { return _isReliable; } SequenceNumber getSequenceNumber() const { return _sequenceNumber; } + + void setSequenceNumber(); protected: Packet(qint64 size, bool isReliable = false, bool isPartOfMessage = false); @@ -61,9 +64,8 @@ protected: Packet& operator=(Packet&& other); // Header readers - these read data to member variables after pulling packet off wire - void readIsPartOfMessage(); - void readIsReliable(); - void readSequenceNumber(); + void readHeader(); + void writeHeader(); bool _isReliable { false }; bool _isPartOfMessage { false }; From f885fbad8cac8d0cf485aa3b83e4222c72d82ae8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 13:49:11 -0700 Subject: [PATCH 104/549] remove sequence numbers from _naks in SendQueue --- libraries/networking/src/udt/SendQueue.cpp | 26 ++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 34761d57f6..0be80fe98d 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -89,10 +89,28 @@ void SendQueue::ack(SequenceNumber ack) { return; } - // remove any ACKed packets from the map of sent packets - QWriteLocker locker(&_sentLock); - for (auto seq = _lastAck; seq <= ack; ++seq) { - _sentPackets.erase(seq); + { + // remove any ACKed packets from the map of sent packets + QWriteLocker locker(&_sentLock); + for (auto seq = _lastAck; seq <= ack; ++seq) { + _sentPackets.erase(seq); + } + } + + { + // remove any sequence numbers equal to or lower than this ACK in the loss list + QWriteLocker nakLocker(&_naksLock); + + auto it = _naks.begin(); + + while (it != _naks.end()) { + if (*it <= ack) { + it = _naks.erase(it); + } else { + // the NAKs in the NAK list must be in order, so we can break if we hit one > ack + break; + } + } } _lastAck = ack; From c17f4b8991980206aa8fc5ac3a9d7f2115fd32da Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 13:58:21 -0700 Subject: [PATCH 105/549] add a missing bracket, comment for processACK --- libraries/networking/src/udt/Connection.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 6826b4b109..779c8179bf 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -163,6 +163,7 @@ void Connection::processControl(unique_ptr controlPacket) { processACK(move(controlPacket)); } break; + } case ControlPacket::ACK2: processACK2(move(controlPacket)); break; @@ -181,7 +182,9 @@ void Connection::processACK(std::unique_ptr controlPacket) { SequenceNumber currentACKSubSequenceNumber; controlPacket->readPrimitive(¤tACKSubSequenceNumber); - // check if we need send an ACK2 for this ACK + // Check if we need send an ACK2 for this ACK + // This will be the case if it has been longer than the sync interval OR + // it looks like they haven't received our ACK2 for this ACK auto currentTime = high_resolution_clock::now(); static high_resolution_clock::time_point lastACK2SendTime; From ca9969967424f5c01b682fc16430861730f8b64a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Jul 2015 14:00:59 -0700 Subject: [PATCH 106/549] Implement Packet::setSequenceNumber --- libraries/networking/src/udt/Packet.cpp | 6 ++++++ libraries/networking/src/udt/Packet.h | 2 +- libraries/networking/src/udt/SendQueue.cpp | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 5f1aa88937..e40c81accd 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -112,6 +112,11 @@ Packet& Packet::operator=(Packet&& other) { return *this; } +void Packet::setSequenceNumber(SequenceNumber sequenceNumber) { + _sequenceNumber = sequenceNumber; + writeHeader(); +} + static const uint32_t CONTROL_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 1); static const uint32_t RELIABILITY_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 2); static const uint32_t MESSAGE_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 3); @@ -130,6 +135,7 @@ void Packet::writeHeader() { // grab pointer to current SequenceNumberAndBitField SequenceNumberAndBitField* seqNumBitField = reinterpret_cast(_packet.get()); + // 0 for data packets *seqNumBitField &= ~CONTROL_BIT_MASK; if (_isPartOfMessage) { diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index 94bd1be4fa..e7bd41b937 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -52,7 +52,7 @@ public: bool isReliable() const { return _isReliable; } SequenceNumber getSequenceNumber() const { return _sequenceNumber; } - void setSequenceNumber(); + void setSequenceNumber(SequenceNumber sequenceNumber); protected: Packet(qint64 size, bool isReliable = false, bool isPartOfMessage = false); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 0be80fe98d..84d34f4012 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -131,7 +131,7 @@ void SendQueue::sendNextPacket() { _lastSendTimestamp = sendTime; if (_nextPacket) { - _nextPacket->writeSequenceNumber(++_currentSequenceNumber); + _nextPacket->setSequenceNumber(++_currentSequenceNumber); sendPacket(*_nextPacket); _atomicCurrentSequenceNumber.store((uint32_t) _currentSequenceNumber); From b6bdcadd3334d724a9b60fec5aa58f7fcde1ee34 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 14:02:13 -0700 Subject: [PATCH 107/549] make updateRTT take an int --- libraries/networking/src/udt/Connection.cpp | 2 +- libraries/networking/src/udt/Connection.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 779c8179bf..3807134776 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -312,7 +312,7 @@ void Connection::processNAK(std::unique_ptr controlPacket) { } } -void Connection::updateRTT(int32_t rtt) { +void Connection::updateRTT(int rtt) { // this updates the RTT using exponential weighted moving average _rttVariance = (_rttVariance * 3 + abs(rtt - _rtt)) >> 2; _rtt = (_rtt * 7 + rtt) >> 3; diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 5bf15f3031..e85c8a3c7e 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -52,7 +52,7 @@ private: void processACK2(std::unique_ptr controlPacket); void processNAK(std::unique_ptr controlPacket); - void updateRTT(int32_t rtt); + void updateRTT(int rtt); int _synInterval; // Periodical Rate Control Interval, defaults to 10ms From f53637f19e07aa2bd2856834c48d912c801f2955 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Jul 2015 14:16:09 -0700 Subject: [PATCH 108/549] Added SendQueue::getNextSeqNum --- libraries/networking/src/udt/SendQueue.cpp | 15 +++++++++++---- libraries/networking/src/udt/SendQueue.h | 9 +++++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 84d34f4012..b69b643ec8 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -80,8 +80,10 @@ void SendQueue::stop() { _running = false; } -void SendQueue::sendPacket(const BasePacket& packet) { - _socket->writeUnreliablePacket(packet, _destination); +void SendQueue::sendPacket(const Packet& packet) { + if (_socket) { + _socket->writePacket(packet, _destination); + } } void SendQueue::ack(SequenceNumber ack) { @@ -121,6 +123,11 @@ void SendQueue::nak(std::list naks) { _naks.splice(_naks.end(), naks); // Add naks at the end } +SequenceNumber SendQueue::getNextSequenceNumber() { + _atomicCurrentSequenceNumber = (SequenceNumber::Type)++_currentSequenceNumber; + return _currentSequenceNumber; +} + void SendQueue::sendNextPacket() { if (!_running) { return; @@ -131,9 +138,9 @@ void SendQueue::sendNextPacket() { _lastSendTimestamp = sendTime; if (_nextPacket) { - _nextPacket->setSequenceNumber(++_currentSequenceNumber); + // Write packet's sequence number and send it off + _nextPacket->setSequenceNumber(getNextSequenceNumber()); sendPacket(*_nextPacket); - _atomicCurrentSequenceNumber.store((uint32_t) _currentSequenceNumber); // Insert the packet we have just sent in the sent list QWriteLocker locker(&_sentLock); diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 60ad1d0101..9e9c5cc024 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -50,7 +50,6 @@ public: public slots: void start(); void stop(); - void sendPacket(const BasePacket& packet); void ack(SequenceNumber ack); void nak(std::list naks); @@ -66,15 +65,21 @@ private: SendQueue(SendQueue&& other) = delete; ~SendQueue(); + // Increments current sequence number and return it + SequenceNumber getNextSequenceNumber(); + + // Send a packet through the socket + void sendPacket(const Packet& packet); + mutable QReadWriteLock _packetsLock; // Protects the packets to be sent list. std::list> _packets; // List of packets to be sent std::unique_ptr _nextPacket; // Next packet to be sent Socket* _socket { nullptr }; // Socket to send packet on HifiSockAddr _destination; // Destination addr - SequenceNumber _currentSequenceNumber; // Last sequence number sent out SequenceNumber _lastAck; // Last ACKed sequence number + SequenceNumber _currentSequenceNumber; // Last sequence number sent out std::atomic _atomicCurrentSequenceNumber; // Atomic for last sequence number sent out std::unique_ptr _sendTimer; // Send timer From e3e8219c11b1c7c5b14fbe6cf763545b0f816da1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 14:20:51 -0700 Subject: [PATCH 109/549] add some comments to help understand the RTT calculation --- libraries/networking/src/udt/Connection.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 3807134776..4bfc679c97 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -313,7 +313,16 @@ void Connection::processNAK(std::unique_ptr controlPacket) { } void Connection::updateRTT(int rtt) { - // this updates the RTT using exponential weighted moving average + // This updates the RTT using exponential weighted moving average + // This is the Jacobson's forumla for RTT estimation + // http://www.mathcs.emory.edu/~cheung/Courses/455/Syllabus/7-transport/Jacobson-88.pdf + + // Estimated RTT = (1 - x)(estimatedRTT) + (x)(sampleRTT) + // (where x = 0.125 via Jacobson) + + // Deviation = (1 - x)(deviation) + x |sampleRTT - estimatedRTT| + // (where x = 0.25 via Jacobson) + _rttVariance = (_rttVariance * 3 + abs(rtt - _rtt)) >> 2; _rtt = (_rtt * 7 + rtt) >> 3; } From 937e46abf22821f9313ba4069da36a561d41b990 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 14:28:19 -0700 Subject: [PATCH 110/549] add path to header for LossList --- libraries/networking/src/udt/LossList.cpp | 4 ++-- libraries/networking/src/udt/LossList.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp index abe26970e1..db312935b8 100644 --- a/libraries/networking/src/udt/LossList.cpp +++ b/libraries/networking/src/udt/LossList.cpp @@ -1,6 +1,6 @@ // // LossList.cpp -// +// libraries/networking/src/udt // // Created by Clement on 7/27/15. // Copyright 2015 High Fidelity, Inc. @@ -101,4 +101,4 @@ void LossList::remove(SequenceNumber start, SequenceNumber end) { SequenceNumber LossList::getFirstSequenceNumber() const { assert(getLength() > 0); return _lossList.front().first; -} \ No newline at end of file +} diff --git a/libraries/networking/src/udt/LossList.h b/libraries/networking/src/udt/LossList.h index ec26947dfc..387c69b70f 100644 --- a/libraries/networking/src/udt/LossList.h +++ b/libraries/networking/src/udt/LossList.h @@ -1,6 +1,6 @@ // // LossList.h -// +// libraries/networking/src/udt // // Created by Clement on 7/27/15. // Copyright 2015 High Fidelity, Inc. From cf30426636646633d83ba70b0317343a90e7f7fe Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 15:21:17 -0700 Subject: [PATCH 111/549] add a PacketTimeWindow to estimate bandwidth and report speed --- libraries/networking/src/udt/Connection.cpp | 18 +++- libraries/networking/src/udt/Connection.h | 3 + .../networking/src/udt/ControlPacket.cpp | 21 ---- libraries/networking/src/udt/ControlPacket.h | 6 +- .../networking/src/udt/PacketTimeWindow.cpp | 101 ++++++++++++++++++ .../networking/src/udt/PacketTimeWindow.h | 48 +++++++++ libraries/networking/src/udt/SendQueue.cpp | 2 + 7 files changed, 168 insertions(+), 31 deletions(-) create mode 100644 libraries/networking/src/udt/PacketTimeWindow.cpp create mode 100644 libraries/networking/src/udt/PacketTimeWindow.h diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 4bfc679c97..a9318fe0e3 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -78,7 +78,9 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { // pack the available buffer size - must be a minimum of 2 if (wasCausedBySyncTimeout) { - // pack in the receive speed and bandwidth + // pack in the receive speed and estimatedBandwidth + ackPacket->writePrimitive(_receiveWindow.getPacketReceiveSpeed()); + ackPacket->writePrimitive(_receiveWindow.getEstimatedBandwidth()); // record this as the last ACK send time lastACKSendTime = high_resolution_clock::now(); @@ -122,6 +124,16 @@ SequenceNumber Connection::nextACK() const { } void Connection::processReceivedSequenceNumber(SequenceNumber seq) { + + // check if this is a packet pair we should estimate bandwidth from, or just a regular packet + if (((uint32_t) seq & 0xF) == 0) { + _receiveWindow.onProbePair1Arrival(); + } else if (((uint32_t) seq & 0xF) == 1) { + _receiveWindow.onProbePair2Arrival(); + } else { + _receiveWindow.onPacketArrival(); + } + // If this is not the next sequence number, report loss if (seq > _lastReceivedSequenceNumber + 1) { if (_lastReceivedSequenceNumber + 1 == seq - 1) { @@ -170,10 +182,6 @@ void Connection::processControl(unique_ptr controlPacket) { case ControlPacket::NAK: processNAK(move(controlPacket)); break; - case ControlPacket::PacketPair: { - - break; - } } } diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index e85c8a3c7e..dc2c335455 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -16,6 +16,7 @@ #include #include "LossList.h" +#include "PacketTimeWindow.h" #include "SendQueue.h" class HifiSockAddr; @@ -74,6 +75,8 @@ private: SentACKMap _sentACKs; // Map of ACK sub-sequence numbers to ACKed sequence number and sent time + PacketTimeWindow _receiveWindow; // Window of received packets for bandwidth estimation and receive speed + std::unique_ptr _sendQueue; }; diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index 5f28b96750..057f3633f9 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -27,13 +27,6 @@ std::unique_ptr ControlPacket::create(Type type, qint64 size) { } } -ControlPacket::ControlPacketPair ControlPacket::createPacketPair(quint64 timestamp) { - // create each of the two packets in the packet pair - ControlPacketPair packetPair { std::unique_ptr(new ControlPacket(timestamp)), - std::unique_ptr(new ControlPacket(timestamp)) }; - return packetPair; -} - qint64 ControlPacket::localHeaderSize() { return sizeof(ControlBitAndType); } @@ -64,20 +57,6 @@ ControlPacket::ControlPacket(Type type, qint64 size) : writeControlBitAndType(); } -ControlPacket::ControlPacket(quint64 timestamp) : - BasePacket(localHeaderSize() + sizeof(timestamp)), - _type(Type::PacketPair) -{ - adjustPayloadStartAndCapacity(); - - open(QIODevice::ReadWrite); - - writeControlBitAndType(); - - // pack in the timestamp - writePrimitive(timestamp); -} - ControlPacket::ControlPacket(ControlPacket&& other) : BasePacket(std::move(other)) { diff --git a/libraries/networking/src/udt/ControlPacket.h b/libraries/networking/src/udt/ControlPacket.h index d17e12e182..4563b657a9 100644 --- a/libraries/networking/src/udt/ControlPacket.h +++ b/libraries/networking/src/udt/ControlPacket.h @@ -25,17 +25,14 @@ class ControlPacket : public BasePacket { Q_OBJECT public: using ControlBitAndType = uint32_t; - using ControlPacketPair = std::pair, std::unique_ptr>; enum Type : uint16_t { ACK, ACK2, - NAK, - PacketPair + NAK }; static std::unique_ptr create(Type type, qint64 size = -1); - static ControlPacketPair createPacketPair(quint64 timestamp); static qint64 localHeaderSize(); // Current level's header size virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers @@ -46,7 +43,6 @@ public: private: ControlPacket(Type type); ControlPacket(Type type, qint64 size); - ControlPacket(quint64 timestamp); ControlPacket(ControlPacket&& other); ControlPacket(const ControlPacket& other) = delete; diff --git a/libraries/networking/src/udt/PacketTimeWindow.cpp b/libraries/networking/src/udt/PacketTimeWindow.cpp new file mode 100644 index 0000000000..c8c49e6603 --- /dev/null +++ b/libraries/networking/src/udt/PacketTimeWindow.cpp @@ -0,0 +1,101 @@ +// +// PacketTimeWindow.cpp +// libraries/networking/src/udt +// +// Created by Stephen Birarda on 2015-07-28. +// Copyright 2015 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 "PacketTimeWindow.h" + +#include + +#include + +using namespace udt; +using namespace std::chrono; + +PacketTimeWindow::PacketTimeWindow(int numPacketIntervals, int numProbeIntervals) : + _numPacketIntervals(numPacketIntervals), + _numProbeIntervals(numProbeIntervals), + _packetIntervals({ _numPacketIntervals }), + _probeIntervals({ _numProbeIntervals }) +{ + +} + +int32_t meanOfMedianFilteredValues(std::vector intervals, int numValues, int valuesRequired = 0) { + // sort the intervals from smallest to largest + std::sort(intervals.begin(), intervals.end()); + + int median = 0; + if (numValues % 2 == 0) { + median = intervals[numValues / 2]; + } else { + median = (intervals[(numValues / 2) - 1] + intervals[numValues / 2]) / 2; + } + + int count = 0; + int sum = 0; + int upperBound = median * 8; + int lowerBound = median / 8; + + for (auto& interval : intervals) { + if ((interval < upperBound) && interval > lowerBound) { + ++count; + sum += interval; + } + } + + if (count >= valuesRequired) { + return (int32_t) ceil((double) USECS_PER_MSEC / ((double) sum) / ((double) count)); + } else { + return 0; + } +} + +int32_t PacketTimeWindow::getPacketReceiveSpeed() const { + // return the mean value of median filtered values (per second) - or zero if there are too few filtered values + return meanOfMedianFilteredValues(_packetIntervals, _numPacketIntervals, _numPacketIntervals / 2); +} + +int32_t PacketTimeWindow::getEstimatedBandwidth() const { + // return mean value of median filtered values (per second) + return meanOfMedianFilteredValues(_probeIntervals, _numProbeIntervals); +} + +void PacketTimeWindow::onPacketArrival() { + // take the current time + auto now = high_resolution_clock::now(); + + // record the interval between this packet and the last one + _packetIntervals[_currentPacketInterval++] = duration_cast(now - _lastPacketTime).count(); + + // reset the currentPacketInterval index when it wraps + if (_currentPacketInterval == _numPacketIntervals) { + _currentPacketInterval = 0; + } + + // remember this as the last packet arrival time + _lastPacketTime = now; +} + +void PacketTimeWindow::onProbePair1Arrival() { + // take the current time as the first probe time + _firstProbeTime = high_resolution_clock::now(); +} + +void PacketTimeWindow::onProbePair2Arrival() { + // store the interval between the two probes + auto now = high_resolution_clock::now(); + + _probeIntervals[_currentProbeInterval++] = duration_cast(now - _firstProbeTime).count(); + + // reset the currentProbeInterval index when it wraps + if (_currentProbeInterval == _numProbeIntervals) { + _currentProbeInterval = 0; + } +} diff --git a/libraries/networking/src/udt/PacketTimeWindow.h b/libraries/networking/src/udt/PacketTimeWindow.h new file mode 100644 index 0000000000..25e3df8a43 --- /dev/null +++ b/libraries/networking/src/udt/PacketTimeWindow.h @@ -0,0 +1,48 @@ +// +// PacketTimeWindow.h +// libraries/networking/src/udt +// +// Created by Stephen Birarda on 2015-07-28. +// Copyright 2015 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 +// + +#pragma once + +#ifndef hifi_PacketTimeWindow_h +#define hifi_PacketTimeWindow_h + +#include +#include + +namespace udt { + +class PacketTimeWindow { +public: + PacketTimeWindow(int numPacketIntervals = 16, int numProbeIntervals = 16); + + void onPacketArrival(); + void onProbePair1Arrival(); + void onProbePair2Arrival(); + + int32_t getPacketReceiveSpeed() const; + int32_t getEstimatedBandwidth() const; +private: + int _numPacketIntervals { 0 }; // the number of packet intervals to store + int _numProbeIntervals { 0 }; // the number of probe intervals to store + + int _currentPacketInterval { 0 }; // index for the current packet interval + int _currentProbeInterval { 0 }; // index for the current probe interval + + std::vector _packetIntervals; // vector of microsecond intervals between packet arrivals + std::vector _probeIntervals; // vector of microsecond intervals between probe pair arrivals + + std::chrono::high_resolution_clock::time_point _lastPacketTime; // the time_point when last packet arrived + std::chrono::high_resolution_clock::time_point _firstProbeTime; // the time_point when first probe in pair arrived +}; + +} + +#endif // hifi_PacketTimeWindow_h diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 0be80fe98d..c324792475 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -174,6 +174,8 @@ void SendQueue::sendNextPacket() { _packets.pop_front(); } + // check if we need to fire off a packet pair - we do this + // How long before next packet send auto timeToSleep = (sendTime + _packetSendPeriod) - msecTimestampNow(); // msec _sendTimer->start(std::max((quint64)0, timeToSleep)); From b0147144cb48f275160535c086c3fc230160d824 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 15:25:08 -0700 Subject: [PATCH 112/549] fix for comment for PacketTimeWindow --- libraries/networking/src/udt/Connection.cpp | 2 +- libraries/networking/src/udt/Connection.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index a9318fe0e3..de6fbfbe1d 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -80,7 +80,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { if (wasCausedBySyncTimeout) { // pack in the receive speed and estimatedBandwidth ackPacket->writePrimitive(_receiveWindow.getPacketReceiveSpeed()); - ackPacket->writePrimitive(_receiveWindow.getEstimatedBandwidth()); + ackPacket->writePrimitive(_receiveWindow.getEstimatedBandwidth()); // record this as the last ACK send time lastACKSendTime = high_resolution_clock::now(); diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index dc2c335455..66885ef612 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -75,7 +75,7 @@ private: SentACKMap _sentACKs; // Map of ACK sub-sequence numbers to ACKed sequence number and sent time - PacketTimeWindow _receiveWindow; // Window of received packets for bandwidth estimation and receive speed + PacketTimeWindow _receiveWindow { 16, 64 }; // Window of interval between packets (16) and probes (64) for bandwidth and receive speed std::unique_ptr _sendQueue; }; From 24520c5856dd7b2d3e89b41b330a652d45fd42cc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Jul 2015 15:32:00 -0700 Subject: [PATCH 113/549] LNL send cleanup / Added connection hash --- ice-server/src/IceServer.cpp | 2 +- libraries/networking/src/LimitedNodeList.cpp | 74 +++++++++++--------- libraries/networking/src/LimitedNodeList.h | 10 +-- libraries/networking/src/udt/Connection.cpp | 18 +++-- libraries/networking/src/udt/Connection.h | 7 +- libraries/networking/src/udt/SendQueue.cpp | 4 +- libraries/networking/src/udt/SendQueue.h | 6 +- libraries/networking/src/udt/Socket.cpp | 28 ++++++-- libraries/networking/src/udt/Socket.h | 10 +-- 9 files changed, 97 insertions(+), 62 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 9ddb67677d..ec6f5ef825 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -145,7 +145,7 @@ void IceServer::sendPeerInformationPacket(const NetworkPeer& peer, const HifiSoc peerPacket->write(peer.toByteArray()); // write the current packet - _serverSocket.writeUnreliablePacket(*peerPacket, *destinationSockAddr); + _serverSocket.writePacket(*peerPacket, *destinationSockAddr); } void IceServer::clearInactivePeers() { diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index edfdd682e9..c705542bf5 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -244,18 +244,13 @@ bool LimitedNodeList::packetSourceAndHashMatch(const udt::Packet& packet) { return false; } -qint64 LimitedNodeList::writePacket(const NLPacket& packet, const Node& destinationNode) { - if (!destinationNode.getActiveSocket()) { - return 0; - } - - emit dataSent(destinationNode.getType(), packet.getDataSize()); - - return writePacket(packet, *destinationNode.getActiveSocket(), destinationNode.getConnectionSecret()); +void LimitedNodeList::collectPacketStats(const NLPacket& packet) { + // stat collection for packets + ++_numCollectedPackets; + _numCollectedBytes += packet.getDataSize(); } -qint64 LimitedNodeList::writePacket(const NLPacket& packet, const HifiSockAddr& destinationSockAddr, - const QUuid& connectionSecret) { +void LimitedNodeList::fillPacketHeader(const NLPacket& packet, const QUuid& connectionSecret) { if (!NON_SOURCED_PACKETS.contains(packet.getType())) { const_cast(packet).writeSourceID(getSessionUUID()); } @@ -265,55 +260,66 @@ qint64 LimitedNodeList::writePacket(const NLPacket& packet, const HifiSockAddr& && !NON_VERIFIED_PACKETS.contains(packet.getType())) { const_cast(packet).writeVerificationHashGivenSecret(connectionSecret); } - - emit dataSent(NodeType::Unassigned, packet.getDataSize()); - - return writePacketAndCollectStats(packet, destinationSockAddr); -} - -qint64 LimitedNodeList::writePacketAndCollectStats(const NLPacket& packet, const HifiSockAddr& destinationSockAddr) { - // XXX can BandwidthRecorder be used for this? - // stat collection for packets - ++_numCollectedPackets; - _numCollectedBytes += packet.getDataSize(); - - qint64 bytesWritten = _nodeSocket.writeUnreliablePacket(packet, destinationSockAddr); - - return bytesWritten; } qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const Node& destinationNode) { - return writePacket(packet, destinationNode); + if (!destinationNode.getActiveSocket()) { + return 0; + } + emit dataSent(destinationNode.getType(), packet.getDataSize()); + return sendUnreliablePacket(packet, *destinationNode.getActiveSocket(), destinationNode.getConnectionSecret()); } qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const HifiSockAddr& sockAddr, const QUuid& connectionSecret) { - return writePacket(packet, sockAddr, connectionSecret); + 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::sendPacket(std::unique_ptr packet, const Node& destinationNode) { - // Keep unique_ptr alive during write - auto result = writePacket(*packet, destinationNode); - return result; + if (!destinationNode.getActiveSocket()) { + return 0; + } + emit dataSent(destinationNode.getType(), packet->getDataSize()); + return sendPacket(std::move(packet), *destinationNode.getActiveSocket(), destinationNode.getConnectionSecret()); } qint64 LimitedNodeList::sendPacket(std::unique_ptr packet, const HifiSockAddr& sockAddr, const QUuid& connectionSecret) { - // Keep unique_ptr alive during write - auto result = writePacket(*packet, sockAddr, connectionSecret); - return result; + if (packet->isReliable()) { + collectPacketStats(*packet); + fillPacketHeader(*packet, connectionSecret); + + auto size = packet->getDataSize(); + _nodeSocket.writePacket(std::move(packet), sockAddr); + + return size; + } else { + return sendUnreliablePacket(*packet, sockAddr, connectionSecret); + } } qint64 LimitedNodeList::sendPacketList(NLPacketList& packetList, const Node& destinationNode) { + auto activeSocket = destinationNode.getActiveSocket(); + if (!activeSocket) { + return 0; + } qint64 bytesSent = 0; + auto connectionSecret = destinationNode.getConnectionSecret(); // close the last packet in the list packetList.closeCurrentPacket(); while (!packetList._packets.empty()) { - bytesSent += sendPacket(packetList.takeFront(), destinationNode); + bytesSent += sendPacket(packetList.takeFront(), *activeSocket, connectionSecret); } + emit dataSent(destinationNode.getType(), bytesSent); return bytesSent; } diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index e09617b88f..9c3ff058fc 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -247,11 +247,13 @@ protected: LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton void operator=(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton - qint64 writePacket(const NLPacket& packet, const Node& destinationNode); + qint64 sendPacket(std::unique_ptr packet, const Node& destinationNode, + const HifiSockAddr& overridenSockAddr); qint64 writePacket(const NLPacket& packet, const HifiSockAddr& destinationSockAddr, const QUuid& connectionSecret = QUuid()); - qint64 writePacketAndCollectStats(const NLPacket& packet, const HifiSockAddr& destinationSockAddr); - + void collectPacketStats(const NLPacket& packet); + void fillPacketHeader(const NLPacket& packet, const QUuid& connectionSecret); + bool isPacketVerified(const udt::Packet& packet); bool packetVersionMatch(const udt::Packet& packet); bool packetSourceAndHashMatch(const udt::Packet& packet); @@ -264,8 +266,6 @@ protected: void sendPacketToIceServer(PacketType packetType, const HifiSockAddr& iceServerSockAddr, const QUuid& clientID, const QUuid& peerRequestID = QUuid()); - qint64 sendPacket(std::unique_ptr packet, const Node& destinationNode, - const HifiSockAddr& overridenSockAddr); QUuid _sessionUUID; diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 8e72a53c69..a46af2bbde 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -20,14 +20,21 @@ using namespace udt; using namespace std; using namespace std::chrono; -Connection::Connection(Socket* parentSocket, HifiSockAddr destination) { - +Connection::Connection(Socket* parentSocket, HifiSockAddr destination) : + _parentSocket(parentSocket), + _destination(destination) +{ } -void Connection::send(unique_ptr packet) { - if (_sendQueue) { - _sendQueue->queuePacket(move(packet)); +void Connection::sendReliablePacket(unique_ptr packet) { + Q_ASSERT_X(packet->isReliable(), "Connection::send", "Trying to send an unreliable packet reliably."); + + if (!_sendQueue) { + // Lasily create send queue + _sendQueue = SendQueue::create(_parentSocket, _destination); } + + _sendQueue->queuePacket(move(packet)); } void Connection::sendACK(bool wasCausedBySyncTimeout) { @@ -163,7 +170,6 @@ void Connection::processControl(unique_ptr controlPacket) { processACK(move(controlPacket)); } break; - } case ControlPacket::ACK2: processACK2(move(controlPacket)); break; diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 5bf15f3031..bd3e6b82e4 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -17,8 +17,7 @@ #include "LossList.h" #include "SendQueue.h" - -class HifiSockAddr; +#include "../HifiSockAddr.h" namespace udt { @@ -34,7 +33,7 @@ public: Connection(Socket* parentSocket, HifiSockAddr destination); - void send(std::unique_ptr packet); + void sendReliablePacket(std::unique_ptr packet); void sendACK(bool wasCausedBySyncTimeout = true); void sendLightACK() const; @@ -74,6 +73,8 @@ private: SentACKMap _sentACKs; // Map of ACK sub-sequence numbers to ACKed sequence number and sent time + Socket* _parentSocket { nullptr }; + HifiSockAddr _destination; std::unique_ptr _sendQueue; }; diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index b69b643ec8..ef37bf7f9a 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -80,9 +80,9 @@ void SendQueue::stop() { _running = false; } -void SendQueue::sendPacket(const Packet& packet) { +void SendQueue::sendPacket(const BasePacket& packet) { if (_socket) { - _socket->writePacket(packet, _destination); + _socket->writeDatagram(packet.getData(), packet.getDataSize(), _destination); } } diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 9e9c5cc024..1c30d1580a 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -47,6 +47,9 @@ public: int getPacketSendPeriod() const { return _packetSendPeriod; } void setPacketSendPeriod(int newPeriod) { _packetSendPeriod = newPeriod; } + // Send a packet through the socket + void sendPacket(const BasePacket& packet); + public slots: void start(); void stop(); @@ -67,9 +70,6 @@ private: // Increments current sequence number and return it SequenceNumber getNextSequenceNumber(); - - // Send a packet through the socket - void sendPacket(const Packet& packet); mutable QReadWriteLock _packetsLock; // Protects the packets to be sent list. std::list> _packets; // List of packets to be sent diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 6923879201..a5719da9a4 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -14,6 +14,7 @@ #include #include "../NetworkLogging.h" +#include "ControlPacket.h" #include "Packet.h" using namespace udt; @@ -66,17 +67,36 @@ void Socket::setBufferSizes(int numBytes) { } } -qint64 Socket::writeUnreliablePacket(const BasePacket& packet, const HifiSockAddr& sockAddr) { +qint64 Socket::writePacket(const Packet& packet, const HifiSockAddr& sockAddr) { + Q_ASSERT_X(!packet.isReliable(), "Socket::writePacket", "Cannot send a reliable packet unreliably"); + + // TODO: write the correct sequence number to the Packet here + // const_cast(packet).writeSequenceNumber(sequenceNumber); + return writeDatagram(packet.getData(), packet.getDataSize(), sockAddr); } +qint64 Socket::writePacket(std::unique_ptr packet, const HifiSockAddr& sockAddr) { + if (packet->isReliable()) { + auto it = _connectionsHash.find(sockAddr); + if (it == _connectionsHash.end()) { + it = _connectionsHash.insert(it, std::make_pair(sockAddr, new Connection(this, sockAddr))); + } + it->second->sendReliablePacket(std::move(packet)); + return 0; + } + + return writePacket(*packet, sockAddr); +} + +qint64 Socket::writeDatagram(const char* data, qint64 size, const HifiSockAddr& sockAddr) { + return writeDatagram(QByteArray::fromRawData(data, size), sockAddr); +} + qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr) { qint64 bytesWritten = _udpSocket.writeDatagram(datagram, sockAddr.getAddress(), sockAddr.getPort()); - // TODO: write the correct sequence number to the Packet here - // const_cast(packet).writeSequenceNumber(sequenceNumber); - if (bytesWritten < 0) { qCDebug(networking) << "ERROR in writeDatagram:" << _udpSocket.error() << "-" << _udpSocket.errorString(); } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 5b8ebb5d0f..24fa8c8404 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -22,6 +22,7 @@ #include #include "../HifiSockAddr.h" +#include "Connection.h" namespace udt { @@ -42,10 +43,10 @@ public: quint16 localPort() const { return _udpSocket.localPort(); } - qint64 writeUnreliablePacket(const BasePacket& packet, const HifiSockAddr& sockAddr); - - qint64 writeDatagram(const char* data, qint64 size, const HifiSockAddr& sockAddr) - { return writeDatagram(QByteArray::fromRawData(data, size), sockAddr); } + // Simple functions writing to the socket with no processing + qint64 writePacket(const Packet& packet, const HifiSockAddr& sockAddr); + qint64 writePacket(std::unique_ptr packet, const HifiSockAddr& sockAddr); + qint64 writeDatagram(const char* data, qint64 size, const HifiSockAddr& sockAddr); qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr); void bind(const QHostAddress& address, quint16 port = 0) { _udpSocket.bind(address, port); } @@ -71,6 +72,7 @@ private: std::unordered_map _unfilteredHandlers; std::unordered_map _packetSequenceNumbers; + std::unordered_map _connectionsHash; int32_t _synInterval = 10; // 10ms QTimer _synTimer; From ffdd54d41f74dddd21e9783bfca99ceacf8238db Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Jul 2015 15:42:53 -0700 Subject: [PATCH 114/549] Make sendUnreliable take a non const --- libraries/networking/src/LimitedNodeList.cpp | 6 +++--- libraries/networking/src/LimitedNodeList.h | 4 ++-- libraries/networking/src/udt/Socket.cpp | 4 ++-- libraries/networking/src/udt/Socket.h | 4 +++- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index c705542bf5..8d0f1aa5d7 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -262,7 +262,7 @@ void LimitedNodeList::fillPacketHeader(const NLPacket& packet, const QUuid& conn } } -qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const Node& destinationNode) { +qint64 LimitedNodeList::sendUnreliablePacket(NLPacket& packet, const Node& destinationNode) { if (!destinationNode.getActiveSocket()) { return 0; } @@ -270,7 +270,7 @@ qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const Node& return sendUnreliablePacket(packet, *destinationNode.getActiveSocket(), destinationNode.getConnectionSecret()); } -qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const HifiSockAddr& sockAddr, +qint64 LimitedNodeList::sendUnreliablePacket(NLPacket& packet, const HifiSockAddr& sockAddr, const QUuid& connectionSecret) { Q_ASSERT_X(!packet.isReliable(), "LimitedNodeList::sendUnreliablePacket", "Trying to send a reliable packet unreliably."); @@ -516,7 +516,7 @@ unsigned int LimitedNodeList::broadcastToNodes(std::unique_ptr packet, eachNode([&](const SharedNodePointer& node){ if (node && destinationNodeTypes.contains(node->getType())) { - writePacket(*packet, *node); + sendUnreliablePacket(*packet, *node); ++n; } }); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 9c3ff058fc..777d6f9679 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -116,8 +116,8 @@ public: PacketReceiver& getPacketReceiver() { return *_packetReceiver; } - qint64 sendUnreliablePacket(const NLPacket& packet, const Node& destinationNode); - qint64 sendUnreliablePacket(const NLPacket& packet, const HifiSockAddr& sockAddr, + qint64 sendUnreliablePacket(NLPacket& packet, const Node& destinationNode); + qint64 sendUnreliablePacket(NLPacket& packet, const HifiSockAddr& sockAddr, const QUuid& connectionSecret = QUuid()); qint64 sendPacket(std::unique_ptr packet, const Node& destinationNode); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index a5719da9a4..360a59e53f 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -67,11 +67,11 @@ void Socket::setBufferSizes(int numBytes) { } } -qint64 Socket::writePacket(const Packet& packet, const HifiSockAddr& sockAddr) { +qint64 Socket::writePacket(Packet& packet, const HifiSockAddr& sockAddr) { Q_ASSERT_X(!packet.isReliable(), "Socket::writePacket", "Cannot send a reliable packet unreliably"); // TODO: write the correct sequence number to the Packet here - // const_cast(packet).writeSequenceNumber(sequenceNumber); + packet.setSequenceNumber(_currentUnreliableSequenceNumber); return writeDatagram(packet.getData(), packet.getDataSize(), sockAddr); } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 24fa8c8404..67cc82d299 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -44,7 +44,7 @@ public: quint16 localPort() const { return _udpSocket.localPort(); } // Simple functions writing to the socket with no processing - qint64 writePacket(const Packet& packet, const HifiSockAddr& sockAddr); + qint64 writePacket(Packet& packet, const HifiSockAddr& sockAddr); qint64 writePacket(std::unique_ptr packet, const HifiSockAddr& sockAddr); qint64 writeDatagram(const char* data, qint64 size, const HifiSockAddr& sockAddr); qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr); @@ -69,6 +69,8 @@ private: PacketFilterOperator _packetFilterOperator; PacketHandler _packetHandler; + SequenceNumber _currentUnreliableSequenceNumber; + std::unordered_map _unfilteredHandlers; std::unordered_map _packetSequenceNumbers; From c2c188c5dd1633be100774acd71d6bd32e68e359 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Jul 2015 15:46:26 -0700 Subject: [PATCH 115/549] Remove TODO --- libraries/networking/src/udt/Socket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 360a59e53f..f48df77db3 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -70,7 +70,7 @@ void Socket::setBufferSizes(int numBytes) { qint64 Socket::writePacket(Packet& packet, const HifiSockAddr& sockAddr) { Q_ASSERT_X(!packet.isReliable(), "Socket::writePacket", "Cannot send a reliable packet unreliably"); - // TODO: write the correct sequence number to the Packet here + // write the correct sequence number to the Packet here packet.setSequenceNumber(_currentUnreliableSequenceNumber); return writeDatagram(packet.getData(), packet.getDataSize(), sockAddr); From 65fa4c4e6d20b60d2a1917eb696fe93c5095e694 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 15:47:36 -0700 Subject: [PATCH 116/549] add the periodic rate control packet sending --- libraries/networking/src/udt/Socket.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 360a59e53f..8c2658cb12 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -144,7 +144,10 @@ void Socket::readPendingDatagrams() { void Socket::rateControlSync() { - // TODO: enumerate our list of connections and ask each of them to send off periodic ACK packet for rate control + // enumerate our list of connections and ask each of them to send off periodic ACK packet for rate control + for (auto& connection : _connectionsHash) { + connection.second->sendACK(); + } if (_synTimer.interval() != _synInterval) { // if the _synTimer interval doesn't match the current _synInterval (changes when the CC factory is changed) From 747f2b0c07babb1b517a9e363ef108c17ffb9bcb Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Jul 2015 15:48:35 -0700 Subject: [PATCH 117/549] Remove seqcmp declaration --- libraries/networking/src/udt/SequenceNumber.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/udt/SequenceNumber.h b/libraries/networking/src/udt/SequenceNumber.h index f04f532bad..6215d23494 100644 --- a/libraries/networking/src/udt/SequenceNumber.h +++ b/libraries/networking/src/udt/SequenceNumber.h @@ -131,7 +131,6 @@ inline SequenceNumber operator-(const SequenceNumber::Type& a, SequenceNumber b) return b; } -int seqcmp(const SequenceNumber& seq1, const SequenceNumber& seq2); int seqlen(const SequenceNumber& seq1, const SequenceNumber& seq2); int seqoff(const SequenceNumber& seq1, const SequenceNumber& seq2); From ba226d168dddb5a5e2c15a3f09de9f77af971ce7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 15:48:37 -0700 Subject: [PATCH 118/549] remove SeqNum since it is replaced by SequenceNumber --- libraries/networking/src/udt/SeqNum.cpp | 29 ----- libraries/networking/src/udt/SeqNum.h | 145 ------------------------ 2 files changed, 174 deletions(-) delete mode 100644 libraries/networking/src/udt/SeqNum.cpp delete mode 100644 libraries/networking/src/udt/SeqNum.h diff --git a/libraries/networking/src/udt/SeqNum.cpp b/libraries/networking/src/udt/SeqNum.cpp deleted file mode 100644 index 53afbcada7..0000000000 --- a/libraries/networking/src/udt/SeqNum.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// -// SeqNum.cpp -// libraries/networking/src/udt -// -// Created by Clement on 7/23/15. -// Copyright 2015 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 "SeqNum.h" - -int udt::seqlen(const SeqNum& seq1, const SeqNum& seq2) { - return (seq1._value <= seq2._value) ? (seq2._value - seq1._value + 1) - : (seq2._value - seq1._value + SeqNum::MAX + 2); -} - -int udt::seqoff(const SeqNum& seq1, const SeqNum& seq2) { - if (glm::abs(seq1._value - seq2._value) < SeqNum::THRESHOLD) { - return seq2._value - seq1._value; - } - - if (seq1._value < seq2._value) { - return seq2._value - seq1._value - SeqNum::MAX - 1; - } - - return seq2._value - seq1._value + SeqNum::MAX + 1; -} diff --git a/libraries/networking/src/udt/SeqNum.h b/libraries/networking/src/udt/SeqNum.h deleted file mode 100644 index 90b327e4c9..0000000000 --- a/libraries/networking/src/udt/SeqNum.h +++ /dev/null @@ -1,145 +0,0 @@ -// -// SeqNum.h -// libraries/networking/src/udt -// -// Created by Clement on 7/23/15. -// Copyright 2015 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 -// - -#ifndef hifi_SeqNum_h -#define hifi_SeqNum_h - -#include - -#include - -namespace udt { - -class SeqNum { -public: - // Base type of sequence numbers - using Type = uint32_t; - - // Values are for 29 bit SeqNum - static const Type THRESHOLD = 0x0FFFFFFF; // threshold for comparing sequence numbers - static const Type MAX = 0x1FFFFFFF; // maximum sequence number used in UDT - - SeqNum() = default; - SeqNum(const SeqNum& other) : _value(other._value) {} - - // Only explicit conversions - explicit SeqNum(char* value) { _value = (*reinterpret_cast(value)) & MAX; } - explicit SeqNum(Type value) { _value = (value <= MAX) ? value : MAX; } - explicit operator Type() { return _value; } - - inline SeqNum& operator++() { - _value = (_value == MAX) ? 0 : ++_value; - return *this; - } - inline SeqNum& operator--() { - _value = (_value == 0) ? MAX : --_value; - return *this; - } - inline SeqNum operator++(int) { - SeqNum before = *this; - (*this)++; - return before; - } - inline SeqNum operator--(int) { - SeqNum before = *this; - (*this)--; - return before; - } - - inline SeqNum& operator=(const SeqNum& other) { - _value = other._value; - return *this; - } - inline SeqNum& operator+=(Type inc) { - _value = (_value + inc > MAX) ? _value + inc - (MAX + 1) : _value + inc; - return *this; - } - inline SeqNum& operator-=(Type dec) { - _value = (_value < dec) ? MAX - (dec - _value + 1) : _value - dec; - return *this; - } - - inline bool operator==(const SeqNum& other) const { - return _value == other._value; - } - inline bool operator!=(const SeqNum& other) const { - return _value != other._value; - } - - friend bool operator<(const SeqNum& a, const SeqNum& b); - friend bool operator>(const SeqNum& a, const SeqNum& b); - friend bool operator<=(const SeqNum& a, const SeqNum& b); - friend bool operator>=(const SeqNum& a, const SeqNum& b); - - friend SeqNum operator+(const SeqNum a, const Type& b); - friend SeqNum operator+(const Type& a, const SeqNum b); - friend SeqNum operator-(const SeqNum a, const Type& b); - friend SeqNum operator-(const Type& a, const SeqNum b); - - friend int seqlen(const SeqNum& seq1, const SeqNum& seq2); - friend int seqoff(const SeqNum& seq1, const SeqNum& seq2); - -private: - Type _value { 0 }; - - friend struct std::hash; -}; - - -inline bool operator<(const SeqNum& a, const SeqNum& b) { - return (glm::abs(a._value - b._value) < SeqNum::THRESHOLD) ? a._value < b._value : b._value < a._value; -} - -inline bool operator>(const SeqNum& a, const SeqNum& b) { - return (glm::abs(a._value - b._value) < SeqNum::THRESHOLD) ? a._value > b._value : b._value > a._value; -} - -inline bool operator<=(const SeqNum& a, const SeqNum& b) { - return (glm::abs(a._value - b._value) < SeqNum::THRESHOLD) ? a._value <= b._value : b._value <= a._value; -} - -inline bool operator>=(const SeqNum& a, const SeqNum& b) { - return (glm::abs(a._value - b._value) < SeqNum::THRESHOLD) ? a._value >= b._value : b._value >= a._value; -} - - -inline SeqNum operator+(SeqNum a, const SeqNum::Type& b) { - a += b; - return a; -} - -inline SeqNum operator+(const SeqNum::Type& a, SeqNum b) { - b += a; - return b; -} - -inline SeqNum operator-(SeqNum a, const SeqNum::Type& b) { - a -= b; - return a; -} - -inline SeqNum operator-(const SeqNum::Type& a, SeqNum b) { - b -= a; - return b; -} - -int seqlen(const SeqNum& seq1, const SeqNum& seq2); -int seqoff(const SeqNum& seq1, const SeqNum& seq2); - -} - -template<> struct std::hash { - size_t operator()(const udt::SeqNum& seqNum) const { - return std::hash()(seqNum._value); - } -}; - -#endif // hifi_SeqNum_h From cfba30078652198de02baf4a1f49bb682bdb0fc0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 15:51:50 -0700 Subject: [PATCH 119/549] send an unreliable sequence number from Socket --- libraries/networking/src/udt/Socket.cpp | 3 +-- libraries/networking/src/udt/Socket.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 8c2658cb12..6fc135118c 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -70,8 +70,7 @@ void Socket::setBufferSizes(int numBytes) { qint64 Socket::writePacket(Packet& packet, const HifiSockAddr& sockAddr) { Q_ASSERT_X(!packet.isReliable(), "Socket::writePacket", "Cannot send a reliable packet unreliably"); - // TODO: write the correct sequence number to the Packet here - packet.setSequenceNumber(_currentUnreliableSequenceNumber); + packet.setSequenceNumber(_unreliableSequenceNumbers[sockAddr]++); return writeDatagram(packet.getData(), packet.getDataSize(), sockAddr); } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 67cc82d299..9ca4adcc74 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -73,7 +73,7 @@ private: std::unordered_map _unfilteredHandlers; - std::unordered_map _packetSequenceNumbers; + std::unordered_map _unreliableSequenceNumbers; std::unordered_map _connectionsHash; int32_t _synInterval = 10; // 10ms From a49ad92d87f4c425e526857a62ae00ec33053078 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 15:55:18 -0700 Subject: [PATCH 120/549] use a constant for the bounds for median filtering --- libraries/networking/src/udt/PacketTimeWindow.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/PacketTimeWindow.cpp b/libraries/networking/src/udt/PacketTimeWindow.cpp index c8c49e6603..ab540e9bc0 100644 --- a/libraries/networking/src/udt/PacketTimeWindow.cpp +++ b/libraries/networking/src/udt/PacketTimeWindow.cpp @@ -40,8 +40,9 @@ int32_t meanOfMedianFilteredValues(std::vector intervals, int numValues, in int count = 0; int sum = 0; - int upperBound = median * 8; - int lowerBound = median / 8; + static const int MEDIAN_FILTERING_BOUND_MULTIPLIER = 8; + int upperBound = median * MEDIAN_FILTERING_BOUND_MULTIPLIER; + int lowerBound = median / MEDIAN_FILTERING_BOUND_MULTIPLIER; for (auto& interval : intervals) { if ((interval < upperBound) && interval > lowerBound) { From 13568d3d694dae00ce2e85523f0a85d4e03a2552 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 15:59:13 -0700 Subject: [PATCH 121/549] add constants for RTT estimation calculations --- libraries/networking/src/udt/Connection.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index dbcee6e622..2ad4171f69 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -337,6 +337,11 @@ void Connection::updateRTT(int rtt) { // Deviation = (1 - x)(deviation) + x |sampleRTT - estimatedRTT| // (where x = 0.25 via Jacobson) - _rttVariance = (_rttVariance * 3 + abs(rtt - _rtt)) >> 2; - _rtt = (_rtt * 7 + rtt) >> 3; + static const int RTT_ESTIMATION_ALPHA_NUMERATOR = 8; + static const int RTT_ESTIMATION_VARIANCE_ALPHA_NUMERATOR = 4; + + _rtt = (_rtt * (1 - RTT_ESTIMATION_ALPHA_NUMERATOR) + rtt) / RTT_ESTIMATION_ALPHA_NUMERATOR; + + _rttVariance = (_rttVariance * (1 - RTT_ESTIMATION_VARIANCE_ALPHA_NUMERATOR) + + abs(rtt - _rtt)) / RTT_ESTIMATION_VARIANCE_ALPHA_NUMERATOR; } From 64e1281d4751eac7dc7fff4da9464870a7cdde1b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Jul 2015 16:02:33 -0700 Subject: [PATCH 122/549] Restore const, make helper memebers mutable --- libraries/networking/src/LimitedNodeList.cpp | 4 ++-- libraries/networking/src/LimitedNodeList.h | 4 ++-- libraries/networking/src/udt/Packet.cpp | 6 +++--- libraries/networking/src/udt/Packet.h | 14 ++++++++------ libraries/networking/src/udt/SendQueue.cpp | 2 +- libraries/networking/src/udt/Socket.cpp | 4 ++-- libraries/networking/src/udt/Socket.h | 4 +--- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 8d0f1aa5d7..fc8e6ad8fe 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -262,7 +262,7 @@ void LimitedNodeList::fillPacketHeader(const NLPacket& packet, const QUuid& conn } } -qint64 LimitedNodeList::sendUnreliablePacket(NLPacket& packet, const Node& destinationNode) { +qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const Node& destinationNode) { if (!destinationNode.getActiveSocket()) { return 0; } @@ -270,7 +270,7 @@ qint64 LimitedNodeList::sendUnreliablePacket(NLPacket& packet, const Node& desti return sendUnreliablePacket(packet, *destinationNode.getActiveSocket(), destinationNode.getConnectionSecret()); } -qint64 LimitedNodeList::sendUnreliablePacket(NLPacket& packet, const HifiSockAddr& sockAddr, +qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const HifiSockAddr& sockAddr, const QUuid& connectionSecret) { Q_ASSERT_X(!packet.isReliable(), "LimitedNodeList::sendUnreliablePacket", "Trying to send a reliable packet unreliably."); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 777d6f9679..9c3ff058fc 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -116,8 +116,8 @@ public: PacketReceiver& getPacketReceiver() { return *_packetReceiver; } - qint64 sendUnreliablePacket(NLPacket& packet, const Node& destinationNode); - qint64 sendUnreliablePacket(NLPacket& packet, const HifiSockAddr& sockAddr, + qint64 sendUnreliablePacket(const NLPacket& packet, const Node& destinationNode); + qint64 sendUnreliablePacket(const NLPacket& packet, const HifiSockAddr& sockAddr, const QUuid& connectionSecret = QUuid()); qint64 sendPacket(std::unique_ptr packet, const Node& destinationNode); diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index e40c81accd..4223986aee 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -112,7 +112,7 @@ Packet& Packet::operator=(Packet&& other) { return *this; } -void Packet::setSequenceNumber(SequenceNumber sequenceNumber) { +void Packet::writeSequenceNumber(SequenceNumber sequenceNumber) const { _sequenceNumber = sequenceNumber; writeHeader(); } @@ -122,7 +122,7 @@ static const uint32_t RELIABILITY_BIT_MASK = 1 << (sizeof(Packet::SequenceNumber static const uint32_t MESSAGE_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 3); static const uint32_t BIT_FIELD_MASK = CONTROL_BIT_MASK | RELIABILITY_BIT_MASK | MESSAGE_BIT_MASK; -void Packet::readHeader() { +void Packet::readHeader() const { SequenceNumberAndBitField seqNumBitField = *reinterpret_cast(_packet.get()); Q_ASSERT_X((bool) (seqNumBitField & CONTROL_BIT_MASK), "Packet::readHeader()", "This should be a data packet"); @@ -131,7 +131,7 @@ void Packet::readHeader() { _sequenceNumber = SequenceNumber{ seqNumBitField & ~BIT_FIELD_MASK }; // Remove the bit field } -void Packet::writeHeader() { +void Packet::writeHeader() const { // grab pointer to current SequenceNumberAndBitField SequenceNumberAndBitField* seqNumBitField = reinterpret_cast(_packet.get()); diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index e7bd41b937..8a6832205f 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -52,7 +52,7 @@ public: bool isReliable() const { return _isReliable; } SequenceNumber getSequenceNumber() const { return _sequenceNumber; } - void setSequenceNumber(SequenceNumber sequenceNumber); + void writeSequenceNumber(SequenceNumber sequenceNumber) const; protected: Packet(qint64 size, bool isReliable = false, bool isPartOfMessage = false); @@ -63,13 +63,15 @@ protected: Packet& operator=(const Packet& other); Packet& operator=(Packet&& other); +private: // Header readers - these read data to member variables after pulling packet off wire - void readHeader(); - void writeHeader(); + void readHeader() const; + void writeHeader() const; - bool _isReliable { false }; - bool _isPartOfMessage { false }; - SequenceNumber _sequenceNumber; + // Simple holders to prevent multiple reading and bitwise ops + mutable bool _isReliable { false }; + mutable bool _isPartOfMessage { false }; + mutable SequenceNumber _sequenceNumber; }; } // namespace udt diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 7824e01d17..787bf60ca7 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -139,7 +139,7 @@ void SendQueue::sendNextPacket() { if (_nextPacket) { // Write packet's sequence number and send it off - _nextPacket->setSequenceNumber(getNextSequenceNumber()); + _nextPacket->writeSequenceNumber(getNextSequenceNumber()); sendPacket(*_nextPacket); // Insert the packet we have just sent in the sent list diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 2ccddde918..358fb95638 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -67,11 +67,11 @@ void Socket::setBufferSizes(int numBytes) { } } -qint64 Socket::writePacket(Packet& packet, const HifiSockAddr& sockAddr) { +qint64 Socket::writePacket(const Packet& packet, const HifiSockAddr& sockAddr) { Q_ASSERT_X(!packet.isReliable(), "Socket::writePacket", "Cannot send a reliable packet unreliably"); // write the correct sequence number to the Packet here - packet.setSequenceNumber(_currentUnreliableSequenceNumber); + packet.writeSequenceNumber(_currentUnreliableSequenceNumber); return writeDatagram(packet.getData(), packet.getDataSize(), sockAddr); } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 67cc82d299..dee6af4117 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -44,7 +44,7 @@ public: quint16 localPort() const { return _udpSocket.localPort(); } // Simple functions writing to the socket with no processing - qint64 writePacket(Packet& packet, const HifiSockAddr& sockAddr); + qint64 writePacket(const Packet& packet, const HifiSockAddr& sockAddr); qint64 writePacket(std::unique_ptr packet, const HifiSockAddr& sockAddr); qint64 writeDatagram(const char* data, qint64 size, const HifiSockAddr& sockAddr); qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr); @@ -72,8 +72,6 @@ private: SequenceNumber _currentUnreliableSequenceNumber; std::unordered_map _unfilteredHandlers; - - std::unordered_map _packetSequenceNumbers; std::unordered_map _connectionsHash; int32_t _synInterval = 10; // 10ms From 09a497a59b7417dc87455d37dc62f85a543b0f96 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 16:23:10 -0700 Subject: [PATCH 123/549] add default interval values for PacketTimeWindow --- libraries/networking/src/udt/PacketTimeWindow.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/PacketTimeWindow.cpp b/libraries/networking/src/udt/PacketTimeWindow.cpp index ab540e9bc0..469915d311 100644 --- a/libraries/networking/src/udt/PacketTimeWindow.cpp +++ b/libraries/networking/src/udt/PacketTimeWindow.cpp @@ -18,11 +18,14 @@ using namespace udt; using namespace std::chrono; +static const int DEFAULT_PACKET_INTERVAL_MICROSECONDS = 1000000; +static const int DEFAULT_PROBE_INTERVAL_MICROSECONDS = 1000; + PacketTimeWindow::PacketTimeWindow(int numPacketIntervals, int numProbeIntervals) : _numPacketIntervals(numPacketIntervals), _numProbeIntervals(numProbeIntervals), - _packetIntervals({ _numPacketIntervals }), - _probeIntervals({ _numProbeIntervals }) + _packetIntervals({ _numPacketIntervals, DEFAULT_PACKET_INTERVAL_MICROSECONDS }), + _probeIntervals({ _numProbeIntervals, DEFAULT_PROBE_INTERVAL_MICROSECONDS }) { } From 74b0fa7e8734707991cfedc1a39d306e1506583f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 16:43:21 -0700 Subject: [PATCH 124/549] use microseconds for intervals, setup timeout NAKs --- libraries/networking/src/udt/Connection.cpp | 51 +++++++++++++++++++-- libraries/networking/src/udt/Connection.h | 18 ++++++-- libraries/networking/src/udt/Socket.cpp | 2 +- 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 2ad4171f69..cc7d1f6c09 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -11,6 +11,8 @@ #include "Connection.h" +#include + #include "../HifiSockAddr.h" #include "ControlPacket.h" #include "Packet.h" @@ -37,6 +39,28 @@ void Connection::sendReliablePacket(unique_ptr packet) { _sendQueue->queuePacket(move(packet)); } +void Connection::sync() { + // we send out a periodic ACK every rate control interval + sendACK(); + + // check if we need to re-transmit a loss list + // we do this if it has been longer than the current nakInterval since we last sent + auto now = high_resolution_clock::now(); + + if (duration_cast(now - _lastNAKTime).count() >= _nakInterval) { + // construct a NAK packet that will hold all of the lost sequence numbers + auto lossListPacket = ControlPacket::create(ControlPacket::NAK, _lossList.getLength() * sizeof(SequenceNumber)); + + + + // have our SendQueue send off this control packet + _sendQueue->sendPacket(*lossListPacket); + + _lastNAKTime = high_resolution_clock::now(); + } + +} + void Connection::sendACK(bool wasCausedBySyncTimeout) { static const int ACK_PACKET_PAYLOAD_BYTES = sizeof(_lastSentACK) + sizeof(_currentACKSubSequenceNumber) + sizeof(_rtt) + sizeof(int32_t) + sizeof(int32_t); @@ -65,10 +89,10 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { } else if (nextACKNumber == _lastSentACK) { // We already sent this ACK, but check if we should re-send it. - // We will re-send if it has been more than RTT + (4 * RTT variance) since the last ACK - milliseconds sinceLastACK = duration_cast(currentTime - lastACKSendTime); + // We will re-send if it has been more than the estimated timeout since the last ACK + microseconds sinceLastACK = duration_cast(currentTime - lastACKSendTime); - if (sinceLastACK.count() < (_rtt + (4 * _rttVariance))) { + if (sinceLastACK.count() < estimatedTimeout()) { return; } } @@ -162,6 +186,23 @@ void Connection::processReceivedSequenceNumber(SequenceNumber seq) { // have the send queue send off our packet immediately _sendQueue->sendPacket(*lossReport); + + // record our last NAK time + _lastNAKTime = high_resolution_clock::now(); + + // figure out when we should send the next loss report, if we haven't heard anything back + _nakInterval = (_rtt + 4 * _rttVariance); + + int receivedPacketsPerSecond = _receiveWindow.getPacketReceiveSpeed(); + if (receivedPacketsPerSecond > 0) { + // the NAK interval is at least the _minNAKInterval + // but might be the time required for all lost packets to be retransmitted + _nakInterval = std::max((int) (_lossList.getLength() * (USECS_PER_SECOND / receivedPacketsPerSecond)), + _minNAKInterval); + } else { + // the NAK interval is at least the _minNAKInterval but might be the estimated timeout + _nakInterval = std::max(estimatedTimeout(), _minNAKInterval); + } } if (seq > _lastReceivedSequenceNumber) { @@ -202,7 +243,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { auto currentTime = high_resolution_clock::now(); static high_resolution_clock::time_point lastACK2SendTime; - milliseconds sinceLastACK2 = duration_cast(currentTime - lastACK2SendTime); + microseconds sinceLastACK2 = duration_cast(currentTime - lastACK2SendTime); if (sinceLastACK2.count() > _synInterval || currentACKSubSequenceNumber == _lastSentACK2) { // setup a static ACK2 packet we will re-use @@ -304,7 +345,7 @@ void Connection::processACK2(std::unique_ptr controlPacket) { // calculate the RTT (time now - time ACK sent) auto now = high_resolution_clock::now(); - int rtt = duration_cast(now - pair.second).count(); + int rtt = duration_cast(now - pair.second).count(); updateRTT(rtt); diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 11c5126023..27057da3a9 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -35,9 +35,8 @@ public: Connection(Socket* parentSocket, HifiSockAddr destination); void sendReliablePacket(std::unique_ptr packet); - - void sendACK(bool wasCausedBySyncTimeout = true); - void sendLightACK() const; + + void sync(); // rate control method, fired by Socket for all connections on SYN interval SequenceNumber nextACK() const; @@ -47,6 +46,9 @@ public: void processControl(std::unique_ptr controlPacket); private: + void sendACK(bool wasCausedBySyncTimeout = true); + void sendLightACK() const; + void processACK(std::unique_ptr controlPacket); void processLightACK(std::unique_ptr controlPacket); void processACK2(std::unique_ptr controlPacket); @@ -54,7 +56,13 @@ private: void updateRTT(int rtt); - int _synInterval; // Periodical Rate Control Interval, defaults to 10ms + int estimatedTimeout() const { return _rtt + _rttVariance * 4; } + + int _synInterval; // Periodical Rate Control Interval, in microseconds, defaults to 10ms + + int _nakInterval; // NAK timeout interval, in microseconds + int _minNAKInterval { 100000 }; // NAK timeout interval lower bound, default of 100ms + std::chrono::high_resolution_clock::time_point _lastNAKTime; LossList _lossList; // List of all missing packets SequenceNumber _lastReceivedSequenceNumber { SequenceNumber::MAX }; // The largest sequence number received from the peer @@ -68,7 +76,7 @@ private: int _totalReceivedACKs { 0 }; - int32_t _rtt; // RTT, in milliseconds + int32_t _rtt; // RTT, in microseconds int32_t _rttVariance; // RTT variance int _flowWindowSize; // Flow control window size diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 6fc135118c..15f0febc9b 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -145,7 +145,7 @@ void Socket::rateControlSync() { // enumerate our list of connections and ask each of them to send off periodic ACK packet for rate control for (auto& connection : _connectionsHash) { - connection.second->sendACK(); + connection.second->sync(); } if (_synTimer.interval() != _synInterval) { From 05d9845077d6991b6455f465af42a4c15ced2cf5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 17:01:13 -0700 Subject: [PATCH 125/549] add counting of total control packets sent/received --- libraries/networking/src/udt/Connection.cpp | 34 ++++++++++++++++++-- libraries/networking/src/udt/Connection.h | 22 +++++++++++-- libraries/networking/src/udt/ControlPacket.h | 3 +- 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index cc7d1f6c09..507e11f206 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -49,14 +49,17 @@ void Connection::sync() { if (duration_cast(now - _lastNAKTime).count() >= _nakInterval) { // construct a NAK packet that will hold all of the lost sequence numbers - auto lossListPacket = ControlPacket::create(ControlPacket::NAK, _lossList.getLength() * sizeof(SequenceNumber)); - + auto lossListPacket = ControlPacket::create(ControlPacket::TimeoutNAK, _lossList.getLength() * sizeof(SequenceNumber)); + // TODO: pack in the lost sequence numbers // have our SendQueue send off this control packet _sendQueue->sendPacket(*lossListPacket); + // record this as the last NAK time _lastNAKTime = high_resolution_clock::now(); + + ++_totalSentTimeoutNAKs; } } @@ -122,9 +125,11 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { // write this ACK to the map of sent ACKs _sentACKs[_currentACKSubSequenceNumber] = { nextACKNumber, high_resolution_clock::now() }; + + ++_totalSentACKs; } -void Connection::sendLightACK() const { +void Connection::sendLightACK() { // create the light ACK packet, make it static so we can re-use it static const int LIGHT_ACK_PACKET_PAYLOAD_BYTES = sizeof(SequenceNumber); static auto lightACKPacket = ControlPacket::create(ControlPacket::ACK, LIGHT_ACK_PACKET_PAYLOAD_BYTES); @@ -144,6 +149,8 @@ void Connection::sendLightACK() const { // have the send queue send off our packet immediately _sendQueue->sendPacket(*lightACKPacket); + + ++_totalSentLightACKs; } SequenceNumber Connection::nextACK() const { @@ -190,6 +197,8 @@ void Connection::processReceivedSequenceNumber(SequenceNumber seq) { // record our last NAK time _lastNAKTime = high_resolution_clock::now(); + ++_totalSentNAKs; + // figure out when we should send the next loss report, if we haven't heard anything back _nakInterval = (_rtt + 4 * _rttVariance); @@ -212,6 +221,8 @@ void Connection::processReceivedSequenceNumber(SequenceNumber seq) { // Otherwise, it's a resend, remove it from the loss list _lossList.remove(seq); } + + ++_totalReceivedDataPackets; } void Connection::processControl(unique_ptr controlPacket) { @@ -229,6 +240,9 @@ void Connection::processControl(unique_ptr controlPacket) { case ControlPacket::NAK: processNAK(move(controlPacket)); break; + case ControlPacket::TimeoutNAK: + processTimeoutNAK(move(controlPacket)); + break; } } @@ -259,6 +273,8 @@ void Connection::processACK(std::unique_ptr controlPacket) { // update the last sent ACK2 and the last ACK2 send time _lastSentACK2 = currentACKSubSequenceNumber; lastACK2SendTime = high_resolution_clock::now(); + + ++_totalSentACK2s; } // read the ACKed sequence number @@ -330,6 +346,8 @@ void Connection::processLightACK(std::unique_ptr controlPacket) { // update the last received ACK to the this one _lastReceivedACK = ack; } + + ++_totalReceivedLightACKs; } void Connection::processACK2(std::unique_ptr controlPacket) { @@ -356,6 +374,8 @@ void Connection::processACK2(std::unique_ptr controlPacket) { _lastReceivedAcknowledgedACK = pair.first; } } + + ++_totalReceivedACK2s; } void Connection::processNAK(std::unique_ptr controlPacket) { @@ -365,6 +385,14 @@ void Connection::processNAK(std::unique_ptr controlPacket) { if (controlPacket->bytesLeftToRead() >= (qint64)sizeof(SequenceNumber)) { controlPacket->readPrimitive(&end); } + + ++_totalReceivedNAKs; +} + +void Connection::processTimeoutNAK(std::unique_ptr controlPacket) { + // read the NAKed sequence numbers from the packet + + ++_totalReceivedTimeoutNAKs; } void Connection::updateRTT(int rtt) { diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 27057da3a9..76725cae42 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -47,12 +47,13 @@ public: private: void sendACK(bool wasCausedBySyncTimeout = true); - void sendLightACK() const; + void sendLightACK(); void processACK(std::unique_ptr controlPacket); void processLightACK(std::unique_ptr controlPacket); void processACK2(std::unique_ptr controlPacket); void processNAK(std::unique_ptr controlPacket); + void processTimeoutNAK(std::unique_ptr controlPacket); void updateRTT(int rtt); @@ -74,8 +75,6 @@ private: SequenceNumber _lastSentACK { SequenceNumber::MAX }; // The last sent ACK SequenceNumber _lastSentACK2; // The last sent ACK sub-sequence number in an ACK2 - int _totalReceivedACKs { 0 }; - int32_t _rtt; // RTT, in microseconds int32_t _rttVariance; // RTT variance int _flowWindowSize; // Flow control window size @@ -88,6 +87,23 @@ private: PacketTimeWindow _receiveWindow { 16, 64 }; // Window of interval between packets (16) and probes (64) for bandwidth and receive speed std::unique_ptr _sendQueue; + + // Control Packet stat collection + int _totalReceivedACKs { 0 }; + int _totalSentACKs { 0 }; + int _totalSentLightACKs { 0 }; + int _totalReceivedLightACKs { 0 }; + int _totalReceivedACK2s { 0 }; + int _totalSentACK2s { 0 }; + int _totalReceivedNAKs { 0 }; + int _totalSentNAKs { 0 }; + int _totalReceivedTimeoutNAKs { 0 }; + int _totalSentTimeoutNAKs { 0 }; + + // Data packet stat collection + int _totalReceivedDataPackets { 0 }; + + }; } diff --git a/libraries/networking/src/udt/ControlPacket.h b/libraries/networking/src/udt/ControlPacket.h index 4563b657a9..fdd0b65e36 100644 --- a/libraries/networking/src/udt/ControlPacket.h +++ b/libraries/networking/src/udt/ControlPacket.h @@ -29,7 +29,8 @@ public: enum Type : uint16_t { ACK, ACK2, - NAK + NAK, + TimeoutNAK }; static std::unique_ptr create(Type type, qint64 size = -1); From 988bd226ca82d705ef4b07ff9e359f586e5dd65a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 17:16:20 -0700 Subject: [PATCH 126/549] change SendQueue timing to use usleep and std::chrono --- libraries/networking/src/udt/Connection.cpp | 15 ++ libraries/networking/src/udt/Connection.h | 1 + libraries/networking/src/udt/SendQueue.cpp | 145 ++++++++++---------- libraries/networking/src/udt/SendQueue.h | 17 +-- 4 files changed, 95 insertions(+), 83 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 507e11f206..9b58dc41a5 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -11,6 +11,8 @@ #include "Connection.h" +#include + #include #include "../HifiSockAddr.h" @@ -28,6 +30,19 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination) : { } +Connection::~Connection() { + if (_sendQueue) { + // tell our send queue to stop and wait until its send thread is done + QThread* sendQueueThread = _sendQueue->thread(); + + _sendQueue->stop(); + _sendQueue->deleteLater(); + + sendQueueThread->quit(); + sendQueueThread->wait(); + } +} + void Connection::sendReliablePacket(unique_ptr packet) { Q_ASSERT_X(packet->isReliable(), "Connection::send", "Trying to send an unreliable packet reliably."); diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 76725cae42..200f8acda8 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -33,6 +33,7 @@ public: using SentACKMap = std::unordered_map; Connection(Socket* parentSocket, HifiSockAddr destination); + ~Connection(); void sendReliablePacket(std::unique_ptr packet); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 7824e01d17..c5542af978 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -13,6 +13,7 @@ #include +#include #include #include @@ -21,6 +22,7 @@ #include "Socket.h" using namespace udt; +using namespace std::chrono; std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr dest) { auto queue = std::unique_ptr(new SendQueue(socket, dest)); @@ -42,17 +44,7 @@ SendQueue::SendQueue(Socket* socket, HifiSockAddr dest) : _socket(socket), _destination(dest) { - _sendTimer.reset(new QTimer(this)); - _sendTimer->setSingleShot(true); - QObject::connect(_sendTimer.get(), &QTimer::timeout, this, &SendQueue::sendNextPacket); - _packetSendPeriod = DEFAULT_SEND_PERIOD; - _lastSendTimestamp = 0; -} - -SendQueue::~SendQueue() { - assert(thread() == QThread::currentThread()); - _sendTimer->stop(); } void SendQueue::queuePacket(std::unique_ptr packet) { @@ -60,24 +52,24 @@ void SendQueue::queuePacket(std::unique_ptr packet) { QWriteLocker locker(&_packetsLock); _packets.push_back(std::move(packet)); } - if (!_running) { - start(); + if (!_isRunning) { + run(); } } -void SendQueue::start() { +void SendQueue::run() { // We need to make sure this is called on the right thread if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection); + QMetaObject::invokeMethod(this, "run", Qt::QueuedConnection); } - _running = true; + _isRunning = true; - // This will send a packet and fire the send timer - sendNextPacket(); + // This will loop and sleep to send packets + loop(); } void SendQueue::stop() { - _running = false; + _isRunning = false; } void SendQueue::sendPacket(const BasePacket& packet) { @@ -128,62 +120,69 @@ SequenceNumber SendQueue::getNextSequenceNumber() { return _currentSequenceNumber; } -void SendQueue::sendNextPacket() { - if (!_running) { - return; - } - - // Record timing - auto sendTime = msecTimestampNow(); // msec - _lastSendTimestamp = sendTime; - - if (_nextPacket) { - // Write packet's sequence number and send it off - _nextPacket->setSequenceNumber(getNextSequenceNumber()); - sendPacket(*_nextPacket); +void SendQueue::loop() { + while (_isRunning) { + // Record timing + _lastSendTimestamp = high_resolution_clock::now(); - // Insert the packet we have just sent in the sent list - QWriteLocker locker(&_sentLock); - _sentPackets[_nextPacket->getSequenceNumber()].swap(_nextPacket); - Q_ASSERT_X(!_nextPacket, - "SendQueue::sendNextPacket()", "Overriden packet in sent list"); - } - - bool hasResend = false; - SequenceNumber seqNum; - { - // Check nak list for packet to resend - QWriteLocker locker(&_naksLock); - if (!_naks.empty()) { - hasResend = true; - seqNum = _naks.front(); - _naks.pop_front(); + if (_nextPacket) { + // Write packet's sequence number and send it off + _nextPacket->setSequenceNumber(getNextSequenceNumber()); + sendPacket(*_nextPacket); + + // Insert the packet we have just sent in the sent list + QWriteLocker locker(&_sentLock); + _sentPackets[_nextPacket->getSequenceNumber()].swap(_nextPacket); + Q_ASSERT_X(!_nextPacket, + "SendQueue::sendNextPacket()", "Overriden packet in sent list"); + } + + bool hasResend = false; + SequenceNumber seqNum; + { + // Check nak list for packet to resend + QWriteLocker locker(&_naksLock); + if (!_naks.empty()) { + hasResend = true; + seqNum = _naks.front(); + _naks.pop_front(); + } + } + + // Find packet in sent list using SequenceNumber + if (hasResend) { + QWriteLocker locker(&_sentLock); + auto it = _sentPackets.find(seqNum); + Q_ASSERT_X(it != _sentPackets.end(), + "SendQueue::sendNextPacket()", "Couldn't find NAKed packet to resend"); + + if (it != _sentPackets.end()) { + it->second.swap(_nextPacket); + _sentPackets.erase(it); + } + } + + // If there is no packet to resend, grab the next one in the list + if (!_nextPacket) { + QWriteLocker locker(&_packetsLock); + _nextPacket.swap(_packets.front()); + _packets.pop_front(); + } + + // since we're a while loop, give the thread a chance to process events + QCoreApplication::processEvents(); + + // we just processed events so check now if we were just told to stop + if (!_isRunning) { + break; + } + + // sleep as long as we need until next packet send, if we can + auto now = high_resolution_clock::now(); + auto microsecondDuration = (_lastSendTimestamp + microseconds(_packetSendPeriod)) - now; + + if (microsecondDuration.count() > 0) { + usleep(microsecondDuration.count()); } } - - // Find packet in sent list using SequenceNumber - if (hasResend) { - QWriteLocker locker(&_sentLock); - auto it = _sentPackets.find(seqNum); - Q_ASSERT_X(it != _sentPackets.end(), - "SendQueue::sendNextPacket()", "Couldn't find NAKed packet to resend"); - - if (it != _sentPackets.end()) { - it->second.swap(_nextPacket); - _sentPackets.erase(it); - } - } - - // If there is no packet to resend, grab the next one in the list - if (!_nextPacket) { - QWriteLocker locker(&_packetsLock); - _nextPacket.swap(_packets.front()); - _packets.pop_front(); - } - - // check if we need to fire off a packet pair - we do this - - // How long before next packet send - auto timeToSleep = (sendTime + _packetSendPeriod) - msecTimestampNow(); // msec - _sendTimer->start(std::max((quint64)0, timeToSleep)); } diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 1c30d1580a..f532bf7fe2 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -12,6 +12,7 @@ #ifndef hifi_SendQueue_h #define hifi_SendQueue_h +#include #include #include @@ -33,15 +34,13 @@ class SendQueue : public QObject { Q_OBJECT public: - static const int DEFAULT_SEND_PERIOD = 16; // msec + static const int DEFAULT_SEND_PERIOD = 16 * 1000; // 16ms, in microseconds static std::unique_ptr create(Socket* socket, HifiSockAddr dest); void queuePacket(std::unique_ptr packet); int getQueueSize() const { QReadLocker locker(&_packetsLock); return _packets.size(); } - quint64 getLastSendTimestamp() const { return _lastSendTimestamp; } - SequenceNumber getCurrentSequenceNumber() const { return SequenceNumber(_atomicCurrentSequenceNumber); } int getPacketSendPeriod() const { return _packetSendPeriod; } @@ -51,14 +50,14 @@ public: void sendPacket(const BasePacket& packet); public slots: - void start(); + void run(); void stop(); void ack(SequenceNumber ack); void nak(std::list naks); private slots: - void sendNextPacket(); + void loop(); private: friend struct std::default_delete; @@ -66,7 +65,6 @@ private: SendQueue(Socket* socket, HifiSockAddr dest); SendQueue(SendQueue& other) = delete; SendQueue(SendQueue&& other) = delete; - ~SendQueue(); // Increments current sequence number and return it SequenceNumber getNextSequenceNumber(); @@ -82,10 +80,9 @@ private: SequenceNumber _currentSequenceNumber; // Last sequence number sent out std::atomic _atomicCurrentSequenceNumber; // Atomic for last sequence number sent out - std::unique_ptr _sendTimer; // Send timer - std::atomic _packetSendPeriod { 0 }; // Interval between two packet send envent in msec - std::atomic _lastSendTimestamp { 0 }; // Record last time of packet departure - std::atomic _running { false }; + std::atomic _packetSendPeriod { 0 }; // Interval between two packet send event in microseconds + std::chrono::high_resolution_clock::time_point _lastSendTimestamp; // Record last time of packet departure + std::atomic _isRunning { false }; mutable QReadWriteLock _naksLock; // Protects the naks list. std::list _naks; // Sequence numbers of packets to resend From 1df657c3594633a2d3a22fe5df2ed983f060e9c8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Jul 2015 17:39:05 -0700 Subject: [PATCH 127/549] Added insert function to LossList --- libraries/networking/src/udt/LossList.cpp | 47 ++++++++++++++++++++++- libraries/networking/src/udt/LossList.h | 3 ++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp index db312935b8..86b80fd3f2 100644 --- a/libraries/networking/src/udt/LossList.cpp +++ b/libraries/networking/src/udt/LossList.cpp @@ -34,6 +34,50 @@ void LossList::append(SequenceNumber start, SequenceNumber end) { _length += seqlen(start, end); } +void LossList::insert(SequenceNumber start, SequenceNumber end) { + auto it = find_if_not(_lossList.begin(), _lossList.end(), [&start](pair pair){ + return pair.second < start; + }); + + if (it == _lossList.end()) { + // No overlap, simply insert + _lossList.insert(it, make_pair(start, end)); + _length += seqlen(start, end); + } else { + // If it starts before segment, extend segment + if (start < it->first) { + _length += seqlen(start, it->first - 1); + it->first = start; + } + + if (end > it->second) { + // If it goes further, find the actual end + auto it2 = find_if(it, _lossList.end(), [&end](pair pair){ + return end <= pair.second; + }); + + // If it ends inside a segment, change end (segment will be deleted) + // Or backup iterator so segment doesn't get deleted + if (it2->first <= end) { + end = it2->second; + } else { + --it2; + } + + // Change the end of the original segment + _length += seqlen(it->second + 1, end); + it->second = end; + + // remove all underlapping segments + ++it; ++it2; + while (it != it2) { + _length -= seqlen(it->first, it->second); + it = _lossList.erase(it); + } + } + } +} + void LossList::remove(SequenceNumber seq) { auto it = find_if(_lossList.begin(), _lossList.end(), [&seq](pair pair) { return pair.first <= seq && seq <= pair.second; @@ -58,8 +102,7 @@ void LossList::remove(SequenceNumber seq) { void LossList::remove(SequenceNumber start, SequenceNumber end) { // Find the first segment sharing sequence numbers auto it = find_if(_lossList.begin(), _lossList.end(), [&start, &end](pair pair) { - return (pair.first <= start && start <= pair.second) || - (start <= pair.first && pair.first <= end); + return (pair.first <= start && start <= pair.second) || (start <= pair.first && pair.first <= end); }); // If we found one diff --git a/libraries/networking/src/udt/LossList.h b/libraries/networking/src/udt/LossList.h index 387c69b70f..53ccf3ba50 100644 --- a/libraries/networking/src/udt/LossList.h +++ b/libraries/networking/src/udt/LossList.h @@ -26,6 +26,9 @@ public: void append(SequenceNumber seq); void append(SequenceNumber start, SequenceNumber end); + // Inserts anywhere - MUCH slower + void insert(SequenceNumber start, SequenceNumber end); + void remove(SequenceNumber seq); void remove(SequenceNumber start, SequenceNumber end); From 5d1c0f69355822534ba0c410e4032b4154da9803 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Jul 2015 17:56:11 -0700 Subject: [PATCH 128/549] Added pop to loss list --- libraries/networking/src/udt/LossList.cpp | 6 ++++++ libraries/networking/src/udt/LossList.h | 1 + 2 files changed, 7 insertions(+) diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp index 86b80fd3f2..ab66634b3e 100644 --- a/libraries/networking/src/udt/LossList.cpp +++ b/libraries/networking/src/udt/LossList.cpp @@ -145,3 +145,9 @@ SequenceNumber LossList::getFirstSequenceNumber() const { assert(getLength() > 0); return _lossList.front().first; } + +SequenceNumber LossList::popFirstSequenceNumber() { + auto front = getFirstSequenceNumber(); + remove(front); + return front; +} diff --git a/libraries/networking/src/udt/LossList.h b/libraries/networking/src/udt/LossList.h index 53ccf3ba50..a669317e9d 100644 --- a/libraries/networking/src/udt/LossList.h +++ b/libraries/networking/src/udt/LossList.h @@ -34,6 +34,7 @@ public: int getLength() const { return _length; } SequenceNumber getFirstSequenceNumber() const; + SequenceNumber popFirstSequenceNumber(); private: std::list> _lossList; From 0e0968f7483c8bce5fd12b67704785fa09774877 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 17:58:49 -0700 Subject: [PATCH 129/549] initial support to get CongestionControl down to Connection --- .../networking/src/udt/CongestionControl.cpp | 23 ++++++++-------- .../networking/src/udt/CongestionControl.h | 26 +++++++++++-------- libraries/networking/src/udt/Connection.cpp | 8 ++++-- libraries/networking/src/udt/Connection.h | 5 +++- libraries/networking/src/udt/Socket.cpp | 10 ++++++- libraries/networking/src/udt/Socket.h | 5 ++++ 6 files changed, 50 insertions(+), 27 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 47a45485fa..5acba518e4 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -15,10 +15,9 @@ using namespace udt; -void UdtCC::init() { - _rcInterval = _synInterval; +void DefaultCC::init() { _lastRCTime = usecTimestampNow(); - setAckTimer(_rcInterval); + setAckTimer(synInterval()); _lastAck = _sendCurrSeqNum; _lastDecSeq = SequenceNumber{ SequenceNumber::MAX }; @@ -27,7 +26,7 @@ void UdtCC::init() { _packetSendPeriod = 1.0; } -void UdtCC::onACK(SequenceNumber ackNum) { +void DefaultCC::onACK(SequenceNumber ackNum) { int64_t B = 0; double inc = 0; // Note: 1/24/2012 @@ -37,7 +36,7 @@ void UdtCC::onACK(SequenceNumber ackNum) { const double min_inc = 0.01; uint64_t currtime = usecTimestampNow(); - if (currtime - _lastRCTime < (uint64_t)_rcInterval) { + if (currtime - _lastRCTime < (uint64_t)synInterval()) { return; } @@ -52,11 +51,11 @@ void UdtCC::onACK(SequenceNumber ackNum) { if (_recvieveRate > 0) { _packetSendPeriod = 1000000.0 / _recvieveRate; } else { - _packetSendPeriod = (_rtt + _rcInterval) / _congestionWindowSize; + _packetSendPeriod = (_rtt + synInterval()) / _congestionWindowSize; } } } else { - _congestionWindowSize = _recvieveRate / 1000000.0 * (_rtt + _rcInterval) + 16; + _congestionWindowSize = _recvieveRate / 1000000.0 * (_rtt + synInterval()) + 16; } // During Slow Start, no rate increase @@ -86,10 +85,10 @@ void UdtCC::onACK(SequenceNumber ackNum) { } } - _packetSendPeriod = (_packetSendPeriod * _rcInterval) / (_packetSendPeriod * inc + _rcInterval); + _packetSendPeriod = (_packetSendPeriod * synInterval()) / (_packetSendPeriod * inc + synInterval()); } -void UdtCC::onLoss(const std::vector& losslist) { +void DefaultCC::onLoss(const std::vector& losslist) { //Slow Start stopped, if it hasn't yet if (_slowStart) { _slowStart = false; @@ -101,7 +100,7 @@ void UdtCC::onLoss(const std::vector& losslist) { // If no receiving rate is observed, we have to compute the sending // rate according to the current window size, and decrease it // using the method below. - _packetSendPeriod = _congestionWindowSize / (_rtt + _rcInterval); + _packetSendPeriod = _congestionWindowSize / (_rtt + synInterval()); } _loss = true; @@ -128,13 +127,13 @@ void UdtCC::onLoss(const std::vector& losslist) { } } -void UdtCC::onTimeout() { +void DefaultCC::onTimeout() { if (_slowStart) { _slowStart = false; if (_recvieveRate > 0) { _packetSendPeriod = 1000000.0 / _recvieveRate; } else { - _packetSendPeriod = _congestionWindowSize / (_rtt + _rcInterval); + _packetSendPeriod = _congestionWindowSize / (_rtt + synInterval()); } } else { /* diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index 9f61c7944f..c54405e73d 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -17,15 +17,19 @@ #include "SequenceNumber.h" namespace udt { + +static const int32_t DEFAULT_SYN_INTERVAL = 10000; // 10 ms class Packet; class CongestionControl { public: - static const int32_t DEFAULT_SYN_INTERVAL = 10000; // 10 ms - CongestionControl() {} + CongestionControl() {}; + CongestionControl(int synInterval) : _synInterval(synInterval) {} virtual ~CongestionControl() {} + + int synInterval() const { return _synInterval; } virtual void init() {} virtual void close() {} @@ -35,12 +39,10 @@ public: virtual void onPacketReceived(const Packet& packet) {} protected: - void setAckTimer(int syn) { _ackPeriod = (syn > _synInterval) ? _synInterval : syn; } - void setAckInterval(int interval) { _ackInterval = interval; } + void setAckTimer(int period) { _ackPeriod = (period > _synInterval) ? _synInterval : period; } + void setAckInterval(int ackInterval) { _ackInterval = ackInterval; } void setRto(int rto) { _userDefinedRto = true; _rto = rto; } - int32_t _synInterval = DEFAULT_SYN_INTERVAL; // UDT constant parameter, SYN - double _packetSendPeriod = 1.0; // Packet sending period, in microseconds double _congestionWindowSize = 16.0; // Congestion window size, in packets @@ -66,6 +68,8 @@ private: int _ackPeriod = 0; // Periodical timer to send an ACK, in milliseconds int _ackInterval = 0; // How many packets to send one ACK, in packets + int _synInterval { DEFAULT_SYN_INTERVAL }; + bool _userDefinedRto = false; // if the RTO value is defined by users int _rto = -1; // RTO value, microseconds }; @@ -75,6 +79,8 @@ class CongestionControlVirtualFactory { public: virtual ~CongestionControlVirtualFactory() {} + static int synInterval() { return DEFAULT_SYN_INTERVAL; } + virtual std::unique_ptr create() = 0; }; @@ -82,13 +88,12 @@ template class CongestionControlFactory: public CongestionControlVirtu { public: virtual ~CongestionControlFactory() {} - virtual std::unique_ptr create() { return std::unique_ptr(new T()); } }; -class UdtCC: public CongestionControl { +class DefaultCC: public CongestionControl { public: - UdtCC() {} + DefaultCC() {} public: virtual void init(); @@ -97,7 +102,6 @@ public: virtual void onTimeout(); private: - int _rcInterval = 0; // UDT Rate control interval uint64_t _lastRCTime = 0; // last rate increase time bool _slowStart = true; // if in slow start phase SequenceNumber _lastAck; // last ACKed seq num @@ -112,4 +116,4 @@ private: } -#endif // hifi_CongestionControl_h \ No newline at end of file +#endif // hifi_CongestionControl_h diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 9b58dc41a5..0f09e67a72 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -16,6 +16,7 @@ #include #include "../HifiSockAddr.h" +#include "CongestionControl.h" #include "ControlPacket.h" #include "Packet.h" #include "Socket.h" @@ -24,10 +25,12 @@ using namespace udt; using namespace std; using namespace std::chrono; -Connection::Connection(Socket* parentSocket, HifiSockAddr destination) : +Connection::Connection(Socket* parentSocket, HifiSockAddr destination, unique_ptr congestionControl) : _parentSocket(parentSocket), - _destination(destination) + _destination(destination), + _congestionControl(move(congestionControl)) { + } Connection::~Connection() { @@ -343,6 +346,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { } // fire the onACK callback for congestion control + _congestionControl->onAck(ack); // update the total count of received ACKs ++_totalReceivedACKs; diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 200f8acda8..7cc2563fc5 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -22,6 +22,7 @@ namespace udt { +class CongestionControl; class ControlPacket; class Packet; class Socket; @@ -32,7 +33,7 @@ public: using SequenceNumberTimePair = std::pair; using SentACKMap = std::unordered_map; - Connection(Socket* parentSocket, HifiSockAddr destination); + Connection(Socket* parentSocket, HifiSockAddr destination, std::unique_ptr congestionControl); ~Connection(); void sendReliablePacket(std::unique_ptr packet); @@ -89,6 +90,8 @@ private: std::unique_ptr _sendQueue; + std::unique_ptr _congestionControl; + // Control Packet stat collection int _totalReceivedACKs { 0 }; int _totalSentACKs { 0 }; diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 15f0febc9b..c2ad40b9f5 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -79,7 +79,7 @@ qint64 Socket::writePacket(std::unique_ptr packet, const HifiSockAddr& s if (packet->isReliable()) { auto it = _connectionsHash.find(sockAddr); if (it == _connectionsHash.end()) { - it = _connectionsHash.insert(it, std::make_pair(sockAddr, new Connection(this, sockAddr))); + it = _connectionsHash.insert(it, std::make_pair(sockAddr, new Connection(this, sockAddr, _ccFactory->create()))); } it->second->sendReliablePacket(std::move(packet)); return 0; @@ -154,3 +154,11 @@ void Socket::rateControlSync() { _synTimer.start(_synInterval); } } + +void Socket::setCongestionControlFactory(std::unique_ptr ccFactory) { + // swap the current unique_ptr for the new factory + _ccFactory.swap(ccFactory); + + // update the _synInterval to the value from the factory + _synInterval = _ccFactory->synInterval(); +} diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 9ca4adcc74..497c98b296 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -22,6 +22,7 @@ #include #include "../HifiSockAddr.h" +#include "CongestionControl.h" #include "Connection.h" namespace udt { @@ -59,6 +60,8 @@ public: void addUnfilteredHandler(const HifiSockAddr& senderSockAddr, BasePacketHandler handler) { _unfilteredHandlers[senderSockAddr] = handler; } + + void setCongestionControlFactory(std::unique_ptr ccFactory); private slots: void readPendingDatagrams(); @@ -78,6 +81,8 @@ private: int32_t _synInterval = 10; // 10ms QTimer _synTimer; + + std::unique_ptr _ccFactory { new CongestionControlFactory() }; }; } // namespace udt From cb134f4685dc04721510f3446865d08707a4a33a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 18:04:18 -0700 Subject: [PATCH 130/549] remove onPacketSent and onPacketReceived from CC, use setRTT --- libraries/networking/src/udt/CongestionControl.h | 4 ++-- libraries/networking/src/udt/Connection.cpp | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index c54405e73d..27c1c8e8fd 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -20,9 +20,11 @@ namespace udt { static const int32_t DEFAULT_SYN_INTERVAL = 10000; // 10 ms +class Connection; class Packet; class CongestionControl { + friend class Connection; public: CongestionControl() {}; @@ -35,8 +37,6 @@ public: virtual void close() {} virtual void onAck(SequenceNumber ackNum) {} virtual void onLoss(const std::vector& lossList) {} - virtual void onPacketSent(const Packet& packet) {} - virtual void onPacketReceived(const Packet& packet) {} protected: void setAckTimer(int period) { _ackPeriod = (period > _synInterval) ? _synInterval : period; } diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 0f09e67a72..d4dd0be7bf 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -336,6 +336,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { updateRTT(rtt); // set the RTT for congestion control + _congestionControl->setRtt(_rtt); if (controlPacket->getPayloadSize() > (qint64) (sizeof(SequenceNumber) + sizeof(SequenceNumber) + sizeof(rtt))) { int32_t deliveryRate, bandwidth; @@ -343,6 +344,8 @@ void Connection::processACK(std::unique_ptr controlPacket) { controlPacket->readPrimitive(&bandwidth); // set the delivery rate and bandwidth for congestion control + _congestionControl->setRcvRate(deliveryRate); + _congestionControl->setBandwidth(bandwidth); } // fire the onACK callback for congestion control @@ -387,6 +390,7 @@ void Connection::processACK2(std::unique_ptr controlPacket) { updateRTT(rtt); // set the RTT for congestion control + _congestionControl->setRtt(_rtt); // update the last ACKed ACK if (pair.first > _lastReceivedAcknowledgedACK) { @@ -401,10 +405,13 @@ void Connection::processNAK(std::unique_ptr controlPacket) { // read the loss report SequenceNumber start, end; controlPacket->readPrimitive(&start); + if (controlPacket->bytesLeftToRead() >= (qint64)sizeof(SequenceNumber)) { controlPacket->readPrimitive(&end); } + + ++_totalReceivedNAKs; } From b9b4245dfee687927600dd8641ce13e5068c54fc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 18:05:42 -0700 Subject: [PATCH 131/549] NAK interval is in microseconds --- libraries/networking/src/udt/Connection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index d4dd0be7bf..d43901f705 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -65,7 +65,7 @@ void Connection::sync() { // we do this if it has been longer than the current nakInterval since we last sent auto now = high_resolution_clock::now(); - if (duration_cast(now - _lastNAKTime).count() >= _nakInterval) { + if (duration_cast(now - _lastNAKTime).count() >= _nakInterval) { // construct a NAK packet that will hold all of the lost sequence numbers auto lossListPacket = ControlPacket::create(ControlPacket::TimeoutNAK, _lossList.getLength() * sizeof(SequenceNumber)); From b5b7fa850489a063e9bfb7ebcfdc5ad5af3caf18 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Jul 2015 18:08:02 -0700 Subject: [PATCH 132/549] SendQueue uses LossList --- libraries/networking/src/udt/SendQueue.cpp | 27 ++++++---------------- libraries/networking/src/udt/SendQueue.h | 5 ++-- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 787bf60ca7..bc619d95bc 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -91,36 +91,24 @@ void SendQueue::ack(SequenceNumber ack) { return; } - { - // remove any ACKed packets from the map of sent packets + { // remove any ACKed packets from the map of sent packets QWriteLocker locker(&_sentLock); for (auto seq = _lastAck; seq <= ack; ++seq) { _sentPackets.erase(seq); } } - { - // remove any sequence numbers equal to or lower than this ACK in the loss list + { // remove any sequence numbers equal to or lower than this ACK in the loss list QWriteLocker nakLocker(&_naksLock); - - auto it = _naks.begin(); - - while (it != _naks.end()) { - if (*it <= ack) { - it = _naks.erase(it); - } else { - // the NAKs in the NAK list must be in order, so we can break if we hit one > ack - break; - } - } + _naks.remove(_naks.getFirstSequenceNumber(), ack); } _lastAck = ack; } -void SendQueue::nak(std::list naks) { +void SendQueue::nak(SequenceNumber start, SequenceNumber end) { QWriteLocker locker(&_naksLock); - _naks.splice(_naks.end(), naks); // Add naks at the end + _naks.insert(start, end); } SequenceNumber SendQueue::getNextSequenceNumber() { @@ -154,10 +142,9 @@ void SendQueue::sendNextPacket() { { // Check nak list for packet to resend QWriteLocker locker(&_naksLock); - if (!_naks.empty()) { + if (_naks.getLength() > 0) { hasResend = true; - seqNum = _naks.front(); - _naks.pop_front(); + seqNum = _naks.popFirstSequenceNumber(); } } diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 1c30d1580a..82c569f6c5 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -22,6 +22,7 @@ #include "../HifiSockAddr.h" #include "SequenceNumber.h" +#include "LossList.h" namespace udt { @@ -55,7 +56,7 @@ public slots: void stop(); void ack(SequenceNumber ack); - void nak(std::list naks); + void nak(SequenceNumber start, SequenceNumber end); private slots: void sendNextPacket(); @@ -88,7 +89,7 @@ private: std::atomic _running { false }; mutable QReadWriteLock _naksLock; // Protects the naks list. - std::list _naks; // Sequence numbers of packets to resend + LossList _naks; // Sequence numbers of packets to resend mutable QReadWriteLock _sentLock; // Protects the sent packet list std::unordered_map> _sentPackets; // Packets waiting for ACK. From dc65a2fe1ac7b7360978b15f97a0d27fd542c448 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 18:11:21 -0700 Subject: [PATCH 133/549] use user defined RTO for timeout (if defined) --- libraries/networking/src/udt/Connection.cpp | 4 ++++ libraries/networking/src/udt/Connection.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index d43901f705..5ba749ad30 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -440,3 +440,7 @@ void Connection::updateRTT(int rtt) { _rttVariance = (_rttVariance * (1 - RTT_ESTIMATION_VARIANCE_ALPHA_NUMERATOR) + abs(rtt - _rtt)) / RTT_ESTIMATION_VARIANCE_ALPHA_NUMERATOR; } + +int Connection::estimatedTimeout() const { + return _congestionControl->_userDefinedRto ? _rtt + _rttVariance * 4 : _congestionControl->_rto; +} diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 7cc2563fc5..c0a8cf1aa1 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -59,7 +59,7 @@ private: void updateRTT(int rtt); - int estimatedTimeout() const { return _rtt + _rttVariance * 4; } + int estimatedTimeout() const; int _synInterval; // Periodical Rate Control Interval, in microseconds, defaults to 10ms From e69cc2aae8b69d97ee760e51be6c1967730ae4be Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 18:20:37 -0700 Subject: [PATCH 134/549] pass const ref LossList to CongestionControl --- libraries/networking/src/udt/CongestionControl.cpp | 4 ++-- libraries/networking/src/udt/CongestionControl.h | 5 +++-- libraries/networking/src/udt/Connection.cpp | 10 ++++++++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 5acba518e4..1f241a1e09 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -88,7 +88,7 @@ void DefaultCC::onACK(SequenceNumber ackNum) { _packetSendPeriod = (_packetSendPeriod * synInterval()) / (_packetSendPeriod * inc + synInterval()); } -void DefaultCC::onLoss(const std::vector& losslist) { +void DefaultCC::onLoss(const LossList& losslist) { //Slow Start stopped, if it hasn't yet if (_slowStart) { _slowStart = false; @@ -105,7 +105,7 @@ void DefaultCC::onLoss(const std::vector& losslist) { _loss = true; - if (losslist[0] > _lastDecSeq) { + if (losslist.getFirstSequenceNumber() > _lastDecSeq) { _lastDecPeriod = _packetSendPeriod; _packetSendPeriod = ceil(_packetSendPeriod * 1.125); diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index 27c1c8e8fd..c328afb9dd 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -14,6 +14,7 @@ #include +#include "LossList.h" #include "SequenceNumber.h" namespace udt { @@ -36,7 +37,7 @@ public: virtual void init() {} virtual void close() {} virtual void onAck(SequenceNumber ackNum) {} - virtual void onLoss(const std::vector& lossList) {} + virtual void onLoss(const LossList& lossList) {} protected: void setAckTimer(int period) { _ackPeriod = (period > _synInterval) ? _synInterval : period; } @@ -98,7 +99,7 @@ public: public: virtual void init(); virtual void onACK(SequenceNumber ackNum); - virtual void onLoss(const std::vector& lossList); + virtual void onLoss(const LossList& lossList); virtual void onTimeout(); private: diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 5ba749ad30..b5ca118730 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -217,6 +217,9 @@ void Connection::processReceivedSequenceNumber(SequenceNumber seq) { ++_totalSentNAKs; + // tell the CC that there was loss + _congestionControl->onLoss(_lossList); + // figure out when we should send the next loss report, if we haven't heard anything back _nakInterval = (_rtt + 4 * _rttVariance); @@ -406,12 +409,15 @@ void Connection::processNAK(std::unique_ptr controlPacket) { SequenceNumber start, end; controlPacket->readPrimitive(&start); + end = start; + if (controlPacket->bytesLeftToRead() >= (qint64)sizeof(SequenceNumber)) { controlPacket->readPrimitive(&end); } - - + // send that off to the send queue so it knows there was loss + _sendQueue->nak(start, end); + ++_totalReceivedNAKs; } From 3b7d0ab62aecadf1a6371bb86900daa29cb1f04d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 18:21:00 -0700 Subject: [PATCH 135/549] make TODO a TODO --- libraries/networking/src/udt/Connection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index b5ca118730..0418298d9d 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -333,7 +333,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { // update the atomic for last received ACK, the send queue uses this to re-transmit _atomicLastReceivedACK.store((uint32_t) _lastReceivedACK); - // remove everything up to this ACK from the sender loss list + // TODO: remove everything up to this ACK from the sender loss list // update the RTT updateRTT(rtt); From 43e81420bdda60c0dfc7c22c6b4b652b7b47831a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 18:21:32 -0700 Subject: [PATCH 136/549] add a TODO for processTimeoutNAK --- libraries/networking/src/udt/Connection.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 0418298d9d..e237535f2f 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -424,6 +424,8 @@ void Connection::processNAK(std::unique_ptr controlPacket) { void Connection::processTimeoutNAK(std::unique_ptr controlPacket) { // read the NAKed sequence numbers from the packet + // TODO: enumerate the received NAKs and create ranges if possible, then call _sendQueue->nak + ++_totalReceivedTimeoutNAKs; } From b7d80ca435a70bb56dfe9a7e6d2e4aa01760f9fd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 18:22:33 -0700 Subject: [PATCH 137/549] remove a TODO that is actually done --- libraries/networking/src/udt/Connection.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index e237535f2f..0e3724b030 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -333,8 +333,6 @@ void Connection::processACK(std::unique_ptr controlPacket) { // update the atomic for last received ACK, the send queue uses this to re-transmit _atomicLastReceivedACK.store((uint32_t) _lastReceivedACK); - // TODO: remove everything up to this ACK from the sender loss list - // update the RTT updateRTT(rtt); From 065353eb6bcc89d04a958438d3f36d90dbe66df8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Jul 2015 18:27:02 -0700 Subject: [PATCH 138/549] Fix LossList::insert --- libraries/networking/src/udt/LossList.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp index ab66634b3e..5dbdac6de0 100644 --- a/libraries/networking/src/udt/LossList.cpp +++ b/libraries/networking/src/udt/LossList.cpp @@ -52,9 +52,10 @@ void LossList::insert(SequenceNumber start, SequenceNumber end) { if (end > it->second) { // If it goes further, find the actual end - auto it2 = find_if(it, _lossList.end(), [&end](pair pair){ + auto it2 = find_if_not(it, _lossList.end(), [&end](pair pair){ return end <= pair.second; }); + --it2; // If it ends inside a segment, change end (segment will be deleted) // Or backup iterator so segment doesn't get deleted From 99f9a4a712d434b241126bd252c50cbfeecabc66 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Jul 2015 19:23:38 -0700 Subject: [PATCH 139/549] add TODOs for onLoss, handle ACK from packet count --- libraries/networking/src/udt/Connection.cpp | 22 ++++++++++++++++----- libraries/networking/src/udt/Connection.h | 1 + 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 0e3724b030..29706148f0 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -79,7 +79,6 @@ void Connection::sync() { ++_totalSentTimeoutNAKs; } - } void Connection::sendACK(bool wasCausedBySyncTimeout) { @@ -144,6 +143,9 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { // write this ACK to the map of sent ACKs _sentACKs[_currentACKSubSequenceNumber] = { nextACKNumber, high_resolution_clock::now() }; + // reset the number of data packets received since last ACK + _packetsSinceACK = 0; + ++_totalSentACKs; } @@ -217,9 +219,6 @@ void Connection::processReceivedSequenceNumber(SequenceNumber seq) { ++_totalSentNAKs; - // tell the CC that there was loss - _congestionControl->onLoss(_lossList); - // figure out when we should send the next loss report, if we haven't heard anything back _nakInterval = (_rtt + 4 * _rttVariance); @@ -243,7 +242,14 @@ void Connection::processReceivedSequenceNumber(SequenceNumber seq) { _lossList.remove(seq); } + // increment the counters for data packets received + ++_packetsSinceACK; ++_totalReceivedDataPackets; + + // check if we need to send an ACK, according to CC params + if (_congestionControl->_ackInterval > 0 && _packetsSinceACK >= _congestionControl->_ackInterval) { + sendACK(false); + } } void Connection::processControl(unique_ptr controlPacket) { @@ -413,9 +419,12 @@ void Connection::processNAK(std::unique_ptr controlPacket) { controlPacket->readPrimitive(&end); } + // TODO: tell the congestion control object that there was loss + // _congestionControl->onLoss(); + // send that off to the send queue so it knows there was loss _sendQueue->nak(start, end); - + ++_totalReceivedNAKs; } @@ -424,6 +433,9 @@ void Connection::processTimeoutNAK(std::unique_ptr controlPacket) // TODO: enumerate the received NAKs and create ranges if possible, then call _sendQueue->nak + // TODO: tell the congestion control object that there was loss + // _congestionControl->onLoss(); + ++_totalReceivedTimeoutNAKs; } diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index c0a8cf1aa1..a98f4c394c 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -106,6 +106,7 @@ private: // Data packet stat collection int _totalReceivedDataPackets { 0 }; + int _packetsSinceACK { 0 }; // The number of packets that have been received during the current ACK interval }; From 7b3761f07a8805e236d3eb93429936ad971e2457 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 28 Jul 2015 19:27:29 -0700 Subject: [PATCH 140/549] Implement NAK timeout packets read/write --- libraries/networking/src/udt/Connection.cpp | 12 ++++------ libraries/networking/src/udt/LossList.cpp | 26 +++++++++++++++++++++ libraries/networking/src/udt/LossList.h | 5 ++++ libraries/networking/src/udt/SendQueue.cpp | 5 ++++ libraries/networking/src/udt/SendQueue.h | 1 + 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 0e3724b030..8fdcbd14f7 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -30,7 +30,6 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination, unique_pt _destination(destination), _congestionControl(move(congestionControl)) { - } Connection::~Connection() { @@ -69,7 +68,8 @@ void Connection::sync() { // construct a NAK packet that will hold all of the lost sequence numbers auto lossListPacket = ControlPacket::create(ControlPacket::TimeoutNAK, _lossList.getLength() * sizeof(SequenceNumber)); - // TODO: pack in the lost sequence numbers + // Pack in the lost sequence numbers + _lossList.write(*lossListPacket); // have our SendQueue send off this control packet _sendQueue->sendPacket(*lossListPacket); @@ -79,7 +79,6 @@ void Connection::sync() { ++_totalSentTimeoutNAKs; } - } void Connection::sendACK(bool wasCausedBySyncTimeout) { @@ -331,7 +330,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { _sendQueue->ack(ack); // update the atomic for last received ACK, the send queue uses this to re-transmit - _atomicLastReceivedACK.store((uint32_t) _lastReceivedACK); + _atomicLastReceivedACK = (SequenceNumber::Type)_lastReceivedACK; // update the RTT updateRTT(rtt); @@ -420,9 +419,8 @@ void Connection::processNAK(std::unique_ptr controlPacket) { } void Connection::processTimeoutNAK(std::unique_ptr controlPacket) { - // read the NAKed sequence numbers from the packet - - // TODO: enumerate the received NAKs and create ranges if possible, then call _sendQueue->nak + // Override SendQueue's LossList with the timeout NAK list + _sendQueue->overrideNAKListFromPacket(*controlPacket); ++_totalReceivedTimeoutNAKs; } diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp index 5dbdac6de0..2e1346daae 100644 --- a/libraries/networking/src/udt/LossList.cpp +++ b/libraries/networking/src/udt/LossList.cpp @@ -11,6 +11,8 @@ #include "LossList.h" +#include "ControlPacket.h" + using namespace udt; using namespace std; @@ -152,3 +154,27 @@ SequenceNumber LossList::popFirstSequenceNumber() { remove(front); return front; } + +void LossList::write(ControlPacket& packet) { + for(const auto& pair : _lossList) { + packet.writePrimitive(pair.first); + packet.writePrimitive(pair.second); + } +} + +void LossList::read(ControlPacket& packet) { + _lossList.clear(); + + SequenceNumber first, second; + while (packet.bytesLeftToRead() > (qint64)(2 * sizeof(SequenceNumber))) { + packet.readPrimitive(&first); + packet.readPrimitive(&second); + + if (first == second) { + append(first); + } else { + append(first, second); + } + + } +} diff --git a/libraries/networking/src/udt/LossList.h b/libraries/networking/src/udt/LossList.h index a669317e9d..c88bef8baa 100644 --- a/libraries/networking/src/udt/LossList.h +++ b/libraries/networking/src/udt/LossList.h @@ -18,6 +18,8 @@ namespace udt { +class ControlPacket; + class LossList { public: LossList() {} @@ -36,6 +38,9 @@ public: SequenceNumber getFirstSequenceNumber() const; SequenceNumber popFirstSequenceNumber(); + void write(ControlPacket& packet); + void read(ControlPacket& packet); + private: std::list> _lossList; int _length { 0 }; diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 0931159483..e9f835b918 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -103,6 +103,11 @@ void SendQueue::nak(SequenceNumber start, SequenceNumber end) { _naks.insert(start, end); } +void SendQueue::overrideNAKListFromPacket(ControlPacket& packet) { + QWriteLocker locker(&_naksLock); + _naks.read(packet); +} + SequenceNumber SendQueue::getNextSequenceNumber() { _atomicCurrentSequenceNumber = (SequenceNumber::Type)++_currentSequenceNumber; return _currentSequenceNumber; diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 10b35079b0..2bb61a5002 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -56,6 +56,7 @@ public slots: void ack(SequenceNumber ack); void nak(SequenceNumber start, SequenceNumber end); + void overrideNAKListFromPacket(ControlPacket& packet); private slots: void loop(); From 7084c12434332e2977721a1597b7009bea8a38fb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 10:28:59 -0700 Subject: [PATCH 141/549] make the CongestionControl object take a range for loss --- libraries/networking/src/udt/CongestionControl.cpp | 4 ++-- libraries/networking/src/udt/CongestionControl.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 1f241a1e09..a7cd45cfe7 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -88,7 +88,7 @@ void DefaultCC::onACK(SequenceNumber ackNum) { _packetSendPeriod = (_packetSendPeriod * synInterval()) / (_packetSendPeriod * inc + synInterval()); } -void DefaultCC::onLoss(const LossList& losslist) { +void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) { //Slow Start stopped, if it hasn't yet if (_slowStart) { _slowStart = false; @@ -105,7 +105,7 @@ void DefaultCC::onLoss(const LossList& losslist) { _loss = true; - if (losslist.getFirstSequenceNumber() > _lastDecSeq) { + if (rangeStart > _lastDecSeq) { _lastDecPeriod = _packetSendPeriod; _packetSendPeriod = ceil(_packetSendPeriod * 1.125); diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index c328afb9dd..93e842a21a 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -37,7 +37,7 @@ public: virtual void init() {} virtual void close() {} virtual void onAck(SequenceNumber ackNum) {} - virtual void onLoss(const LossList& lossList) {} + virtual void onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) {} protected: void setAckTimer(int period) { _ackPeriod = (period > _synInterval) ? _synInterval : period; } @@ -99,7 +99,7 @@ public: public: virtual void init(); virtual void onACK(SequenceNumber ackNum); - virtual void onLoss(const LossList& lossList); + virtual void onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd); virtual void onTimeout(); private: From 94db77155ea5547069e5e7072522f3a4d3b78bf9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 10:55:22 -0700 Subject: [PATCH 142/549] fix for RTT numerator calculations --- libraries/networking/src/udt/Connection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index cc421e5298..4de12d28b0 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -452,9 +452,9 @@ void Connection::updateRTT(int rtt) { static const int RTT_ESTIMATION_ALPHA_NUMERATOR = 8; static const int RTT_ESTIMATION_VARIANCE_ALPHA_NUMERATOR = 4; - _rtt = (_rtt * (1 - RTT_ESTIMATION_ALPHA_NUMERATOR) + rtt) / RTT_ESTIMATION_ALPHA_NUMERATOR; + _rtt = (_rtt * (RTT_ESTIMATION_ALPHA_NUMERATOR - 1) + rtt) / RTT_ESTIMATION_ALPHA_NUMERATOR; - _rttVariance = (_rttVariance * (1 - RTT_ESTIMATION_VARIANCE_ALPHA_NUMERATOR) + _rttVariance = (_rttVariance * (RTT_ESTIMATION_VARIANCE_ALPHA_NUMERATOR - 1) + abs(rtt - _rtt)) / RTT_ESTIMATION_VARIANCE_ALPHA_NUMERATOR; } From d344ba57434ff85ec918c6cec76f780fd0a94c57 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 10:56:38 -0700 Subject: [PATCH 143/549] add a comment for Connection processTimeoutNAK --- libraries/networking/src/udt/Connection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 4de12d28b0..af8a0e1f75 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -432,8 +432,8 @@ void Connection::processTimeoutNAK(std::unique_ptr controlPacket) // Override SendQueue's LossList with the timeout NAK list _sendQueue->overrideNAKListFromPacket(*controlPacket); - // TODO: tell the congestion control object that there was loss - // _congestionControl->onLoss(); + // we don't tell the congestion control object there was loss here - this matches UDTs implementation + // a possible improvement would be to tell it which new loss this timeout packet told us about ++_totalReceivedTimeoutNAKs; } From 2cdaea4e730a8a82c8f5d6c209ef019decbabaf0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 29 Jul 2015 11:09:39 -0700 Subject: [PATCH 144/549] Remove LossList::read method and add clear --- libraries/networking/src/udt/LossList.cpp | 17 ----------------- libraries/networking/src/udt/LossList.h | 3 ++- libraries/networking/src/udt/SendQueue.cpp | 15 ++++++++++++++- libraries/networking/src/udt/SendQueue.h | 3 ++- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp index 2e1346daae..0bf08fbc1d 100644 --- a/libraries/networking/src/udt/LossList.cpp +++ b/libraries/networking/src/udt/LossList.cpp @@ -161,20 +161,3 @@ void LossList::write(ControlPacket& packet) { packet.writePrimitive(pair.second); } } - -void LossList::read(ControlPacket& packet) { - _lossList.clear(); - - SequenceNumber first, second; - while (packet.bytesLeftToRead() > (qint64)(2 * sizeof(SequenceNumber))) { - packet.readPrimitive(&first); - packet.readPrimitive(&second); - - if (first == second) { - append(first); - } else { - append(first, second); - } - - } -} diff --git a/libraries/networking/src/udt/LossList.h b/libraries/networking/src/udt/LossList.h index c88bef8baa..5b5fb9f0c8 100644 --- a/libraries/networking/src/udt/LossList.h +++ b/libraries/networking/src/udt/LossList.h @@ -24,6 +24,8 @@ class LossList { public: LossList() {} + void clear() { _length = 0; _lossList.clear(); } + // Should always add at the end void append(SequenceNumber seq); void append(SequenceNumber start, SequenceNumber end); @@ -39,7 +41,6 @@ public: SequenceNumber popFirstSequenceNumber(); void write(ControlPacket& packet); - void read(ControlPacket& packet); private: std::list> _lossList; diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index e9f835b918..ce1ce41d13 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -18,6 +18,7 @@ #include +#include "ControlPacket.h" #include "Packet.h" #include "Socket.h" @@ -105,7 +106,19 @@ void SendQueue::nak(SequenceNumber start, SequenceNumber end) { void SendQueue::overrideNAKListFromPacket(ControlPacket& packet) { QWriteLocker locker(&_naksLock); - _naks.read(packet); + _naks.clear(); + + SequenceNumber first, second; + while (packet.bytesLeftToRead() > (qint64)(2 * sizeof(SequenceNumber))) { + packet.readPrimitive(&first); + packet.readPrimitive(&second); + + if (first == second) { + _naks.append(first); + } else { + _naks.append(first, second); + } + } } SequenceNumber SendQueue::getNextSequenceNumber() { diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 2bb61a5002..4437565ded 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -27,9 +27,10 @@ namespace udt { -class Socket; class BasePacket; +class ControlPacket; class Packet; +class Socket; class SendQueue : public QObject { Q_OBJECT From 89e32e4a6beddd0ffee571d8fd465e42f56646f9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 11:11:06 -0700 Subject: [PATCH 145/549] some initial cleanup in CongestionControl --- .../networking/src/udt/CongestionControl.cpp | 41 ++++++++++--------- .../networking/src/udt/CongestionControl.h | 15 +++---- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index a7cd45cfe7..969909e956 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -11,16 +11,17 @@ #include "CongestionControl.h" -#include +#include using namespace udt; +using namespace std::chrono; void DefaultCC::init() { - _lastRCTime = usecTimestampNow(); + _lastRCTime = high_resolution_clock::now(); setAckTimer(synInterval()); _lastAck = _sendCurrSeqNum; - _lastDecSeq = SequenceNumber{ SequenceNumber::MAX }; + _lastDecreaseMaxSeq = SequenceNumber { SequenceNumber::MAX }; _congestionWindowSize = 16.0; _packetSendPeriod = 1.0; @@ -35,12 +36,12 @@ void DefaultCC::onACK(SequenceNumber ackNum) { // for long time. const double min_inc = 0.01; - uint64_t currtime = usecTimestampNow(); - if (currtime - _lastRCTime < (uint64_t)synInterval()) { + auto now = high_resolution_clock::now(); + if (duration_cast(now - _lastRCTime).count() < synInterval()) { return; } - _lastRCTime = currtime; + _lastRCTime = now; if (_slowStart) { _congestionWindowSize += seqlen(_lastAck, ackNum); @@ -48,14 +49,14 @@ void DefaultCC::onACK(SequenceNumber ackNum) { if (_congestionWindowSize > _maxCongestionWindowSize) { _slowStart = false; - if (_recvieveRate > 0) { - _packetSendPeriod = 1000000.0 / _recvieveRate; + if (_receiveRate > 0) { + _packetSendPeriod = USECS_PER_SECOND / _receiveRate; } else { _packetSendPeriod = (_rtt + synInterval()) / _congestionWindowSize; } } } else { - _congestionWindowSize = _recvieveRate / 1000000.0 * (_rtt + synInterval()) + 16; + _congestionWindowSize = _receiveRate / USECS_PER_SECOND * (_rtt + synInterval()) + 16; } // During Slow Start, no rate increase @@ -69,7 +70,7 @@ void DefaultCC::onACK(SequenceNumber ackNum) { } B = (int64_t)(_bandwidth - 1000000.0 / _packetSendPeriod); - if ((_packetSendPeriod > _lastDecPeriod) && ((_bandwidth / 9) < B)) { + if ((_packetSendPeriod > _lastDecreasePeriod) && ((_bandwidth / 9) < B)) { B = _bandwidth / 9; } if (B <= 0) { @@ -92,9 +93,9 @@ void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) { //Slow Start stopped, if it hasn't yet if (_slowStart) { _slowStart = false; - if (_recvieveRate > 0) { + if (_receiveRate > 0) { // Set the sending rate to the receiving rate. - _packetSendPeriod = 1000000.0 / _recvieveRate; + _packetSendPeriod = USECS_PER_SECOND / _receiveRate; return; } // If no receiving rate is observed, we have to compute the sending @@ -105,33 +106,33 @@ void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) { _loss = true; - if (rangeStart > _lastDecSeq) { - _lastDecPeriod = _packetSendPeriod; + if (rangeStart > _lastDecreaseMaxSeq) { + _lastDecreasePeriod = _packetSendPeriod; _packetSendPeriod = ceil(_packetSendPeriod * 1.125); _avgNAKNum = (int)ceil(_avgNAKNum * 0.875 + _nakCount * 0.125); _nakCount = 1; _decCount = 1; - _lastDecSeq = _sendCurrSeqNum; + _lastDecreaseMaxSeq = _sendCurrSeqNum; // remove global synchronization using randomization - srand((uint32_t)_lastDecSeq); + srand((uint32_t)_lastDecreaseMaxSeq); _decRandom = (int)ceil(_avgNAKNum * (double(rand()) / RAND_MAX)); if (_decRandom < 1) _decRandom = 1; - } else if ((_decCount ++ < 5) && (0 == (++ _nakCount % _decRandom))) { + } else if ((_decCount++ < 5) && (0 == (++_nakCount % _decRandom))) { // 0.875^5 = 0.51, rate should not be decreased by more than half within a congestion period _packetSendPeriod = ceil(_packetSendPeriod * 1.125); - _lastDecSeq = _sendCurrSeqNum; + _lastDecreaseMaxSeq = _sendCurrSeqNum; } } void DefaultCC::onTimeout() { if (_slowStart) { _slowStart = false; - if (_recvieveRate > 0) { - _packetSendPeriod = 1000000.0 / _recvieveRate; + if (_receiveRate > 0) { + _packetSendPeriod = USECS_PER_SECOND / _receiveRate; } else { _packetSendPeriod = _congestionWindowSize / (_rtt + synInterval()); } diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index 93e842a21a..83959f034f 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -12,6 +12,7 @@ #ifndef hifi_CongestionControl_h #define hifi_CongestionControl_h +#include #include #include "LossList.h" @@ -52,7 +53,7 @@ protected: int _mss = 0; // Maximum Packet Size, including all packet headers SequenceNumber _sendCurrSeqNum; // current maximum seq num sent out - int _recvieveRate = 0; // packet arrive rate at receiver side, packets per second + int _receiveRate = 0; // packet arrive rate at receiver side, packets per second int _rtt = 0; // current estimated RTT, microsecond private: @@ -62,9 +63,9 @@ private: void setMss(int mss) { _mss = mss; } void setMaxCongestionWindowSize(int window) { _maxCongestionWindowSize = window; } void setBandwidth(int bandwidth) { _bandwidth = bandwidth; } - void setSndCurrSeqNum(SequenceNumber seqNum) { _sendCurrSeqNum = seqNum; } - void setRcvRate(int rate) { _recvieveRate = rate; } - void setRtt(int rtt) { _rtt = rtt; } + void setSendCurrentSequenceNumber(SequenceNumber seqNum) { _sendCurrSeqNum = seqNum; } + void setReceiveRate(int rate) { _receiveRate = rate; } + void setRTT(int rtt) { _rtt = rtt; } int _ackPeriod = 0; // Periodical timer to send an ACK, in milliseconds int _ackInterval = 0; // How many packets to send one ACK, in packets @@ -103,12 +104,12 @@ public: virtual void onTimeout(); private: - uint64_t _lastRCTime = 0; // last rate increase time + std::chrono::high_resolution_clock::time_point _lastRCTime; // last rate increase time bool _slowStart = true; // if in slow start phase SequenceNumber _lastAck; // last ACKed seq num bool _loss = false; // if loss happened since last rate increase - SequenceNumber _lastDecSeq; // max pkt seq num sent out when last decrease happened - double _lastDecPeriod = 1; // value of pktsndperiod when last decrease happened + SequenceNumber _lastDecreaseMaxSeq; // max pkt seq num sent out when last decrease happened + double _lastDecreasePeriod = 1; // value of _packetSendPeriod when last decrease happened int _nakCount = 0; // NAK counter int _decRandom = 1; // random threshold on decrease by number of loss events int _avgNAKNum = 0; // average number of NAKs per congestion From f65472cbc760195552586c71f6eed3f6431227d4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 11:14:03 -0700 Subject: [PATCH 146/549] use a double USECS_PER_SECOND in CongestionControl --- libraries/networking/src/udt/CongestionControl.cpp | 8 ++++---- libraries/networking/src/udt/Connection.cpp | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 969909e956..37b198ffb9 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -11,11 +11,11 @@ #include "CongestionControl.h" -#include - using namespace udt; using namespace std::chrono; +static const double USECS_PER_SECOND = 1000000.0; + void DefaultCC::init() { _lastRCTime = high_resolution_clock::now(); setAckTimer(synInterval()); @@ -69,7 +69,7 @@ void DefaultCC::onACK(SequenceNumber ackNum) { return; } - B = (int64_t)(_bandwidth - 1000000.0 / _packetSendPeriod); + B = (int64_t)(_bandwidth - USECS_PER_SECOND/ _packetSendPeriod); if ((_packetSendPeriod > _lastDecreasePeriod) && ((_bandwidth / 9) < B)) { B = _bandwidth / 9; } @@ -121,7 +121,7 @@ void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) { _decRandom = (int)ceil(_avgNAKNum * (double(rand()) / RAND_MAX)); if (_decRandom < 1) _decRandom = 1; - } else if ((_decCount++ < 5) && (0 == (++_nakCount % _decRandom))) { + } else if ((_decCount ++ < 5) && (0 == (++ _nakCount % _decRandom))) { // 0.875^5 = 0.51, rate should not be decreased by more than half within a congestion period _packetSendPeriod = ceil(_packetSendPeriod * 1.125); _lastDecreaseMaxSeq = _sendCurrSeqNum; diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index af8a0e1f75..a3fb200302 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -343,7 +343,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { updateRTT(rtt); // set the RTT for congestion control - _congestionControl->setRtt(_rtt); + _congestionControl->setRTT(_rtt); if (controlPacket->getPayloadSize() > (qint64) (sizeof(SequenceNumber) + sizeof(SequenceNumber) + sizeof(rtt))) { int32_t deliveryRate, bandwidth; @@ -351,7 +351,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { controlPacket->readPrimitive(&bandwidth); // set the delivery rate and bandwidth for congestion control - _congestionControl->setRcvRate(deliveryRate); + _congestionControl->setReceiveRate(deliveryRate); _congestionControl->setBandwidth(bandwidth); } @@ -397,7 +397,7 @@ void Connection::processACK2(std::unique_ptr controlPacket) { updateRTT(rtt); // set the RTT for congestion control - _congestionControl->setRtt(_rtt); + _congestionControl->setRTT(_rtt); // update the last ACKed ACK if (pair.first > _lastReceivedAcknowledgedACK) { From 169cb97db501e1ae068d9f84c810c6a26d1575ab Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 11:35:06 -0700 Subject: [PATCH 147/549] fix bandwidth and receive rate EWMA in Connection --- libraries/networking/src/udt/Connection.cpp | 14 ++++++++++---- libraries/networking/src/udt/Connection.h | 3 +++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index a3fb200302..d952b245f2 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -346,13 +346,19 @@ void Connection::processACK(std::unique_ptr controlPacket) { _congestionControl->setRTT(_rtt); if (controlPacket->getPayloadSize() > (qint64) (sizeof(SequenceNumber) + sizeof(SequenceNumber) + sizeof(rtt))) { - int32_t deliveryRate, bandwidth; - controlPacket->readPrimitive(&deliveryRate); + int32_t receiveRate, bandwidth; + controlPacket->readPrimitive(&receiveRate); controlPacket->readPrimitive(&bandwidth); // set the delivery rate and bandwidth for congestion control - _congestionControl->setReceiveRate(deliveryRate); - _congestionControl->setBandwidth(bandwidth); + // these are calculated using an EWMA + static const int EMWA_ALPHA_NUMERATOR = 8; + + _deliveryRate = (_deliveryRate * (EMWA_ALPHA_NUMERATOR - 1) + _deliveryRate) / EMWA_ALPHA_NUMERATOR; + _bandwidth = (_bandwidth * (EMWA_ALPHA_NUMERATOR - 1) + _bandwidth) / EMWA_ALPHA_NUMERATOR; + + _congestionControl->setReceiveRate(_deliveryRate); + _congestionControl->setBandwidth(_bandwidth); } // fire the onACK callback for congestion control diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index a98f4c394c..8a385ca02d 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -81,6 +81,9 @@ private: int32_t _rttVariance; // RTT variance int _flowWindowSize; // Flow control window size + int _bandwidth { 1 }; // Exponential moving average for estimated bandwidth, in packets per second + int _deliveryRate { 16 }; // Exponential moving average for receiver's receive rate, in packets per second + SentACKMap _sentACKs; // Map of ACK sub-sequence numbers to ACKed sequence number and sent time Socket* _parentSocket { nullptr }; From abfe434b3034651f5861cc2bc2e7b8811137f1d8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 29 Jul 2015 11:39:33 -0700 Subject: [PATCH 148/549] Synchronise SendQueue and CongestionControl --- libraries/networking/src/udt/Connection.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index d952b245f2..9e68d05699 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -362,7 +362,9 @@ void Connection::processACK(std::unique_ptr controlPacket) { } // fire the onACK callback for congestion control + _congestionControl->setSendCurrentSequenceNumber(_sendQueue->getCurrentSequenceNumber()); _congestionControl->onAck(ack); + _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); // update the total count of received ACKs ++_totalReceivedACKs; @@ -425,12 +427,14 @@ void Connection::processNAK(std::unique_ptr controlPacket) { controlPacket->readPrimitive(&end); } - // TODO: tell the congestion control object that there was loss - // _congestionControl->onLoss(); - // send that off to the send queue so it knows there was loss _sendQueue->nak(start, end); + // Tell the congestion control object that there was loss + _congestionControl->setSendCurrentSequenceNumber(_sendQueue->getCurrentSequenceNumber()); + _congestionControl->onLoss(start, end); + _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); + ++_totalReceivedNAKs; } From c35fa6eaae3effa8bf01c828e3a36f678149c81c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 11:48:00 -0700 Subject: [PATCH 149/549] some more cleanup in congestion control --- .../networking/src/udt/CongestionControl.cpp | 37 ++++++++++++------- .../networking/src/udt/CongestionControl.h | 2 +- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 37b198ffb9..aef86c8923 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -28,13 +28,13 @@ void DefaultCC::init() { } void DefaultCC::onACK(SequenceNumber ackNum) { - int64_t B = 0; - double inc = 0; + double increase = 0; + // Note: 1/24/2012 // The minimum increase parameter is increased from "1.0 / _mss" to 0.01 // because the original was too small and caused sending rate to stay at low level // for long time. - const double min_inc = 0.01; + const double minimumIncrease = 0.01; auto now = high_resolution_clock::now(); if (duration_cast(now - _lastRCTime).count() < synInterval()) { @@ -69,24 +69,30 @@ void DefaultCC::onACK(SequenceNumber ackNum) { return; } - B = (int64_t)(_bandwidth - USECS_PER_SECOND/ _packetSendPeriod); - if ((_packetSendPeriod > _lastDecreasePeriod) && ((_bandwidth / 9) < B)) { - B = _bandwidth / 9; + int capacitySpeedDelta = (int) (_bandwidth - USECS_PER_SECOND / _packetSendPeriod); + + if ((_packetSendPeriod > _lastDecreasePeriod) && ((_bandwidth / 9) < capacitySpeedDelta)) { + capacitySpeedDelta = _bandwidth / 9; } - if (B <= 0) { - inc = min_inc; + + if (capacitySpeedDelta <= 0) { + increase = minimumIncrease; } else { - // inc = max(10 ^ ceil(log10( B * MSS * 8 ) * Beta / MSS, 1/MSS) + // inc = max(10 ^ ceil(log10(B * MSS * 8 ) * Beta / MSS, minimumIncrease) + // B = estimated link capacity // Beta = 1.5 * 10^(-6) - inc = pow(10.0, ceil(log10(B * _mss * 8.0))) * 0.0000015 / _mss; + static const double BETA = 0.0000015; + static const double BITS_PER_BYTE = 8.0; - if (inc < min_inc) { - inc = min_inc; + increase = pow(10.0, ceil(log10(capacitySpeedDelta * _mss * BITS_PER_BYTE))) * BETA / _mss; + + if (increase < minimumIncrease) { + increase = minimumIncrease; } } - _packetSendPeriod = (_packetSendPeriod * synInterval()) / (_packetSendPeriod * inc + synInterval()); + _packetSendPeriod = (_packetSendPeriod * synInterval()) / (_packetSendPeriod * increase + synInterval()); } void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) { @@ -119,8 +125,11 @@ void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) { // remove global synchronization using randomization srand((uint32_t)_lastDecreaseMaxSeq); _decRandom = (int)ceil(_avgNAKNum * (double(rand()) / RAND_MAX)); - if (_decRandom < 1) + + if (_decRandom < 1) { _decRandom = 1; + } + } else if ((_decCount ++ < 5) && (0 == (++ _nakCount % _decRandom))) { // 0.875^5 = 0.51, rate should not be decreased by more than half within a congestion period _packetSendPeriod = ceil(_packetSendPeriod * 1.125); diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index 83959f034f..c65901ce15 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -60,7 +60,7 @@ private: CongestionControl(const CongestionControl& other) = delete; CongestionControl& operator=(const CongestionControl& other) = delete; - void setMss(int mss) { _mss = mss; } + void setMSS(int mss) { _mss = mss; } void setMaxCongestionWindowSize(int window) { _maxCongestionWindowSize = window; } void setBandwidth(int bandwidth) { _bandwidth = bandwidth; } void setSendCurrentSequenceNumber(SequenceNumber seqNum) { _sendCurrSeqNum = seqNum; } From 236c09785337555d0740b433e83518f8bf44d6ef Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 29 Jul 2015 12:30:55 -0700 Subject: [PATCH 150/549] Bit of code cleanup --- libraries/networking/src/NetworkPeer.cpp | 4 +- libraries/networking/src/NetworkPeer.h | 4 +- .../networking/src/udt/CongestionControl.h | 53 ++++++++++--------- libraries/networking/src/udt/Connection.cpp | 1 + libraries/networking/src/udt/Connection.h | 2 - 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index 28f19d4f60..52e53e9665 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -32,7 +32,7 @@ NetworkPeer::NetworkPeer(QObject* parent) : _wakeTimestamp(QDateTime::currentMSecsSinceEpoch()), _connectionAttempts(0) { - _lastHeardMicrostamp.store(usecTimestampNow()); + _lastHeardMicrostamp = usecTimestampNow(); } NetworkPeer::NetworkPeer(const QUuid& uuid, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, QObject* parent) : @@ -45,7 +45,7 @@ NetworkPeer::NetworkPeer(const QUuid& uuid, const HifiSockAddr& publicSocket, co _wakeTimestamp(QDateTime::currentMSecsSinceEpoch()), _connectionAttempts(0) { - _lastHeardMicrostamp.store(usecTimestampNow()); + _lastHeardMicrostamp = usecTimestampNow(); } void NetworkPeer::setPublicSocket(const HifiSockAddr& publicSocket) { diff --git a/libraries/networking/src/NetworkPeer.h b/libraries/networking/src/NetworkPeer.h index 1e03677587..8446586121 100644 --- a/libraries/networking/src/NetworkPeer.h +++ b/libraries/networking/src/NetworkPeer.h @@ -61,8 +61,8 @@ public: quint64 getWakeTimestamp() const { return _wakeTimestamp; } void setWakeTimestamp(quint64 wakeTimestamp) { _wakeTimestamp = wakeTimestamp; } - quint64 getLastHeardMicrostamp() const { return _lastHeardMicrostamp.load(); } - void setLastHeardMicrostamp(quint64 lastHeardMicrostamp) { _lastHeardMicrostamp.store(lastHeardMicrostamp); } + quint64 getLastHeardMicrostamp() const { return _lastHeardMicrostamp; } + void setLastHeardMicrostamp(quint64 lastHeardMicrostamp) { _lastHeardMicrostamp = lastHeardMicrostamp; } QByteArray toByteArray() const; diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index 83959f034f..43a6413361 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -45,21 +45,6 @@ protected: void setAckInterval(int ackInterval) { _ackInterval = ackInterval; } void setRto(int rto) { _userDefinedRto = true; _rto = rto; } - double _packetSendPeriod = 1.0; // Packet sending period, in microseconds - double _congestionWindowSize = 16.0; // Congestion window size, in packets - - int _bandwidth = 0; // estimated bandwidth, packets per second - double _maxCongestionWindowSize = 0.0; // maximum cwnd size, in packets - - int _mss = 0; // Maximum Packet Size, including all packet headers - SequenceNumber _sendCurrSeqNum; // current maximum seq num sent out - int _receiveRate = 0; // packet arrive rate at receiver side, packets per second - int _rtt = 0; // current estimated RTT, microsecond - -private: - CongestionControl(const CongestionControl& other) = delete; - CongestionControl& operator=(const CongestionControl& other) = delete; - void setMss(int mss) { _mss = mss; } void setMaxCongestionWindowSize(int window) { _maxCongestionWindowSize = window; } void setBandwidth(int bandwidth) { _bandwidth = bandwidth; } @@ -67,13 +52,29 @@ private: void setReceiveRate(int rate) { _receiveRate = rate; } void setRTT(int rtt) { _rtt = rtt; } - int _ackPeriod = 0; // Periodical timer to send an ACK, in milliseconds - int _ackInterval = 0; // How many packets to send one ACK, in packets + + double _packetSendPeriod { 1.0 }; // Packet sending period, in microseconds + double _congestionWindowSize { 16.0 }; // Congestion window size, in packets + + int _bandwidth { 0 }; // estimated bandwidth, packets per second + double _maxCongestionWindowSize { 0.0 }; // maximum cwnd size, in packets + + int _mss { 0 }; // Maximum Packet Size, including all packet headers + SequenceNumber _sendCurrSeqNum; // current maximum seq num sent out + int _receiveRate { 0 }; // packet arrive rate at receiver side, packets per second + int _rtt { 0 }; // current estimated RTT, microsecond + +private: + CongestionControl(const CongestionControl& other) = delete; + CongestionControl& operator=(const CongestionControl& other) = delete; + + int _ackPeriod { 0 }; // Periodical timer to send an ACK, in milliseconds + int _ackInterval { 0 }; // How many packets to send one ACK, in packets int _synInterval { DEFAULT_SYN_INTERVAL }; - bool _userDefinedRto = false; // if the RTO value is defined by users - int _rto = -1; // RTO value, microseconds + bool _userDefinedRto { false }; // if the RTO value is defined by users + int _rto { -1 }; // RTO value, microseconds }; @@ -105,15 +106,15 @@ public: private: std::chrono::high_resolution_clock::time_point _lastRCTime; // last rate increase time - bool _slowStart = true; // if in slow start phase + bool _slowStart { true }; // if in slow start phase SequenceNumber _lastAck; // last ACKed seq num - bool _loss = false; // if loss happened since last rate increase + bool _loss { false }; // if loss happened since last rate increase SequenceNumber _lastDecreaseMaxSeq; // max pkt seq num sent out when last decrease happened - double _lastDecreasePeriod = 1; // value of _packetSendPeriod when last decrease happened - int _nakCount = 0; // NAK counter - int _decRandom = 1; // random threshold on decrease by number of loss events - int _avgNAKNum = 0; // average number of NAKs per congestion - int _decCount = 0; // number of decreases in a congestion epoch + double _lastDecreasePeriod { 1 }; // value of _packetSendPeriod when last decrease happened + int _nakCount { 0 }; // NAK counter + int _decRandom { 1 }; // random threshold on decrease by number of loss events + int _avgNAKNum { 0 }; // average number of NAKs per congestion + int _decCount { 0 }; // number of decreases in a congestion epoch }; } diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 9e68d05699..146714df10 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -253,6 +253,7 @@ void Connection::processReceivedSequenceNumber(SequenceNumber seq) { } void Connection::processControl(unique_ptr controlPacket) { + // Simple dispatch to control packets processing methods based on their type switch (controlPacket->getType()) { case ControlPacket::ACK: if (controlPacket->getPayloadSize() == sizeof(SequenceNumber)) { diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 8a385ca02d..b42ef0d8ea 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -110,8 +110,6 @@ private: // Data packet stat collection int _totalReceivedDataPackets { 0 }; int _packetsSinceACK { 0 }; // The number of packets that have been received during the current ACK interval - - }; } From 94fd7b428d28a8a8248de564e3d2be062b202253 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 12:37:36 -0700 Subject: [PATCH 151/549] add some comments to CongestionControl --- .../networking/src/udt/CongestionControl.cpp | 43 +++++++++++++++---- .../networking/src/udt/CongestionControl.h | 2 +- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index aef86c8923..a5e5b23304 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -20,7 +20,7 @@ void DefaultCC::init() { _lastRCTime = high_resolution_clock::now(); setAckTimer(synInterval()); - _lastAck = _sendCurrSeqNum; + _slowStartLastAck = _sendCurrSeqNum; _lastDecreaseMaxSeq = SequenceNumber { SequenceNumber::MAX }; _congestionWindowSize = 16.0; @@ -36,34 +36,45 @@ void DefaultCC::onACK(SequenceNumber ackNum) { // for long time. const double minimumIncrease = 0.01; + // we will only adjust once per sync interval so check that it has been at least that long now auto now = high_resolution_clock::now(); if (duration_cast(now - _lastRCTime).count() < synInterval()) { return; } + // our last rate increase time is now _lastRCTime = now; - + if (_slowStart) { - _congestionWindowSize += seqlen(_lastAck, ackNum); - _lastAck = ackNum; + // we are in slow start phase - increase the congestion window size by the number of packets just ACKed + _congestionWindowSize += seqlen(_slowStartLastAck, ackNum); + // update the last ACK + _slowStartLastAck = ackNum; + + // check if we can get out of slow start (is our new congestion window size bigger than the max) if (_congestionWindowSize > _maxCongestionWindowSize) { _slowStart = false; + if (_receiveRate > 0) { + // if we have a valid receive rate we set the send period to whatever the receive rate dictates _packetSendPeriod = USECS_PER_SECOND / _receiveRate; } else { + // no valid receive rate, packet send period is dictated by estimated RTT and current congestion window size _packetSendPeriod = (_rtt + synInterval()) / _congestionWindowSize; } } } else { + // not in slow start - window size should be arrival rate * (RTT + SYN) + 16 _congestionWindowSize = _receiveRate / USECS_PER_SECOND * (_rtt + synInterval()) + 16; } - // During Slow Start, no rate increase + // during slow start we perform no rate increases if (_slowStart) { return; } + // if loss has happened since the last rate increase we do not perform another increase if (_loss) { _loss = false; return; @@ -71,13 +82,19 @@ void DefaultCC::onACK(SequenceNumber ackNum) { int capacitySpeedDelta = (int) (_bandwidth - USECS_PER_SECOND / _packetSendPeriod); - if ((_packetSendPeriod > _lastDecreasePeriod) && ((_bandwidth / 9) < capacitySpeedDelta)) { - capacitySpeedDelta = _bandwidth / 9; + // UDT uses what they call DAIMD - additive increase multiplicative decrease with decreasing increases + // This factor is a protocol parameter that is part of the DAIMD algorithim + static const int AIMD_DECREASING_INCREASE_FACTOR = 9; + + if ((_packetSendPeriod > _lastDecreasePeriod) && ((_bandwidth / AIMD_DECREASING_INCREASE_FACTOR) < capacitySpeedDelta)) { + capacitySpeedDelta = _bandwidth / AIMD_DECREASING_INCREASE_FACTOR; } if (capacitySpeedDelta <= 0) { increase = minimumIncrease; } else { + // use UDTs DAIMD algorithm to figure out what the send period increase factor should be + // inc = max(10 ^ ceil(log10(B * MSS * 8 ) * Beta / MSS, minimumIncrease) // B = estimated link capacity // Beta = 1.5 * 10^(-6) @@ -112,11 +129,19 @@ void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) { _loss = true; + // check if this NAK starts a new congestion period - this will be the case if the + // NAK received occured for a packet sent after the last decrease if (rangeStart > _lastDecreaseMaxSeq) { _lastDecreasePeriod = _packetSendPeriod; - _packetSendPeriod = ceil(_packetSendPeriod * 1.125); - _avgNAKNum = (int)ceil(_avgNAKNum * 0.875 + _nakCount * 0.125); + static const double INTER_PACKET_ARRIVAL_INCREASE = 1.125; + _packetSendPeriod = ceil(_packetSendPeriod * INTER_PACKET_ARRIVAL_INCREASE); + + // use EWMA to update the average number of NAKs per congestion + static const double NAK_EWMA_ALPHA = 0.125; + _avgNAKNum = (int)ceil(_avgNAKNum * (1 - NAK_EWMA_ALPHA) + _nakCount * NAK_EWMA_ALPHA); + + _nakCount = 1; _decCount = 1; diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index c65901ce15..bf7161fffc 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -106,7 +106,7 @@ public: private: std::chrono::high_resolution_clock::time_point _lastRCTime; // last rate increase time bool _slowStart = true; // if in slow start phase - SequenceNumber _lastAck; // last ACKed seq num + SequenceNumber _slowStartLastAck; // last ACKed seq num, used only during slow start bool _loss = false; // if loss happened since last rate increase SequenceNumber _lastDecreaseMaxSeq; // max pkt seq num sent out when last decrease happened double _lastDecreasePeriod = 1; // value of _packetSendPeriod when last decrease happened From 7602c352d6d632defd4582d5af0812eccb650b95 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 13:57:05 -0700 Subject: [PATCH 152/549] finish cleanup in CongestionControl --- .../networking/src/udt/CongestionControl.cpp | 70 ++++++++++--------- .../networking/src/udt/CongestionControl.h | 8 ++- 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 0f158f1b15..14d88a4761 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -112,68 +112,72 @@ void DefaultCC::onACK(SequenceNumber ackNum) { } void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) { - //Slow Start stopped, if it hasn't yet + // stop the slow start if we haven't yet if (_slowStart) { - _slowStart = false; - if (_receiveRate > 0) { - // Set the sending rate to the receiving rate. - _packetSendPeriod = USECS_PER_SECOND / _receiveRate; - return; - } - // If no receiving rate is observed, we have to compute the sending - // rate according to the current window size, and decrease it - // using the method below. - _packetSendPeriod = _congestionWindowSize / (_rtt + synInterval()); + stopSlowStart(); } _loss = true; + static const double INTER_PACKET_ARRIVAL_INCREASE = 1.125; + static const int MAX_DECREASES_PER_CONGESTION_EPOCH = 5; + // check if this NAK starts a new congestion period - this will be the case if the // NAK received occured for a packet sent after the last decrease if (rangeStart > _lastDecreaseMaxSeq) { _lastDecreasePeriod = _packetSendPeriod; - static const double INTER_PACKET_ARRIVAL_INCREASE = 1.125; _packetSendPeriod = ceil(_packetSendPeriod * INTER_PACKET_ARRIVAL_INCREASE); // use EWMA to update the average number of NAKs per congestion static const double NAK_EWMA_ALPHA = 0.125; _avgNAKNum = (int)ceil(_avgNAKNum * (1 - NAK_EWMA_ALPHA) + _nakCount * NAK_EWMA_ALPHA); - + // update the count of NAKs and count of decreases in this interval _nakCount = 1; - _decCount = 1; + _decreaseCount = 1; _lastDecreaseMaxSeq = _sendCurrSeqNum; - // remove global synchronization using randomization - srand((uint32_t)_lastDecreaseMaxSeq); - _decRandom = (int)ceil(_avgNAKNum * (double(rand()) / RAND_MAX)); + // avoid synchronous rate decrease across connections using randomization + srand((unsigned) _lastDecreaseMaxSeq); + _randomDecreaseThreshold = (int) ceil(_avgNAKNum * (double(rand()) / RAND_MAX)); - if (_decRandom < 1) { - _decRandom = 1; + if (_randomDecreaseThreshold < 1) { + _randomDecreaseThreshold = 1; } - } else if ((_decCount ++ < 5) && (0 == (++ _nakCount % _decRandom))) { - // 0.875^5 = 0.51, rate should not be decreased by more than half within a congestion period - _packetSendPeriod = ceil(_packetSendPeriod * 1.125); + } else if ((_decreaseCount++ < MAX_DECREASES_PER_CONGESTION_EPOCH) && ((++_nakCount % _randomDecreaseThreshold) == 0)) { + // there have been fewer than MAX_DECREASES_PER_CONGESTION_EPOCH AND this NAK matches the random count at which we + // decided we would decrease the packet send period + + _packetSendPeriod = ceil(_packetSendPeriod * INTER_PACKET_ARRIVAL_INCREASE); _lastDecreaseMaxSeq = _sendCurrSeqNum; } } void DefaultCC::onTimeout() { if (_slowStart) { - _slowStart = false; - if (_receiveRate > 0) { - _packetSendPeriod = USECS_PER_SECOND / _receiveRate; - } else { - _packetSendPeriod = _congestionWindowSize / (_rtt + synInterval()); - } + stopSlowStart(); } else { - /* - _lastDecPeriod = _packetSendPeriod; - _packetSendPeriod = ceil(_packetSendPeriod * 2); - _lastDecSeq = _lastAck; - */ + // UDT used to do the following on timeout if not in slow start - we should check if it could be helpful + // _lastDecreasePeriod = _packetSendPeriod; + // _packetSendPeriod = ceil(_packetSendPeriod * 2); + + // this seems odd - the last ack they were setting _lastDecreaseMaxSeq to only applies to slow start + // _lastDecreaseMaxSeq = _slowStartLastAck; } } + +void DefaultCC::stopSlowStart() { + _slowStart = false; + if (_receiveRate > 0) { + // Set the sending rate to the receiving rate. + _packetSendPeriod = USECS_PER_SECOND / _receiveRate; + return; + } + // If no receiving rate is observed, we have to compute the sending + // rate according to the current window size, and decrease it + // using the method below. + _packetSendPeriod = _congestionWindowSize / (_rtt + synInterval()); +} diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index d37c5c883e..75590d88b5 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -103,16 +103,18 @@ public: virtual void onTimeout(); private: + void stopSlowStart(); // stops the slow start on loss or timeout, if it's still on + std::chrono::high_resolution_clock::time_point _lastRCTime; // last rate increase time bool _slowStart { true }; // if in slow start phase SequenceNumber _slowStartLastAck; // last ACKed seq num bool _loss { false }; // if loss happened since last rate increase SequenceNumber _lastDecreaseMaxSeq; // max pkt seq num sent out when last decrease happened double _lastDecreasePeriod { 1 }; // value of _packetSendPeriod when last decrease happened - int _nakCount { 0 }; // NAK counter - int _decRandom { 1 }; // random threshold on decrease by number of loss events + int _nakCount { 0 }; // number of NAKs in congestion epoch + int _randomDecreaseThreshold { 1 }; // random threshold on decrease by number of loss events int _avgNAKNum { 0 }; // average number of NAKs per congestion - int _decCount { 0 }; // number of decreases in a congestion epoch + int _decreaseCount { 0 }; // number of decreases in a congestion epoch }; } From bb62231ebcf362c25be1488816811eb2cd13b17a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 29 Jul 2015 14:14:28 -0700 Subject: [PATCH 153/549] Code cleanup --- libraries/networking/src/udt/SendQueue.h | 2 -- libraries/networking/src/udt/Socket.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 4437565ded..a75b784d9b 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -63,8 +63,6 @@ private slots: void loop(); private: - friend struct std::default_delete; - SendQueue(Socket* socket, HifiSockAddr dest); SendQueue(SendQueue& other) = delete; SendQueue(SendQueue&& other) = delete; diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index d82915c68f..c7c1d90666 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -136,7 +136,7 @@ void Socket::readPendingDatagrams() { if (!_packetFilterOperator || _packetFilterOperator(*packet)) { if (_packetHandler) { // call the verified packet callback to let it handle this packet - return _packetHandler(std::move(packet)); + _packetHandler(std::move(packet)); } } } From 85156b9d0fd8d18acfeaa12c6620e9ad56a2e880 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 15:11:12 -0700 Subject: [PATCH 154/549] add a constants file for UDT --- libraries/networking/src/LimitedNodeList.cpp | 5 ---- libraries/networking/src/udt/BasePacket.h | 3 +-- .../networking/src/udt/CongestionControl.cpp | 3 +++ libraries/networking/src/udt/Constants.h | 26 +++++++++++++++++++ libraries/networking/src/udt/Socket.cpp | 8 +++++- libraries/networking/src/udt/Socket.h | 4 +-- libraries/networking/src/udt/udt.cpp | 12 --------- libraries/networking/src/udt/udt.h | 15 ----------- 8 files changed, 39 insertions(+), 37 deletions(-) create mode 100644 libraries/networking/src/udt/Constants.h delete mode 100644 libraries/networking/src/udt/udt.cpp delete mode 100644 libraries/networking/src/udt/udt.h diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index fc8e6ad8fe..2ca4e89c12 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -33,8 +33,6 @@ #include "UUID.h" #include "NetworkLogging.h" -#include "udt/udt.h" - const char SOLO_NODE_TYPES[2] = { NodeType::AvatarMixer, NodeType::AudioMixer @@ -81,9 +79,6 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short qCDebug(networking) << "NodeList DTLS socket is listening on" << _dtlsSocket->localPort(); } - const int LARGER_BUFFER_SIZE = 1048576; - _nodeSocket.setBufferSizes(LARGER_BUFFER_SIZE); - // check for local socket updates every so often const int LOCAL_SOCKET_UPDATE_INTERVAL_MSECS = 5 * 1000; QTimer* localSocketUpdate = new QTimer(this); diff --git a/libraries/networking/src/udt/BasePacket.h b/libraries/networking/src/udt/BasePacket.h index d943e05204..8dcc3ab9be 100644 --- a/libraries/networking/src/udt/BasePacket.h +++ b/libraries/networking/src/udt/BasePacket.h @@ -17,11 +17,10 @@ #include #include "../HifiSockAddr.h" +#include "Constants.h" namespace udt { -static const int MAX_PACKET_SIZE = 1450; - class BasePacket : public QIODevice { Q_OBJECT public: diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 14d88a4761..06b63ec60e 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -10,6 +10,7 @@ // #include "CongestionControl.h" +#include "Packet.h" using namespace udt; using namespace std::chrono; @@ -19,6 +20,8 @@ static const double USECS_PER_SECOND = 1000000.0; void DefaultCC::init() { _lastRCTime = high_resolution_clock::now(); + _mss = udt::MAX_PACKET_SIZE; + _slowStartLastAck = _sendCurrSeqNum; _lastDecreaseMaxSeq = SequenceNumber { SequenceNumber::MAX }; diff --git a/libraries/networking/src/udt/Constants.h b/libraries/networking/src/udt/Constants.h new file mode 100644 index 0000000000..5c5ba392a1 --- /dev/null +++ b/libraries/networking/src/udt/Constants.h @@ -0,0 +1,26 @@ +// +// Constants.h +// libraries/networking/src/udt +// +// Created by Clement on 7/13/15. +// Copyright 2015 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 +// + +#pragma once + +#ifndef hifi_udt_Constants_h +#define hifi_udt_Constants_h + +namespace udt { + static const int MAX_PACKET_SIZE = 1450; + static const int MAX_PACKETS_IN_FLIGHT = 25600; + static const int CONNECTION_RECEIVE_BUFFER_SIZE_PACKETS = 8192; + static const int CONNECTION_SEND_BUFFER_SIZE_PACKETS = 8192; + static const int UDP_SEND_BUFFER_SIZE_BYTES = 1048576; + static const int UDP_RECEIVE_BUFFER_SIZE_BYTES = 1048576; +} + +#endif // hifi_udt_Constants_h diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index d82915c68f..1307aef931 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -22,6 +22,8 @@ using namespace udt; Socket::Socket(QObject* parent) : QObject(parent) { + setSystemBufferSizes(); + connect(&_udpSocket, &QUdpSocket::readyRead, this, &Socket::readPendingDatagrams); // make sure our synchronization method is called every SYN interval @@ -38,17 +40,21 @@ void Socket::rebind() { _udpSocket.bind(QHostAddress::AnyIPv4, oldPort); } -void Socket::setBufferSizes(int numBytes) { +void Socket::setSystemBufferSizes() { for (int i = 0; i < 2; i++) { QAbstractSocket::SocketOption bufferOpt; QString bufferTypeString; + int numBytes = 0; + if (i == 0) { bufferOpt = QAbstractSocket::SendBufferSizeSocketOption; + numBytes = udt::UDP_SEND_BUFFER_SIZE_BYTES; bufferTypeString = "send"; } else { bufferOpt = QAbstractSocket::ReceiveBufferSizeSocketOption; + numBytes = udt::UDP_RECEIVE_BUFFER_SIZE_BYTES; bufferTypeString = "receive"; } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 7cf4283cf3..0bc23cdf0a 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -56,8 +56,6 @@ public: void setPacketFilterOperator(PacketFilterOperator filterOperator) { _packetFilterOperator = filterOperator; } void setPacketHandler(PacketHandler handler) { _packetHandler = handler; } - void setBufferSizes(int numBytes); - void addUnfilteredHandler(const HifiSockAddr& senderSockAddr, BasePacketHandler handler) { _unfilteredHandlers[senderSockAddr] = handler; } @@ -68,6 +66,8 @@ private slots: void rateControlSync(); private: + void setSystemBufferSizes(); + QUdpSocket _udpSocket { this }; PacketFilterOperator _packetFilterOperator; PacketHandler _packetHandler; diff --git a/libraries/networking/src/udt/udt.cpp b/libraries/networking/src/udt/udt.cpp deleted file mode 100644 index d580a9f7f8..0000000000 --- a/libraries/networking/src/udt/udt.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// -// udt.cpp -// -// -// Created by Clement on 7/13/15. -// Copyright 2015 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 "udt.h" diff --git a/libraries/networking/src/udt/udt.h b/libraries/networking/src/udt/udt.h deleted file mode 100644 index 74803151d1..0000000000 --- a/libraries/networking/src/udt/udt.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// udt.h -// -// -// Created by Clement on 7/13/15. -// Copyright 2015 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 -// - -#ifndef hifi_udt_h -#define hifi_udt_h - -#endif // hifi_udt_h \ No newline at end of file From 05421aaf8ab002589f852c6ecaf825ad50a0358b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 29 Jul 2015 15:17:34 -0700 Subject: [PATCH 155/549] Added ConnectionStats object for monitoring --- .../networking/src/udt/ConnectionStats.cpp | 92 +++++++++++++++++++ .../networking/src/udt/ConnectionStats.h | 67 ++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 libraries/networking/src/udt/ConnectionStats.cpp create mode 100644 libraries/networking/src/udt/ConnectionStats.h diff --git a/libraries/networking/src/udt/ConnectionStats.cpp b/libraries/networking/src/udt/ConnectionStats.cpp new file mode 100644 index 0000000000..394448afec --- /dev/null +++ b/libraries/networking/src/udt/ConnectionStats.cpp @@ -0,0 +1,92 @@ +// +// ConnectionStats.cpp +// libraries/networking/src/udt +// +// Created by Clement on 7/29/15. +// Copyright 2015 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 "ConnectionStats.h" + +using namespace udt; +using namespace std::chrono; + +ConnectionStats::ConnectionStats() { + auto now = duration_cast(high_resolution_clock::now().time_since_epoch()); + _currentSample.startTime = now; + _total.startTime = now; +} + +ConnectionStats::Stats ConnectionStats::sample() { + Stats sample; + std::swap(sample, _currentSample); + + auto now = duration_cast(high_resolution_clock::now().time_since_epoch()); + sample.endTime = now; + _currentSample.startTime = now; + + return sample; +} + +void ConnectionStats::recordSentACK() { + ++_currentSample.sentACKs; + ++_total.sentACKs; +} + +void ConnectionStats::recordReceivedACK() { + ++_currentSample.receivedACKs; + ++_total.receivedACKs; +} + +void ConnectionStats::recordSentLightACK() { + ++_currentSample.sentLightACKs; + ++_total.sentLightACKs; +} + +void ConnectionStats::recordReceivedLightACK() { + ++_currentSample.receivedLightACKs; + ++_total.receivedLightACKs; +} + +void ConnectionStats::recordSentACK2() { + ++_currentSample.sentACK2s; + ++_total.sentACK2s; +} + +void ConnectionStats::recordReceivedACK2() { + ++_currentSample.receivedACK2s; + ++_total.receivedACK2s; +} + +void ConnectionStats::recordSentNAK() { + ++_currentSample.sentNAKs; + ++_total.sentNAKs; +} + +void ConnectionStats::recordReceivedNAK() { + ++_currentSample.receivedNAKs; + ++_total.receivedNAKs; +} + +void ConnectionStats::recordSentTimeoutNAK() { + ++_currentSample.sentTimeoutNAKs; + ++_total.sentTimeoutNAKs; +} + +void ConnectionStats::recordReceivedTimeoutNAK() { + ++_currentSample.receivedTimeoutNAKs; + ++_total.receivedTimeoutNAKs; +} + +void ConnectionStats::recordSentPackets() { + ++_currentSample.sentPackets; + ++_total.sentPackets; +} + +void ConnectionStats::recordReceivedPackets() { + ++_currentSample.recievedPackets; + ++_total.recievedPackets; +} \ No newline at end of file diff --git a/libraries/networking/src/udt/ConnectionStats.h b/libraries/networking/src/udt/ConnectionStats.h new file mode 100644 index 0000000000..df7dfd1545 --- /dev/null +++ b/libraries/networking/src/udt/ConnectionStats.h @@ -0,0 +1,67 @@ +// +// ConnectionStats.h +// libraries/networking/src/udt +// +// Created by Clement on 7/29/15. +// Copyright 2015 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 +// + +#ifndef hifi_ConnectionStats_h +#define hifi_ConnectionStats_h + +#include + +namespace udt { + +class ConnectionStats { +public: + struct Stats { + std::chrono::microseconds startTime; + std::chrono::microseconds endTime; + + // Control Packet stat collection + int sentACKs { 0 }; + int receivedACKs { 0 }; + int sentLightACKs { 0 }; + int receivedLightACKs { 0 }; + int sentACK2s { 0 }; + int receivedACK2s { 0 }; + int sentNAKs { 0 }; + int receivedNAKs { 0 }; + int sentTimeoutNAKs { 0 }; + int receivedTimeoutNAKs { 0 }; + + int sentPackets { 0 }; + int recievedPackets { 0 }; + }; + + ConnectionStats(); + + Stats sample(); + Stats getTotalStats(); + + void recordSentACK(); + void recordReceivedACK(); + void recordSentLightACK(); + void recordReceivedLightACK(); + void recordSentACK2(); + void recordReceivedACK2(); + void recordSentNAK(); + void recordReceivedNAK(); + void recordSentTimeoutNAK(); + void recordReceivedTimeoutNAK(); + + void recordSentPackets(); + void recordReceivedPackets(); + +private: + Stats _currentSample; + Stats _total; +}; + +} + +#endif // hifi_ConnectionStats_h \ No newline at end of file From 5236abe561992296aa0b1c47d86e0645d5edc562 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 29 Jul 2015 15:18:42 -0700 Subject: [PATCH 156/549] Connetion record stats/factored send for control packets --- libraries/networking/src/udt/Connection.cpp | 140 +++++++++++--------- libraries/networking/src/udt/Connection.h | 18 +-- 2 files changed, 84 insertions(+), 74 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 146714df10..46915ce229 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -65,30 +65,12 @@ void Connection::sync() { auto now = high_resolution_clock::now(); if (duration_cast(now - _lastNAKTime).count() >= _nakInterval) { - // construct a NAK packet that will hold all of the lost sequence numbers - auto lossListPacket = ControlPacket::create(ControlPacket::TimeoutNAK, _lossList.getLength() * sizeof(SequenceNumber)); - - // Pack in the lost sequence numbers - _lossList.write(*lossListPacket); - - // have our SendQueue send off this control packet - _sendQueue->sendPacket(*lossListPacket); - - // record this as the last NAK time - _lastNAKTime = high_resolution_clock::now(); - - ++_totalSentTimeoutNAKs; + // Send a timeout NAK packet + sendTimeoutNAK(); } } void Connection::sendACK(bool wasCausedBySyncTimeout) { - static const int ACK_PACKET_PAYLOAD_BYTES = sizeof(_lastSentACK) + sizeof(_currentACKSubSequenceNumber) - + sizeof(_rtt) + sizeof(int32_t) + sizeof(int32_t); - - // setup the ACK packet, make it static so we can re-use it - static auto ackPacket = ControlPacket::create(ControlPacket::ACK, ACK_PACKET_PAYLOAD_BYTES); - ackPacket->reset(); // We need to reset it every time. - auto currentTime = high_resolution_clock::now(); static high_resolution_clock::time_point lastACKSendTime; @@ -117,6 +99,12 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { } } + // setup the ACK packet, make it static so we can re-use it + static const int ACK_PACKET_PAYLOAD_BYTES = sizeof(_lastSentACK) + sizeof(_currentACKSubSequenceNumber) + + sizeof(_rtt) + sizeof(int32_t) + sizeof(int32_t); + static auto ackPacket = ControlPacket::create(ControlPacket::ACK, ACK_PACKET_PAYLOAD_BYTES); + ackPacket->reset(); // We need to reset it every time. + // pack in the ACK sub-sequence number ackPacket->writePrimitive(_currentACKSubSequenceNumber++); @@ -146,14 +134,10 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { // reset the number of data packets received since last ACK _packetsSinceACK = 0; - ++_totalSentACKs; + _stats.recordSentACK(); } void Connection::sendLightACK() { - // create the light ACK packet, make it static so we can re-use it - static const int LIGHT_ACK_PACKET_PAYLOAD_BYTES = sizeof(SequenceNumber); - static auto lightACKPacket = ControlPacket::create(ControlPacket::ACK, LIGHT_ACK_PACKET_PAYLOAD_BYTES); - SequenceNumber nextACKNumber = nextACK(); if (nextACKNumber == _lastReceivedAcknowledgedACK) { @@ -161,6 +145,10 @@ void Connection::sendLightACK() { return; } + // create the light ACK packet, make it static so we can re-use it + static const int LIGHT_ACK_PACKET_PAYLOAD_BYTES = sizeof(SequenceNumber); + static auto lightACKPacket = ControlPacket::create(ControlPacket::ACK, LIGHT_ACK_PACKET_PAYLOAD_BYTES); + // reset the lightACKPacket before we go to write the ACK to it lightACKPacket->reset(); @@ -170,7 +158,62 @@ void Connection::sendLightACK() { // have the send queue send off our packet immediately _sendQueue->sendPacket(*lightACKPacket); - ++_totalSentLightACKs; + _stats.recordSentLightACK(); +} + +void Connection::sendACK2(SequenceNumber currentACKSubSequenceNumber) { + // setup a static ACK2 packet we will re-use + static const int ACK2_PAYLOAD_BYTES = sizeof(SequenceNumber); + static auto ack2Packet = ControlPacket::create(ControlPacket::ACK2, ACK2_PAYLOAD_BYTES); + + // reset the ACK2 Packet before writing the sub-sequence number to it + ack2Packet->reset(); + + // write the sub sequence number for this ACK2 + ack2Packet->writePrimitive(currentACKSubSequenceNumber); + + // update the last sent ACK2 and the last ACK2 send time + _lastSentACK2 = currentACKSubSequenceNumber; + + _stats.recordSentACK2(); +} + +void Connection::sendNAK(SequenceNumber sequenceNumberRecieved) { + // create the loss report packet, make it static so we can re-use it + static const int NAK_PACKET_PAYLOAD_BYTES = 2 * sizeof(SequenceNumber); + static auto lossReport = ControlPacket::create(ControlPacket::NAK, NAK_PACKET_PAYLOAD_BYTES); + lossReport->reset(); // We need to reset it every time. + + // pack in the loss report + lossReport->writePrimitive(_lastReceivedSequenceNumber + 1); + if (_lastReceivedSequenceNumber + 1 != sequenceNumberRecieved - 1) { + lossReport->writePrimitive(sequenceNumberRecieved - 1); + } + + // have the send queue send off our packet immediately + _sendQueue->sendPacket(*lossReport); + + // record our last NAK time + _lastNAKTime = high_resolution_clock::now(); + + _stats.recordSentNAK(); +} + +void Connection::sendTimeoutNAK() { + // construct a NAK packet that will hold all of the lost sequence numbers + // TODO size is wrong, fix it. + auto lossListPacket = ControlPacket::create(ControlPacket::TimeoutNAK, _lossList.getLength() * sizeof(SequenceNumber)); + + // Pack in the lost sequence numbers + _lossList.write(*lossListPacket); + + // have our SendQueue send off this control packet + _sendQueue->sendPacket(*lossListPacket); + + // record this as the last NAK time + _lastNAKTime = high_resolution_clock::now(); + + _stats.recordSentTimeoutNAK(); } SequenceNumber Connection::nextACK() const { @@ -200,24 +243,8 @@ void Connection::processReceivedSequenceNumber(SequenceNumber seq) { _lossList.append(_lastReceivedSequenceNumber + 1, seq - 1); } - // create the loss report packet, make it static so we can re-use it - static const int NAK_PACKET_PAYLOAD_BYTES = 2 * sizeof(SequenceNumber); - static auto lossReport = ControlPacket::create(ControlPacket::NAK, NAK_PACKET_PAYLOAD_BYTES); - lossReport->reset(); // We need to reset it every time. - - // pack in the loss report - lossReport->writePrimitive(_lastReceivedSequenceNumber + 1); - if (_lastReceivedSequenceNumber + 1 != seq - 1) { - lossReport->writePrimitive(seq - 1); - } - - // have the send queue send off our packet immediately - _sendQueue->sendPacket(*lossReport); - - // record our last NAK time - _lastNAKTime = high_resolution_clock::now(); - - ++_totalSentNAKs; + // Send a NAK packet + sendNAK(seq); // figure out when we should send the next loss report, if we haven't heard anything back _nakInterval = (_rtt + 4 * _rttVariance); @@ -288,21 +315,10 @@ void Connection::processACK(std::unique_ptr controlPacket) { microseconds sinceLastACK2 = duration_cast(currentTime - lastACK2SendTime); if (sinceLastACK2.count() > _synInterval || currentACKSubSequenceNumber == _lastSentACK2) { - // setup a static ACK2 packet we will re-use - static const int ACK2_PAYLOAD_BYTES = sizeof(SequenceNumber); - static auto ack2Packet = ControlPacket::create(ControlPacket::ACK2, ACK2_PAYLOAD_BYTES); + // Send ACK2 packet + sendACK2(currentACKSubSequenceNumber); - // reset the ACK2 Packet before writing the sub-sequence number to it - ack2Packet->reset(); - - // write the sub sequence number for this ACK2 - ack2Packet->writePrimitive(currentACKSubSequenceNumber); - - // update the last sent ACK2 and the last ACK2 send time - _lastSentACK2 = currentACKSubSequenceNumber; lastACK2SendTime = high_resolution_clock::now(); - - ++_totalSentACK2s; } // read the ACKed sequence number @@ -368,7 +384,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); // update the total count of received ACKs - ++_totalReceivedACKs; + _stats.recordReceivedACK(); } void Connection::processLightACK(std::unique_ptr controlPacket) { @@ -385,7 +401,7 @@ void Connection::processLightACK(std::unique_ptr controlPacket) { _lastReceivedACK = ack; } - ++_totalReceivedLightACKs; + _stats.recordReceivedLightACK(); } void Connection::processACK2(std::unique_ptr controlPacket) { @@ -414,7 +430,7 @@ void Connection::processACK2(std::unique_ptr controlPacket) { } } - ++_totalReceivedACK2s; + _stats.recordReceivedACK2(); } void Connection::processNAK(std::unique_ptr controlPacket) { @@ -436,7 +452,7 @@ void Connection::processNAK(std::unique_ptr controlPacket) { _congestionControl->onLoss(start, end); _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); - ++_totalReceivedNAKs; + _stats.recordReceivedNAK(); } void Connection::processTimeoutNAK(std::unique_ptr controlPacket) { @@ -446,7 +462,7 @@ void Connection::processTimeoutNAK(std::unique_ptr controlPacket) // we don't tell the congestion control object there was loss here - this matches UDTs implementation // a possible improvement would be to tell it which new loss this timeout packet told us about - ++_totalReceivedTimeoutNAKs; + _stats.recordReceivedTimeoutNAK(); } void Connection::updateRTT(int rtt) { diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index b42ef0d8ea..c5ff009fc9 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -15,6 +15,7 @@ #include #include +#include "ConnectionStats.h" #include "LossList.h" #include "PacketTimeWindow.h" #include "SendQueue.h" @@ -50,6 +51,9 @@ public: private: void sendACK(bool wasCausedBySyncTimeout = true); void sendLightACK(); + void sendACK2(SequenceNumber currentACKSubSequenceNumber); + void sendNAK(SequenceNumber sequenceNumberRecieved); + void sendTimeoutNAK(); void processACK(std::unique_ptr controlPacket); void processLightACK(std::unique_ptr controlPacket); @@ -95,21 +99,11 @@ private: std::unique_ptr _congestionControl; - // Control Packet stat collection - int _totalReceivedACKs { 0 }; - int _totalSentACKs { 0 }; - int _totalSentLightACKs { 0 }; - int _totalReceivedLightACKs { 0 }; - int _totalReceivedACK2s { 0 }; - int _totalSentACK2s { 0 }; - int _totalReceivedNAKs { 0 }; - int _totalSentNAKs { 0 }; - int _totalReceivedTimeoutNAKs { 0 }; - int _totalSentTimeoutNAKs { 0 }; - // Data packet stat collection int _totalReceivedDataPackets { 0 }; int _packetsSinceACK { 0 }; // The number of packets that have been received during the current ACK interval + + ConnectionStats _stats; }; } From 55555cf13e10579b800a7e26f1849ae9659b843c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 15:28:20 -0700 Subject: [PATCH 157/549] setup default for RTT, RTT variance, _synInterval --- libraries/networking/src/udt/CongestionControl.cpp | 2 +- libraries/networking/src/udt/Connection.cpp | 8 +++++++- libraries/networking/src/udt/Connection.h | 5 +++-- libraries/networking/src/udt/Constants.h | 4 +++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 06b63ec60e..1450e60930 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -20,7 +20,7 @@ static const double USECS_PER_SECOND = 1000000.0; void DefaultCC::init() { _lastRCTime = high_resolution_clock::now(); - _mss = udt::MAX_PACKET_SIZE; + _mss = udt::MAX_PACKET_SIZE_WITH_UDP_HEADER; _slowStartLastAck = _sendCurrSeqNum; _lastDecreaseMaxSeq = SequenceNumber { SequenceNumber::MAX }; diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 146714df10..39e4254895 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -30,6 +30,10 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination, unique_pt _destination(destination), _congestionControl(move(congestionControl)) { + // setup default SYN, RTT and RTT Variance based on the SYN interval in CongestionControl object + _synInterval = _congestionControl->synInterval(); + _rtt = _synInterval * 10; + _rttVariance = _rtt / 2; } Connection::~Connection() { @@ -126,7 +130,9 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { // pack in the RTT and variance ackPacket->writePrimitive(_rtt); - // pack the available buffer size - must be a minimum of 2 + // pack the available buffer size, in packets + // in our implementation we have no hard limit on receive buffer size, send the default value + ackPacket->writePrimitive((int32_t) udt::CONNECTION_RECEIVE_BUFFER_SIZE_PACKETS); if (wasCausedBySyncTimeout) { // pack in the receive speed and estimatedBandwidth diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index b42ef0d8ea..d957339b9f 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -15,6 +15,7 @@ #include #include +#include "Constants.h" #include "LossList.h" #include "PacketTimeWindow.h" #include "SendQueue.h" @@ -61,7 +62,7 @@ private: int estimatedTimeout() const; - int _synInterval; // Periodical Rate Control Interval, in microseconds, defaults to 10ms + int _synInterval; // Periodical Rate Control Interval, in microseconds int _nakInterval; // NAK timeout interval, in microseconds int _minNAKInterval { 100000 }; // NAK timeout interval lower bound, default of 100ms @@ -79,7 +80,7 @@ private: int32_t _rtt; // RTT, in microseconds int32_t _rttVariance; // RTT variance - int _flowWindowSize; // Flow control window size + int _flowWindowSize { udt::MAX_PACKETS_IN_FLIGHT }; // Flow control window size int _bandwidth { 1 }; // Exponential moving average for estimated bandwidth, in packets per second int _deliveryRate { 16 }; // Exponential moving average for receiver's receive rate, in packets per second diff --git a/libraries/networking/src/udt/Constants.h b/libraries/networking/src/udt/Constants.h index 5c5ba392a1..e8a7658bf9 100644 --- a/libraries/networking/src/udt/Constants.h +++ b/libraries/networking/src/udt/Constants.h @@ -15,12 +15,14 @@ #define hifi_udt_Constants_h namespace udt { - static const int MAX_PACKET_SIZE = 1450; + static const int MAX_PACKET_SIZE_WITH_UDP_HEADER = 1500; + static const int MAX_PACKET_SIZE = MAX_PACKET_SIZE_WITH_UDP_HEADER - 28; static const int MAX_PACKETS_IN_FLIGHT = 25600; static const int CONNECTION_RECEIVE_BUFFER_SIZE_PACKETS = 8192; static const int CONNECTION_SEND_BUFFER_SIZE_PACKETS = 8192; static const int UDP_SEND_BUFFER_SIZE_BYTES = 1048576; static const int UDP_RECEIVE_BUFFER_SIZE_BYTES = 1048576; + static const int DEFAULT_SYN_INTERVAL_USECS = 10 * 1000; } #endif // hifi_udt_Constants_h From 785d14f8352fb625a235959271cc72c19decd433 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 29 Jul 2015 15:43:44 -0700 Subject: [PATCH 158/549] Cleanup sendACK --- libraries/networking/src/udt/Connection.cpp | 36 ++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 46915ce229..bce650b85a 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -63,7 +63,7 @@ void Connection::sync() { // check if we need to re-transmit a loss list // we do this if it has been longer than the current nakInterval since we last sent auto now = high_resolution_clock::now(); - + if (duration_cast(now - _lastNAKTime).count() >= _nakInterval) { // Send a timeout NAK packet sendTimeoutNAK(); @@ -71,26 +71,19 @@ void Connection::sync() { } void Connection::sendACK(bool wasCausedBySyncTimeout) { - auto currentTime = high_resolution_clock::now(); static high_resolution_clock::time_point lastACKSendTime; + auto currentTime = high_resolution_clock::now(); SequenceNumber nextACKNumber = nextACK(); + Q_ASSERT_X(nextACKNumber < _lastSentACK, "Connection::sendACK", "Sending lower ACK, something is wrong"); - if (nextACKNumber <= _lastReceivedAcknowledgedACK) { - // we already got an ACK2 for this ACK we would be sending, don't bother - return; - } - - if (nextACKNumber >= _lastSentACK) { - // we have received new packets since the last sent ACK - - // update the last sent ACK - _lastSentACK = nextACKNumber; - - // remove the ACKed packets from the receive queue - - } else if (nextACKNumber == _lastSentACK) { + if (nextACKNumber == _lastSentACK) { // We already sent this ACK, but check if we should re-send it. + if (nextACKNumber <= _lastReceivedAcknowledgedACK) { + // we already got an ACK2 for this ACK we would be sending, don't bother + return; + } + // We will re-send if it has been more than the estimated timeout since the last ACK microseconds sinceLastACK = duration_cast(currentTime - lastACKSendTime); @@ -98,6 +91,13 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { return; } } + // we have received new packets since the last sent ACK + + // update the last sent ACK + _lastSentACK = nextACKNumber; + + // remove the ACKed packets from the receive queue + // TODO? // setup the ACK packet, make it static so we can re-use it static const int ACK_PACKET_PAYLOAD_BYTES = sizeof(_lastSentACK) + sizeof(_currentACKSubSequenceNumber) @@ -129,7 +129,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { _sendQueue->sendPacket(*ackPacket); // write this ACK to the map of sent ACKs - _sentACKs[_currentACKSubSequenceNumber] = { nextACKNumber, high_resolution_clock::now() }; + _sentACKs[_currentACKSubSequenceNumber] = { nextACKNumber, currentTime }; // reset the number of data packets received since last ACK _packetsSinceACK = 0; @@ -218,7 +218,7 @@ void Connection::sendTimeoutNAK() { SequenceNumber Connection::nextACK() const { if (_lossList.getLength() > 0) { - return _lossList.getFirstSequenceNumber(); + return _lossList.getFirstSequenceNumber() - 1; } else { return _lastReceivedSequenceNumber; } From 4907418587cedb26ce30942f316d4bc231642328 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 15:53:44 -0700 Subject: [PATCH 159/549] update the flow window size for the send queue --- libraries/networking/src/udt/Connection.cpp | 14 +++- libraries/networking/src/udt/SendQueue.cpp | 84 +++++++++++---------- libraries/networking/src/udt/SendQueue.h | 9 ++- 3 files changed, 63 insertions(+), 44 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 39e4254895..6e4080f4f2 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -368,10 +368,15 @@ void Connection::processACK(std::unique_ptr controlPacket) { _congestionControl->setBandwidth(_bandwidth); } - // fire the onACK callback for congestion control + // update the last sent sequence number in congestion control _congestionControl->setSendCurrentSequenceNumber(_sendQueue->getCurrentSequenceNumber()); + + // fire the onACK callback for congestion control _congestionControl->onAck(ack); + + // now that we've updated the congestion control, update the packet send period and flow window size _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); + _sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); // update the total count of received ACKs ++_totalReceivedACKs; @@ -437,10 +442,15 @@ void Connection::processNAK(std::unique_ptr controlPacket) { // send that off to the send queue so it knows there was loss _sendQueue->nak(start, end); - // Tell the congestion control object that there was loss + // update the last sent sequence number in congestion control _congestionControl->setSendCurrentSequenceNumber(_sendQueue->getCurrentSequenceNumber()); + + // give the loss to the congestion control object _congestionControl->onLoss(start, end); + + // now that we've updated the congestion control, update the packet send period and flow window size _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); + _sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); ++_totalReceivedNAKs; } diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index ce1ce41d13..df8260b4f5 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -80,13 +80,13 @@ void SendQueue::sendPacket(const BasePacket& packet) { } void SendQueue::ack(SequenceNumber ack) { - if (_lastAck == ack) { + if (_lastACKSequenceNumber == (uint32_t) ack) { return; } { // remove any ACKed packets from the map of sent packets QWriteLocker locker(&_sentLock); - for (auto seq = _lastAck; seq <= ack; ++seq) { + for (auto seq = SequenceNumber { (uint32_t) _lastACKSequenceNumber }; seq <= ack; ++seq) { _sentPackets.erase(seq); } } @@ -96,7 +96,7 @@ void SendQueue::ack(SequenceNumber ack) { _naks.remove(_naks.getFirstSequenceNumber(), ack); } - _lastAck = ack; + _lastACKSequenceNumber = (uint32_t) ack; } void SendQueue::nak(SequenceNumber start, SequenceNumber end) { @@ -131,48 +131,52 @@ void SendQueue::loop() { // Record timing _lastSendTimestamp = high_resolution_clock::now(); - if (_nextPacket) { + // we're only allowed to send if the flow window size + // is greater than or equal to the gap between the last ACKed sent and the one we are about to send + if (seqlen(SequenceNumber { (uint32_t) _lastACKSequenceNumber }, _currentSequenceNumber + 1) <= _flowWindowSize) { + bool hasResend = false; + SequenceNumber seqNum; + { + // Check nak list for packet to resend + QWriteLocker locker(&_naksLock); + if (_naks.getLength() > 0) { + hasResend = true; + seqNum = _naks.popFirstSequenceNumber(); + } + } + + std::unique_ptr nextPacket; + + // Find packet in sent list using SequenceNumber + if (hasResend) { + QWriteLocker locker(&_sentLock); + auto it = _sentPackets.find(seqNum); + Q_ASSERT_X(it != _sentPackets.end(), + "SendQueue::sendNextPacket()", "Couldn't find NAKed packet to resend"); + + if (it != _sentPackets.end()) { + it->second.swap(nextPacket); + _sentPackets.erase(it); + } + } + + // If there is no packet to resend, grab the next one in the list + if (!nextPacket) { + QWriteLocker locker(&_packetsLock); + nextPacket.swap(_packets.front()); + _packets.pop_front(); + } + // Write packet's sequence number and send it off - _nextPacket->writeSequenceNumber(getNextSequenceNumber()); - sendPacket(*_nextPacket); + nextPacket->writeSequenceNumber(getNextSequenceNumber()); + sendPacket(*nextPacket); // Insert the packet we have just sent in the sent list QWriteLocker locker(&_sentLock); - _sentPackets[_nextPacket->getSequenceNumber()].swap(_nextPacket); - Q_ASSERT_X(!_nextPacket, + _sentPackets[nextPacket->getSequenceNumber()].swap(nextPacket); + Q_ASSERT_X(!nextPacket, "SendQueue::sendNextPacket()", "Overriden packet in sent list"); - } - - bool hasResend = false; - SequenceNumber seqNum; - { - // Check nak list for packet to resend - QWriteLocker locker(&_naksLock); - if (_naks.getLength() > 0) { - hasResend = true; - seqNum = _naks.popFirstSequenceNumber(); - } - } - - // Find packet in sent list using SequenceNumber - if (hasResend) { - QWriteLocker locker(&_sentLock); - auto it = _sentPackets.find(seqNum); - Q_ASSERT_X(it != _sentPackets.end(), - "SendQueue::sendNextPacket()", "Couldn't find NAKed packet to resend"); - - if (it != _sentPackets.end()) { - it->second.swap(_nextPacket); - _sentPackets.erase(it); - } - } - - // If there is no packet to resend, grab the next one in the list - if (!_nextPacket) { - QWriteLocker locker(&_packetsLock); - _nextPacket.swap(_packets.front()); - _packets.pop_front(); - } + } // since we're a while loop, give the thread a chance to process events QCoreApplication::processEvents(); diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 4437565ded..0b3919a25b 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -22,6 +22,7 @@ #include "../HifiSockAddr.h" +#include "Constants.h" #include "SequenceNumber.h" #include "LossList.h" @@ -45,6 +46,8 @@ public: SequenceNumber getCurrentSequenceNumber() const { return SequenceNumber(_atomicCurrentSequenceNumber); } + void setFlowWindowSize(int flowWindowSize) { _flowWindowSize = flowWindowSize; } + int getPacketSendPeriod() const { return _packetSendPeriod; } void setPacketSendPeriod(int newPeriod) { _packetSendPeriod = newPeriod; } @@ -74,11 +77,11 @@ private: mutable QReadWriteLock _packetsLock; // Protects the packets to be sent list. std::list> _packets; // List of packets to be sent - std::unique_ptr _nextPacket; // Next packet to be sent Socket* _socket { nullptr }; // Socket to send packet on HifiSockAddr _destination; // Destination addr - SequenceNumber _lastAck; // Last ACKed sequence number + + std::atomic _lastACKSequenceNumber; // Last ACKed sequence number SequenceNumber _currentSequenceNumber; // Last sequence number sent out std::atomic _atomicCurrentSequenceNumber; // Atomic for last sequence number sent out @@ -87,6 +90,8 @@ private: std::chrono::high_resolution_clock::time_point _lastSendTimestamp; // Record last time of packet departure std::atomic _isRunning { false }; + std::atomic _flowWindowSize { udt::MAX_PACKETS_IN_FLIGHT }; // Flow control window size (number of packets that can be on wire) + mutable QReadWriteLock _naksLock; // Protects the naks list. LossList _naks; // Sequence numbers of packets to resend From f7f7ff385fbc551a931a1a713779be389f704b4e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 29 Jul 2015 16:04:13 -0700 Subject: [PATCH 160/549] Code cleanup --- libraries/networking/src/udt/Connection.cpp | 27 ++++++++++----------- libraries/networking/src/udt/Connection.h | 3 --- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index de675bfca8..07c3f1a143 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -334,6 +334,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { // validate that this isn't a BS ACK if (ack > _sendQueue->getCurrentSequenceNumber()) { // in UDT they specifically break the connection here - do we want to do anything? + Q_ASSERT_X(true, "Connection::processACK", "ACK recieved higher than largest sent sequence number"); return; } @@ -341,26 +342,24 @@ void Connection::processACK(std::unique_ptr controlPacket) { int32_t rtt; controlPacket->readPrimitive(&rtt); - // read the desired flow window size - int flowWindowSize; - controlPacket->readPrimitive(&flowWindowSize); - - if (ack <= _lastReceivedACK) { - // this is a valid ACKed sequence number - update the flow window size and the last received ACK - _flowWindowSize = flowWindowSize; - _lastReceivedACK = ack; - } - - // make sure this isn't a repeated ACK - if (ack <= SequenceNumber(_atomicLastReceivedACK)) { + if (ack < _lastReceivedACK) { + // Bail return; } + // this is a valid ACKed sequence number - update the flow window size and the last received ACK + controlPacket->readPrimitive(&_flowWindowSize); + + if (ack == _lastReceivedACK) { + // Bail + return; + } + + _lastReceivedACK = ack; + // ACK the send queue so it knows what was received _sendQueue->ack(ack); - // update the atomic for last received ACK, the send queue uses this to re-transmit - _atomicLastReceivedACK = (SequenceNumber::Type)_lastReceivedACK; // update the RTT updateRTT(rtt); diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 2af89000e6..1ce81734b2 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -44,8 +44,6 @@ public: SequenceNumber nextACK() const; - SequenceNumber getLastReceivedACK() const { return SequenceNumber(_atomicLastReceivedACK); } - void processReceivedSequenceNumber(SequenceNumber seq); void processControl(std::unique_ptr controlPacket); @@ -75,7 +73,6 @@ private: LossList _lossList; // List of all missing packets SequenceNumber _lastReceivedSequenceNumber { SequenceNumber::MAX }; // The largest sequence number received from the peer SequenceNumber _lastReceivedACK { SequenceNumber::MAX }; // The last ACK received - std::atomic _atomicLastReceivedACK { (uint32_t) SequenceNumber::MAX }; // Atomic for thread-safe get of last ACK received SequenceNumber _lastReceivedAcknowledgedACK { SequenceNumber::MAX }; // The last sent ACK that has been acknowledged via an ACK2 from the peer SequenceNumber _currentACKSubSequenceNumber; // The current ACK sub-sequence number (used for Acknowledgment of ACKs) From 5fc3e7dbf1b19a3ef518d564b29a30b411807d0c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 16:12:00 -0700 Subject: [PATCH 161/549] add an updater that takes a lambda for CC update --- libraries/networking/src/udt/Connection.cpp | 38 +++++++++++---------- libraries/networking/src/udt/Connection.h | 2 ++ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 935622f4d8..626833c5c5 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -383,15 +383,10 @@ void Connection::processACK(std::unique_ptr controlPacket) { _congestionControl->setBandwidth(_bandwidth); } - // update the last sent sequence number in congestion control - _congestionControl->setSendCurrentSequenceNumber(_sendQueue->getCurrentSequenceNumber()); - - // fire the onACK callback for congestion control - _congestionControl->onAck(ack); - - // now that we've updated the congestion control, update the packet send period and flow window size - _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); - _sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); + // give this ACK to the congestion control and update the send queue parameters + updateCongestionControlAndSentQueue([this, ack](){ + _congestionControl->onAck(ack); + }); // update the total count of received ACKs _stats.recordReceivedACK(); @@ -457,15 +452,10 @@ void Connection::processNAK(std::unique_ptr controlPacket) { // send that off to the send queue so it knows there was loss _sendQueue->nak(start, end); - // update the last sent sequence number in congestion control - _congestionControl->setSendCurrentSequenceNumber(_sendQueue->getCurrentSequenceNumber()); - - // give the loss to the congestion control object - _congestionControl->onLoss(start, end); - - // now that we've updated the congestion control, update the packet send period and flow window size - _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); - _sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); + // give the loss to the congestion control object and update the send queue parameters + updateCongestionControlAndSentQueue([this, start, end](){ + _congestionControl->onLoss(start, end); + }); _stats.recordReceivedNAK(); } @@ -503,3 +493,15 @@ void Connection::updateRTT(int rtt) { int Connection::estimatedTimeout() const { return _congestionControl->_userDefinedRto ? _rtt + _rttVariance * 4 : _congestionControl->_rto; } + +void Connection::updateCongestionControlAndSentQueue(std::function congestionCallback) { + // update the last sent sequence number in congestion control + _congestionControl->setSendCurrentSequenceNumber(_sendQueue->getCurrentSequenceNumber()); + + // fire congestion control callback + congestionCallback(); + + // now that we've update the congestion control, update the packet send period and flow window size + _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); + _sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); +} diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 1ce81734b2..b46d2c37cf 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -64,6 +64,8 @@ private: int estimatedTimeout() const; + void updateCongestionControlAndSentQueue(std::function congestionCallback); + int _synInterval; // Periodical Rate Control Interval, in microseconds int _nakInterval; // NAK timeout interval, in microseconds From 35f00f9ba1388f362d2c21e4bfe2e7407cfdc23a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 16:12:50 -0700 Subject: [PATCH 162/549] rename the CC and send queue updater --- libraries/networking/src/udt/Connection.cpp | 6 +++--- libraries/networking/src/udt/Connection.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 626833c5c5..ec175d8f39 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -384,7 +384,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { } // give this ACK to the congestion control and update the send queue parameters - updateCongestionControlAndSentQueue([this, ack](){ + updateCongestionControlAndSendQueue([this, ack](){ _congestionControl->onAck(ack); }); @@ -453,7 +453,7 @@ void Connection::processNAK(std::unique_ptr controlPacket) { _sendQueue->nak(start, end); // give the loss to the congestion control object and update the send queue parameters - updateCongestionControlAndSentQueue([this, start, end](){ + updateCongestionControlAndSendQueue([this, start, end](){ _congestionControl->onLoss(start, end); }); @@ -494,7 +494,7 @@ int Connection::estimatedTimeout() const { return _congestionControl->_userDefinedRto ? _rtt + _rttVariance * 4 : _congestionControl->_rto; } -void Connection::updateCongestionControlAndSentQueue(std::function congestionCallback) { +void Connection::updateCongestionControlAndSendQueue(std::function congestionCallback) { // update the last sent sequence number in congestion control _congestionControl->setSendCurrentSequenceNumber(_sendQueue->getCurrentSequenceNumber()); diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index b46d2c37cf..eaa55797d9 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -64,7 +64,7 @@ private: int estimatedTimeout() const; - void updateCongestionControlAndSentQueue(std::function congestionCallback); + void updateCongestionControlAndSendQueue(std::function congestionCallback); int _synInterval; // Periodical Rate Control Interval, in microseconds From ce1fc4baa9f7863020d6c5f5c3103d78bd9c41f5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 29 Jul 2015 16:24:58 -0700 Subject: [PATCH 163/549] Send light acks based on CC member --- libraries/networking/src/udt/CongestionControl.h | 1 + libraries/networking/src/udt/Connection.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index 75590d88b5..f8f4860a89 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -68,6 +68,7 @@ private: CongestionControl& operator=(const CongestionControl& other) = delete; int _ackInterval { 0 }; // How many packets to send one ACK, in packets + int _lightACKInterval { 64 }; // How many packets to send one light ACK, in packets int _synInterval { DEFAULT_SYN_INTERVAL }; diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 935622f4d8..2051ca9627 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -282,6 +282,8 @@ void Connection::processReceivedSequenceNumber(SequenceNumber seq) { // check if we need to send an ACK, according to CC params if (_congestionControl->_ackInterval > 0 && _packetsSinceACK >= _congestionControl->_ackInterval) { sendACK(false); + } else if (_congestionControl->_lightACKInterval > 0 && _packetsSinceACK >= _congestionControl->_lightACKInterval) { + sendLightACK(); } } From 116ff17fcfcfc8482e80388c306dd1dc9e018248 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 29 Jul 2015 16:38:37 -0700 Subject: [PATCH 164/549] SendQueue auto thread cleanup --- libraries/networking/src/udt/Connection.cpp | 7 +------ libraries/networking/src/udt/Connection.h | 3 +-- libraries/networking/src/udt/SendQueue.cpp | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 9170017297..17c11100eb 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -38,14 +38,9 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination, unique_pt Connection::~Connection() { if (_sendQueue) { - // tell our send queue to stop and wait until its send thread is done - QThread* sendQueueThread = _sendQueue->thread(); - _sendQueue->stop(); _sendQueue->deleteLater(); - - sendQueueThread->quit(); - sendQueueThread->wait(); + _sendQueue.release(); } } diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index eaa55797d9..e68efd2887 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -42,8 +42,6 @@ public: void sync(); // rate control method, fired by Socket for all connections on SYN interval - SequenceNumber nextACK() const; - void processReceivedSequenceNumber(SequenceNumber seq); void processControl(std::unique_ptr controlPacket); @@ -60,6 +58,7 @@ private: void processNAK(std::unique_ptr controlPacket); void processTimeoutNAK(std::unique_ptr controlPacket); + SequenceNumber nextACK() const; void updateRTT(int rtt); int estimatedTimeout() const; diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index df8260b4f5..05d69dde6c 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -29,7 +29,7 @@ std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr dest) auto queue = std::unique_ptr(new SendQueue(socket, dest)); // Setup queue private thread - QThread* thread = new QThread(queue.get()); + QThread* thread = new QThread(); thread->setObjectName("Networking: SendQueue"); // Name thread for easier debug connect(queue.get(), &QObject::destroyed, thread, &QThread::quit); // Thread auto cleanup connect(thread, &QThread::finished, thread, &QThread::deleteLater); // Thread auto cleanup From 66c308b43682a1b8df364148c12bcc5c9a758a9c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 16:48:14 -0700 Subject: [PATCH 165/549] actually process control and sequence numbers from Socket --- libraries/networking/src/udt/BasePacket.h | 3 +- libraries/networking/src/udt/Connection.cpp | 26 +++++++----- libraries/networking/src/udt/Connection.h | 2 +- libraries/networking/src/udt/Constants.h | 3 ++ .../networking/src/udt/ControlPacket.cpp | 39 +++++++++++++++++- libraries/networking/src/udt/ControlPacket.h | 6 +++ libraries/networking/src/udt/LossList.cpp | 8 +++- libraries/networking/src/udt/LossList.h | 2 +- libraries/networking/src/udt/Packet.cpp | 1 - libraries/networking/src/udt/Socket.cpp | 41 +++++++++++++++---- 10 files changed, 106 insertions(+), 25 deletions(-) diff --git a/libraries/networking/src/udt/BasePacket.h b/libraries/networking/src/udt/BasePacket.h index 8dcc3ab9be..7ebf2d1e65 100644 --- a/libraries/networking/src/udt/BasePacket.h +++ b/libraries/networking/src/udt/BasePacket.h @@ -27,7 +27,8 @@ public: static const qint64 PACKET_WRITE_ERROR; static std::unique_ptr create(qint64 size = -1); - static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); + static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, + const HifiSockAddr& senderSockAddr); static qint64 maxPayloadSize() { return MAX_PACKET_SIZE; } // The maximum payload size this packet can use to fit in MTU static qint64 localHeaderSize() { return 0; } // Current level's header size diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index ec175d8f39..9867584e96 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -230,27 +230,27 @@ SequenceNumber Connection::nextACK() const { } } -void Connection::processReceivedSequenceNumber(SequenceNumber seq) { +bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber) { // check if this is a packet pair we should estimate bandwidth from, or just a regular packet - if (((uint32_t) seq & 0xF) == 0) { + if (((uint32_t) sequenceNumber & 0xF) == 0) { _receiveWindow.onProbePair1Arrival(); - } else if (((uint32_t) seq & 0xF) == 1) { + } else if (((uint32_t) sequenceNumber & 0xF) == 1) { _receiveWindow.onProbePair2Arrival(); } else { _receiveWindow.onPacketArrival(); } // If this is not the next sequence number, report loss - if (seq > _lastReceivedSequenceNumber + 1) { - if (_lastReceivedSequenceNumber + 1 == seq - 1) { + if (sequenceNumber > _lastReceivedSequenceNumber + 1) { + if (_lastReceivedSequenceNumber + 1 == sequenceNumber - 1) { _lossList.append(_lastReceivedSequenceNumber + 1); } else { - _lossList.append(_lastReceivedSequenceNumber + 1, seq - 1); + _lossList.append(_lastReceivedSequenceNumber + 1, sequenceNumber - 1); } // Send a NAK packet - sendNAK(seq); + sendNAK(sequenceNumber); // figure out when we should send the next loss report, if we haven't heard anything back _nakInterval = (_rtt + 4 * _rttVariance); @@ -267,12 +267,14 @@ void Connection::processReceivedSequenceNumber(SequenceNumber seq) { } } - if (seq > _lastReceivedSequenceNumber) { + bool wasDuplicate = false; + + if (sequenceNumber > _lastReceivedSequenceNumber) { // Update largest recieved sequence number - _lastReceivedSequenceNumber = seq; + _lastReceivedSequenceNumber = sequenceNumber; } else { - // Otherwise, it's a resend, remove it from the loss list - _lossList.remove(seq); + // Otherwise, it could be a resend, try and remove it from the loss list + wasDuplicate = !_lossList.remove(sequenceNumber); } // increment the counters for data packets received @@ -283,6 +285,8 @@ void Connection::processReceivedSequenceNumber(SequenceNumber seq) { if (_congestionControl->_ackInterval > 0 && _packetsSinceACK >= _congestionControl->_ackInterval) { sendACK(false); } + + return wasDuplicate; } void Connection::processControl(unique_ptr controlPacket) { diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index eaa55797d9..2e6d665e4f 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -44,7 +44,7 @@ public: SequenceNumber nextACK() const; - void processReceivedSequenceNumber(SequenceNumber seq); + bool processReceivedSequenceNumber(SequenceNumber sequenceNumber); // returns indicates if this packet was a duplicate void processControl(std::unique_ptr controlPacket); private: diff --git a/libraries/networking/src/udt/Constants.h b/libraries/networking/src/udt/Constants.h index e8a7658bf9..5e0f130f13 100644 --- a/libraries/networking/src/udt/Constants.h +++ b/libraries/networking/src/udt/Constants.h @@ -14,6 +14,8 @@ #ifndef hifi_udt_Constants_h #define hifi_udt_Constants_h +#include "SequenceNumber.h" + namespace udt { static const int MAX_PACKET_SIZE_WITH_UDP_HEADER = 1500; static const int MAX_PACKET_SIZE = MAX_PACKET_SIZE_WITH_UDP_HEADER - 28; @@ -23,6 +25,7 @@ namespace udt { static const int UDP_SEND_BUFFER_SIZE_BYTES = 1048576; static const int UDP_RECEIVE_BUFFER_SIZE_BYTES = 1048576; static const int DEFAULT_SYN_INTERVAL_USECS = 10 * 1000; + static const uint32_t CONTROL_BIT_MASK = 1 << (sizeof(SequenceNumber) - 1); } #endif // hifi_udt_Constants_h diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index 057f3633f9..2bc081e197 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -11,8 +11,26 @@ #include "ControlPacket.h" +#include "Constants.h" + using namespace udt; +std::unique_ptr ControlPacket::fromReceivedPacket(std::unique_ptr data, qint64 size, + const HifiSockAddr &senderSockAddr) { + // Fail with null data + Q_ASSERT(data); + + // Fail with invalid size + Q_ASSERT(size >= 0); + + // allocate memory + auto packet = std::unique_ptr(new ControlPacket(std::move(data), size, senderSockAddr)); + + packet->open(QIODevice::ReadOnly); + + return packet; +} + std::unique_ptr ControlPacket::create(Type type, qint64 size) { std::unique_ptr controlPacket; @@ -57,6 +75,17 @@ ControlPacket::ControlPacket(Type type, qint64 size) : writeControlBitAndType(); } +ControlPacket::ControlPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr) : + BasePacket(std::move(data), size, senderSockAddr) +{ + // sanity check before we decrease the payloadSize with the payloadCapacity + Q_ASSERT(_payloadSize == _payloadCapacity); + + adjustPayloadStartAndCapacity(_payloadSize > 0); + + readType(); +} + ControlPacket::ControlPacket(ControlPacket&& other) : BasePacket(std::move(other)) { @@ -71,8 +100,6 @@ ControlPacket& ControlPacket::operator=(ControlPacket&& other) { return *this; } -static const uint32_t CONTROL_BIT_MASK = 1 << (sizeof(ControlPacket::ControlBitAndType) - 1); - void ControlPacket::setType(udt::ControlPacket::Type type) { _type = type; @@ -94,3 +121,11 @@ void ControlPacket::writeType() { // write the type by OR'ing the new type with the current value & CONTROL_BIT_MASK *bitAndType = (*bitAndType & CONTROL_BIT_MASK) | (_type << sizeof((ControlPacket::Type) - 1)); } + +void ControlPacket::readType() { + ControlBitAndType bitAndType = *reinterpret_cast(_packet.get()); + + // read the type + uint32_t oversizeType = (uint32_t) (bitAndType & ~CONTROL_BIT_MASK); + _type = (Type) oversizeType; +} diff --git a/libraries/networking/src/udt/ControlPacket.h b/libraries/networking/src/udt/ControlPacket.h index fdd0b65e36..6d13c06d33 100644 --- a/libraries/networking/src/udt/ControlPacket.h +++ b/libraries/networking/src/udt/ControlPacket.h @@ -33,6 +33,8 @@ public: TimeoutNAK }; + static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, + const HifiSockAddr& senderSockAddr); static std::unique_ptr create(Type type, qint64 size = -1); static qint64 localHeaderSize(); // Current level's header size @@ -44,6 +46,7 @@ public: private: ControlPacket(Type type); ControlPacket(Type type, qint64 size); + ControlPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); ControlPacket(ControlPacket&& other); ControlPacket(const ControlPacket& other) = delete; @@ -54,6 +57,9 @@ private: void writeControlBitAndType(); void writeType(); + // Header readers + void readType(); + Type _type; }; diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp index 0bf08fbc1d..32812be10b 100644 --- a/libraries/networking/src/udt/LossList.cpp +++ b/libraries/networking/src/udt/LossList.cpp @@ -81,7 +81,7 @@ void LossList::insert(SequenceNumber start, SequenceNumber end) { } } -void LossList::remove(SequenceNumber seq) { +bool LossList::remove(SequenceNumber seq) { auto it = find_if(_lossList.begin(), _lossList.end(), [&seq](pair pair) { return pair.first <= seq && seq <= pair.second; }); @@ -99,6 +99,12 @@ void LossList::remove(SequenceNumber seq) { _lossList.insert(it, make_pair(seq + 1, temp)); } _length -= 1; + + // this sequence number was found in the loss list, return true + return true; + } else { + // this sequence number was not found in the loss list, return false + return false; } } diff --git a/libraries/networking/src/udt/LossList.h b/libraries/networking/src/udt/LossList.h index 5b5fb9f0c8..fc97206282 100644 --- a/libraries/networking/src/udt/LossList.h +++ b/libraries/networking/src/udt/LossList.h @@ -33,7 +33,7 @@ public: // Inserts anywhere - MUCH slower void insert(SequenceNumber start, SequenceNumber end); - void remove(SequenceNumber seq); + bool remove(SequenceNumber seq); void remove(SequenceNumber start, SequenceNumber end); int getLength() const { return _length; } diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 4223986aee..96cf5210b4 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -117,7 +117,6 @@ void Packet::writeSequenceNumber(SequenceNumber sequenceNumber) const { writeHeader(); } -static const uint32_t CONTROL_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 1); static const uint32_t RELIABILITY_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 2); static const uint32_t MESSAGE_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 3); static const uint32_t BIT_FIELD_MASK = CONTROL_BIT_MASK | RELIABILITY_BIT_MASK | MESSAGE_BIT_MASK; diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 650bdd7906..5ded97135b 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -135,14 +135,41 @@ void Socket::readPendingDatagrams() { return; } - // setup a Packet from the data we just read - auto packet = Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); + // check if this was a control packet or a data packet + bool isControlPacket = *buffer & CONTROL_BIT_MASK; - // call our verification operator to see if this packet is verified - if (!_packetFilterOperator || _packetFilterOperator(*packet)) { - if (_packetHandler) { - // call the verified packet callback to let it handle this packet - _packetHandler(std::move(packet)); + if (isControlPacket) { + // setup a control packet from the data we just read + auto controlPacket = ControlPacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); + + // move this control packet to the matching connection + auto it = _connectionsHash.find(senderSockAddr); + + if (it != _connectionsHash.end()) { + it->second->processControl(move(controlPacket)); + } + + } else { + // setup a Packet from the data we just read + auto packet = Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); + + // call our verification operator to see if this packet is verified + if (!_packetFilterOperator || _packetFilterOperator(*packet)) { + + if (packet->isReliable()) { + // if this was a reliable packet then signal the matching connection with the sequence number + // assuming it exists + auto it = _connectionsHash.find(senderSockAddr); + + if (it != _connectionsHash.end()) { + it->second->processReceivedSequenceNumber(packet->getSequenceNumber()); + } + } + + if (_packetHandler) { + // call the verified packet callback to let it handle this packet + _packetHandler(std::move(packet)); + } } } } From b8085086c65238a72f392366b1d2ffeeef04c828 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 29 Jul 2015 17:28:37 -0700 Subject: [PATCH 166/549] HifiSockAddr have object names --- assignment-client/src/AssignmentClient.cpp | 2 ++ libraries/networking/src/DomainHandler.cpp | 3 +++ libraries/networking/src/HifiSockAddr.cpp | 15 ++++++++++----- libraries/networking/src/NetworkPeer.cpp | 6 ++++++ libraries/networking/src/Node.cpp | 12 +++++++++++- libraries/networking/src/Node.h | 2 +- libraries/networking/src/udt/SendQueue.cpp | 2 +- libraries/networking/src/udt/Socket.cpp | 1 + libraries/networking/src/udt/Socket.h | 2 +- 9 files changed, 36 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 40aef1c707..6b7365fc01 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -95,6 +95,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri } _assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerPort, true); + _assignmentServerSocket.setObjectName("AssigmentServer"); nodeList->setAssignmentServerSocket(_assignmentServerSocket); qDebug() << "Assignment server socket is" << _assignmentServerSocket; @@ -119,6 +120,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri // did we get an assignment-client monitor port? if (assignmentMonitorPort > 0) { _assignmentClientMonitorSocket = HifiSockAddr(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME, assignmentMonitorPort); + _assignmentClientMonitorSocket.setObjectName("AssignmentClientMonitor"); qDebug() << "Assignment-client monitor socket is" << _assignmentClientMonitorSocket; diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index afb362053e..d38ae35826 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -37,6 +37,8 @@ DomainHandler::DomainHandler(QObject* parent) : _settingsObject(), _failedSettingsRequests(0) { + _sockAddr.setObjectName("DomainServer"); + // if we get a socket that make sure our NetworkPeer ping timer stops connect(this, &DomainHandler::completedSocketDiscovery, &_icePeer, &NetworkPeer::stopPingTimer); } @@ -145,6 +147,7 @@ void DomainHandler::setIceServerHostnameAndID(const QString& iceServerHostname, HifiSockAddr* replaceableSockAddr = &_iceServerSockAddr; replaceableSockAddr->~HifiSockAddr(); replaceableSockAddr = new (replaceableSockAddr) HifiSockAddr(iceServerHostname, ICE_SERVER_DEFAULT_PORT); + _iceServerSockAddr.setObjectName("IceServer"); auto nodeList = DependencyManager::get(); diff --git a/libraries/networking/src/HifiSockAddr.cpp b/libraries/networking/src/HifiSockAddr.cpp index 39210db81e..813d19d22c 100644 --- a/libraries/networking/src/HifiSockAddr.cpp +++ b/libraries/networking/src/HifiSockAddr.cpp @@ -33,16 +33,16 @@ HifiSockAddr::HifiSockAddr(const QHostAddress& address, quint16 port) : } HifiSockAddr::HifiSockAddr(const HifiSockAddr& otherSockAddr) : - QObject(), _address(otherSockAddr._address), _port(otherSockAddr._port) { - + setObjectName(otherSockAddr.objectName()); } HifiSockAddr& HifiSockAddr::operator=(const HifiSockAddr& rhsSockAddr) { - HifiSockAddr temp(rhsSockAddr); - swap(temp); + setObjectName(rhsSockAddr.objectName()); + _address = rhsSockAddr._address; + _port = rhsSockAddr._port; return *this; } @@ -76,9 +76,14 @@ HifiSockAddr::HifiSockAddr(const sockaddr* sockaddr) { void HifiSockAddr::swap(HifiSockAddr& otherSockAddr) { using std::swap; - + swap(_address, otherSockAddr._address); swap(_port, otherSockAddr._port); + + // Swap objects name + auto temp = otherSockAddr.objectName(); + otherSockAddr.setObjectName(objectName()); + setObjectName(temp); } bool HifiSockAddr::operator==(const HifiSockAddr& rhsSockAddr) const { diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index 52e53e9665..9e51bc5dac 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -57,7 +57,9 @@ void NetworkPeer::setPublicSocket(const HifiSockAddr& publicSocket) { bool wasOldSocketNull = _publicSocket.isNull(); + auto temp = _publicSocket.objectName(); _publicSocket = publicSocket; + _publicSocket.setObjectName(temp); if (!wasOldSocketNull) { qCDebug(networking) << "Public socket change for node" << *this; @@ -74,7 +76,9 @@ void NetworkPeer::setLocalSocket(const HifiSockAddr& localSocket) { bool wasOldSocketNull = _localSocket.isNull(); + auto temp = _localSocket.objectName(); _localSocket = localSocket; + _localSocket.setObjectName(temp); if (!wasOldSocketNull) { qCDebug(networking) << "Local socket change for node" << *this; @@ -91,7 +95,9 @@ void NetworkPeer::setSymmetricSocket(const HifiSockAddr& symmetricSocket) { bool wasOldSocketNull = _symmetricSocket.isNull(); + auto temp = _symmetricSocket.objectName(); _symmetricSocket = symmetricSocket; + _symmetricSocket.setObjectName(temp); if (!wasOldSocketNull) { qCDebug(networking) << "Symmetric socket change for node" << *this; diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 355aa6994e..6f10e6dbdb 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -55,13 +55,23 @@ Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, _canAdjustLocks(canAdjustLocks), _canRez(canRez) { - + // Update socket's object name + setType(_type); } Node::~Node() { delete _linkedData; } +void Node::setType(char type) { + _type = type; + + auto typeString = NodeType::getNodeTypeName(type); + _publicSocket.setObjectName(typeString); + _localSocket.setObjectName(typeString); + _symmetricSocket.setObjectName(typeString); +} + void Node::updateClockSkewUsec(int clockSkewSample) { _clockSkewMovingPercentile.updatePercentile((float)clockSkewSample); _clockSkewUsec = (int)_clockSkewMovingPercentile.getValueAtPercentile(); diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 53a2aced8c..573569f92b 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -40,7 +40,7 @@ public: bool operator!=(const Node& otherNode) const { return !(*this == otherNode); } char getType() const { return _type; } - void setType(char type) { _type = type; } + void setType(char type); const QUuid& getConnectionSecret() const { return _connectionSecret; } void setConnectionSecret(const QUuid& connectionSecret) { _connectionSecret = connectionSecret; } diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 05d69dde6c..9a2e371616 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -30,7 +30,7 @@ std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr dest) // Setup queue private thread QThread* thread = new QThread(); - thread->setObjectName("Networking: SendQueue"); // Name thread for easier debug + thread->setObjectName("Networking: SendQueue " + dest.objectName()); // Name thread for easier debug connect(queue.get(), &QObject::destroyed, thread, &QThread::quit); // Thread auto cleanup connect(thread, &QThread::finished, thread, &QThread::deleteLater); // Thread auto cleanup diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 650bdd7906..4c8b5a4329 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -14,6 +14,7 @@ #include #include "../NetworkLogging.h" +#include "Connection.h" #include "ControlPacket.h" #include "Packet.h" diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 0bc23cdf0a..1827dc8234 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -23,11 +23,11 @@ #include "../HifiSockAddr.h" #include "CongestionControl.h" -#include "Connection.h" namespace udt { class BasePacket; +class Connection; class ControlSender; class Packet; class SequenceNumber; From 7c87ee3a725c93dfc6484583854fc9610c8d0aa7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 17:37:33 -0700 Subject: [PATCH 167/549] type and version fixes after refactor --- libraries/networking/src/NLPacket.cpp | 12 ++++++------ libraries/networking/src/NodeList.cpp | 1 + libraries/networking/src/udt/BasePacket.cpp | 3 +-- libraries/networking/src/udt/BasePacket.h | 2 +- libraries/networking/src/udt/Constants.h | 3 ++- libraries/networking/src/udt/ControlPacket.cpp | 8 +++++--- libraries/networking/src/udt/Packet.cpp | 13 +++++++------ libraries/networking/src/udt/Socket.cpp | 3 +++ 8 files changed, 26 insertions(+), 19 deletions(-) diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 5359d6cf2c..4568561fa2 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -26,7 +26,7 @@ qint64 NLPacket::maxPayloadSize() const { } qint64 NLPacket::totalHeadersSize() const { - return localHeaderSize() + Packet::localHeaderSize(); + return Packet::totalHeadersSize() + localHeaderSize(); } qint64 NLPacket::localHeaderSize() const { @@ -84,7 +84,7 @@ NLPacket::NLPacket(PacketType type, bool isReliable, bool isPartOfMessage) : _type(type), _version(versionForPacketType(type)) { - adjustPayloadStartAndCapacity(); + adjustPayloadStartAndCapacity(localHeaderSize()); writeTypeAndVersion(); } @@ -96,7 +96,7 @@ NLPacket::NLPacket(PacketType type, qint64 size, bool isReliable, bool isPartOfM { Q_ASSERT(size >= 0); - adjustPayloadStartAndCapacity(); + adjustPayloadStartAndCapacity(localHeaderSize()); writeTypeAndVersion(); } @@ -108,7 +108,7 @@ NLPacket::NLPacket(std::unique_ptr packet) : readVersion(); readSourceID(); - adjustPayloadStartAndCapacity(_payloadSize > 0); + adjustPayloadStartAndCapacity(localHeaderSize(), _payloadSize > 0); } NLPacket::NLPacket(const NLPacket& other) : Packet(other) { @@ -123,7 +123,7 @@ NLPacket::NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& // sanity check before we decrease the payloadSize with the payloadCapacity Q_ASSERT(_payloadSize == _payloadCapacity); - adjustPayloadStartAndCapacity(_payloadSize > 0); + adjustPayloadStartAndCapacity(localHeaderSize(), _payloadSize > 0); readType(); readVersion(); @@ -194,7 +194,7 @@ QByteArray NLPacket::hashForPacketAndSecret(const udt::Packet& packet, const QUu } void NLPacket::writeTypeAndVersion() { - auto headerOffset = Packet::totalHeadersSize(); + auto headerOffset = Packet::localHeaderSize(); // Pack the packet type memcpy(_packet.get() + headerOffset, &_type, sizeof(PacketType)); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 0864cb9fcd..d55489a84d 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -252,6 +252,7 @@ void NodeList::sendDomainServerCheckIn() { } auto domainPacket = NLPacket::create(domainPacketType); + QDataStream packetStream(domainPacket.get()); if (domainPacketType == PacketType::DomainConnectRequest) { diff --git a/libraries/networking/src/udt/BasePacket.cpp b/libraries/networking/src/udt/BasePacket.cpp index 083a62b155..38fb9e849e 100644 --- a/libraries/networking/src/udt/BasePacket.cpp +++ b/libraries/networking/src/udt/BasePacket.cpp @@ -177,8 +177,7 @@ qint64 BasePacket::readData(char* dest, qint64 maxSize) { return numBytesToRead; } -void BasePacket::adjustPayloadStartAndCapacity(bool shouldDecreasePayloadSize) { - qint64 headerSize = localHeaderSize(); +void BasePacket::adjustPayloadStartAndCapacity(qint64 headerSize, bool shouldDecreasePayloadSize) { _payloadStart += headerSize; _payloadCapacity -= headerSize; diff --git a/libraries/networking/src/udt/BasePacket.h b/libraries/networking/src/udt/BasePacket.h index 7ebf2d1e65..d8c1aaeddf 100644 --- a/libraries/networking/src/udt/BasePacket.h +++ b/libraries/networking/src/udt/BasePacket.h @@ -86,7 +86,7 @@ protected: virtual qint64 writeData(const char* data, qint64 maxSize); virtual qint64 readData(char* data, qint64 maxSize); - virtual void adjustPayloadStartAndCapacity(bool shouldDecreasePayloadSize = false); + virtual void adjustPayloadStartAndCapacity(qint64 headerSize, bool shouldDecreasePayloadSize = false); qint64 _packetSize = 0; // Total size of the allocated memory std::unique_ptr _packet; // Allocated memory diff --git a/libraries/networking/src/udt/Constants.h b/libraries/networking/src/udt/Constants.h index 5e0f130f13..eaad77d03e 100644 --- a/libraries/networking/src/udt/Constants.h +++ b/libraries/networking/src/udt/Constants.h @@ -25,7 +25,8 @@ namespace udt { static const int UDP_SEND_BUFFER_SIZE_BYTES = 1048576; static const int UDP_RECEIVE_BUFFER_SIZE_BYTES = 1048576; static const int DEFAULT_SYN_INTERVAL_USECS = 10 * 1000; - static const uint32_t CONTROL_BIT_MASK = 1 << (sizeof(SequenceNumber) - 1); + static const int SEQUENCE_NUMBER_BITS = sizeof(SequenceNumber) * 8; + static const uint32_t CONTROL_BIT_MASK = uint32_t(1) << (SEQUENCE_NUMBER_BITS - 1); } #endif // hifi_udt_Constants_h diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index 2bc081e197..01d92bfa07 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -57,7 +57,7 @@ ControlPacket::ControlPacket(Type type) : BasePacket(-1), _type(type) { - adjustPayloadStartAndCapacity(); + adjustPayloadStartAndCapacity(localHeaderSize()); open(QIODevice::ReadWrite); @@ -68,7 +68,7 @@ ControlPacket::ControlPacket(Type type, qint64 size) : BasePacket(localHeaderSize() + size), _type(type) { - adjustPayloadStartAndCapacity(); + adjustPayloadStartAndCapacity(localHeaderSize()); open(QIODevice::ReadWrite); @@ -119,12 +119,14 @@ void ControlPacket::writeType() { ControlBitAndType* bitAndType = reinterpret_cast(_packet.get()); // write the type by OR'ing the new type with the current value & CONTROL_BIT_MASK - *bitAndType = (*bitAndType & CONTROL_BIT_MASK) | (_type << sizeof((ControlPacket::Type) - 1)); + *bitAndType = (*bitAndType & CONTROL_BIT_MASK) | (_type << (sizeof(ControlPacket::Type) * 8 - 1)); } void ControlPacket::readType() { ControlBitAndType bitAndType = *reinterpret_cast(_packet.get()); + Q_ASSERT_X(bitAndType & CONTROL_BIT_MASK, "ControlPacket::readHeader()", "This should be a control packet"); + // read the type uint32_t oversizeType = (uint32_t) (bitAndType & ~CONTROL_BIT_MASK); _type = (Type) oversizeType; diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 96cf5210b4..6ec8ac398e 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -50,7 +50,7 @@ qint64 Packet::maxPayloadSize() const { } qint64 Packet::totalHeadersSize() const { - return BasePacket::localHeaderSize() + localHeaderSize(); + return BasePacket::totalHeadersSize() + Packet::localHeaderSize(); } qint64 Packet::localHeaderSize() const { @@ -62,7 +62,7 @@ Packet::Packet(qint64 size, bool isReliable, bool isPartOfMessage) : _isReliable(isReliable), _isPartOfMessage(isPartOfMessage) { - adjustPayloadStartAndCapacity(); + adjustPayloadStartAndCapacity(localHeaderSize()); // set the UDT header to default values writeHeader(); @@ -117,14 +117,15 @@ void Packet::writeSequenceNumber(SequenceNumber sequenceNumber) const { writeHeader(); } -static const uint32_t RELIABILITY_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 2); -static const uint32_t MESSAGE_BIT_MASK = 1 << (sizeof(Packet::SequenceNumberAndBitField) - 3); +static const uint32_t RELIABILITY_BIT_MASK = uint32_t(1) << (SEQUENCE_NUMBER_BITS - 2); +static const uint32_t MESSAGE_BIT_MASK = uint32_t(1) << (SEQUENCE_NUMBER_BITS - 3); static const uint32_t BIT_FIELD_MASK = CONTROL_BIT_MASK | RELIABILITY_BIT_MASK | MESSAGE_BIT_MASK; void Packet::readHeader() const { SequenceNumberAndBitField seqNumBitField = *reinterpret_cast(_packet.get()); - Q_ASSERT_X((bool) (seqNumBitField & CONTROL_BIT_MASK), - "Packet::readHeader()", "This should be a data packet"); + + Q_ASSERT_X(!(seqNumBitField & CONTROL_BIT_MASK), "Packet::readHeader()", "This should be a data packet"); + _isReliable = (bool) (seqNumBitField & RELIABILITY_BIT_MASK); // Only keep reliability bit _isPartOfMessage = (bool) (seqNumBitField & MESSAGE_BIT_MASK); // Only keep message bit _sequenceNumber = SequenceNumber{ seqNumBitField & ~BIT_FIELD_MASK }; // Remove the bit field diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 5ded97135b..8b18bdddcd 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -16,6 +16,7 @@ #include "../NetworkLogging.h" #include "ControlPacket.h" #include "Packet.h" +#include "../NLPacket.h" using namespace udt; @@ -138,6 +139,8 @@ void Socket::readPendingDatagrams() { // check if this was a control packet or a data packet bool isControlPacket = *buffer & CONTROL_BIT_MASK; + qDebug() << "IS CONTROL" << isControlPacket; + if (isControlPacket) { // setup a control packet from the data we just read auto controlPacket = ControlPacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); From 50b80c3c20515cd59843544e2945e68652d0f24e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 17:39:16 -0700 Subject: [PATCH 168/549] remove debug for isControl --- libraries/networking/src/udt/Socket.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 8b18bdddcd..8e1b1685bd 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -139,8 +139,6 @@ void Socket::readPendingDatagrams() { // check if this was a control packet or a data packet bool isControlPacket = *buffer & CONTROL_BIT_MASK; - qDebug() << "IS CONTROL" << isControlPacket; - if (isControlPacket) { // setup a control packet from the data we just read auto controlPacket = ControlPacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); From cb703a9d7800ee5f118c65807c22e3258ec5284f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 17:43:40 -0700 Subject: [PATCH 169/549] repair two calls to adjust payload start and capacity --- libraries/networking/src/udt/ControlPacket.cpp | 2 +- libraries/networking/src/udt/Packet.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index 01d92bfa07..bd9e851a79 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -81,7 +81,7 @@ ControlPacket::ControlPacket(std::unique_ptr data, qint64 size, const Hifi // sanity check before we decrease the payloadSize with the payloadCapacity Q_ASSERT(_payloadSize == _payloadCapacity); - adjustPayloadStartAndCapacity(_payloadSize > 0); + adjustPayloadStartAndCapacity(localHeaderSize(), _payloadSize > 0); readType(); } diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 6ec8ac398e..cbe9c986bd 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -73,7 +73,7 @@ Packet::Packet(std::unique_ptr data, qint64 size, const HifiSockAddr& send { readHeader(); - adjustPayloadStartAndCapacity(_payloadSize > 0); + adjustPayloadStartAndCapacity(localHeaderSize(), _payloadSize > 0); } Packet::Packet(const Packet& other) : From 38037664ba3a435d1df8828f48a143f1be14eb2b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jul 2015 17:51:50 -0700 Subject: [PATCH 170/549] don't attempt to send stats while not connected --- .../networking/src/ThreadedAssignment.cpp | 24 +++++++++++++++---- libraries/networking/src/ThreadedAssignment.h | 2 ++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 1c425806c9..a5df256e29 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -70,10 +70,11 @@ void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeTy _domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); if (shouldSendStats) { - // send a stats packet every 1 second - _statsTimer = new QTimer(); - connect(_statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket); - _statsTimer->start(1000); + // start sending stats packet once we connect to the domain + connect(&nodeList->getDomainHandler(), &DomainHandler::connectedToDomain, this, &ThreadedAssignment::startSendingStats); + + // stop sending stats if we disconnect + connect(&nodeList->getDomainHandler(), &DomainHandler::disconnectedFromDomain, this, &ThreadedAssignment::stopSendingStats); } } @@ -96,6 +97,21 @@ void ThreadedAssignment::sendStatsPacket() { addPacketStatsAndSendStatsPacket(statsObject); } +void ThreadedAssignment::startSendingStats() { + // send the stats packet every 1s + if (!_statsTimer) { + _statsTimer = new QTimer(); + connect(_statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket); + } + + _statsTimer->start(1000); +} + +void ThreadedAssignment::stopSendingStats() { + // stop sending stats, we just disconnected from domain + _statsTimer->stop(); +} + void ThreadedAssignment::checkInWithDomainServerOrExit() { if (DependencyManager::get()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { setFinished(true); diff --git a/libraries/networking/src/ThreadedAssignment.h b/libraries/networking/src/ThreadedAssignment.h index 51917cd74d..9ff3b34add 100644 --- a/libraries/networking/src/ThreadedAssignment.h +++ b/libraries/networking/src/ThreadedAssignment.h @@ -42,6 +42,8 @@ protected: QTimer* _statsTimer = nullptr; private slots: + void startSendingStats(); + void stopSendingStats(); void checkInWithDomainServerOrExit(); }; From db5e5a4f7503076d15cefbf138794722a227653e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 29 Jul 2015 20:04:29 -0700 Subject: [PATCH 171/549] Remove Environment Server --- interface/src/ui/BandwidthDialog.cpp | 2 +- libraries/networking/src/NodeType.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/ui/BandwidthDialog.cpp b/interface/src/ui/BandwidthDialog.cpp index b3bc934006..6272ddf76a 100644 --- a/interface/src/ui/BandwidthDialog.cpp +++ b/interface/src/ui/BandwidthDialog.cpp @@ -90,7 +90,7 @@ BandwidthDialog::BandwidthDialog(QWidget* parent) : new BandwidthChannelDisplay({NodeType::Unassigned}, form, "Other", "Kbps", 1.0, COLOR2); _allChannelDisplays[5] = _totalChannelDisplay = new BandwidthChannelDisplay({NodeType::DomainServer, NodeType::EntityServer, - NodeType::EnvironmentServer, NodeType::AudioMixer, NodeType::Agent, + NodeType::AudioMixer, NodeType::Agent, NodeType::AvatarMixer, NodeType::Unassigned}, form, "Total", "Kbps", 1.0, COLOR2); diff --git a/libraries/networking/src/NodeType.h b/libraries/networking/src/NodeType.h index 4427b87158..38590e1b03 100644 --- a/libraries/networking/src/NodeType.h +++ b/libraries/networking/src/NodeType.h @@ -19,7 +19,6 @@ typedef quint8 NodeType_t; namespace NodeType { const NodeType_t DomainServer = 'D'; const NodeType_t EntityServer = 'o'; // was ModelServer - const NodeType_t EnvironmentServer = 'E'; const NodeType_t Agent = 'I'; const NodeType_t AudioMixer = 'M'; const NodeType_t AvatarMixer = 'W'; From da480bcaf07104dd7b802e5f231296bbae223493 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 29 Jul 2015 20:05:15 -0700 Subject: [PATCH 172/549] Fix ControlPackets read/write header --- .../networking/src/udt/ControlPacket.cpp | 20 +++++-------------- libraries/networking/src/udt/Packet.cpp | 19 +++++++----------- libraries/networking/src/udt/SequenceNumber.h | 1 + 3 files changed, 13 insertions(+), 27 deletions(-) diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index bd9e851a79..cee2436165 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -61,7 +61,7 @@ ControlPacket::ControlPacket(Type type) : open(QIODevice::ReadWrite); - writeControlBitAndType(); + writeType(); } ControlPacket::ControlPacket(Type type, qint64 size) : @@ -72,7 +72,7 @@ ControlPacket::ControlPacket(Type type, qint64 size) : open(QIODevice::ReadWrite); - writeControlBitAndType(); + writeType(); } ControlPacket::ControlPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr) : @@ -106,20 +106,11 @@ void ControlPacket::setType(udt::ControlPacket::Type type) { writeType(); } -void ControlPacket::writeControlBitAndType() { - ControlBitAndType* bitAndType = reinterpret_cast(_packet.get()); - - // write the control bit by OR'ing the current value with the CONTROL_BIT_MASK - *bitAndType = (*bitAndType | CONTROL_BIT_MASK); - - writeType(); -} - void ControlPacket::writeType() { ControlBitAndType* bitAndType = reinterpret_cast(_packet.get()); - // write the type by OR'ing the new type with the current value & CONTROL_BIT_MASK - *bitAndType = (*bitAndType & CONTROL_BIT_MASK) | (_type << (sizeof(ControlPacket::Type) * 8 - 1)); + // We override the control bit here by writing the type but it's okay, it'll always be 1 + *bitAndType = CONTROL_BIT_MASK | (ControlBitAndType(_type) << (8 * sizeof(Type))); } void ControlPacket::readType() { @@ -128,6 +119,5 @@ void ControlPacket::readType() { Q_ASSERT_X(bitAndType & CONTROL_BIT_MASK, "ControlPacket::readHeader()", "This should be a control packet"); // read the type - uint32_t oversizeType = (uint32_t) (bitAndType & ~CONTROL_BIT_MASK); - _type = (Type) oversizeType; + _type = (Type) ((bitAndType & ~CONTROL_BIT_MASK) >> (8 * sizeof(Type))); } diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index cbe9c986bd..673013a4a7 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -135,21 +135,16 @@ void Packet::writeHeader() const { // grab pointer to current SequenceNumberAndBitField SequenceNumberAndBitField* seqNumBitField = reinterpret_cast(_packet.get()); - // 0 for data packets - *seqNumBitField &= ~CONTROL_BIT_MASK; - - if (_isPartOfMessage) { - *seqNumBitField |= MESSAGE_BIT_MASK; - } else { - *seqNumBitField &= ~MESSAGE_BIT_MASK; - } + // Write sequence number and reset bit field + Q_ASSERT_X(!((SequenceNumber::Type)_sequenceNumber & BIT_FIELD_MASK), + "Packet::writeHeader()", "Sequence number is overflowing into bit field"); + *seqNumBitField = ((SequenceNumber::Type)_sequenceNumber); if (_isReliable) { *seqNumBitField |= RELIABILITY_BIT_MASK; - } else { - *seqNumBitField &= ~RELIABILITY_BIT_MASK; } - // write new value by ORing (old value & BIT_FIELD_MASK) with new seqNum - *seqNumBitField = (*seqNumBitField & BIT_FIELD_MASK) | (SequenceNumber::Type)_sequenceNumber; + if (_isPartOfMessage) { + *seqNumBitField |= MESSAGE_BIT_MASK; + } } diff --git a/libraries/networking/src/udt/SequenceNumber.h b/libraries/networking/src/udt/SequenceNumber.h index 6215d23494..d5b61c0a95 100644 --- a/libraries/networking/src/udt/SequenceNumber.h +++ b/libraries/networking/src/udt/SequenceNumber.h @@ -92,6 +92,7 @@ private: friend struct std::hash; }; +static_assert(sizeof(SequenceNumber) == sizeof(uint32_t), "SequenceNumber invalid size"); inline bool operator<(const SequenceNumber& a, const SequenceNumber& b) { From 3d523552f8242ec8164721935cbd724bda380326 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 30 Jul 2015 01:02:53 -0700 Subject: [PATCH 173/549] Cast buffer ptr before bitwise op --- libraries/networking/src/udt/Socket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index dc808ff286..a93a4d0e9e 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -138,7 +138,7 @@ void Socket::readPendingDatagrams() { } // check if this was a control packet or a data packet - bool isControlPacket = *buffer & CONTROL_BIT_MASK; + bool isControlPacket = *reinterpret_cast(buffer.get()) & CONTROL_BIT_MASK; if (isControlPacket) { // setup a control packet from the data we just read From 57025cff74352634fe760197c48ab3cb65a86faf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jul 2015 10:20:09 -0700 Subject: [PATCH 174/549] fix packet pair sending from SendQueue --- libraries/networking/src/udt/Connection.cpp | 4 +- libraries/networking/src/udt/SendQueue.cpp | 43 +++++++++++++++++++-- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index f7f32d7480..690f47adab 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -228,9 +228,9 @@ SequenceNumber Connection::nextACK() const { bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber) { // check if this is a packet pair we should estimate bandwidth from, or just a regular packet - if (((uint32_t) sequenceNumber & 0xF) == 0) { + if (((uint32_t) sequenceNumber & 0xFF) == 0) { _receiveWindow.onProbePair1Arrival(); - } else if (((uint32_t) sequenceNumber & 0xF) == 1) { + } else if (((uint32_t) sequenceNumber & 0xFF) == 1) { _receiveWindow.onProbePair2Arrival(); } else { _receiveWindow.onPacketArrival(); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 9a2e371616..628ac020f5 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -135,13 +135,13 @@ void SendQueue::loop() { // is greater than or equal to the gap between the last ACKed sent and the one we are about to send if (seqlen(SequenceNumber { (uint32_t) _lastACKSequenceNumber }, _currentSequenceNumber + 1) <= _flowWindowSize) { bool hasResend = false; - SequenceNumber seqNum; + SequenceNumber sequenceNumber; { // Check nak list for packet to resend QWriteLocker locker(&_naksLock); if (_naks.getLength() > 0) { hasResend = true; - seqNum = _naks.popFirstSequenceNumber(); + sequenceNumber = _naks.popFirstSequenceNumber(); } } @@ -150,7 +150,7 @@ void SendQueue::loop() { // Find packet in sent list using SequenceNumber if (hasResend) { QWriteLocker locker(&_sentLock); - auto it = _sentPackets.find(seqNum); + auto it = _sentPackets.find(sequenceNumber); Q_ASSERT_X(it != _sentPackets.end(), "SendQueue::sendNextPacket()", "Couldn't find NAKed packet to resend"); @@ -167,8 +167,20 @@ void SendQueue::loop() { _packets.pop_front(); } + bool shouldSendSecondOfPair = false; + + if (!hasResend) { + // if we're not re-sending a packet then need to check if this should be a packet pair + sequenceNumber = getNextSequenceNumber(); + + // the first packet in the pair is every 16 (rightmost 16 bits = 0) packets + if (((uint32_t) sequenceNumber & 0xFF) == 0) { + shouldSendSecondOfPair = true; + } + } + // Write packet's sequence number and send it off - nextPacket->writeSequenceNumber(getNextSequenceNumber()); + nextPacket->writeSequenceNumber(sequenceNumber); sendPacket(*nextPacket); // Insert the packet we have just sent in the sent list @@ -176,6 +188,29 @@ void SendQueue::loop() { _sentPackets[nextPacket->getSequenceNumber()].swap(nextPacket); Q_ASSERT_X(!nextPacket, "SendQueue::sendNextPacket()", "Overriden packet in sent list"); + + if (shouldSendSecondOfPair) { + std::unique_ptr pairedPacket; + + // we've detected we should send the second packet in a pair, do that now before sleeping + { + QWriteLocker locker(&_packetsLock); + pairedPacket.swap(_packets.front()); + _packets.pop_front(); + } + + if (pairedPacket) { + // write this packet's sequence number and send it off + pairedPacket->writeSequenceNumber(getNextSequenceNumber()); + sendPacket(*pairedPacket); + + // add the paired packet to the sent list + QWriteLocker locker(&_sentLock); + _sentPackets[pairedPacket->getSequenceNumber()].swap(pairedPacket); + Q_ASSERT_X(!pairedPacket, + "SendQueue::sendNextPacket()", "Overriden packet in sent list"); + } + } } // since we're a while loop, give the thread a chance to process events From e7f5bec3d0a45012e0c8e3f27c8029a8e040676b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jul 2015 10:30:14 -0700 Subject: [PATCH 175/549] take out the incorrect attempt to cast for bitwise --- libraries/networking/src/udt/Connection.cpp | 4 ++-- libraries/networking/src/udt/SendQueue.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 690f47adab..f7f32d7480 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -228,9 +228,9 @@ SequenceNumber Connection::nextACK() const { bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber) { // check if this is a packet pair we should estimate bandwidth from, or just a regular packet - if (((uint32_t) sequenceNumber & 0xFF) == 0) { + if (((uint32_t) sequenceNumber & 0xF) == 0) { _receiveWindow.onProbePair1Arrival(); - } else if (((uint32_t) sequenceNumber & 0xFF) == 1) { + } else if (((uint32_t) sequenceNumber & 0xF) == 1) { _receiveWindow.onProbePair2Arrival(); } else { _receiveWindow.onPacketArrival(); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 628ac020f5..e6bc59c6cb 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -174,7 +174,7 @@ void SendQueue::loop() { sequenceNumber = getNextSequenceNumber(); // the first packet in the pair is every 16 (rightmost 16 bits = 0) packets - if (((uint32_t) sequenceNumber & 0xFF) == 0) { + if (((uint32_t) sequenceNumber & 0xF) == 0) { shouldSendSecondOfPair = true; } } From 3f0eecc599f044dc5a4991fc621ef42a83a6c45c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jul 2015 15:04:48 -0700 Subject: [PATCH 176/549] actually change the system socket buffer size --- libraries/networking/src/udt/Socket.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index a93a4d0e9e..3dd00d0834 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -39,7 +39,7 @@ void Socket::rebind() { quint16 oldPort = _udpSocket.localPort(); _udpSocket.close(); - _udpSocket.bind(QHostAddress::AnyIPv4, oldPort); + bind(QHostAddress::AnyIPv4, oldPort); } void Socket::setSystemBufferSizes() { @@ -63,6 +63,7 @@ void Socket::setSystemBufferSizes() { int oldBufferSize = _udpSocket.socketOption(bufferOpt).toInt(); if (oldBufferSize < numBytes) { + _udpSocket.setSocketOption(bufferOpt, QVariant(numBytes)); int newBufferSize = _udpSocket.socketOption(bufferOpt).toInt(); qCDebug(networking) << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to" From 9e7644ee785af686baa14e932d23fe1717c34018 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 30 Jul 2015 15:05:51 -0700 Subject: [PATCH 177/549] Change headers/payload size computation --- .../octree/OctreeInboundPacketProcessor.cpp | 2 +- libraries/networking/src/NLPacket.cpp | 62 ++++++++----------- libraries/networking/src/NLPacket.h | 14 ++--- libraries/networking/src/udt/BasePacket.cpp | 16 ++++- libraries/networking/src/udt/BasePacket.h | 14 +++-- .../networking/src/udt/ControlPacket.cpp | 26 ++++---- libraries/networking/src/udt/ControlPacket.h | 20 +++--- libraries/networking/src/udt/Packet.cpp | 38 +++++------- libraries/networking/src/udt/Packet.h | 13 ++-- 9 files changed, 102 insertions(+), 103 deletions(-) diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index 8d76be2c78..1d9adab28b 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -128,7 +128,7 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer packet } if (debugProcessPacket) { - qDebug() << " numBytesPacketHeader=" << packet->totalHeadersSize(); + qDebug() << " numBytesPacketHeader=" << NLPacket::totalHeaderSize(packetType); qDebug() << " sizeof(sequence)=" << sizeof(sequence); qDebug() << " sizeof(sentAt)=" << sizeof(sentAt); } diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 4568561fa2..a5e7feb6f5 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -11,26 +11,17 @@ #include "NLPacket.h" -qint64 NLPacket::maxPayloadSize(PacketType type) { - return Packet::maxPayloadSize(false) - localHeaderSize(type); -} - -qint64 NLPacket::localHeaderSize(PacketType type) { - qint64 optionalSize = ((NON_SOURCED_PACKETS.contains(type)) ? 0 : NUM_BYTES_RFC4122_UUID) + - ((NON_SOURCED_PACKETS.contains(type) || NON_VERIFIED_PACKETS.contains(type)) ? 0 : NUM_BYTES_MD5_HASH); +int NLPacket::localHeaderSize(PacketType type) { + bool sourced = NON_SOURCED_PACKETS.contains(type); + bool verified = NON_VERIFIED_PACKETS.contains(type); + qint64 optionalSize = (sourced ? 0 : NUM_BYTES_RFC4122_UUID) + ((sourced || verified) ? 0 : NUM_BYTES_MD5_HASH); return sizeof(PacketType) + sizeof(PacketVersion) + optionalSize; } - -qint64 NLPacket::maxPayloadSize() const { - return Packet::maxPayloadSize() - localHeaderSize(); +int NLPacket::totalHeaderSize(PacketType type, bool isPartOfMessage) { + return Packet::totalHeaderSize(isPartOfMessage) + NLPacket::localHeaderSize(type); } - -qint64 NLPacket::totalHeadersSize() const { - return Packet::totalHeadersSize() + localHeaderSize(); -} - -qint64 NLPacket::localHeaderSize() const { - return localHeaderSize(_type); +int NLPacket::maxPayloadSize(PacketType type, bool isPartOfMessage) { + return Packet::maxPayloadSize(isPartOfMessage) - NLPacket::localHeaderSize(type); } std::unique_ptr NLPacket::create(PacketType type, qint64 size, bool isReliable, bool isPartOfMessage) { @@ -84,19 +75,19 @@ NLPacket::NLPacket(PacketType type, bool isReliable, bool isPartOfMessage) : _type(type), _version(versionForPacketType(type)) { - adjustPayloadStartAndCapacity(localHeaderSize()); + adjustPayloadStartAndCapacity(NLPacket::localHeaderSize(_type)); writeTypeAndVersion(); } NLPacket::NLPacket(PacketType type, qint64 size, bool isReliable, bool isPartOfMessage) : - Packet(localHeaderSize(type) + size, isReliable, isPartOfMessage), + Packet(NLPacket::localHeaderSize(type) + size, isReliable, isPartOfMessage), _type(type), _version(versionForPacketType(type)) { Q_ASSERT(size >= 0); - adjustPayloadStartAndCapacity(localHeaderSize()); + adjustPayloadStartAndCapacity(NLPacket::localHeaderSize(_type)); writeTypeAndVersion(); } @@ -108,7 +99,7 @@ NLPacket::NLPacket(std::unique_ptr packet) : readVersion(); readSourceID(); - adjustPayloadStartAndCapacity(localHeaderSize(), _payloadSize > 0); + adjustPayloadStartAndCapacity(NLPacket::localHeaderSize(_type), _payloadSize > 0); } NLPacket::NLPacket(const NLPacket& other) : Packet(other) { @@ -123,11 +114,11 @@ NLPacket::NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& // sanity check before we decrease the payloadSize with the payloadCapacity Q_ASSERT(_payloadSize == _payloadCapacity); - adjustPayloadStartAndCapacity(localHeaderSize(), _payloadSize > 0); - readType(); readVersion(); readSourceID(); + + adjustPayloadStartAndCapacity(NLPacket::localHeaderSize(_type), _payloadSize > 0); } NLPacket::NLPacket(NLPacket&& other) : @@ -160,29 +151,29 @@ NLPacket& NLPacket::operator=(NLPacket&& other) { } PacketType NLPacket::typeInHeader(const udt::Packet& packet) { - auto headerOffset = packet.Packet::totalHeadersSize(); + auto headerOffset = Packet::totalHeaderSize(packet.isPartOfMessage()); return *reinterpret_cast(packet.getData() + headerOffset); } PacketVersion NLPacket::versionInHeader(const udt::Packet& packet) { - auto headerOffset = packet.Packet::totalHeadersSize(); + auto headerOffset = Packet::totalHeaderSize(packet.isPartOfMessage()); return *reinterpret_cast(packet.getData() + headerOffset + sizeof(PacketType)); } QUuid NLPacket::sourceIDInHeader(const udt::Packet& packet) { - int offset = packet.Packet::totalHeadersSize() + sizeof(PacketType) + sizeof(PacketVersion); + int offset = Packet::totalHeaderSize(packet.isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion); return QUuid::fromRfc4122(QByteArray::fromRawData(packet.getData() + offset, NUM_BYTES_RFC4122_UUID)); } QByteArray NLPacket::verificationHashInHeader(const udt::Packet& packet) { - int offset = packet.Packet::totalHeadersSize() + sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID; + int offset = Packet::totalHeaderSize(packet.isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID; return QByteArray(packet.getData() + offset, NUM_BYTES_MD5_HASH); } QByteArray NLPacket::hashForPacketAndSecret(const udt::Packet& packet, const QUuid& connectionSecret) { QCryptographicHash hash(QCryptographicHash::Md5); - int offset = packet.Packet::totalHeadersSize() + sizeof(PacketType) + sizeof(PacketVersion) + int offset = Packet::totalHeaderSize(packet.isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH; // add the packet payload and the connection UUID @@ -194,7 +185,7 @@ QByteArray NLPacket::hashForPacketAndSecret(const udt::Packet& packet, const QUu } void NLPacket::writeTypeAndVersion() { - auto headerOffset = Packet::localHeaderSize(); + auto headerOffset = Packet::localHeaderSize(isPartOfMessage()); // Pack the packet type memcpy(_packet.get() + headerOffset, &_type, sizeof(PacketType)); @@ -204,16 +195,14 @@ void NLPacket::writeTypeAndVersion() { } void NLPacket::setType(PacketType type) { - auto currentHeaderSize = totalHeadersSize(); + // Setting new packet type with a different header size not currently supported + Q_ASSERT(NLPacket::totalHeaderSize(_type, isPartOfMessage()) == + NLPacket::totalHeaderSize(type, isPartOfMessage())); _type = type; _version = versionForPacketType(_type); writeTypeAndVersion(); - - // Setting new packet type with a different header size not currently supported - Q_ASSERT(currentHeaderSize == totalHeadersSize()); - Q_UNUSED(currentHeaderSize); } void NLPacket::readType() { @@ -233,7 +222,7 @@ void NLPacket::readSourceID() { void NLPacket::writeSourceID(const QUuid& sourceID) { Q_ASSERT(!NON_SOURCED_PACKETS.contains(_type)); - auto offset = Packet::totalHeadersSize() + sizeof(PacketType) + sizeof(PacketVersion); + auto offset = Packet::totalHeaderSize(isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion); memcpy(_packet.get() + offset, sourceID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); _sourceID = sourceID; @@ -242,7 +231,8 @@ void NLPacket::writeSourceID(const QUuid& sourceID) { void NLPacket::writeVerificationHashGivenSecret(const QUuid& connectionSecret) { Q_ASSERT(!NON_SOURCED_PACKETS.contains(_type) && !NON_VERIFIED_PACKETS.contains(_type)); - auto offset = Packet::totalHeadersSize() + sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID; + auto offset = Packet::totalHeaderSize(isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion) + + NUM_BYTES_RFC4122_UUID; QByteArray verificationHash = hashForPacketAndSecret(*this, connectionSecret); memcpy(_packet.get() + offset, verificationHash.data(), verificationHash.size()); diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index 896fbaa66d..25efd673aa 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -35,6 +35,13 @@ public: // Provided for convenience, try to limit use static std::unique_ptr createCopy(const NLPacket& other); + // Current level's header size + static int localHeaderSize(PacketType type); + // Cumulated size of all the headers + static int totalHeaderSize(PacketType type, bool isPartOfMessage = false); + // The maximum payload size this packet can use to fit in MTU + static int maxPayloadSize(PacketType type, bool isPartOfMessage = false); + static PacketType typeInHeader(const udt::Packet& packet); static PacketVersion versionInHeader(const udt::Packet& packet); @@ -42,13 +49,6 @@ public: static QByteArray verificationHashInHeader(const udt::Packet& packet); static QByteArray hashForPacketAndSecret(const udt::Packet& packet, const QUuid& connectionSecret); - static qint64 maxPayloadSize(PacketType type); - static qint64 localHeaderSize(PacketType type); - - virtual qint64 maxPayloadSize() const; // The maximum payload size this packet can use to fit in MTU - virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers - virtual qint64 localHeaderSize() const; // Current level's header size - PacketType getType() const { return _type; } void setType(PacketType type); diff --git a/libraries/networking/src/udt/BasePacket.cpp b/libraries/networking/src/udt/BasePacket.cpp index 38fb9e849e..e8b660dd75 100644 --- a/libraries/networking/src/udt/BasePacket.cpp +++ b/libraries/networking/src/udt/BasePacket.cpp @@ -15,6 +15,16 @@ using namespace udt; const qint64 BasePacket::PACKET_WRITE_ERROR = -1; +int BasePacket::localHeaderSize() { + return 0; +} +int BasePacket::totalHeaderSize() { + return 0; +} +int BasePacket::maxPayloadSize() { + return MAX_PACKET_SIZE; +} + std::unique_ptr BasePacket::create(qint64 size) { auto packet = std::unique_ptr(new BasePacket(size)); @@ -37,7 +47,7 @@ std::unique_ptr BasePacket::fromReceivedPacket(std::unique_ptr } BasePacket::BasePacket(qint64 size) { - auto maxPayload = maxPayloadSize(); + auto maxPayload = BasePacket::maxPayloadSize(); if (size == -1) { // default size of -1, means biggest packet possible @@ -116,6 +126,10 @@ BasePacket& BasePacket::operator=(BasePacket&& other) { return *this; } +qint64 BasePacket::getDataSize() const { + return (_payloadStart - _packet.get()) + _payloadSize; +} + void BasePacket::setPayloadSize(qint64 payloadSize) { if (isWritable()) { Q_ASSERT(payloadSize <= _payloadCapacity); diff --git a/libraries/networking/src/udt/BasePacket.h b/libraries/networking/src/udt/BasePacket.h index d8c1aaeddf..959ef8900c 100644 --- a/libraries/networking/src/udt/BasePacket.h +++ b/libraries/networking/src/udt/BasePacket.h @@ -30,10 +30,12 @@ public: static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); - static qint64 maxPayloadSize() { return MAX_PACKET_SIZE; } // The maximum payload size this packet can use to fit in MTU - static qint64 localHeaderSize() { return 0; } // Current level's header size - - virtual qint64 totalHeadersSize() const { return 0; } // Cumulated size of all the headers + // Current level's header size + static int localHeaderSize(); + // Cumulated size of all the headers + static int totalHeaderSize(); + // The maximum payload size this packet can use to fit in MTU + static int maxPayloadSize(); // Payload direct access to the payload, use responsibly! char* getPayload() { return _payloadStart; } @@ -44,7 +46,7 @@ public: const char* getData() const { return _packet.get(); } // Returns the size of the packet, including the header - qint64 getDataSize() const { return totalHeadersSize() + _payloadSize; } + qint64 getDataSize() const; // Returns the size of the payload only qint64 getPayloadSize() const { return _payloadSize; } @@ -86,7 +88,7 @@ protected: virtual qint64 writeData(const char* data, qint64 maxSize); virtual qint64 readData(char* data, qint64 maxSize); - virtual void adjustPayloadStartAndCapacity(qint64 headerSize, bool shouldDecreasePayloadSize = false); + void adjustPayloadStartAndCapacity(qint64 headerSize, bool shouldDecreasePayloadSize = false); qint64 _packetSize = 0; // Total size of the allocated memory std::unique_ptr _packet; // Allocated memory diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index cee2436165..7378b2f314 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -15,6 +15,16 @@ using namespace udt; +int ControlPacket::localHeaderSize() { + return sizeof(ControlPacket::ControlBitAndType); +} +int ControlPacket::totalHeaderSize() { + return BasePacket::totalHeaderSize() + ControlPacket::localHeaderSize(); +} +int ControlPacket::maxPayloadSize() { + return BasePacket::maxPayloadSize() - ControlPacket::localHeaderSize(); +} + std::unique_ptr ControlPacket::fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr &senderSockAddr) { // Fail with null data @@ -45,19 +55,11 @@ std::unique_ptr ControlPacket::create(Type type, qint64 size) { } } -qint64 ControlPacket::localHeaderSize() { - return sizeof(ControlBitAndType); -} - -qint64 ControlPacket::totalHeadersSize() const { - return BasePacket::totalHeadersSize() + localHeaderSize(); -} - ControlPacket::ControlPacket(Type type) : BasePacket(-1), _type(type) { - adjustPayloadStartAndCapacity(localHeaderSize()); + adjustPayloadStartAndCapacity(ControlPacket::localHeaderSize()); open(QIODevice::ReadWrite); @@ -65,10 +67,10 @@ ControlPacket::ControlPacket(Type type) : } ControlPacket::ControlPacket(Type type, qint64 size) : - BasePacket(localHeaderSize() + size), + BasePacket(ControlPacket::localHeaderSize() + size), _type(type) { - adjustPayloadStartAndCapacity(localHeaderSize()); + adjustPayloadStartAndCapacity(ControlPacket::localHeaderSize()); open(QIODevice::ReadWrite); @@ -81,7 +83,7 @@ ControlPacket::ControlPacket(std::unique_ptr data, qint64 size, const Hifi // sanity check before we decrease the payloadSize with the payloadCapacity Q_ASSERT(_payloadSize == _payloadCapacity); - adjustPayloadStartAndCapacity(localHeaderSize(), _payloadSize > 0); + adjustPayloadStartAndCapacity(ControlPacket::localHeaderSize(), _payloadSize > 0); readType(); } diff --git a/libraries/networking/src/udt/ControlPacket.h b/libraries/networking/src/udt/ControlPacket.h index 6d13c06d33..c4ad7065a7 100644 --- a/libraries/networking/src/udt/ControlPacket.h +++ b/libraries/networking/src/udt/ControlPacket.h @@ -33,12 +33,15 @@ public: TimeoutNAK }; + static std::unique_ptr create(Type type, qint64 size = -1); static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); - static std::unique_ptr create(Type type, qint64 size = -1); - - static qint64 localHeaderSize(); // Current level's header size - virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers + // Current level's header size + static int localHeaderSize(); + // Cumulated size of all the headers + static int totalHeaderSize(); + // The maximum payload size this packet can use to fit in MTU + static int maxPayloadSize(); Type getType() const { return _type; } void setType(Type type); @@ -53,16 +56,13 @@ private: ControlPacket& operator=(ControlPacket&& other); ControlPacket& operator=(const ControlPacket& other) = delete; - // Header writers - void writeControlBitAndType(); - void writeType(); - - // Header readers + // Header read/write void readType(); + void writeType(); Type _type; }; - + } // namespace udt diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 673013a4a7..754d1534b1 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -13,6 +13,20 @@ using namespace udt; +int Packet::localHeaderSize(bool isPartOfMessage) { + return sizeof(Packet::SequenceNumberAndBitField) + + (isPartOfMessage ? sizeof(Packet::MessageNumberAndBitField) : 0); +} + +int Packet::totalHeaderSize(bool isPartOfMessage) { + return BasePacket::totalHeaderSize() + Packet::localHeaderSize(isPartOfMessage); +} + +int Packet::maxPayloadSize(bool isPartOfMessage) { + return BasePacket::maxPayloadSize() - Packet::localHeaderSize(isPartOfMessage); +} + + std::unique_ptr Packet::create(qint64 size, bool isReliable, bool isPartOfMessage) { auto packet = std::unique_ptr(new Packet(size, isReliable, isPartOfMessage)); @@ -37,32 +51,12 @@ std::unique_ptr Packet::createCopy(const Packet& other) { return std::unique_ptr(new Packet(other)); } -qint64 Packet::maxPayloadSize(bool isPartOfMessage) { - return MAX_PACKET_SIZE - localHeaderSize(isPartOfMessage); -} - -qint64 Packet::localHeaderSize(bool isPartOfMessage) { - return sizeof(SequenceNumberAndBitField) + (isPartOfMessage ? sizeof(MessageNumberAndBitField) : 0); -} - -qint64 Packet::maxPayloadSize() const { - return MAX_PACKET_SIZE - localHeaderSize(); -} - -qint64 Packet::totalHeadersSize() const { - return BasePacket::totalHeadersSize() + Packet::localHeaderSize(); -} - -qint64 Packet::localHeaderSize() const { - return localHeaderSize(_isPartOfMessage); -} - Packet::Packet(qint64 size, bool isReliable, bool isPartOfMessage) : BasePacket(size), _isReliable(isReliable), _isPartOfMessage(isPartOfMessage) { - adjustPayloadStartAndCapacity(localHeaderSize()); + adjustPayloadStartAndCapacity(Packet::localHeaderSize(_isPartOfMessage)); // set the UDT header to default values writeHeader(); @@ -73,7 +67,7 @@ Packet::Packet(std::unique_ptr data, qint64 size, const HifiSockAddr& send { readHeader(); - adjustPayloadStartAndCapacity(localHeaderSize(), _payloadSize > 0); + adjustPayloadStartAndCapacity(Packet::localHeaderSize(_isPartOfMessage), _payloadSize > 0); } Packet::Packet(const Packet& other) : diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index 8a6832205f..22eec97d97 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -38,15 +38,12 @@ public: // Provided for convenience, try to limit use static std::unique_ptr createCopy(const Packet& other); - // The maximum payload size this packet can use to fit in MTU - static qint64 maxPayloadSize(bool isPartOfMessage); - virtual qint64 maxPayloadSize() const; - // Current level's header size - static qint64 localHeaderSize(bool isPartOfMessage); - virtual qint64 localHeaderSize() const; - - virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers + static int localHeaderSize(bool isPartOfMessage = false); + // Cumulated size of all the headers + static int totalHeaderSize(bool isPartOfMessage = false); + // The maximum payload size this packet can use to fit in MTU + static int maxPayloadSize(bool isPartOfMessage = false); bool isPartOfMessage() const { return _isPartOfMessage; } bool isReliable() const { return _isReliable; } From 8e55655ec3aed5698a9e724e1213ab9f3720e060 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jul 2015 15:07:49 -0700 Subject: [PATCH 178/549] call setSystemBufferSizes once bound --- libraries/networking/src/udt/Socket.cpp | 2 -- libraries/networking/src/udt/Socket.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 3dd00d0834..f8515affe6 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -24,8 +24,6 @@ using namespace udt; Socket::Socket(QObject* parent) : QObject(parent) { - setSystemBufferSizes(); - connect(&_udpSocket, &QUdpSocket::readyRead, this, &Socket::readPendingDatagrams); // make sure our synchronization method is called every SYN interval diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 1827dc8234..e923f4b307 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -50,7 +50,7 @@ public: qint64 writeDatagram(const char* data, qint64 size, const HifiSockAddr& sockAddr); qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr); - void bind(const QHostAddress& address, quint16 port = 0) { _udpSocket.bind(address, port); } + void bind(const QHostAddress& address, quint16 port = 0) { _udpSocket.bind(address, port); setSystemBufferSizes(); } void rebind(); void setPacketFilterOperator(PacketFilterOperator filterOperator) { _packetFilterOperator = filterOperator; } From 784cc880a7d4186b67d199e4e21915e1f04b4c44 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 30 Jul 2015 15:15:51 -0700 Subject: [PATCH 179/549] Fix Packet ctor --- libraries/networking/src/udt/Packet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 754d1534b1..67fb3b8378 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -52,7 +52,7 @@ std::unique_ptr Packet::createCopy(const Packet& other) { } Packet::Packet(qint64 size, bool isReliable, bool isPartOfMessage) : - BasePacket(size), + BasePacket(Packet::localHeaderSize() + size), _isReliable(isReliable), _isPartOfMessage(isPartOfMessage) { From 532ac690912b65f8657511b37c50d11e5df9ee72 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jul 2015 15:36:54 -0700 Subject: [PATCH 180/549] initial version of UDTTest tool --- tools/CMakeLists.txt | 4 ++- tools/udt-test/CMakeLists.txt | 6 +++++ tools/udt-test/src/UDTTest.cpp | 46 ++++++++++++++++++++++++++++++++++ tools/udt-test/src/UDTTest.h | 32 +++++++++++++++++++++++ tools/udt-test/src/main.cpp | 19 ++++++++++++++ 5 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 tools/udt-test/CMakeLists.txt create mode 100644 tools/udt-test/src/UDTTest.cpp create mode 100644 tools/udt-test/src/UDTTest.h create mode 100644 tools/udt-test/src/main.cpp diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 55994f3d89..2056044a4b 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -5,6 +5,8 @@ set_target_properties(mtc PROPERTIES FOLDER "Tools") add_subdirectory(scribe) set_target_properties(scribe PROPERTIES FOLDER "Tools") +add_subdirectory(udt-test) +set_target_properties(udt-test PROPERTIES FOLDER "Tools") + add_subdirectory(vhacd-util) set_target_properties(vhacd-util PROPERTIES FOLDER "Tools") - diff --git a/tools/udt-test/CMakeLists.txt b/tools/udt-test/CMakeLists.txt new file mode 100644 index 0000000000..7f47677269 --- /dev/null +++ b/tools/udt-test/CMakeLists.txt @@ -0,0 +1,6 @@ +set(TARGET_NAME udt-test) +setup_hifi_project() + +link_hifi_libraries(networking) + +copy_dlls_beside_windows_executable() \ No newline at end of file diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp new file mode 100644 index 0000000000..d2f8bf6e40 --- /dev/null +++ b/tools/udt-test/src/UDTTest.cpp @@ -0,0 +1,46 @@ +// +// UDTTest.cpp +// tools/udt-test/src +// +// Created by Stephen Birarda on 2015-07-30. +// Copyright 2015 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 "UDTTest.h" + +#include + +const QCommandLineOption PORT_OPTION { "p", "listening port for socket (defaults to random)", "port", 0 }; + +UDTTest::UDTTest(int& argc, char** argv) : + QCoreApplication(argc, argv) +{ + parseArguments(); + + _socket.bind(QHostAddress::LocalHost, _argumentParser.value(PORT_OPTION).toUInt()); + qDebug() << "Test socket is listening on" << _socket.localPort(); +} + +void UDTTest::parseArguments() { + // use a QCommandLineParser to setup command line arguments and give helpful output + _argumentParser.setApplicationDescription("High Fidelity Assignment Client"); + _argumentParser.addHelpOption(); + + const QCommandLineOption helpOption = _argumentParser.addHelpOption(); + + _argumentParser.addOption(PORT_OPTION); + + if (!_argumentParser.parse(QCoreApplication::arguments())) { + qCritical() << _argumentParser.errorText(); + _argumentParser.showHelp(); + Q_UNREACHABLE(); + } + + if (_argumentParser.isSet(helpOption)) { + _argumentParser.showHelp(); + Q_UNREACHABLE(); + } +} diff --git a/tools/udt-test/src/UDTTest.h b/tools/udt-test/src/UDTTest.h new file mode 100644 index 0000000000..86d15974d0 --- /dev/null +++ b/tools/udt-test/src/UDTTest.h @@ -0,0 +1,32 @@ +// +// UDTTest.h +// tools/udt-test/src +// +// Created by Stephen Birarda on 2015-07-30. +// Copyright 2015 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 +// + +#pragma once + +#ifndef hifi_UDTTest_h +#define hifi_UDTTest_h + +#include +#include + +#include + +class UDTTest : public QCoreApplication { +public: + UDTTest(int& argc, char** argv); +private: + void parseArguments(); + + QCommandLineParser _argumentParser; + udt::Socket _socket; +}; + +#endif // hifi_UDTTest_h diff --git a/tools/udt-test/src/main.cpp b/tools/udt-test/src/main.cpp new file mode 100644 index 0000000000..ccb7d0af0f --- /dev/null +++ b/tools/udt-test/src/main.cpp @@ -0,0 +1,19 @@ +// +// main.cpp +// tools/udt-test/src +// +// Created by Stephen Birarda on 7/30/15. +// Copyright 2015 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 + +#include "UDTTest.h" + +int main(int argc, char* argv[]) { + UDTTest app(argc, argv); + return app.exec(); +} + From 3a9aedea68daf7ace5d86c9b848916db0a1e7f27 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 30 Jul 2015 15:56:42 -0700 Subject: [PATCH 181/549] Fix packet ctors size param --- libraries/networking/src/NLPacket.cpp | 25 ++----------------------- libraries/networking/src/NLPacket.h | 3 +-- libraries/networking/src/udt/Packet.cpp | 2 +- 3 files changed, 4 insertions(+), 26 deletions(-) diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index a5e7feb6f5..146054ccc7 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -25,16 +25,7 @@ int NLPacket::maxPayloadSize(PacketType type, bool isPartOfMessage) { } std::unique_ptr NLPacket::create(PacketType type, qint64 size, bool isReliable, bool isPartOfMessage) { - std::unique_ptr packet; - - if (size == -1) { - packet = std::unique_ptr(new NLPacket(type, isReliable, isPartOfMessage)); - } else { - // Fail with invalid size - Q_ASSERT(size >= 0); - - packet = std::unique_ptr(new NLPacket(type, size, isReliable, isPartOfMessage)); - } + auto packet = std::unique_ptr(new NLPacket(type, size, isReliable, isPartOfMessage)); packet->open(QIODevice::ReadWrite); @@ -70,23 +61,11 @@ std::unique_ptr NLPacket::createCopy(const NLPacket& other) { return std::unique_ptr(new NLPacket(other)); } -NLPacket::NLPacket(PacketType type, bool isReliable, bool isPartOfMessage) : - Packet(-1, isReliable, isPartOfMessage), - _type(type), - _version(versionForPacketType(type)) -{ - adjustPayloadStartAndCapacity(NLPacket::localHeaderSize(_type)); - - writeTypeAndVersion(); -} - NLPacket::NLPacket(PacketType type, qint64 size, bool isReliable, bool isPartOfMessage) : - Packet(NLPacket::localHeaderSize(type) + size, isReliable, isPartOfMessage), + Packet((size == -1) ? -1 : NLPacket::localHeaderSize(type) + size, isReliable, isPartOfMessage), _type(type), _version(versionForPacketType(type)) { - Q_ASSERT(size >= 0); - adjustPayloadStartAndCapacity(NLPacket::localHeaderSize(_type)); writeTypeAndVersion(); diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index 25efd673aa..2303150e66 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -61,8 +61,7 @@ public: protected: - NLPacket(PacketType type, bool forceReliable = false, bool isPartOfMessage = false); - NLPacket(PacketType type, qint64 size, bool forceReliable = false, bool isPartOfMessage = false); + NLPacket(PacketType type, qint64 size = -1, bool forceReliable = false, bool isPartOfMessage = false); NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); NLPacket(std::unique_ptr packet); NLPacket(const NLPacket& other); diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 67fb3b8378..4e77079a22 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -52,7 +52,7 @@ std::unique_ptr Packet::createCopy(const Packet& other) { } Packet::Packet(qint64 size, bool isReliable, bool isPartOfMessage) : - BasePacket(Packet::localHeaderSize() + size), + BasePacket((size == -1) ? -1 : (Packet::localHeaderSize() + size)), _isReliable(isReliable), _isPartOfMessage(isPartOfMessage) { From e8ffe962325d261de9430e83355c2fc8649be906 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 30 Jul 2015 15:58:05 -0700 Subject: [PATCH 182/549] Remove const_cast --- libraries/networking/src/Assignment.cpp | 4 +--- libraries/networking/src/LimitedNodeList.cpp | 4 ++-- libraries/networking/src/NLPacket.cpp | 4 ++-- libraries/networking/src/NLPacket.h | 6 +++--- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index 293d86475f..e8ba67c4a6 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -150,11 +150,9 @@ QDataStream& operator<<(QDataStream &out, const Assignment& assignment) { QDataStream& operator>>(QDataStream &in, Assignment& assignment) { quint8 packedType; - in >> packedType; + in >> packedType >> assignment._uuid >> assignment._pool >> assignment._payload; assignment._type = (Assignment::Type) packedType; - in >> assignment._uuid >> assignment._pool >> assignment._payload; - if (assignment._command == Assignment::RequestCommand) { in >> assignment._walletUUID; } diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 2ca4e89c12..5f547ecaf3 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -247,13 +247,13 @@ void LimitedNodeList::collectPacketStats(const NLPacket& packet) { void LimitedNodeList::fillPacketHeader(const NLPacket& packet, const QUuid& connectionSecret) { if (!NON_SOURCED_PACKETS.contains(packet.getType())) { - const_cast(packet).writeSourceID(getSessionUUID()); + packet.writeSourceID(getSessionUUID()); } if (!connectionSecret.isNull() && !NON_SOURCED_PACKETS.contains(packet.getType()) && !NON_VERIFIED_PACKETS.contains(packet.getType())) { - const_cast(packet).writeVerificationHashGivenSecret(connectionSecret); + packet.writeVerificationHashGivenSecret(connectionSecret); } } diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 146054ccc7..84330b0d77 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -198,7 +198,7 @@ void NLPacket::readSourceID() { } } -void NLPacket::writeSourceID(const QUuid& sourceID) { +void NLPacket::writeSourceID(const QUuid& sourceID) const { Q_ASSERT(!NON_SOURCED_PACKETS.contains(_type)); auto offset = Packet::totalHeaderSize(isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion); @@ -207,7 +207,7 @@ void NLPacket::writeSourceID(const QUuid& sourceID) { _sourceID = sourceID; } -void NLPacket::writeVerificationHashGivenSecret(const QUuid& connectionSecret) { +void NLPacket::writeVerificationHashGivenSecret(const QUuid& connectionSecret) const { Q_ASSERT(!NON_SOURCED_PACKETS.contains(_type) && !NON_VERIFIED_PACKETS.contains(_type)); auto offset = Packet::totalHeaderSize(isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion) diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index 2303150e66..f5c08b308a 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -56,8 +56,8 @@ public: const QUuid& getSourceID() const { return _sourceID; } - void writeSourceID(const QUuid& sourceID); - void writeVerificationHashGivenSecret(const QUuid& connectionSecret); + void writeSourceID(const QUuid& sourceID) const; + void writeVerificationHashGivenSecret(const QUuid& connectionSecret) const; protected: @@ -80,7 +80,7 @@ protected: PacketType _type; PacketVersion _version; - QUuid _sourceID; + mutable QUuid _sourceID; }; #endif // hifi_NLPacket_h From 80ef80ec2e4f6015bf435d2168addf85d3a4cf42 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jul 2015 16:07:14 -0700 Subject: [PATCH 183/549] add all initial command line options for UDTTest --- tools/udt-test/src/UDTTest.cpp | 95 ++++++++++++++++++++++++++++++++-- tools/udt-test/src/UDTTest.h | 12 ++++- 2 files changed, 103 insertions(+), 4 deletions(-) diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index d2f8bf6e40..6bfac4ad26 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -13,7 +13,32 @@ #include +#include + const QCommandLineOption PORT_OPTION { "p", "listening port for socket (defaults to random)", "port", 0 }; +const QCommandLineOption TARGET_OPTION { + "target", "target for sent packets (default is listen only)", + "IP:PORT or HOSTNAME:PORT" +}; +const QCommandLineOption PACKET_SIZE { + "packet-size", "size for sent packets in bytes (defaults to 1500)", "bytes", + QString(udt::MAX_PACKET_SIZE_WITH_UDP_HEADER) +}; +const QCommandLineOption MIN_PACKET_SIZE { + "min-packet-size", "min size for sent packets in bytes", "min-bytes" +}; +const QCommandLineOption MAX_PACKET_SIZE { + "max-packet-size", "max size for sent packets in bytes", "max-bytes" +}; +const QCommandLineOption MAX_SEND_BYTES { + "max-send-bytes", "number of bytes to send before stopping (default is infinite)", "max-bytes" +}; +const QCommandLineOption MAX_SEND_PACKETS { + "max-send-packets", "number of packets to send before stopping (default is infinite)", "max-packets" +}; +const QCommandLineOption UNRELIABLE_PACKETS { + "unreliable", "send unreliable packets (default is reliable)" +}; UDTTest::UDTTest(int& argc, char** argv) : QCoreApplication(argc, argv) @@ -22,18 +47,82 @@ UDTTest::UDTTest(int& argc, char** argv) : _socket.bind(QHostAddress::LocalHost, _argumentParser.value(PORT_OPTION).toUInt()); qDebug() << "Test socket is listening on" << _socket.localPort(); + + if (_argumentParser.isSet(TARGET_OPTION)) { + // parse the IP and port combination for this target + QString hostnamePortString = _argumentParser.value(TARGET_OPTION); + + QHostAddress address { hostnamePortString.left(hostnamePortString.indexOf(':')) }; + quint16 port { (quint16) hostnamePortString.right(hostnamePortString.indexOf(':') + 1).toUInt() }; + + if (address.isNull() || port == 0) { + qCritical() << "Could not parse an IP address and port combination from" << hostnamePortString << "-" << + "The parsed IP was" << address.toString() << "and the parsed port was" << port; + + QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); + } else { + _target = HifiSockAddr(address, port); + } + } + + if (_argumentParser.isSet(PACKET_SIZE)) { + // parse the desired packet size + _minPacketSize = _maxPacketSize = _argumentParser.value(PACKET_SIZE).toInt(); + + if (_argumentParser.isSet(MIN_PACKET_SIZE) || _argumentParser.isSet(MAX_PACKET_SIZE)) { + qCritical() << "Cannot set a min packet size or max packet size AND a specific packet size."; + QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); + } + } else { + + bool customMinSize = false; + + if (_argumentParser.isSet(MIN_PACKET_SIZE)) { + _minPacketSize = _argumentParser.value(MIN_PACKET_SIZE).toInt(); + customMinSize = true; + } + + if (_argumentParser.isSet(MAX_PACKET_SIZE)) { + _maxPacketSize = _argumentParser.value(MAX_PACKET_SIZE).toInt(); + + // if we don't have a min packet size we should make it zero, because we have a max + if (customMinSize) { + _minPacketSize = 0; + } + } + + if (_maxPacketSize < _minPacketSize) { + qCritical() << "Cannot set a max packet size that is smaller than the min packet size."; + QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); + } + } + + if (_argumentParser.isSet(MAX_SEND_BYTES)) { + _maxSendBytes = _argumentParser.value(MAX_SEND_BYTES).toInt(); + } + + if (_argumentParser.isSet(MAX_SEND_PACKETS)) { + _maxSendPackets = _argumentParser.value(MAX_SEND_PACKETS).toInt(); + } + + if (_argumentParser.isSet(UNRELIABLE_PACKETS)) { + _sendReliable = false; + } } void UDTTest::parseArguments() { // use a QCommandLineParser to setup command line arguments and give helpful output - _argumentParser.setApplicationDescription("High Fidelity Assignment Client"); + _argumentParser.setApplicationDescription("High Fidelity UDT Protocol Test Client"); _argumentParser.addHelpOption(); const QCommandLineOption helpOption = _argumentParser.addHelpOption(); - _argumentParser.addOption(PORT_OPTION); + _argumentParser.addOptions({ + PORT_OPTION, TARGET_OPTION, PACKET_SIZE, MIN_PACKET_SIZE, MAX_PACKET_SIZE, + MAX_SEND_BYTES, MAX_SEND_PACKETS, UNRELIABLE_PACKETS + }); - if (!_argumentParser.parse(QCoreApplication::arguments())) { + if (!_argumentParser.parse(arguments())) { qCritical() << _argumentParser.errorText(); _argumentParser.showHelp(); Q_UNREACHABLE(); diff --git a/tools/udt-test/src/UDTTest.h b/tools/udt-test/src/UDTTest.h index 86d15974d0..678a067114 100644 --- a/tools/udt-test/src/UDTTest.h +++ b/tools/udt-test/src/UDTTest.h @@ -17,7 +17,8 @@ #include #include -#include +#include +#include class UDTTest : public QCoreApplication { public: @@ -27,6 +28,15 @@ private: QCommandLineParser _argumentParser; udt::Socket _socket; + + HifiSockAddr _target; // the target for sent packets + + int _minPacketSize = udt::MAX_PACKET_SIZE_WITH_UDP_HEADER; + int _maxPacketSize = udt::MAX_PACKET_SIZE_WITH_UDP_HEADER; + int _maxSendBytes = -1; // the number of bytes to send to the target before stopping + int _maxSendPackets = -1; // the number of packets to send to the target before stopping + + bool _sendReliable = true; // wether packets are sent reliably or unreliably }; #endif // hifi_UDTTest_h From d340515ab3f513eef0095f4903cfe1f293d842fc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jul 2015 17:09:25 -0700 Subject: [PATCH 184/549] complete the initial version of UDTTest --- libraries/entities/src/EntityItemID.cpp | 2 + libraries/networking/src/AddressManager.cpp | 4 +- libraries/networking/src/NLPacket.h | 1 + libraries/networking/src/NetworkPeer.cpp | 5 +- libraries/networking/src/Node.cpp | 3 +- libraries/{shared => networking}/src/UUID.cpp | 0 libraries/{shared => networking}/src/UUID.h | 0 .../networking/src/WalletTransaction.cpp | 8 +-- libraries/networking/src/udt/Connection.cpp | 2 + libraries/networking/src/udt/Connection.h | 9 ++- libraries/networking/src/udt/PacketHeaders.h | 2 - libraries/networking/src/udt/SendQueue.cpp | 4 ++ libraries/networking/src/udt/SendQueue.h | 3 + libraries/networking/src/udt/Socket.cpp | 30 +++++--- libraries/networking/src/udt/Socket.h | 3 + tools/udt-test/src/UDTTest.cpp | 69 ++++++++++++++++++- tools/udt-test/src/UDTTest.h | 21 ++++-- 17 files changed, 133 insertions(+), 33 deletions(-) rename libraries/{shared => networking}/src/UUID.cpp (100%) rename libraries/{shared => networking}/src/UUID.h (100%) diff --git a/libraries/entities/src/EntityItemID.cpp b/libraries/entities/src/EntityItemID.cpp index ab2c39324f..36664f5457 100644 --- a/libraries/entities/src/EntityItemID.cpp +++ b/libraries/entities/src/EntityItemID.cpp @@ -11,8 +11,10 @@ #include #include + #include #include +#include #include "RegisteredMetaTypes.h" #include "EntityItemID.h" diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 3f3234a307..ed4728ad78 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -18,11 +18,11 @@ #include #include -#include +#include "AddressManager.h" #include "NodeList.h" #include "NetworkLogging.h" -#include "AddressManager.h" +#include "UUID.h" const QString ADDRESS_MANAGER_SETTINGS_GROUP = "AddressManager"; const QString SETTINGS_CURRENT_ADDRESS_KEY = "address"; diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index 25efd673aa..11cebd2468 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -14,6 +14,7 @@ #include +#include "UUID.h" #include "udt/Packet.h" class NLPacket : public udt::Packet { diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index 9e51bc5dac..0ffb87fe6c 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -16,11 +16,10 @@ #include #include -#include - -#include "NetworkLogging.h" #include "BandwidthRecorder.h" +#include "NetworkLogging.h" +#include "UUID.h" NetworkPeer::NetworkPeer(QObject* parent) : QObject(parent), diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 6f10e6dbdb..9f580c6d20 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -12,10 +12,9 @@ #include #include -#include - #include "Node.h" #include "SharedUtil.h" +#include "UUID.h" #include #include diff --git a/libraries/shared/src/UUID.cpp b/libraries/networking/src/UUID.cpp similarity index 100% rename from libraries/shared/src/UUID.cpp rename to libraries/networking/src/UUID.cpp diff --git a/libraries/shared/src/UUID.h b/libraries/networking/src/UUID.h similarity index 100% rename from libraries/shared/src/UUID.h rename to libraries/networking/src/UUID.h diff --git a/libraries/networking/src/WalletTransaction.cpp b/libraries/networking/src/WalletTransaction.cpp index 9c8226a908..67fc73de07 100644 --- a/libraries/networking/src/WalletTransaction.cpp +++ b/libraries/networking/src/WalletTransaction.cpp @@ -1,6 +1,6 @@ // // WalletTransaction.cpp -// domain-server/src +// libraries/networking/src // // Created by Stephen Birarda on 2014-05-20. // Copyright 2014 High Fidelity, Inc. @@ -11,10 +11,10 @@ #include -#include - +#include "UUID.h" #include "WalletTransaction.h" + WalletTransaction::WalletTransaction() : _uuid(), _destinationUUID(), @@ -64,4 +64,4 @@ void WalletTransaction::loadFromJson(const QJsonObject& jsonObject) { _uuid = QUuid(transactionObject.value(TRANSACTION_ID_KEY).toString()); _destinationUUID = QUuid(transactionObject.value(TRANSACTION_DESTINATION_WALLET_ID_KEY).toString()); _amount = transactionObject.value(TRANSACTION_AMOUNT_KEY).toInt(); -} \ No newline at end of file +} diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index f7f32d7480..8f6d9a2812 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -50,6 +50,8 @@ void Connection::sendReliablePacket(unique_ptr packet) { if (!_sendQueue) { // Lasily create send queue _sendQueue = SendQueue::create(_parentSocket, _destination); + + QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::packetSent); } _sendQueue->queuePacket(move(packet)); diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 0c9fa831df..a86c8f817f 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -15,6 +15,8 @@ #include #include +#include + #include "ConnectionStats.h" #include "Constants.h" #include "LossList.h" @@ -29,8 +31,8 @@ class ControlPacket; class Packet; class Socket; -class Connection { - +class Connection : public QObject { + Q_OBJECT public: using SequenceNumberTimePair = std::pair; using SentACKMap = std::unordered_map; @@ -44,6 +46,9 @@ public: bool processReceivedSequenceNumber(SequenceNumber sequenceNumber); // returns indicates if this packet was a duplicate void processControl(std::unique_ptr controlPacket); + +signals: + void packetSent(); private: void sendACK(bool wasCausedBySyncTimeout = true); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index d8bc1d52e6..8283a95e4f 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -21,8 +21,6 @@ #include #include -#include "UUID.h" - // If adding a new packet packetType, you can replace one marked usable or add at the end. // If you want the name of the packet packetType to be available for debugging or logging, update nameForPacketType() as well // This enum must hold 256 or fewer packet types (so the value is <= 255) since it is statically typed as a uint8_t diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index e6bc59c6cb..7d0edf9d7c 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -189,6 +189,8 @@ void SendQueue::loop() { Q_ASSERT_X(!nextPacket, "SendQueue::sendNextPacket()", "Overriden packet in sent list"); + emit packetSent(); + if (shouldSendSecondOfPair) { std::unique_ptr pairedPacket; @@ -209,6 +211,8 @@ void SendQueue::loop() { _sentPackets[pairedPacket->getSequenceNumber()].swap(pairedPacket); Q_ASSERT_X(!pairedPacket, "SendQueue::sendNextPacket()", "Overriden packet in sent list"); + + emit packetSent(); } } } diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 4b8bf6a11f..1b6b6181b8 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -61,6 +61,9 @@ public slots: void ack(SequenceNumber ack); void nak(SequenceNumber start, SequenceNumber end); void overrideNAKListFromPacket(ControlPacket& packet); + +signals: + void packetSent(); private slots: void loop(); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index f8515affe6..99817f9790 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -85,11 +85,7 @@ qint64 Socket::writePacket(const Packet& packet, const HifiSockAddr& sockAddr) { qint64 Socket::writePacket(std::unique_ptr packet, const HifiSockAddr& sockAddr) { if (packet->isReliable()) { - auto it = _connectionsHash.find(sockAddr); - if (it == _connectionsHash.end()) { - it = _connectionsHash.insert(it, std::make_pair(sockAddr, new Connection(this, sockAddr, _ccFactory->create()))); - } - it->second->sendReliablePacket(std::move(packet)); + auto connection = findOrCreateConnection(sockAddr); return 0; } @@ -111,6 +107,16 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc return bytesWritten; } +Connection* Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { + auto it = _connectionsHash.find(sockAddr); + + if (it == _connectionsHash.end()) { + it = _connectionsHash.insert(it, std::make_pair(sockAddr, new Connection(this, sockAddr, _ccFactory->create()))); + } + + return it->second; +} + void Socket::readPendingDatagrams() { while (_udpSocket.hasPendingDatagrams()) { // setup a HifiSockAddr to read into @@ -144,11 +150,8 @@ void Socket::readPendingDatagrams() { auto controlPacket = ControlPacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); // move this control packet to the matching connection - auto it = _connectionsHash.find(senderSockAddr); - - if (it != _connectionsHash.end()) { - it->second->processControl(move(controlPacket)); - } + auto connection = findOrCreateConnection(senderSockAddr); + connection->processControl(move(controlPacket)); } else { // setup a Packet from the data we just read @@ -176,6 +179,13 @@ void Socket::readPendingDatagrams() { } } +void Socket::connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* receiver, const char* slot) { + auto it = _connectionsHash.find(destinationAddr); + if (it != _connectionsHash.end()) { + connect(it->second, SIGNAL(packetSent()), receiver, slot); + } +} + void Socket::rateControlSync() { // enumerate our list of connections and ask each of them to send off periodic ACK packet for rate control diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index e923f4b307..8c8ecb32b2 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -60,6 +60,8 @@ public: { _unfilteredHandlers[senderSockAddr] = handler; } void setCongestionControlFactory(std::unique_ptr ccFactory); + + void connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* receiver, const char* slot); private slots: void readPendingDatagrams(); @@ -67,6 +69,7 @@ private slots: private: void setSystemBufferSizes(); + Connection* findOrCreateConnection(const HifiSockAddr& sockAddr); QUdpSocket _udpSocket { this }; PacketFilterOperator _packetFilterOperator; diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 6bfac4ad26..810f68ccb6 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -14,6 +14,7 @@ #include #include +#include const QCommandLineOption PORT_OPTION { "p", "listening port for socket (defaults to random)", "port", 0 }; const QCommandLineOption TARGET_OPTION { @@ -45,6 +46,9 @@ UDTTest::UDTTest(int& argc, char** argv) : { parseArguments(); + // randomize the seed for packet size randomization + srand(time(NULL)); + _socket.bind(QHostAddress::LocalHost, _argumentParser.value(PORT_OPTION).toUInt()); qDebug() << "Test socket is listening on" << _socket.localPort(); @@ -53,7 +57,7 @@ UDTTest::UDTTest(int& argc, char** argv) : QString hostnamePortString = _argumentParser.value(TARGET_OPTION); QHostAddress address { hostnamePortString.left(hostnamePortString.indexOf(':')) }; - quint16 port { (quint16) hostnamePortString.right(hostnamePortString.indexOf(':') + 1).toUInt() }; + quint16 port { (quint16) hostnamePortString.mid(hostnamePortString.indexOf(':') + 1).toUInt() }; if (address.isNull() || port == 0) { qCritical() << "Could not parse an IP address and port combination from" << hostnamePortString << "-" << @@ -85,9 +89,9 @@ UDTTest::UDTTest(int& argc, char** argv) : if (_argumentParser.isSet(MAX_PACKET_SIZE)) { _maxPacketSize = _argumentParser.value(MAX_PACKET_SIZE).toInt(); - // if we don't have a min packet size we should make it zero, because we have a max + // if we don't have a min packet size we should make it 1, because we have a max if (customMinSize) { - _minPacketSize = 0; + _minPacketSize = 1; } } @@ -108,6 +112,10 @@ UDTTest::UDTTest(int& argc, char** argv) : if (_argumentParser.isSet(UNRELIABLE_PACKETS)) { _sendReliable = false; } + + if (!_target.isNull()) { + sendInitialPackets(); + } } void UDTTest::parseArguments() { @@ -133,3 +141,58 @@ void UDTTest::parseArguments() { Q_UNREACHABLE(); } } + +void UDTTest::sendInitialPackets() { + static const int NUM_INITIAL_PACKETS = 500; + + int numPackets = std::max(NUM_INITIAL_PACKETS, _maxSendPackets); + + for (int i = 0; i < numPackets; ++i) { + sendPacket(); + } + + if (numPackets == NUM_INITIAL_PACKETS) { + // we've put 500 initial packets in the queue, everytime we hear one has gone out we should add a new one + _socket.connectToSendSignal(_target, this, SLOT(refillPacket())); + } +} + +void UDTTest::sendPacket() { + + qDebug() << "Sending packet" << _totalQueuedPackets + 1; + + if (_maxSendPackets != -1 && _totalQueuedPackets > _maxSendPackets) { + // don't send more packets, we've hit max + return; + } + + if (_maxSendBytes != -1 && _totalQueuedBytes > _maxSendBytes) { + // don't send more packets, we've hit max + return; + } + + // we're good to send a new packet, construct it now + + // figure out what size the packet will be + int packetPayloadSize = 0; + + if (_minPacketSize == _maxPacketSize) { + // we know what size we want - figure out the payload size + packetPayloadSize = _maxPacketSize - udt::Packet::localHeaderSize(false); + } else { + // pick a random size in our range + int randomPacketSize = rand() % _maxPacketSize + _minPacketSize; + packetPayloadSize = randomPacketSize - udt::Packet::localHeaderSize(false); + } + + auto newPacket = udt::Packet::create(packetPayloadSize, _sendReliable); + + // queue or send this packet by calling write packet on the socket for our target + if (_sendReliable) { + _socket.writePacket(std::move(newPacket), _target); + } else { + _socket.writePacket(*newPacket, _target); + } + + ++_totalQueuedPackets; +} diff --git a/tools/udt-test/src/UDTTest.h b/tools/udt-test/src/UDTTest.h index 678a067114..050c5dc75a 100644 --- a/tools/udt-test/src/UDTTest.h +++ b/tools/udt-test/src/UDTTest.h @@ -21,22 +21,33 @@ #include class UDTTest : public QCoreApplication { + Q_OBJECT public: UDTTest(int& argc, char** argv); + +public slots: + void refillPacket() { sendPacket(); } // adds a new packet to the queue when we are told one is sent + private: void parseArguments(); + void sendInitialPackets(); // fills the queue with packets to start + void sendPacket(); // constructs and sends a packet according to the test parameters + QCommandLineParser _argumentParser; udt::Socket _socket; HifiSockAddr _target; // the target for sent packets - int _minPacketSize = udt::MAX_PACKET_SIZE_WITH_UDP_HEADER; - int _maxPacketSize = udt::MAX_PACKET_SIZE_WITH_UDP_HEADER; - int _maxSendBytes = -1; // the number of bytes to send to the target before stopping - int _maxSendPackets = -1; // the number of packets to send to the target before stopping + int _minPacketSize { udt::MAX_PACKET_SIZE }; + int _maxPacketSize { udt::MAX_PACKET_SIZE }; + int _maxSendBytes { -1 }; // the number of bytes to send to the target before stopping + int _maxSendPackets { -1 }; // the number of packets to send to the target before stopping - bool _sendReliable = true; // wether packets are sent reliably or unreliably + bool _sendReliable { true }; // wether packets are sent reliably or unreliably + + int _totalQueuedPackets { 0 }; // keeps track of the number of packets we have already queued + int _totalQueuedBytes { 0 }; // keeps track of the number of bytes we have already queued }; #endif // hifi_UDTTest_h From 0f1d1a16a71f9a6a97f036221c6cf5b1d73d469d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jul 2015 17:12:42 -0700 Subject: [PATCH 185/549] actually call sendReliablePacket for write of reliable --- libraries/networking/src/udt/Socket.cpp | 2 +- tools/udt-test/src/UDTTest.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 99817f9790..810eaa73e2 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -85,7 +85,7 @@ qint64 Socket::writePacket(const Packet& packet, const HifiSockAddr& sockAddr) { qint64 Socket::writePacket(std::unique_ptr packet, const HifiSockAddr& sockAddr) { if (packet->isReliable()) { - auto connection = findOrCreateConnection(sockAddr); + findOrCreateConnection(sockAddr)->sendReliablePacket(move(packet)); return 0; } diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 810f68ccb6..f6aad9ee8a 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -143,7 +143,7 @@ void UDTTest::parseArguments() { } void UDTTest::sendInitialPackets() { - static const int NUM_INITIAL_PACKETS = 500; + static const int NUM_INITIAL_PACKETS = 10; int numPackets = std::max(NUM_INITIAL_PACKETS, _maxSendPackets); @@ -187,6 +187,8 @@ void UDTTest::sendPacket() { auto newPacket = udt::Packet::create(packetPayloadSize, _sendReliable); + _totalQueuedBytes += newPacket->getDataSize(); + // queue or send this packet by calling write packet on the socket for our target if (_sendReliable) { _socket.writePacket(std::move(newPacket), _target); From 1724e3c6320fa621dfe68b8bb1b0204d39b18168 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jul 2015 17:17:03 -0700 Subject: [PATCH 186/549] fix a couple of bugs in SendQueue --- libraries/networking/src/udt/SendQueue.cpp | 94 ++++++++++++---------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 7d0edf9d7c..d0ec6ee38e 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -62,7 +62,9 @@ void SendQueue::run() { // We need to make sure this is called on the right thread if (thread() != QThread::currentThread()) { QMetaObject::invokeMethod(this, "run", Qt::QueuedConnection); + return; } + _isRunning = true; // This will loop and sleep to send packets @@ -161,60 +163,64 @@ void SendQueue::loop() { } // If there is no packet to resend, grab the next one in the list - if (!nextPacket) { + if (!nextPacket && _packets.size() > 0) { QWriteLocker locker(&_packetsLock); nextPacket.swap(_packets.front()); _packets.pop_front(); } - bool shouldSendSecondOfPair = false; - - if (!hasResend) { - // if we're not re-sending a packet then need to check if this should be a packet pair - sequenceNumber = getNextSequenceNumber(); + if (nextPacket) { + bool shouldSendSecondOfPair = false; - // the first packet in the pair is every 16 (rightmost 16 bits = 0) packets - if (((uint32_t) sequenceNumber & 0xF) == 0) { - shouldSendSecondOfPair = true; + if (!hasResend) { + // if we're not re-sending a packet then need to check if this should be a packet pair + sequenceNumber = getNextSequenceNumber(); + + // the first packet in the pair is every 16 (rightmost 16 bits = 0) packets + if (((uint32_t) sequenceNumber & 0xF) == 0) { + shouldSendSecondOfPair = true; + } + } + + // Write packet's sequence number and send it off + nextPacket->writeSequenceNumber(sequenceNumber); + sendPacket(*nextPacket); + + // Insert the packet we have just sent in the sent list + QWriteLocker locker(&_sentLock); + _sentPackets[nextPacket->getSequenceNumber()].swap(nextPacket); + Q_ASSERT_X(!nextPacket, + "SendQueue::sendNextPacket()", "Overriden packet in sent list"); + + emit packetSent(); + + if (shouldSendSecondOfPair) { + std::unique_ptr pairedPacket; + + // we've detected we should send the second packet in a pair, do that now before sleeping + { + QWriteLocker locker(&_packetsLock); + pairedPacket.swap(_packets.front()); + _packets.pop_front(); + } + + if (pairedPacket) { + // write this packet's sequence number and send it off + pairedPacket->writeSequenceNumber(getNextSequenceNumber()); + sendPacket(*pairedPacket); + + // add the paired packet to the sent list + QWriteLocker locker(&_sentLock); + _sentPackets[pairedPacket->getSequenceNumber()].swap(pairedPacket); + Q_ASSERT_X(!pairedPacket, + "SendQueue::sendNextPacket()", "Overriden packet in sent list"); + + emit packetSent(); + } } } - // Write packet's sequence number and send it off - nextPacket->writeSequenceNumber(sequenceNumber); - sendPacket(*nextPacket); - // Insert the packet we have just sent in the sent list - QWriteLocker locker(&_sentLock); - _sentPackets[nextPacket->getSequenceNumber()].swap(nextPacket); - Q_ASSERT_X(!nextPacket, - "SendQueue::sendNextPacket()", "Overriden packet in sent list"); - - emit packetSent(); - - if (shouldSendSecondOfPair) { - std::unique_ptr pairedPacket; - - // we've detected we should send the second packet in a pair, do that now before sleeping - { - QWriteLocker locker(&_packetsLock); - pairedPacket.swap(_packets.front()); - _packets.pop_front(); - } - - if (pairedPacket) { - // write this packet's sequence number and send it off - pairedPacket->writeSequenceNumber(getNextSequenceNumber()); - sendPacket(*pairedPacket); - - // add the paired packet to the sent list - QWriteLocker locker(&_sentLock); - _sentPackets[pairedPacket->getSequenceNumber()].swap(pairedPacket); - Q_ASSERT_X(!pairedPacket, - "SendQueue::sendNextPacket()", "Overriden packet in sent list"); - - emit packetSent(); - } - } } // since we're a while loop, give the thread a chance to process events From 367fa7b07b11fa828c18a38b3a214acab7648f4b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jul 2015 17:20:22 -0700 Subject: [PATCH 187/549] fixes for assert in Connection and ControlPacket create --- libraries/networking/src/udt/Connection.cpp | 2 +- libraries/networking/src/udt/ControlPacket.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 8f6d9a2812..e26f524c31 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -76,7 +76,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { auto currentTime = high_resolution_clock::now(); SequenceNumber nextACKNumber = nextACK(); - Q_ASSERT_X(nextACKNumber < _lastSentACK, "Connection::sendACK", "Sending lower ACK, something is wrong"); + Q_ASSERT_X(nextACKNumber >= _lastSentACK, "Connection::sendACK", "Sending lower ACK, something is wrong"); if (nextACKNumber == _lastSentACK) { // We already sent this ACK, but check if we should re-send it. diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index 7378b2f314..626e126c03 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -46,12 +46,12 @@ std::unique_ptr ControlPacket::create(Type type, qint64 size) { std::unique_ptr controlPacket; if (size == -1) { - return ControlPacket::create(type); + return std::unique_ptr(new ControlPacket(type)); } else { // Fail with invalid size Q_ASSERT(size >= 0); - return ControlPacket::create(type, size); + return std::unique_ptr(new ControlPacket(type, size)); } } From 805c5a6affce36fceb345b55ebdc6dd1256383b3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jul 2015 17:22:25 -0700 Subject: [PATCH 188/549] reset initial to 500, remove debug --- tools/udt-test/src/UDTTest.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index f6aad9ee8a..8d9655437d 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -143,7 +143,7 @@ void UDTTest::parseArguments() { } void UDTTest::sendInitialPackets() { - static const int NUM_INITIAL_PACKETS = 10; + static const int NUM_INITIAL_PACKETS = 500; int numPackets = std::max(NUM_INITIAL_PACKETS, _maxSendPackets); @@ -159,8 +159,6 @@ void UDTTest::sendInitialPackets() { void UDTTest::sendPacket() { - qDebug() << "Sending packet" << _totalQueuedPackets + 1; - if (_maxSendPackets != -1 && _totalQueuedPackets > _maxSendPackets) { // don't send more packets, we've hit max return; From 8e786cb95313dde784b70fa5e6786ef6d156ca44 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jul 2015 17:40:51 -0700 Subject: [PATCH 189/549] repairs while testing with UDTTest --- libraries/networking/src/udt/Connection.cpp | 30 +++++++++++---------- libraries/networking/src/udt/SendQueue.cpp | 25 ++++++++--------- libraries/networking/src/udt/SendQueue.h | 3 +-- tools/udt-test/src/UDTTest.cpp | 2 ++ 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index e26f524c31..0d0140dbca 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -203,20 +203,22 @@ void Connection::sendNAK(SequenceNumber sequenceNumberRecieved) { } void Connection::sendTimeoutNAK() { - // construct a NAK packet that will hold all of the lost sequence numbers - // TODO size is wrong, fix it. - auto lossListPacket = ControlPacket::create(ControlPacket::TimeoutNAK, _lossList.getLength() * sizeof(SequenceNumber)); - - // Pack in the lost sequence numbers - _lossList.write(*lossListPacket); - - // have our SendQueue send off this control packet - _sendQueue->sendPacket(*lossListPacket); - - // record this as the last NAK time - _lastNAKTime = high_resolution_clock::now(); - - _stats.recordSentTimeoutNAK(); + if (_lossList.getLength() > 0) { + // construct a NAK packet that will hold all of the lost sequence numbers + // TODO size is wrong, fix it. + auto lossListPacket = ControlPacket::create(ControlPacket::TimeoutNAK, _lossList.getLength() * sizeof(SequenceNumber)); + + // Pack in the lost sequence numbers + _lossList.write(*lossListPacket); + + // have our SendQueue send off this control packet + _sendQueue->sendPacket(*lossListPacket); + + // record this as the last NAK time + _lastNAKTime = high_resolution_clock::now(); + + _stats.recordSentTimeoutNAK(); + } } SequenceNumber Connection::nextACK() const { diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index d0ec6ee38e..66051ad1c4 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -58,19 +58,6 @@ void SendQueue::queuePacket(std::unique_ptr packet) { } } -void SendQueue::run() { - // We need to make sure this is called on the right thread - if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, "run", Qt::QueuedConnection); - return; - } - - _isRunning = true; - - // This will loop and sleep to send packets - loop(); -} - void SendQueue::stop() { _isRunning = false; } @@ -128,7 +115,16 @@ SequenceNumber SendQueue::getNextSequenceNumber() { return _currentSequenceNumber; } -void SendQueue::loop() { +void SendQueue::run() { + + // We need to make sure this is called on the right thread + if (thread() != QThread::currentThread()) { + QMetaObject::invokeMethod(this, "run", Qt::QueuedConnection); + return; + } + + _isRunning = true; + while (_isRunning) { // Record timing _lastSendTimestamp = high_resolution_clock::now(); @@ -170,6 +166,7 @@ void SendQueue::loop() { } if (nextPacket) { + qDebug() << "the next packet is" << nextPacket->getDataSize() << "bytes"; bool shouldSendSecondOfPair = false; if (!hasResend) { diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 1b6b6181b8..3915414e1f 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -55,7 +55,6 @@ public: void sendPacket(const BasePacket& packet); public slots: - void run(); void stop(); void ack(SequenceNumber ack); @@ -66,7 +65,7 @@ signals: void packetSent(); private slots: - void loop(); + void run(); private: SendQueue(Socket* socket, HifiSockAddr dest); diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 8d9655437d..2bfcd48a76 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -66,6 +66,7 @@ UDTTest::UDTTest(int& argc, char** argv) : QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); } else { _target = HifiSockAddr(address, port); + qDebug() << "Packets will be sent to" << _target; } } @@ -184,6 +185,7 @@ void UDTTest::sendPacket() { } auto newPacket = udt::Packet::create(packetPayloadSize, _sendReliable); + newPacket->setPayloadSize(packetPayloadSize); _totalQueuedBytes += newPacket->getDataSize(); From a38e7b0431f55958818d3855ff0a9b61838002a9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jul 2015 17:59:27 -0700 Subject: [PATCH 190/549] cleanup SendQueue start and UDTTest bind --- libraries/networking/src/udt/SendQueue.cpp | 43 ++++++++++------------ libraries/networking/src/udt/SendQueue.h | 4 +- tools/udt-test/src/UDTTest.cpp | 2 +- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 66051ad1c4..5e3d1cc6e4 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -31,6 +31,9 @@ std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr dest) // Setup queue private thread QThread* thread = new QThread(); thread->setObjectName("Networking: SendQueue " + dest.objectName()); // Name thread for easier debug + + connect(thread, &QThread::started, queue.get(), &SendQueue::run); + connect(queue.get(), &QObject::destroyed, thread, &QThread::quit); // Thread auto cleanup connect(thread, &QThread::finished, thread, &QThread::deleteLater); // Thread auto cleanup @@ -45,7 +48,7 @@ SendQueue::SendQueue(Socket* socket, HifiSockAddr dest) : _socket(socket), _destination(dest) { - _packetSendPeriod = DEFAULT_SEND_PERIOD; + } void SendQueue::queuePacket(std::unique_ptr packet) { @@ -53,8 +56,8 @@ void SendQueue::queuePacket(std::unique_ptr packet) { QWriteLocker locker(&_packetsLock); _packets.push_back(std::move(packet)); } - if (!_isRunning) { - run(); + if (!this->thread()->isRunning()) { + this->thread()->start(); } } @@ -116,13 +119,6 @@ SequenceNumber SendQueue::getNextSequenceNumber() { } void SendQueue::run() { - - // We need to make sure this is called on the right thread - if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, "run", Qt::QueuedConnection); - return; - } - _isRunning = true; while (_isRunning) { @@ -166,7 +162,6 @@ void SendQueue::run() { } if (nextPacket) { - qDebug() << "the next packet is" << nextPacket->getDataSize() << "bytes"; bool shouldSendSecondOfPair = false; if (!hasResend) { @@ -183,11 +178,13 @@ void SendQueue::run() { nextPacket->writeSequenceNumber(sequenceNumber); sendPacket(*nextPacket); - // Insert the packet we have just sent in the sent list - QWriteLocker locker(&_sentLock); - _sentPackets[nextPacket->getSequenceNumber()].swap(nextPacket); - Q_ASSERT_X(!nextPacket, - "SendQueue::sendNextPacket()", "Overriden packet in sent list"); + { + // Insert the packet we have just sent in the sent list + QWriteLocker locker(&_sentLock); + _sentPackets[nextPacket->getSequenceNumber()].swap(nextPacket); + Q_ASSERT_X(!nextPacket, + "SendQueue::sendNextPacket()", "Overriden packet in sent list"); + } emit packetSent(); @@ -206,18 +203,18 @@ void SendQueue::run() { pairedPacket->writeSequenceNumber(getNextSequenceNumber()); sendPacket(*pairedPacket); - // add the paired packet to the sent list - QWriteLocker locker(&_sentLock); - _sentPackets[pairedPacket->getSequenceNumber()].swap(pairedPacket); - Q_ASSERT_X(!pairedPacket, - "SendQueue::sendNextPacket()", "Overriden packet in sent list"); + { + // add the paired packet to the sent list + QWriteLocker locker(&_sentLock); + _sentPackets[pairedPacket->getSequenceNumber()].swap(pairedPacket); + Q_ASSERT_X(!pairedPacket, + "SendQueue::sendNextPacket()", "Overriden packet in sent list"); + } emit packetSent(); } } } - - } // since we're a while loop, give the thread a chance to process events diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 3915414e1f..f8ffa91c96 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -37,7 +37,7 @@ class SendQueue : public QObject { Q_OBJECT public: - static const int DEFAULT_SEND_PERIOD = 16 * 1000; // 16ms, in microseconds + static const int DEFAULT_SEND_PERIOD = 1; // in microseconds static std::unique_ptr create(Socket* socket, HifiSockAddr dest); @@ -86,7 +86,7 @@ private: SequenceNumber _currentSequenceNumber; // Last sequence number sent out std::atomic _atomicCurrentSequenceNumber; // Atomic for last sequence number sent out - std::atomic _packetSendPeriod { 0 }; // Interval between two packet send event in microseconds + std::atomic _packetSendPeriod { DEFAULT_SEND_PERIOD }; // Interval between two packet send event in microseconds std::chrono::high_resolution_clock::time_point _lastSendTimestamp; // Record last time of packet departure std::atomic _isRunning { false }; diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 2bfcd48a76..9f149dce52 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -49,7 +49,7 @@ UDTTest::UDTTest(int& argc, char** argv) : // randomize the seed for packet size randomization srand(time(NULL)); - _socket.bind(QHostAddress::LocalHost, _argumentParser.value(PORT_OPTION).toUInt()); + _socket.bind(QHostAddress::AnyIPv4, _argumentParser.value(PORT_OPTION).toUInt()); qDebug() << "Test socket is listening on" << _socket.localPort(); if (_argumentParser.isSet(TARGET_OPTION)) { From a714f8081d963c13028b29e236712080725dd4f9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 30 Jul 2015 18:10:59 -0700 Subject: [PATCH 191/549] Fix a couple networking bugs --- libraries/networking/src/udt/LossList.cpp | 2 +- libraries/networking/src/udt/SequenceNumber.h | 4 ++-- libraries/networking/src/udt/Socket.cpp | 8 ++------ 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp index 32812be10b..90399e319d 100644 --- a/libraries/networking/src/udt/LossList.cpp +++ b/libraries/networking/src/udt/LossList.cpp @@ -17,7 +17,7 @@ using namespace udt; using namespace std; void LossList::append(SequenceNumber seq) { - assert(_lossList.back().second < seq); + assert(_lossList.empty() || _lossList.back().second < seq); if (getLength() > 0 && _lossList.back().second + 1 == seq) { ++_lossList.back().second; diff --git a/libraries/networking/src/udt/SequenceNumber.h b/libraries/networking/src/udt/SequenceNumber.h index d5b61c0a95..c77a14edf9 100644 --- a/libraries/networking/src/udt/SequenceNumber.h +++ b/libraries/networking/src/udt/SequenceNumber.h @@ -45,12 +45,12 @@ public: } inline SequenceNumber operator++(int) { SequenceNumber before = *this; - (*this)++; + ++(*this); return before; } inline SequenceNumber operator--(int) { SequenceNumber before = *this; - (*this)--; + --(*this); return before; } diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 810eaa73e2..ba0e196669 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -162,12 +162,8 @@ void Socket::readPendingDatagrams() { if (packet->isReliable()) { // if this was a reliable packet then signal the matching connection with the sequence number - // assuming it exists - auto it = _connectionsHash.find(senderSockAddr); - - if (it != _connectionsHash.end()) { - it->second->processReceivedSequenceNumber(packet->getSequenceNumber()); - } + auto connection = findOrCreateConnection(senderSockAddr); + connection->processReceivedSequenceNumber(packet->getSequenceNumber()); } if (_packetHandler) { From 98385ce8cd0a1d9e6a1661a358b704224697b464 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jul 2015 18:14:54 -0700 Subject: [PATCH 192/549] default sequence numbers to 0 --- libraries/networking/src/udt/Connection.h | 8 ++++---- libraries/networking/src/udt/SendQueue.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index a86c8f817f..606359e6f5 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -77,12 +77,12 @@ private: std::chrono::high_resolution_clock::time_point _lastNAKTime; LossList _lossList; // List of all missing packets - SequenceNumber _lastReceivedSequenceNumber { SequenceNumber::MAX }; // The largest sequence number received from the peer - SequenceNumber _lastReceivedACK { SequenceNumber::MAX }; // The last ACK received - SequenceNumber _lastReceivedAcknowledgedACK { SequenceNumber::MAX }; // The last sent ACK that has been acknowledged via an ACK2 from the peer + SequenceNumber _lastReceivedSequenceNumber; // The largest sequence number received from the peer + SequenceNumber _lastReceivedACK; // The last ACK received + SequenceNumber _lastReceivedAcknowledgedACK; // The last sent ACK that has been acknowledged via an ACK2 from the peer SequenceNumber _currentACKSubSequenceNumber; // The current ACK sub-sequence number (used for Acknowledgment of ACKs) - SequenceNumber _lastSentACK { SequenceNumber::MAX }; // The last sent ACK + SequenceNumber _lastSentACK; // The last sent ACK SequenceNumber _lastSentACK2; // The last sent ACK sub-sequence number in an ACK2 int32_t _rtt; // RTT, in microseconds diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index f8ffa91c96..24bdea27df 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -84,7 +84,7 @@ private: std::atomic _lastACKSequenceNumber; // Last ACKed sequence number SequenceNumber _currentSequenceNumber; // Last sequence number sent out - std::atomic _atomicCurrentSequenceNumber; // Atomic for last sequence number sent out + std::atomic _atomicCurrentSequenceNumber;// Atomic for last sequence number sent out std::atomic _packetSendPeriod { DEFAULT_SEND_PERIOD }; // Interval between two packet send event in microseconds std::chrono::high_resolution_clock::time_point _lastSendTimestamp; // Record last time of packet departure From e81e1c42b0eb9b48db64f03e09b08b873edf131c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 30 Jul 2015 18:22:27 -0700 Subject: [PATCH 193/549] Add send queue getter --- libraries/networking/src/udt/Connection.cpp | 33 +++++++++++---------- libraries/networking/src/udt/Connection.h | 2 ++ 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 0d0140dbca..474088671f 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -44,9 +44,7 @@ Connection::~Connection() { } } -void Connection::sendReliablePacket(unique_ptr packet) { - Q_ASSERT_X(packet->isReliable(), "Connection::send", "Trying to send an unreliable packet reliably."); - +SendQueue& Connection::getSendQueue() { if (!_sendQueue) { // Lasily create send queue _sendQueue = SendQueue::create(_parentSocket, _destination); @@ -54,7 +52,12 @@ void Connection::sendReliablePacket(unique_ptr packet) { QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::packetSent); } - _sendQueue->queuePacket(move(packet)); + return *_sendQueue; +} + +void Connection::sendReliablePacket(unique_ptr packet) { + Q_ASSERT_X(packet->isReliable(), "Connection::send", "Trying to send an unreliable packet reliably."); + getSendQueue().queuePacket(move(packet)); } void Connection::sync() { @@ -129,7 +132,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { } // have the send queue send off our packet - _sendQueue->sendPacket(*ackPacket); + getSendQueue().sendPacket(*ackPacket); // write this ACK to the map of sent ACKs _sentACKs[_currentACKSubSequenceNumber] = { nextACKNumber, currentTime }; @@ -159,7 +162,7 @@ void Connection::sendLightACK() { lightACKPacket->writePrimitive(nextACKNumber); // have the send queue send off our packet immediately - _sendQueue->sendPacket(*lightACKPacket); + getSendQueue().sendPacket(*lightACKPacket); _stats.recordSentLightACK(); } @@ -194,7 +197,7 @@ void Connection::sendNAK(SequenceNumber sequenceNumberRecieved) { } // have the send queue send off our packet immediately - _sendQueue->sendPacket(*lossReport); + getSendQueue().sendPacket(*lossReport); // record our last NAK time _lastNAKTime = high_resolution_clock::now(); @@ -212,7 +215,7 @@ void Connection::sendTimeoutNAK() { _lossList.write(*lossListPacket); // have our SendQueue send off this control packet - _sendQueue->sendPacket(*lossListPacket); + getSendQueue().sendPacket(*lossListPacket); // record this as the last NAK time _lastNAKTime = high_resolution_clock::now(); @@ -337,7 +340,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { controlPacket->readPrimitive(&ack); // validate that this isn't a BS ACK - if (ack > _sendQueue->getCurrentSequenceNumber()) { + if (ack > getSendQueue().getCurrentSequenceNumber()) { // in UDT they specifically break the connection here - do we want to do anything? Q_ASSERT_X(true, "Connection::processACK", "ACK recieved higher than largest sent sequence number"); return; @@ -363,7 +366,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { _lastReceivedACK = ack; // ACK the send queue so it knows what was received - _sendQueue->ack(ack); + getSendQueue().ack(ack); // update the RTT @@ -455,7 +458,7 @@ void Connection::processNAK(std::unique_ptr controlPacket) { } // send that off to the send queue so it knows there was loss - _sendQueue->nak(start, end); + getSendQueue().nak(start, end); // give the loss to the congestion control object and update the send queue parameters updateCongestionControlAndSendQueue([this, start, end](){ @@ -467,7 +470,7 @@ void Connection::processNAK(std::unique_ptr controlPacket) { void Connection::processTimeoutNAK(std::unique_ptr controlPacket) { // Override SendQueue's LossList with the timeout NAK list - _sendQueue->overrideNAKListFromPacket(*controlPacket); + getSendQueue().overrideNAKListFromPacket(*controlPacket); // we don't tell the congestion control object there was loss here - this matches UDTs implementation // a possible improvement would be to tell it which new loss this timeout packet told us about @@ -501,12 +504,12 @@ int Connection::estimatedTimeout() const { void Connection::updateCongestionControlAndSendQueue(std::function congestionCallback) { // update the last sent sequence number in congestion control - _congestionControl->setSendCurrentSequenceNumber(_sendQueue->getCurrentSequenceNumber()); + _congestionControl->setSendCurrentSequenceNumber(getSendQueue().getCurrentSequenceNumber()); // fire congestion control callback congestionCallback(); // now that we've update the congestion control, update the packet send period and flow window size - _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); - _sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); + getSendQueue().setPacketSendPeriod(_congestionControl->_packetSendPeriod); + getSendQueue().setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); } diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 606359e6f5..b006003526 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -63,6 +63,8 @@ private: void processNAK(std::unique_ptr controlPacket); void processTimeoutNAK(std::unique_ptr controlPacket); + + SendQueue& getSendQueue(); SequenceNumber nextACK() const; void updateRTT(int rtt); From 6c4a36fb7f877373ba7fbc111125b85fcf93a565 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jul 2015 18:22:43 -0700 Subject: [PATCH 194/549] lock then check size --- libraries/networking/src/udt/SendQueue.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 5e3d1cc6e4..249cb6e069 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -155,10 +155,13 @@ void SendQueue::run() { } // If there is no packet to resend, grab the next one in the list - if (!nextPacket && _packets.size() > 0) { + if (!nextPacket) { QWriteLocker locker(&_packetsLock); - nextPacket.swap(_packets.front()); - _packets.pop_front(); + + if (_packets.size() > 0) { + nextPacket.swap(_packets.front()); + _packets.pop_front(); + } } if (nextPacket) { @@ -194,8 +197,11 @@ void SendQueue::run() { // we've detected we should send the second packet in a pair, do that now before sleeping { QWriteLocker locker(&_packetsLock); - pairedPacket.swap(_packets.front()); - _packets.pop_front(); + + if (_packets.size() > 0) { + pairedPacket.swap(_packets.front()); + _packets.pop_front(); + } } if (pairedPacket) { From 0ea1bb578f28591141a68f4c81f9a2cadc131c10 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 08:57:25 -0700 Subject: [PATCH 195/549] support max bandwidth in congestion control --- libraries/networking/src/udt/CongestionControl.cpp | 8 ++++++++ libraries/networking/src/udt/CongestionControl.h | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 1450e60930..65f358e0bf 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -112,6 +112,14 @@ void DefaultCC::onACK(SequenceNumber ackNum) { } _packetSendPeriod = (_packetSendPeriod * synInterval()) / (_packetSendPeriod * increase + synInterval()); + + if (_maxBandwidth > 0) { + // anytime the packet send period is about to be increased, make sure it stays below the minimum period, + // calculated based on the maximum desired bandwidth + int minPacketSendPeriod = USECS_PER_SECOND / (double(_maxBandwidth) / _mss); + _packetSendPeriod = std::max(_packetSendPeriod, (double) minPacketSendPeriod); + } + } void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) { diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index f8f4860a89..e5af8acac8 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -47,15 +47,16 @@ protected: void setMSS(int mss) { _mss = mss; } void setMaxCongestionWindowSize(int window) { _maxCongestionWindowSize = window; } void setBandwidth(int bandwidth) { _bandwidth = bandwidth; } + void setMaxBandwidth(int maxBandwidth) { _maxBandwidth = maxBandwidth; } void setSendCurrentSequenceNumber(SequenceNumber seqNum) { _sendCurrSeqNum = seqNum; } void setReceiveRate(int rate) { _receiveRate = rate; } void setRTT(int rtt) { _rtt = rtt; } - double _packetSendPeriod { 1.0 }; // Packet sending period, in microseconds double _congestionWindowSize { 16.0 }; // Congestion window size, in packets int _bandwidth { 0 }; // estimated bandwidth, packets per second + int _maxBandwidth { -1 }; // Maximum desired bandwidth, packets per second double _maxCongestionWindowSize { 0.0 }; // maximum cwnd size, in packets int _mss { 0 }; // Maximum Packet Size, including all packet headers From c2d39f0f6afe5e1c40009ffccc194ead8c016896 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 09:02:43 -0700 Subject: [PATCH 196/549] make packet send period update respect max bandwidth --- .../networking/src/udt/CongestionControl.cpp | 21 +++++++++++-------- .../networking/src/udt/CongestionControl.h | 1 + 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 65f358e0bf..984d520d07 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -17,6 +17,17 @@ using namespace std::chrono; static const double USECS_PER_SECOND = 1000000.0; +void CongestionControl::setPacketSendPeriod(double newSendPeriod) { + if (_maxBandwidth > 0) { + // anytime the packet send period is about to be increased, make sure it stays below the minimum period, + // calculated based on the maximum desired bandwidth + int minPacketSendPeriod = USECS_PER_SECOND / (double(_maxBandwidth) / _mss); + _packetSendPeriod = std::max(newSendPeriod, (double) minPacketSendPeriod); + } else { + _packetSendPeriod = newSendPeriod; + } +} + void DefaultCC::init() { _lastRCTime = high_resolution_clock::now(); @@ -111,15 +122,7 @@ void DefaultCC::onACK(SequenceNumber ackNum) { } } - _packetSendPeriod = (_packetSendPeriod * synInterval()) / (_packetSendPeriod * increase + synInterval()); - - if (_maxBandwidth > 0) { - // anytime the packet send period is about to be increased, make sure it stays below the minimum period, - // calculated based on the maximum desired bandwidth - int minPacketSendPeriod = USECS_PER_SECOND / (double(_maxBandwidth) / _mss); - _packetSendPeriod = std::max(_packetSendPeriod, (double) minPacketSendPeriod); - } - + setPacketSendPeriod((_packetSendPeriod * synInterval()) / (_packetSendPeriod * increase + synInterval())); } void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) { diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index e5af8acac8..75970ed2fd 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -51,6 +51,7 @@ protected: void setSendCurrentSequenceNumber(SequenceNumber seqNum) { _sendCurrSeqNum = seqNum; } void setReceiveRate(int rate) { _receiveRate = rate; } void setRTT(int rtt) { _rtt = rtt; } + void setPacketSendPeriod(double newSendPeriod); // call this internally to ensure send period doesn't go past max bandwidth double _packetSendPeriod { 1.0 }; // Packet sending period, in microseconds double _congestionWindowSize { 16.0 }; // Congestion window size, in packets From f2ab2fb08a0112a9fe053262fd8f696a0f1318ca Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 09:36:55 -0700 Subject: [PATCH 197/549] start with a congestion window of 16, not 25 grand --- libraries/networking/src/udt/Connection.cpp | 4 ++++ libraries/networking/src/udt/SendQueue.h | 6 ++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 0d0140dbca..b315611cf3 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -52,6 +52,10 @@ void Connection::sendReliablePacket(unique_ptr packet) { _sendQueue = SendQueue::create(_parentSocket, _destination); QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::packetSent); + + // set defaults on the send queue from our congestion control object + _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); + _sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); } _sendQueue->queuePacket(move(packet)); diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 24bdea27df..9c8d6878c0 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -37,8 +37,6 @@ class SendQueue : public QObject { Q_OBJECT public: - static const int DEFAULT_SEND_PERIOD = 1; // in microseconds - static std::unique_ptr create(Socket* socket, HifiSockAddr dest); void queuePacket(std::unique_ptr packet); @@ -86,11 +84,11 @@ private: SequenceNumber _currentSequenceNumber; // Last sequence number sent out std::atomic _atomicCurrentSequenceNumber;// Atomic for last sequence number sent out - std::atomic _packetSendPeriod { DEFAULT_SEND_PERIOD }; // Interval between two packet send event in microseconds + std::atomic _packetSendPeriod; // Interval between two packet send event in microseconds, set from CC std::chrono::high_resolution_clock::time_point _lastSendTimestamp; // Record last time of packet departure std::atomic _isRunning { false }; - std::atomic _flowWindowSize { udt::MAX_PACKETS_IN_FLIGHT }; // Flow control window size (number of packets that can be on wire) + std::atomic _flowWindowSize; // Flow control window size (number of packets that can be on wire) - set from CC mutable QReadWriteLock _naksLock; // Protects the naks list. LossList _naks; // Sequence numbers of packets to resend From 98a53cbd723b484a2d223f2cbf184fd486ddf2dd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 09:56:50 -0700 Subject: [PATCH 198/549] don't require a sendQueue for control packet sending --- libraries/networking/src/udt/Connection.cpp | 18 ++++++++++-------- libraries/networking/src/udt/Connection.h | 6 +++--- libraries/networking/src/udt/SendQueue.cpp | 8 ++++---- libraries/networking/src/udt/SendQueue.h | 5 ++--- libraries/networking/src/udt/Socket.cpp | 10 ++++++++++ libraries/networking/src/udt/Socket.h | 1 + 6 files changed, 30 insertions(+), 18 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index b315611cf3..b6b3f9f12a 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -30,6 +30,8 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination, unique_pt _destination(destination), _congestionControl(move(congestionControl)) { + Q_ASSERT_X(socket, "Connection::Connection", "Must be called with a valid Socket*"); + // setup default SYN, RTT and RTT Variance based on the SYN interval in CongestionControl object _synInterval = _congestionControl->synInterval(); _rtt = _synInterval * 10; @@ -132,8 +134,8 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { lastACKSendTime = high_resolution_clock::now(); } - // have the send queue send off our packet - _sendQueue->sendPacket(*ackPacket); + // have the socket send off our packet + _parentSocket->writeBasePacket(*ackPacket, _destination); // write this ACK to the map of sent ACKs _sentACKs[_currentACKSubSequenceNumber] = { nextACKNumber, currentTime }; @@ -162,8 +164,8 @@ void Connection::sendLightACK() { // pack in the ACK lightACKPacket->writePrimitive(nextACKNumber); - // have the send queue send off our packet immediately - _sendQueue->sendPacket(*lightACKPacket); + // have the socket send off our packet immediately + _parentSocket->writeBasePacket(*lightACKPacket, _destination); _stats.recordSentLightACK(); } @@ -197,8 +199,8 @@ void Connection::sendNAK(SequenceNumber sequenceNumberRecieved) { lossReport->writePrimitive(sequenceNumberRecieved - 1); } - // have the send queue send off our packet immediately - _sendQueue->sendPacket(*lossReport); + // have the parent socket send off our packet immediately + _parentSocket->writeBasePacket(*lossReport, _destination); // record our last NAK time _lastNAKTime = high_resolution_clock::now(); @@ -215,8 +217,8 @@ void Connection::sendTimeoutNAK() { // Pack in the lost sequence numbers _lossList.write(*lossListPacket); - // have our SendQueue send off this control packet - _sendQueue->sendPacket(*lossListPacket); + // have our parent socket send off this control packet + _parentSocket->writeBasePacket(*lossListPacket, _destination); // record this as the last NAK time _lastNAKTime = high_resolution_clock::now(); diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 606359e6f5..71cae880d0 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -98,11 +98,11 @@ private: HifiSockAddr _destination; PacketTimeWindow _receiveWindow { 16, 64 }; // Window of interval between packets (16) and probes (64) for bandwidth and receive speed - - std::unique_ptr _sendQueue; - + std::unique_ptr _congestionControl; + std::unique_ptr _sendQueue; + // Data packet stat collection int _totalReceivedDataPackets { 0 }; int _packetsSinceACK { 0 }; // The number of packets that have been received during the current ACK interval diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 249cb6e069..c092d089c4 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -28,6 +28,8 @@ using namespace std::chrono; std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr dest) { auto queue = std::unique_ptr(new SendQueue(socket, dest)); + Q_ASSERT_X(socket, "SendQueue::create", "Must be called with a valid Socket*"); + // Setup queue private thread QThread* thread = new QThread(); thread->setObjectName("Networking: SendQueue " + dest.objectName()); // Name thread for easier debug @@ -65,10 +67,8 @@ void SendQueue::stop() { _isRunning = false; } -void SendQueue::sendPacket(const BasePacket& packet) { - if (_socket) { - _socket->writeDatagram(packet.getData(), packet.getDataSize(), _destination); - } +void SendQueue::sendPacket(const Packet& packet) { + _socket->writeDatagram(packet.getData(), packet.getDataSize(), _destination); } void SendQueue::ack(SequenceNumber ack) { diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 9c8d6878c0..4a4cf1ffea 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -49,9 +49,6 @@ public: int getPacketSendPeriod() const { return _packetSendPeriod; } void setPacketSendPeriod(int newPeriod) { _packetSendPeriod = newPeriod; } - // Send a packet through the socket - void sendPacket(const BasePacket& packet); - public slots: void stop(); @@ -70,6 +67,8 @@ private: SendQueue(SendQueue& other) = delete; SendQueue(SendQueue&& other) = delete; + void sendPacket(const Packet& packet); + // Increments current sequence number and return it SequenceNumber getNextSequenceNumber(); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index ba0e196669..99cdb06b29 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -74,6 +74,16 @@ void Socket::setSystemBufferSizes() { } } +qint64 Socket::writeBasePacket(const udt::BasePacket& packet, const HifiSockAddr &sockAddr) { + // Since this is a base packet we have no way to know if this is reliable or not - we just fire it off + + // this should not be called with an instance of Packet + Q_ASSERT_X(!dynamic_cast(&packet), + "Socket::writeBasePacket", "Cannot send a Packet/NLPacket via writeBasePacket"); + + return writeDatagram(packet.getData(), packet.getDataSize(), sockAddr); +} + qint64 Socket::writePacket(const Packet& packet, const HifiSockAddr& sockAddr) { Q_ASSERT_X(!packet.isReliable(), "Socket::writePacket", "Cannot send a reliable packet unreliably"); diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 8c8ecb32b2..4f947e4043 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -45,6 +45,7 @@ public: quint16 localPort() const { return _udpSocket.localPort(); } // Simple functions writing to the socket with no processing + qint64 writeBasePacket(const BasePacket& packet, const HifiSockAddr& sockAddr); qint64 writePacket(const Packet& packet, const HifiSockAddr& sockAddr); qint64 writePacket(std::unique_ptr packet, const HifiSockAddr& sockAddr); qint64 writeDatagram(const char* data, qint64 size, const HifiSockAddr& sockAddr); From da7a8f6e2faecdc827171d062d56cb91b2d186cd Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 31 Jul 2015 10:41:16 -0700 Subject: [PATCH 199/549] Added new connection stats --- .../networking/src/udt/ConnectionStats.cpp | 55 +++++++++++++++++-- .../networking/src/udt/ConnectionStats.h | 24 +++++++- 2 files changed, 72 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/udt/ConnectionStats.cpp b/libraries/networking/src/udt/ConnectionStats.cpp index 394448afec..0b53e35618 100644 --- a/libraries/networking/src/udt/ConnectionStats.cpp +++ b/libraries/networking/src/udt/ConnectionStats.cpp @@ -21,8 +21,8 @@ ConnectionStats::ConnectionStats() { } ConnectionStats::Stats ConnectionStats::sample() { - Stats sample; - std::swap(sample, _currentSample); + Stats sample = _currentSample; + _currentSample = Stats(); auto now = duration_cast(high_resolution_clock::now().time_since_epoch()); sample.endTime = now; @@ -81,12 +81,57 @@ void ConnectionStats::recordReceivedTimeoutNAK() { ++_total.receivedTimeoutNAKs; } -void ConnectionStats::recordSentPackets() { + +void ConnectionStats::recordSentPackets(int payload, int total) { ++_currentSample.sentPackets; ++_total.sentPackets; + + _currentSample.sentUtilBytes += payload; + _total.sentUtilBytes += payload; + + _currentSample.sentBytes += total; + _total.sentBytes += total; } -void ConnectionStats::recordReceivedPackets() { +void ConnectionStats::recordReceivedPackets(int payload, int total) { ++_currentSample.recievedPackets; ++_total.recievedPackets; -} \ No newline at end of file + + _currentSample.recievedUtilBytes += payload; + _total.recievedUtilBytes += payload; + + _currentSample.sentBytes += total; + _total.recievedBytes += total; +} + +void ConnectionStats::recordUnreliableSentPackets(int payload, int total) { + ++_currentSample.sentUnreliablePackets; + ++_total.sentUnreliablePackets; + + _currentSample.sentUnreliableUtilBytes += payload; + _total.sentUnreliableUtilBytes += payload; + + _currentSample.sentUnreliableBytes += total; + _total.sentUnreliableBytes += total; +} + +void ConnectionStats::recordUnreliableReceivedPackets(int payload, int total) { + ++_currentSample.recievedUnreliablePackets; + ++_total.recievedUnreliablePackets; + + _currentSample.recievedUnreliableUtilBytes += payload; + _total.recievedUnreliableUtilBytes += payload; + + _currentSample.sentUnreliableBytes += total; + _total.recievedUnreliableBytes += total; +} + +void ConnectionStats::recordRetransmition() { + ++_currentSample.retransmissions; + ++_total.retransmissions; +} + +void ConnectionStats::recordDrop() { + ++_currentSample.drops; + ++_total.drops; +} diff --git a/libraries/networking/src/udt/ConnectionStats.h b/libraries/networking/src/udt/ConnectionStats.h index df7dfd1545..aa3687e481 100644 --- a/libraries/networking/src/udt/ConnectionStats.h +++ b/libraries/networking/src/udt/ConnectionStats.h @@ -36,6 +36,20 @@ public: int sentPackets { 0 }; int recievedPackets { 0 }; + int sentUtilBytes { 0 }; + int recievedUtilBytes { 0 }; + int sentBytes { 0 }; + int recievedBytes { 0 }; + + int sentUnreliablePackets { 0 }; + int recievedUnreliablePackets { 0 }; + int sentUnreliableUtilBytes { 0 }; + int recievedUnreliableUtilBytes { 0 }; + int sentUnreliableBytes { 0 }; + int recievedUnreliableBytes { 0 }; + + int retransmissions { 0 }; + int drops { 0 }; }; ConnectionStats(); @@ -54,8 +68,14 @@ public: void recordSentTimeoutNAK(); void recordReceivedTimeoutNAK(); - void recordSentPackets(); - void recordReceivedPackets(); + void recordSentPackets(int payload, int total); + void recordReceivedPackets(int payload, int total); + + void recordUnreliableSentPackets(int payload, int total); + void recordUnreliableReceivedPackets(int payload, int total); + + void recordRetransmition(); + void recordDrop(); private: Stats _currentSample; From b437f3bca9eaa7e1e51adb4e716a6075919f8108 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 31 Jul 2015 10:42:43 -0700 Subject: [PATCH 200/549] Made connection hash hold unique ptr --- libraries/networking/src/udt/Connection.cpp | 1 - libraries/networking/src/udt/Connection.h | 6 ++---- libraries/networking/src/udt/Socket.cpp | 19 ++++++++++--------- libraries/networking/src/udt/Socket.h | 6 +++--- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index ff10994e27..50bccc1ab3 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -287,7 +287,6 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber) { // increment the counters for data packets received ++_packetsSinceACK; - ++_totalReceivedDataPackets; // check if we need to send an ACK, according to CC params if (_congestionControl->_ackInterval > 0 && _packetsSinceACK >= _congestionControl->_ackInterval) { diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 2cacdf9fe9..c8313ed2fd 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -39,7 +39,7 @@ public: Connection(Socket* parentSocket, HifiSockAddr destination, std::unique_ptr congestionControl); ~Connection(); - + void sendReliablePacket(std::unique_ptr packet); void sync(); // rate control method, fired by Socket for all connections on SYN interval @@ -103,10 +103,8 @@ private: std::unique_ptr _congestionControl; - std::unique_ptr _sendQueue; + std::unique_ptr _sendQueue; - // Data packet stat collection - int _totalReceivedDataPackets { 0 }; int _packetsSinceACK { 0 }; // The number of packets that have been received during the current ACK interval ConnectionStats _stats; diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 99cdb06b29..04fa835f2c 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -95,7 +95,7 @@ qint64 Socket::writePacket(const Packet& packet, const HifiSockAddr& sockAddr) { qint64 Socket::writePacket(std::unique_ptr packet, const HifiSockAddr& sockAddr) { if (packet->isReliable()) { - findOrCreateConnection(sockAddr)->sendReliablePacket(move(packet)); + findOrCreateConnection(sockAddr).sendReliablePacket(move(packet)); return 0; } @@ -117,14 +117,15 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc return bytesWritten; } -Connection* Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { +Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { auto it = _connectionsHash.find(sockAddr); if (it == _connectionsHash.end()) { - it = _connectionsHash.insert(it, std::make_pair(sockAddr, new Connection(this, sockAddr, _ccFactory->create()))); + it = _connectionsHash.insert(it, std::make_pair(sockAddr, + std::unique_ptr(new Connection(this, sockAddr, _ccFactory->create())))); } - return it->second; + return *it->second; } void Socket::readPendingDatagrams() { @@ -160,8 +161,8 @@ void Socket::readPendingDatagrams() { auto controlPacket = ControlPacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); // move this control packet to the matching connection - auto connection = findOrCreateConnection(senderSockAddr); - connection->processControl(move(controlPacket)); + auto& connection = findOrCreateConnection(senderSockAddr); + connection.processControl(move(controlPacket)); } else { // setup a Packet from the data we just read @@ -172,8 +173,8 @@ void Socket::readPendingDatagrams() { if (packet->isReliable()) { // if this was a reliable packet then signal the matching connection with the sequence number - auto connection = findOrCreateConnection(senderSockAddr); - connection->processReceivedSequenceNumber(packet->getSequenceNumber()); + auto& connection = findOrCreateConnection(senderSockAddr); + connection.processReceivedSequenceNumber(packet->getSequenceNumber()); } if (_packetHandler) { @@ -188,7 +189,7 @@ void Socket::readPendingDatagrams() { void Socket::connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* receiver, const char* slot) { auto it = _connectionsHash.find(destinationAddr); if (it != _connectionsHash.end()) { - connect(it->second, SIGNAL(packetSent()), receiver, slot); + connect(it->second.get(), SIGNAL(packetSent()), receiver, slot); } } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 4f947e4043..a8ff255b8d 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -23,11 +23,11 @@ #include "../HifiSockAddr.h" #include "CongestionControl.h" +#include "Connection.h" namespace udt { class BasePacket; -class Connection; class ControlSender; class Packet; class SequenceNumber; @@ -70,7 +70,7 @@ private slots: private: void setSystemBufferSizes(); - Connection* findOrCreateConnection(const HifiSockAddr& sockAddr); + Connection& findOrCreateConnection(const HifiSockAddr& sockAddr); QUdpSocket _udpSocket { this }; PacketFilterOperator _packetFilterOperator; @@ -78,7 +78,7 @@ private: std::unordered_map _unfilteredHandlers; std::unordered_map _unreliableSequenceNumbers; - std::unordered_map _connectionsHash; + std::unordered_map> _connectionsHash; int32_t _synInterval = 10; // 10ms QTimer _synTimer; From 50c0b59ba2e2a113fe75705f2386ba4c938c0c32 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 10:46:52 -0700 Subject: [PATCH 201/549] handle priority of re-transmission of loss --- libraries/networking/src/udt/SendQueue.cpp | 194 +++++++++++---------- libraries/networking/src/udt/SendQueue.h | 1 + 2 files changed, 106 insertions(+), 89 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index c092d089c4..d65cdf951c 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -85,7 +85,10 @@ void SendQueue::ack(SequenceNumber ack) { { // remove any sequence numbers equal to or lower than this ACK in the loss list QWriteLocker nakLocker(&_naksLock); - _naks.remove(_naks.getFirstSequenceNumber(), ack); + + if (_naks.getLength() > 0) { + _naks.remove(_naks.getFirstSequenceNumber(), ack); + } } _lastACKSequenceNumber = (uint32_t) ack; @@ -118,6 +121,21 @@ SequenceNumber SendQueue::getNextSequenceNumber() { return _currentSequenceNumber; } +void SendQueue::sendNewPacketAndAddToSentList(std::unique_ptr newPacket, SequenceNumber sequenceNumber) { + // write the sequence number and send the packet + newPacket->writeSequenceNumber(sequenceNumber); + sendPacket(*newPacket); + + { + // Insert the packet we have just sent in the sent list + QWriteLocker locker(&_sentLock); + _sentPackets[newPacket->getSequenceNumber()].swap(newPacket); + Q_ASSERT_X(!newPacket, "SendQueue::sendNewPacketAndAddToSentList()", "Overriden packet in sent list"); + } + + emit packetSent(); +} + void SendQueue::run() { _isRunning = true; @@ -125,104 +143,102 @@ void SendQueue::run() { // Record timing _lastSendTimestamp = high_resolution_clock::now(); - // we're only allowed to send if the flow window size - // is greater than or equal to the gap between the last ACKed sent and the one we are about to send - if (seqlen(SequenceNumber { (uint32_t) _lastACKSequenceNumber }, _currentSequenceNumber + 1) <= _flowWindowSize) { - bool hasResend = false; - SequenceNumber sequenceNumber; - { - // Check nak list for packet to resend - QWriteLocker locker(&_naksLock); - if (_naks.getLength() > 0) { - hasResend = true; - sequenceNumber = _naks.popFirstSequenceNumber(); - } - } + qDebug() << _lastACKSequenceNumber + << (uint32_t) (_currentSequenceNumber + 1) + << seqlen(SequenceNumber { (uint32_t) _lastACKSequenceNumber }, _currentSequenceNumber + 1); + + bool resentPacket = false; + + while (!resentPacket) { + // prioritize a loss retransmission + _naksLock.lockForWrite(); - std::unique_ptr nextPacket; - - // Find packet in sent list using SequenceNumber - if (hasResend) { - QWriteLocker locker(&_sentLock); - auto it = _sentPackets.find(sequenceNumber); - Q_ASSERT_X(it != _sentPackets.end(), - "SendQueue::sendNextPacket()", "Couldn't find NAKed packet to resend"); + if (_naks.getLength() > 0) { + + // pull the sequence number we need to re-send + SequenceNumber resendNumber = _naks.popFirstSequenceNumber(); + _naksLock.unlock(); + + // pull the packet to re-send from the sent packets list + _sentLock.lockForRead(); + + // see if we can find the packet to re-send + auto it = _sentPackets.find(resendNumber); if (it != _sentPackets.end()) { - it->second.swap(nextPacket); - _sentPackets.erase(it); - } - } - - // If there is no packet to resend, grab the next one in the list - if (!nextPacket) { - QWriteLocker locker(&_packetsLock); - - if (_packets.size() > 0) { - nextPacket.swap(_packets.front()); - _packets.pop_front(); - } - } - - if (nextPacket) { - bool shouldSendSecondOfPair = false; - - if (!hasResend) { - // if we're not re-sending a packet then need to check if this should be a packet pair - sequenceNumber = getNextSequenceNumber(); + // we found the packet - grab it + auto& resendPacket = *(it->second); - // the first packet in the pair is every 16 (rightmost 16 bits = 0) packets - if (((uint32_t) sequenceNumber & 0xF) == 0) { - shouldSendSecondOfPair = true; - } - } - - // Write packet's sequence number and send it off - nextPacket->writeSequenceNumber(sequenceNumber); - sendPacket(*nextPacket); - - { - // Insert the packet we have just sent in the sent list - QWriteLocker locker(&_sentLock); - _sentPackets[nextPacket->getSequenceNumber()].swap(nextPacket); - Q_ASSERT_X(!nextPacket, - "SendQueue::sendNextPacket()", "Overriden packet in sent list"); - } - - emit packetSent(); - - if (shouldSendSecondOfPair) { - std::unique_ptr pairedPacket; + // unlock the sent packets + _sentLock.unlock(); - // we've detected we should send the second packet in a pair, do that now before sleeping - { - QWriteLocker locker(&_packetsLock); - - if (_packets.size() > 0) { - pairedPacket.swap(_packets.front()); - _packets.pop_front(); - } - } + // send it off + sendPacket(resendPacket); - if (pairedPacket) { - // write this packet's sequence number and send it off - pairedPacket->writeSequenceNumber(getNextSequenceNumber()); - sendPacket(*pairedPacket); - - { - // add the paired packet to the sent list - QWriteLocker locker(&_sentLock); - _sentPackets[pairedPacket->getSequenceNumber()].swap(pairedPacket); - Q_ASSERT_X(!pairedPacket, - "SendQueue::sendNextPacket()", "Overriden packet in sent list"); - } - - emit packetSent(); - } + // mark that we did resend a packet + resentPacket = true; + + // break out of our while now that we have re-sent a packet + break; + } else { + // we didn't find this packet in the sentPackets queue - assume this means it was ACKed + // we'll fire the loop again to see if there is another to re-send + + // unlock the sent packets + _sentLock.unlock(); } + + } else { + // unlock the loss list, it's empty + _naksLock.unlock(); + + // break from the while, we didn't resend a packet + break; } } + if (!resentPacket + && seqlen(SequenceNumber { (uint32_t) _lastACKSequenceNumber }, _currentSequenceNumber + 1) <= _flowWindowSize) { + + // we didn't re-send a packet, so time to send a new one + _packetsLock.lockForWrite(); + + if (_packets.size() > 0) { + SequenceNumber nextNumber = getNextSequenceNumber(); + + // grab the first packet we will send + std::unique_ptr firstPacket; + firstPacket.swap(_packets.front()); + _packets.pop_front(); + + std::unique_ptr secondPacket; + + if (((uint32_t) nextNumber & 0xF) == 0) { + // the first packet is the first in a probe pair - every 16 (rightmost 16 bits = 0) packets + // pull off a second packet if we can before we unlock + if (_packets.size() > 0) { + secondPacket.swap(_packets.front()); + _packets.pop_front(); + } + } + + // unlock the packets, we're done pulling + _packetsLock.unlock(); + + // definitely send the first packet + sendNewPacketAndAddToSentList(move(firstPacket), nextNumber); + + // do we have a second in a pair to send as well? + if (secondPacket) { + nextNumber = getNextSequenceNumber(); + sendNewPacketAndAddToSentList(move(secondPacket), nextNumber); + } + + } else { + _packetsLock.unlock(); + } + } + // since we're a while loop, give the thread a chance to process events QCoreApplication::processEvents(); diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 4a4cf1ffea..a438c5635f 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -68,6 +68,7 @@ private: SendQueue(SendQueue&& other) = delete; void sendPacket(const Packet& packet); + void sendNewPacketAndAddToSentList(std::unique_ptr newPacket, SequenceNumber sequenceNumber); // Increments current sequence number and return it SequenceNumber getNextSequenceNumber(); From ee9ae9ceec1881c6ca1bc3cace1be124ab588e4b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 10:51:17 -0700 Subject: [PATCH 202/549] fix for vector initialization in PacketTimeWindow --- libraries/networking/src/udt/PacketTimeWindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/PacketTimeWindow.cpp b/libraries/networking/src/udt/PacketTimeWindow.cpp index 469915d311..9db837bc12 100644 --- a/libraries/networking/src/udt/PacketTimeWindow.cpp +++ b/libraries/networking/src/udt/PacketTimeWindow.cpp @@ -24,8 +24,8 @@ static const int DEFAULT_PROBE_INTERVAL_MICROSECONDS = 1000; PacketTimeWindow::PacketTimeWindow(int numPacketIntervals, int numProbeIntervals) : _numPacketIntervals(numPacketIntervals), _numProbeIntervals(numProbeIntervals), - _packetIntervals({ _numPacketIntervals, DEFAULT_PACKET_INTERVAL_MICROSECONDS }), - _probeIntervals({ _numProbeIntervals, DEFAULT_PROBE_INTERVAL_MICROSECONDS }) + _packetIntervals(_numPacketIntervals, DEFAULT_PACKET_INTERVAL_MICROSECONDS), + _probeIntervals(_numProbeIntervals, DEFAULT_PROBE_INTERVAL_MICROSECONDS) { } From e346dbcfee2b288d713a464f9c5357b47f0a3e61 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 10:59:06 -0700 Subject: [PATCH 203/549] seqlen fix in SendQueue --- libraries/networking/src/udt/SendQueue.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index d65cdf951c..2c3c540fb2 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -143,10 +143,6 @@ void SendQueue::run() { // Record timing _lastSendTimestamp = high_resolution_clock::now(); - qDebug() << _lastACKSequenceNumber - << (uint32_t) (_currentSequenceNumber + 1) - << seqlen(SequenceNumber { (uint32_t) _lastACKSequenceNumber }, _currentSequenceNumber + 1); - bool resentPacket = false; while (!resentPacket) { @@ -195,10 +191,10 @@ void SendQueue::run() { // break from the while, we didn't resend a packet break; } - } + } if (!resentPacket - && seqlen(SequenceNumber { (uint32_t) _lastACKSequenceNumber }, _currentSequenceNumber + 1) <= _flowWindowSize) { + && seqlen(SequenceNumber { (uint32_t) _lastACKSequenceNumber }, _currentSequenceNumber) <= _flowWindowSize) { // we didn't re-send a packet, so time to send a new one _packetsLock.lockForWrite(); From ce212041512aae9e2290b74da5746c8b2295166c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 15:09:30 -0700 Subject: [PATCH 204/549] add output of connection stats in UDTTest --- libraries/networking/src/udt/Connection.cpp | 25 ++++++++++++++-- libraries/networking/src/udt/Connection.h | 2 ++ .../networking/src/udt/ConnectionStats.cpp | 30 ++++++++++++++++++- .../networking/src/udt/ConnectionStats.h | 15 +++++++++- libraries/networking/src/udt/Socket.cpp | 17 +++++++++++ libraries/networking/src/udt/Socket.h | 2 ++ tools/udt-test/src/UDTTest.cpp | 11 +++++++ tools/udt-test/src/UDTTest.h | 1 + 8 files changed, 98 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index b6b3f9f12a..71141656ae 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -126,9 +126,17 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { ackPacket->writePrimitive((int32_t) udt::CONNECTION_RECEIVE_BUFFER_SIZE_PACKETS); if (wasCausedBySyncTimeout) { + // grab the up to date packet receive speed and estimated bandwidth + int32_t packetReceiveSpeed = _receiveWindow.getPacketReceiveSpeed(); + int32_t estimatedBandwidth = _receiveWindow.getEstimatedBandwidth(); + + // update those values in our connection stats + _stats.recordReceiveRate(packetReceiveSpeed); + _stats.recordEstimatedBandwidth(estimatedBandwidth); + // pack in the receive speed and estimatedBandwidth - ackPacket->writePrimitive(_receiveWindow.getPacketReceiveSpeed()); - ackPacket->writePrimitive(_receiveWindow.getEstimatedBandwidth()); + ackPacket->writePrimitive(packetReceiveSpeed); + ackPacket->writePrimitive(estimatedBandwidth); // record this as the last ACK send time lastACKSendTime = high_resolution_clock::now(); @@ -261,6 +269,7 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber) { _nakInterval = (_rtt + 4 * _rttVariance); int receivedPacketsPerSecond = _receiveWindow.getPacketReceiveSpeed(); + if (receivedPacketsPerSecond > 0) { // the NAK interval is at least the _minNAKInterval // but might be the time required for all lost packets to be retransmitted @@ -371,10 +380,12 @@ void Connection::processACK(std::unique_ptr controlPacket) { // ACK the send queue so it knows what was received _sendQueue->ack(ack); - // update the RTT updateRTT(rtt); + // write this RTT to stats + _stats.recordRTT(rtt); + // set the RTT for congestion control _congestionControl->setRTT(_rtt); @@ -387,6 +398,10 @@ void Connection::processACK(std::unique_ptr controlPacket) { // these are calculated using an EWMA static const int EMWA_ALPHA_NUMERATOR = 8; + // record these samples in connection stats + _stats.recordReceiveRate(receiveRate); + _stats.recordEstimatedBandwidth(bandwidth); + _deliveryRate = (_deliveryRate * (EMWA_ALPHA_NUMERATOR - 1) + _deliveryRate) / EMWA_ALPHA_NUMERATOR; _bandwidth = (_bandwidth * (EMWA_ALPHA_NUMERATOR - 1) + _bandwidth) / EMWA_ALPHA_NUMERATOR; @@ -515,4 +530,8 @@ void Connection::updateCongestionControlAndSendQueue(std::function cong // now that we've update the congestion control, update the packet send period and flow window size _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); _sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); + + // record connection stats + _stats.recordPacketSendPeriod(_congestionControl->_packetSendPeriod); + _stats.recordCongestionWindowSize(_congestionControl->_congestionWindowSize); } diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 71cae880d0..83afb88db8 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -46,6 +46,8 @@ public: bool processReceivedSequenceNumber(SequenceNumber sequenceNumber); // returns indicates if this packet was a duplicate void processControl(std::unique_ptr controlPacket); + + ConnectionStats::Stats sampleStats() { return _stats.sample(); } signals: void packetSent(); diff --git a/libraries/networking/src/udt/ConnectionStats.cpp b/libraries/networking/src/udt/ConnectionStats.cpp index 394448afec..b46eb3ee34 100644 --- a/libraries/networking/src/udt/ConnectionStats.cpp +++ b/libraries/networking/src/udt/ConnectionStats.cpp @@ -89,4 +89,32 @@ void ConnectionStats::recordSentPackets() { void ConnectionStats::recordReceivedPackets() { ++_currentSample.recievedPackets; ++_total.recievedPackets; -} \ No newline at end of file +} + +static const double EWMA_CURRENT_SAMPLE_WEIGHT = 0.125; +static const double EWMA_PREVIOUS_SAMPLES_WEIGHT = 1 - 0.125; + +void ConnectionStats::recordReceiveRate(int sample) { + _currentSample.receiveRate = sample; + _total.receiveRate = (_total.receiveRate * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT); +} + +void ConnectionStats::recordEstimatedBandwidth(int sample) { + _currentSample.estimatedBandwith = sample; + _total.estimatedBandwith = (_total.estimatedBandwith * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT); +} + +void ConnectionStats::recordRTT(int sample) { + _currentSample.rtt = sample; + _total.rtt = (_total.rtt * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT); +} + +void ConnectionStats::recordCongestionWindowSize(int sample) { + _currentSample.congestionWindowSize = sample; + _total.congestionWindowSize = (_total.congestionWindowSize * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT); +} + +void ConnectionStats::recordPacketSendPeriod(int sample) { + _currentSample.packetSendPeriod = sample; + _total.packetSendPeriod = (_total.packetSendPeriod * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT); +} diff --git a/libraries/networking/src/udt/ConnectionStats.h b/libraries/networking/src/udt/ConnectionStats.h index df7dfd1545..fed1158bf7 100644 --- a/libraries/networking/src/udt/ConnectionStats.h +++ b/libraries/networking/src/udt/ConnectionStats.h @@ -36,6 +36,13 @@ public: int sentPackets { 0 }; int recievedPackets { 0 }; + + // the following stats are trailing averages in the result, not totals + int receiveRate { 0 }; + int estimatedBandwith { 0 }; + int rtt { 0 }; + int congestionWindowSize { 0 }; + int packetSendPeriod { 0 }; }; ConnectionStats(); @@ -57,6 +64,12 @@ public: void recordSentPackets(); void recordReceivedPackets(); + void recordReceiveRate(int sample); + void recordEstimatedBandwidth(int sample); + void recordRTT(int sample); + void recordCongestionWindowSize(int sample); + void recordPacketSendPeriod(int sample); + private: Stats _currentSample; Stats _total; @@ -64,4 +77,4 @@ private: } -#endif // hifi_ConnectionStats_h \ No newline at end of file +#endif // hifi_ConnectionStats_h diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 99cdb06b29..d1e953d650 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -213,3 +213,20 @@ void Socket::setCongestionControlFactory(std::unique_ptrsynInterval(); } + +void Socket::sampleAndPrintConnectionStats() { + if (thread() != QThread::currentThread()) { + QMetaObject::invokeMethod(this, "sampleAndPrintConnectionStats"); + return; + } + + for(auto& connection : _connectionsHash) { + ConnectionStats::Stats sampleStats = connection.second->sampleStats(); + + qDebug() << connection.first + << sampleStats.receiveRate << sampleStats.rtt + << sampleStats.congestionWindowSize << sampleStats.packetSendPeriod + << sampleStats.sentPackets + << sampleStats.receivedACKs << sampleStats.receivedLightACKs << sampleStats.receivedNAKs; + } +} diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 4f947e4043..02aa733e93 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -63,6 +63,8 @@ public: void setCongestionControlFactory(std::unique_ptr ccFactory); void connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* receiver, const char* slot); + + void sampleAndPrintConnectionStats(); private slots: void readPendingDatagrams(); diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 9f149dce52..55a8a78f6f 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -116,6 +116,13 @@ UDTTest::UDTTest(int& argc, char** argv) : if (!_target.isNull()) { sendInitialPackets(); + + // the sender reports stats every 1 second + static const int STATS_SAMPLE_INTERVAL = 1000; + + QTimer* statsTimer = new QTimer(this); + connect(statsTimer, &QTimer::timeout, this, &UDTTest::sampleStats); + statsTimer->start(STATS_SAMPLE_INTERVAL); } } @@ -198,3 +205,7 @@ void UDTTest::sendPacket() { ++_totalQueuedPackets; } + +void UDTTest::sampleStats() { + _socket.sampleAndPrintConnectionStats(); +} diff --git a/tools/udt-test/src/UDTTest.h b/tools/udt-test/src/UDTTest.h index 050c5dc75a..1fd1836cf9 100644 --- a/tools/udt-test/src/UDTTest.h +++ b/tools/udt-test/src/UDTTest.h @@ -27,6 +27,7 @@ public: public slots: void refillPacket() { sendPacket(); } // adds a new packet to the queue when we are told one is sent + void sampleStats(); private: void parseArguments(); From fcec53bdce9aa7f25cbddcdb5529dc100b5cd5b1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 31 Jul 2015 15:09:58 -0700 Subject: [PATCH 205/549] Fix sequence number crash --- libraries/networking/src/udt/SendQueue.cpp | 2 +- libraries/networking/src/udt/SequenceNumber.h | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 2c3c540fb2..a4f9d16d08 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -86,7 +86,7 @@ void SendQueue::ack(SequenceNumber ack) { { // remove any sequence numbers equal to or lower than this ACK in the loss list QWriteLocker nakLocker(&_naksLock); - if (_naks.getLength() > 0) { + if (_naks.getLength() > 0 && _naks.getFirstSequenceNumber() <= ack) { _naks.remove(_naks.getFirstSequenceNumber(), ack); } } diff --git a/libraries/networking/src/udt/SequenceNumber.h b/libraries/networking/src/udt/SequenceNumber.h index c77a14edf9..d0bea86777 100644 --- a/libraries/networking/src/udt/SequenceNumber.h +++ b/libraries/networking/src/udt/SequenceNumber.h @@ -21,7 +21,8 @@ namespace udt { class SequenceNumber { public: // Base type of sequence numbers - using Type = uint32_t; + using Type = int32_t; + using UType = uint32_t; // Values are for 29 bit SequenceNumber static const Type THRESHOLD = 0x0FFFFFFF; // threshold for comparing sequence numbers @@ -32,8 +33,10 @@ public: // Only explicit conversions explicit SequenceNumber(char* value) { _value = (*reinterpret_cast(value)) & MAX; } - explicit SequenceNumber(Type value) { _value = (value <= MAX) ? value : MAX; } + explicit SequenceNumber(Type value) { _value = (value <= MAX) ? ((value >= 0) ? value : 0) : MAX; } + explicit SequenceNumber(UType value) { _value = (value <= MAX) ? value : MAX; } explicit operator Type() { return _value; } + explicit operator UType() { return static_cast(_value); } inline SequenceNumber& operator++() { _value = (_value == MAX) ? 0 : ++_value; From c5b92d319fcf254227473a82b2b1896369396593 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 31 Jul 2015 16:14:19 -0700 Subject: [PATCH 206/549] Update stats gathering --- libraries/networking/src/udt/Connection.cpp | 19 +++++++++++++++++-- libraries/networking/src/udt/Connection.h | 10 +++++++--- .../networking/src/udt/ConnectionStats.cpp | 8 ++++---- .../networking/src/udt/ConnectionStats.h | 6 +++--- libraries/networking/src/udt/SendQueue.cpp | 7 ++++++- libraries/networking/src/udt/SendQueue.h | 3 ++- libraries/networking/src/udt/Socket.cpp | 4 +++- 7 files changed, 42 insertions(+), 15 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index e141e680c2..b399942a19 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -52,6 +52,8 @@ SendQueue& Connection::getSendQueue() { _sendQueue = SendQueue::create(_parentSocket, _destination); QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::packetSent); + QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::recordSentPackets); + QObject::connect(_sendQueue.get(), &SendQueue::packetRetransmitted, this, &Connection::recordRetransmission); // set defaults on the send queue from our congestion control object _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); @@ -80,6 +82,14 @@ void Connection::sync() { } } +void Connection::recordSentPackets(int dataSize, int payloadSize) { + _stats.recordSentPackets(payloadSize, dataSize); +} + +void Connection::recordRetransmission() { + _stats.recordRetransmission(); +} + void Connection::sendACK(bool wasCausedBySyncTimeout) { static high_resolution_clock::time_point lastACKSendTime; auto currentTime = high_resolution_clock::now(); @@ -246,8 +256,7 @@ SequenceNumber Connection::nextACK() const { } } -bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber) { - +bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, int packetSize, int payloadSize) { // check if this is a packet pair we should estimate bandwidth from, or just a regular packet if (((uint32_t) sequenceNumber & 0xF) == 0) { _receiveWindow.onProbePair1Arrival(); @@ -304,6 +313,12 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber) { sendLightACK(); } + if (wasDuplicate) { + _stats.recordDuplicates(); + } else { + _stats.recordReceivedPackets(payloadSize, packetSize); + } + return wasDuplicate; } diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index d0aa359d08..23a77bf4db 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -43,8 +43,9 @@ public: void sendReliablePacket(std::unique_ptr packet); void sync(); // rate control method, fired by Socket for all connections on SYN interval - - bool processReceivedSequenceNumber(SequenceNumber sequenceNumber); // returns indicates if this packet was a duplicate + + // returns indicates if this packet was a duplicate + bool processReceivedSequenceNumber(SequenceNumber sequenceNumber, int packetSize, int payloadSize); void processControl(std::unique_ptr controlPacket); ConnectionStats::Stats sampleStats() { return _stats.sample(); } @@ -52,6 +53,10 @@ public: signals: void packetSent(); +private slots: + void recordSentPackets(int payload, int total); + void recordRetransmission(); + private: void sendACK(bool wasCausedBySyncTimeout = true); void sendLightACK(); @@ -65,7 +70,6 @@ private: void processNAK(std::unique_ptr controlPacket); void processTimeoutNAK(std::unique_ptr controlPacket); - SendQueue& getSendQueue(); SequenceNumber nextACK() const; void updateRTT(int rtt); diff --git a/libraries/networking/src/udt/ConnectionStats.cpp b/libraries/networking/src/udt/ConnectionStats.cpp index 73dadfbe7e..62497ab496 100644 --- a/libraries/networking/src/udt/ConnectionStats.cpp +++ b/libraries/networking/src/udt/ConnectionStats.cpp @@ -126,14 +126,14 @@ void ConnectionStats::recordUnreliableReceivedPackets(int payload, int total) { _total.recievedUnreliableBytes += total; } -void ConnectionStats::recordRetransmition() { +void ConnectionStats::recordRetransmission() { ++_currentSample.retransmissions; ++_total.retransmissions; } -void ConnectionStats::recordDrop() { - ++_currentSample.drops; - ++_total.drops; +void ConnectionStats::recordDuplicates() { + ++_currentSample.duplicates; + ++_total.duplicates; } static const double EWMA_CURRENT_SAMPLE_WEIGHT = 0.125; diff --git a/libraries/networking/src/udt/ConnectionStats.h b/libraries/networking/src/udt/ConnectionStats.h index cf7c908a83..f4b912ace5 100644 --- a/libraries/networking/src/udt/ConnectionStats.h +++ b/libraries/networking/src/udt/ConnectionStats.h @@ -49,7 +49,7 @@ public: int recievedUnreliableBytes { 0 }; int retransmissions { 0 }; - int drops { 0 }; + int duplicates { 0 }; // the following stats are trailing averages in the result, not totals int receiveRate { 0 }; @@ -81,8 +81,8 @@ public: void recordUnreliableSentPackets(int payload, int total); void recordUnreliableReceivedPackets(int payload, int total); - void recordRetransmition(); - void recordDrop(); + void recordRetransmission(); + void recordDuplicates(); void recordReceiveRate(int sample); void recordEstimatedBandwidth(int sample); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index a4f9d16d08..f271a1c685 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -126,6 +126,10 @@ void SendQueue::sendNewPacketAndAddToSentList(std::unique_ptr newPacket, newPacket->writeSequenceNumber(sequenceNumber); sendPacket(*newPacket); + // Save packet/payload size before we move it + auto packetSize = newPacket->getDataSize(); + auto payloadSize = newPacket->getPayloadSize(); + { // Insert the packet we have just sent in the sent list QWriteLocker locker(&_sentLock); @@ -133,7 +137,7 @@ void SendQueue::sendNewPacketAndAddToSentList(std::unique_ptr newPacket, Q_ASSERT_X(!newPacket, "SendQueue::sendNewPacketAndAddToSentList()", "Overriden packet in sent list"); } - emit packetSent(); + emit packetSent(packetSize, payloadSize); } void SendQueue::run() { @@ -170,6 +174,7 @@ void SendQueue::run() { // send it off sendPacket(resendPacket); + emit packetRetransmitted(); // mark that we did resend a packet resentPacket = true; diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index a438c5635f..004938051e 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -57,7 +57,8 @@ public slots: void overrideNAKListFromPacket(ControlPacket& packet); signals: - void packetSent(); + void packetSent(int dataSize, int payloadSize); + void packetRetransmitted(); private slots: void run(); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 6bb7bf08d0..14fad37005 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -174,7 +174,9 @@ void Socket::readPendingDatagrams() { if (packet->isReliable()) { // if this was a reliable packet then signal the matching connection with the sequence number auto& connection = findOrCreateConnection(senderSockAddr); - connection.processReceivedSequenceNumber(packet->getSequenceNumber()); + connection.processReceivedSequenceNumber(packet->getSequenceNumber(), + packet->getDataSize(), + packet->getPayloadSize()); } if (_packetHandler) { From d420bca88eece3f7f55640629b6ecbb577006b2e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 16:14:33 -0700 Subject: [PATCH 207/549] fix for ACK2 sending, output prettier stats --- libraries/networking/src/udt/Connection.cpp | 3 +++ libraries/networking/src/udt/Socket.cpp | 22 ++++++++---------- libraries/networking/src/udt/Socket.h | 2 +- tools/udt-test/src/UDTTest.cpp | 25 ++++++++++++++++++++- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index e141e680c2..5afd3772a0 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -192,6 +192,9 @@ void Connection::sendACK2(SequenceNumber currentACKSubSequenceNumber) { // write the sub sequence number for this ACK2 ack2Packet->writePrimitive(currentACKSubSequenceNumber); + // send the ACK2 packet + _parentSocket->writeBasePacket(*ack2Packet, _destination); + // update the last sent ACK2 and the last ACK2 send time _lastSentACK2 = currentACKSubSequenceNumber; diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 6bb7bf08d0..25335c99df 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -215,19 +215,15 @@ void Socket::setCongestionControlFactory(std::unique_ptrsynInterval(); } -void Socket::sampleAndPrintConnectionStats() { - if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, "sampleAndPrintConnectionStats"); - return; - } +ConnectionStats::Stats Socket::sampleStatsForConnection(const HifiSockAddr& destination) { + Q_ASSERT_X(thread() == QThread::currentThread(), + "Socket::sampleStatsForConnection", + "Stats sampling for connection must be on socket thread"); - for(auto& connection : _connectionsHash) { - ConnectionStats::Stats sampleStats = connection.second->sampleStats(); - - qDebug() << connection.first - << sampleStats.receiveRate << sampleStats.rtt - << sampleStats.congestionWindowSize << sampleStats.packetSendPeriod - << sampleStats.sentPackets - << sampleStats.receivedACKs << sampleStats.receivedLightACKs << sampleStats.receivedNAKs; + auto it = _connectionsHash.find(destination); + if (it != _connectionsHash.end()) { + return it->second->sampleStats(); + } else { + return ConnectionStats::Stats(); } } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 6b798d64d2..0fee52e755 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -64,7 +64,7 @@ public: void connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* receiver, const char* slot); - void sampleAndPrintConnectionStats(); + ConnectionStats::Stats sampleStatsForConnection(const HifiSockAddr& destination); private slots: void readPendingDatagrams(); diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 55a8a78f6f..067a7ec746 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -41,6 +41,10 @@ const QCommandLineOption UNRELIABLE_PACKETS { "unreliable", "send unreliable packets (default is reliable)" }; +const QStringList STATS_TABLE_HEADERS { + "Send Rate (P/s)", "RTT(ms)", "CW (P)", "Send Period (us)", "Received ACK", "Received NAK", "Sent ACK2" +}; + UDTTest::UDTTest(int& argc, char** argv) : QCoreApplication(argc, argv) { @@ -123,6 +127,9 @@ UDTTest::UDTTest(int& argc, char** argv) : QTimer* statsTimer = new QTimer(this); connect(statsTimer, &QTimer::timeout, this, &UDTTest::sampleStats); statsTimer->start(STATS_SAMPLE_INTERVAL); + + // output the headers for stats for our table + qDebug() << qPrintable(STATS_TABLE_HEADERS.join(" | ")); } } @@ -207,5 +214,21 @@ void UDTTest::sendPacket() { } void UDTTest::sampleStats() { - _socket.sampleAndPrintConnectionStats(); + udt::ConnectionStats::Stats stats = _socket.sampleStatsForConnection(_target); + + int headerIndex = -1; + + // setup a list of left justified values + QStringList values { + QString::number(stats.receiveRate).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.rtt).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.congestionWindowSize).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.packetSendPeriod).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.receivedACKs).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.receivedNAKs).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.sentACK2s).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()) + }; + + // output this line of values + qDebug() << qPrintable(values.join(" | ")); } From 7083d843728d7eb5343821fb7831ed89eacc7cdd Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 31 Jul 2015 16:15:21 -0700 Subject: [PATCH 208/549] Fix ack timestamps --- libraries/networking/src/udt/Connection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index b399942a19..df03b7ea8f 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -159,7 +159,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { _parentSocket->writeBasePacket(*ackPacket, _destination); // write this ACK to the map of sent ACKs - _sentACKs[_currentACKSubSequenceNumber] = { nextACKNumber, currentTime }; + _sentACKs[_currentACKSubSequenceNumber] = { nextACKNumber, high_resolution_clock::now() }; // reset the number of data packets received since last ACK _packetsSinceACK = 0; From e39611dc1cba4fb3b0f7bea47c25ac053defde3e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 16:31:08 -0700 Subject: [PATCH 209/549] fix for PacketTimeWindow calculations --- libraries/networking/src/udt/PacketTimeWindow.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/PacketTimeWindow.cpp b/libraries/networking/src/udt/PacketTimeWindow.cpp index 9db837bc12..a16c736622 100644 --- a/libraries/networking/src/udt/PacketTimeWindow.cpp +++ b/libraries/networking/src/udt/PacketTimeWindow.cpp @@ -48,14 +48,15 @@ int32_t meanOfMedianFilteredValues(std::vector intervals, int numValues, in int lowerBound = median / MEDIAN_FILTERING_BOUND_MULTIPLIER; for (auto& interval : intervals) { - if ((interval < upperBound) && interval > lowerBound) { + if ((interval < upperBound) && (interval > lowerBound)) { ++count; sum += interval; } } if (count >= valuesRequired) { - return (int32_t) ceil((double) USECS_PER_MSEC / ((double) sum) / ((double) count)); + static const double USECS_PER_SEC = 1000000; + return (int32_t) ceil(USECS_PER_SEC / ((double) sum) / ((double) count)); } else { return 0; } From 681c9afe9082fd19d0336e1e370081cc904c05f0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 16:31:42 -0700 Subject: [PATCH 210/549] add parens to PacketTimeWindow division --- libraries/networking/src/udt/PacketTimeWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketTimeWindow.cpp b/libraries/networking/src/udt/PacketTimeWindow.cpp index a16c736622..3a942108a8 100644 --- a/libraries/networking/src/udt/PacketTimeWindow.cpp +++ b/libraries/networking/src/udt/PacketTimeWindow.cpp @@ -56,7 +56,7 @@ int32_t meanOfMedianFilteredValues(std::vector intervals, int numValues, in if (count >= valuesRequired) { static const double USECS_PER_SEC = 1000000; - return (int32_t) ceil(USECS_PER_SEC / ((double) sum) / ((double) count)); + return (int32_t) ceil(USECS_PER_SEC / (((double) sum) / ((double) count))); } else { return 0; } From 2db540ffde4a5fb588e0a28e00340a322d7b21c6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 16:35:42 -0700 Subject: [PATCH 211/549] fix for double in PacketTimeWindow --- libraries/networking/src/udt/PacketTimeWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketTimeWindow.cpp b/libraries/networking/src/udt/PacketTimeWindow.cpp index 3a942108a8..e28b276ed9 100644 --- a/libraries/networking/src/udt/PacketTimeWindow.cpp +++ b/libraries/networking/src/udt/PacketTimeWindow.cpp @@ -55,7 +55,7 @@ int32_t meanOfMedianFilteredValues(std::vector intervals, int numValues, in } if (count >= valuesRequired) { - static const double USECS_PER_SEC = 1000000; + static const double USECS_PER_SEC = 1000000.0; return (int32_t) ceil(USECS_PER_SEC / (((double) sum) / ((double) count))); } else { return 0; From 9b6c8bcf77cbfdcd02e24877e1a695bf8b24b34e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 16:37:38 -0700 Subject: [PATCH 212/549] update EWMA for delivery rate and bandwidth --- libraries/networking/src/udt/Connection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index d7fcdd20a1..0a4d974d08 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -422,8 +422,8 @@ void Connection::processACK(std::unique_ptr controlPacket) { _stats.recordReceiveRate(receiveRate); _stats.recordEstimatedBandwidth(bandwidth); - _deliveryRate = (_deliveryRate * (EMWA_ALPHA_NUMERATOR - 1) + _deliveryRate) / EMWA_ALPHA_NUMERATOR; - _bandwidth = (_bandwidth * (EMWA_ALPHA_NUMERATOR - 1) + _bandwidth) / EMWA_ALPHA_NUMERATOR; + _deliveryRate = (_deliveryRate * (EMWA_ALPHA_NUMERATOR - 1) + receiveRate) / EMWA_ALPHA_NUMERATOR; + _bandwidth = (_bandwidth * (EMWA_ALPHA_NUMERATOR - 1) + bandwidth) / EMWA_ALPHA_NUMERATOR; _congestionControl->setReceiveRate(_deliveryRate); _congestionControl->setBandwidth(_bandwidth); From 84b8fc9f063f9e9b54470a2b0cbdd3b0930424fa Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 16:41:22 -0700 Subject: [PATCH 213/549] fix casing of onACK method in CC --- libraries/networking/src/udt/CongestionControl.h | 2 +- libraries/networking/src/udt/Connection.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index 75970ed2fd..81ade13b41 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -37,7 +37,7 @@ public: virtual void init() {} virtual void close() {} - virtual void onAck(SequenceNumber ackNum) {} + virtual void onACK(SequenceNumber ackNum) {} virtual void onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) {} protected: diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 0a4d974d08..d668ed09fb 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -431,7 +431,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { // give this ACK to the congestion control and update the send queue parameters updateCongestionControlAndSendQueue([this, ack](){ - _congestionControl->onAck(ack); + _congestionControl->onACK(ack); }); // update the total count of received ACKs From fa6628e7eb8ffda609567ad5a86b6b897903090d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 16:52:09 -0700 Subject: [PATCH 214/549] make sure we init CongestionControl --- libraries/networking/src/udt/CongestionControl.cpp | 6 ++++-- libraries/networking/src/udt/Connection.cpp | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 984d520d07..8d8efec51e 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -18,11 +18,13 @@ using namespace std::chrono; static const double USECS_PER_SECOND = 1000000.0; void CongestionControl::setPacketSendPeriod(double newSendPeriod) { + Q_ASSERT_X(newSendPeriod >= 0, "CongestionControl::setPacketPeriod", "Can not set a negative packet send period"); + if (_maxBandwidth > 0) { // anytime the packet send period is about to be increased, make sure it stays below the minimum period, // calculated based on the maximum desired bandwidth - int minPacketSendPeriod = USECS_PER_SECOND / (double(_maxBandwidth) / _mss); - _packetSendPeriod = std::max(newSendPeriod, (double) minPacketSendPeriod); + double minPacketSendPeriod = USECS_PER_SECOND / (((double) _maxBandwidth) / _mss); + _packetSendPeriod = std::max(newSendPeriod, minPacketSendPeriod); } else { _packetSendPeriod = newSendPeriod; } diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index d668ed09fb..8b16e8987f 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -32,6 +32,9 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination, unique_pt { Q_ASSERT_X(socket, "Connection::Connection", "Must be called with a valid Socket*"); + Q_ASSERT_X(congestionControl, "Connection::Connection", "Must be called with a valid CongestionControl object"); + congestionControl->init(); + // setup default SYN, RTT and RTT Variance based on the SYN interval in CongestionControl object _synInterval = _congestionControl->synInterval(); _rtt = _synInterval * 10; From 15ce9aabc54080869e1eb0b1f7ebd91b84645b1d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 16:52:59 -0700 Subject: [PATCH 215/549] don't assert on moved CC --- libraries/networking/src/udt/Connection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 8b16e8987f..a2a8942508 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -32,7 +32,7 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination, unique_pt { Q_ASSERT_X(socket, "Connection::Connection", "Must be called with a valid Socket*"); - Q_ASSERT_X(congestionControl, "Connection::Connection", "Must be called with a valid CongestionControl object"); + Q_ASSERT_X(_congestionControl, "Connection::Connection", "Must be called with a valid CongestionControl object"); congestionControl->init(); // setup default SYN, RTT and RTT Variance based on the SYN interval in CongestionControl object From cba51ac63df7ce91a5533648ecc57289ced49a0e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 31 Jul 2015 16:53:43 -0700 Subject: [PATCH 216/549] Fix congestion control --- libraries/networking/src/udt/Connection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index a2a8942508..93f61c11aa 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -33,7 +33,7 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination, unique_pt Q_ASSERT_X(socket, "Connection::Connection", "Must be called with a valid Socket*"); Q_ASSERT_X(_congestionControl, "Connection::Connection", "Must be called with a valid CongestionControl object"); - congestionControl->init(); + _congestionControl->init(); // setup default SYN, RTT and RTT Variance based on the SYN interval in CongestionControl object _synInterval = _congestionControl->synInterval(); From 0e3403833d5dc16f2783840ef69935abcd6794ee Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 17:00:53 -0700 Subject: [PATCH 217/549] make capacitySpeedDelta a double --- libraries/networking/src/udt/CongestionControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 8d8efec51e..16ee9a0c75 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -95,7 +95,7 @@ void DefaultCC::onACK(SequenceNumber ackNum) { return; } - int capacitySpeedDelta = (int) (_bandwidth - USECS_PER_SECOND / _packetSendPeriod); + double capacitySpeedDelta = (_bandwidth - USECS_PER_SECOND / _packetSendPeriod); // UDT uses what they call DAIMD - additive increase multiplicative decrease with decreasing increases // This factor is a protocol parameter that is part of the DAIMD algorithim From 2946cb7ed5a86b1d6639b5f196e8a127366763eb Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 31 Jul 2015 17:15:10 -0700 Subject: [PATCH 218/549] Collapse ControlPacket ctors --- .../networking/src/udt/ControlPacket.cpp | 25 ++----------------- libraries/networking/src/udt/ControlPacket.h | 3 +-- 2 files changed, 3 insertions(+), 25 deletions(-) diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index 626e126c03..b64e471428 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -42,32 +42,11 @@ std::unique_ptr ControlPacket::fromReceivedPacket(std::unique_ptr } std::unique_ptr ControlPacket::create(Type type, qint64 size) { - - std::unique_ptr controlPacket; - - if (size == -1) { - return std::unique_ptr(new ControlPacket(type)); - } else { - // Fail with invalid size - Q_ASSERT(size >= 0); - - return std::unique_ptr(new ControlPacket(type, size)); - } -} - -ControlPacket::ControlPacket(Type type) : - BasePacket(-1), - _type(type) -{ - adjustPayloadStartAndCapacity(ControlPacket::localHeaderSize()); - - open(QIODevice::ReadWrite); - - writeType(); + return std::unique_ptr(new ControlPacket(type, size)); } ControlPacket::ControlPacket(Type type, qint64 size) : - BasePacket(ControlPacket::localHeaderSize() + size), + BasePacket((size == -1) ? -1 : ControlPacket::localHeaderSize() + size), _type(type) { adjustPayloadStartAndCapacity(ControlPacket::localHeaderSize()); diff --git a/libraries/networking/src/udt/ControlPacket.h b/libraries/networking/src/udt/ControlPacket.h index c4ad7065a7..e0e3e38796 100644 --- a/libraries/networking/src/udt/ControlPacket.h +++ b/libraries/networking/src/udt/ControlPacket.h @@ -47,8 +47,7 @@ public: void setType(Type type); private: - ControlPacket(Type type); - ControlPacket(Type type, qint64 size); + ControlPacket(Type type, qint64 size = -1); ControlPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); ControlPacket(ControlPacket&& other); ControlPacket(const ControlPacket& other) = delete; From df1e97c591cd88d2df7fd8a441acf3fdc40d5d33 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 17:19:14 -0700 Subject: [PATCH 219/549] cleanup RTT stats, add assert for CT --- libraries/networking/src/udt/ControlPacket.cpp | 5 ++++- tools/udt-test/src/UDTTest.cpp | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index 626e126c03..f1e3b71b67 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -120,6 +120,9 @@ void ControlPacket::readType() { Q_ASSERT_X(bitAndType & CONTROL_BIT_MASK, "ControlPacket::readHeader()", "This should be a control packet"); + uint16_t packetType = (bitAndType & ~CONTROL_BIT_MASK) >> (8 * sizeof(Type)); + Q_ASSERT_X(packetType < ControlPacket::Type::TimeoutNAK, "ControlPacket::readType()", "Received a control packet with wrong type"); + // read the type - _type = (Type) ((bitAndType & ~CONTROL_BIT_MASK) >> (8 * sizeof(Type))); + _type = (Type) packetType; } diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 067a7ec746..d0c7b159df 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -218,10 +218,12 @@ void UDTTest::sampleStats() { int headerIndex = -1; + static const double USECS_PER_MSEC = 1000.0; + // setup a list of left justified values QStringList values { QString::number(stats.receiveRate).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.rtt).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.rtt / USECS_PER_MSEC).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.congestionWindowSize).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.packetSendPeriod).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.receivedACKs).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), From 22ead79988a4681b947af1c6b19443771d51ba55 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 17:30:22 -0700 Subject: [PATCH 220/549] fix another char allocation in PacketTests --- tests/networking/src/PacketTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/networking/src/PacketTests.cpp b/tests/networking/src/PacketTests.cpp index 8ac4a6d94e..cbb949aa84 100644 --- a/tests/networking/src/PacketTests.cpp +++ b/tests/networking/src/PacketTests.cpp @@ -18,7 +18,7 @@ QTEST_MAIN(PacketTests) std::unique_ptr copyToReadPacket(std::unique_ptr& packet) { auto size = packet->getDataSize(); - auto data = std::unique_ptr(new char[size]); + auto data = std::unique_ptr(new char[size]); memcpy(data.get(), packet->getData(), size); return Packet::fromReceivedPacket(std::move(data), size, HifiSockAddr()); } From 9537aea5c0aa1db1c4325487d2a006093657081e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 31 Jul 2015 17:31:30 -0700 Subject: [PATCH 221/549] Fix nak timeout packet size --- libraries/networking/src/udt/Connection.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 93f61c11aa..56fc1292b6 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -238,8 +238,7 @@ void Connection::sendNAK(SequenceNumber sequenceNumberRecieved) { void Connection::sendTimeoutNAK() { if (_lossList.getLength() > 0) { // construct a NAK packet that will hold all of the lost sequence numbers - // TODO size is wrong, fix it. - auto lossListPacket = ControlPacket::create(ControlPacket::TimeoutNAK, _lossList.getLength() * sizeof(SequenceNumber)); + auto lossListPacket = ControlPacket::create(ControlPacket::TimeoutNAK, 2 * _lossList.getLength() * sizeof(SequenceNumber)); // Pack in the lost sequence numbers _lossList.write(*lossListPacket); From e74f47b64c4467b9af16b25b09428e44e782662a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 18:13:11 -0700 Subject: [PATCH 222/549] use a list of pairs of pairs for ACK2 --- libraries/networking/src/udt/Connection.cpp | 48 +++++++++++++-------- libraries/networking/src/udt/Connection.h | 6 ++- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 56fc1292b6..62336a31ae 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -161,8 +161,11 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { // have the socket send off our packet _parentSocket->writeBasePacket(*ackPacket, _destination); + Q_ASSERT_X(_sentACKs.empty() || _sentACKs.back().first + 1 == _currentACKSubSequenceNumber, + "Connection::sendACK", "Adding an invalid ACK to _sentACKs"); + // write this ACK to the map of sent ACKs - _sentACKs[_currentACKSubSequenceNumber] = { nextACKNumber, high_resolution_clock::now() }; + _sentACKs.push_back({ _currentACKSubSequenceNumber, { nextACKNumber, high_resolution_clock::now() }}); // reset the number of data packets received since last ACK _packetsSinceACK = 0; @@ -372,7 +375,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { // read the ACKed sequence number SequenceNumber ack; controlPacket->readPrimitive(&ack); - + // validate that this isn't a BS ACK if (ack > getSendQueue().getCurrentSequenceNumber()) { // in UDT they specifically break the connection here - do we want to do anything? @@ -463,23 +466,32 @@ void Connection::processACK2(std::unique_ptr controlPacket) { controlPacket->readPrimitive(&subSequenceNumber); // check if we had that subsequence number in our map - auto it = _sentACKs.find(subSequenceNumber); + auto it = std::find_if_not(_sentACKs.begin(), _sentACKs.end(), [subSequenceNumber](const ACKListPair& pair){ + return subSequenceNumber < pair.first; + }); + if (it != _sentACKs.end()) { - // update the RTT using the ACK window - SequenceNumberTimePair& pair = it->second; - - // calculate the RTT (time now - time ACK sent) - auto now = high_resolution_clock::now(); - int rtt = duration_cast(now - pair.second).count(); - - updateRTT(rtt); - - // set the RTT for congestion control - _congestionControl->setRTT(_rtt); - - // update the last ACKed ACK - if (pair.first > _lastReceivedAcknowledgedACK) { - _lastReceivedAcknowledgedACK = pair.first; + if (it->first == subSequenceNumber){ + // update the RTT using the ACK window + + // calculate the RTT (time now - time ACK sent) + auto now = high_resolution_clock::now(); + int rtt = duration_cast(now - it->second.second).count(); + + updateRTT(rtt); + + // set the RTT for congestion control + _congestionControl->setRTT(_rtt); + + // update the last ACKed ACK + if (it->second.first > _lastReceivedAcknowledgedACK) { + _lastReceivedAcknowledgedACK = it->second.first; + } + + // erase this sub-sequence number and anything below it now that we've gotten our timing information + _sentACKs.erase(_sentACKs.begin(), it); + } else { + Q_UNREACHABLE(); } } diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 23a77bf4db..dd86f9bc5b 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -13,6 +13,7 @@ #define hifi_Connection_h #include +#include #include #include @@ -35,7 +36,8 @@ class Connection : public QObject { Q_OBJECT public: using SequenceNumberTimePair = std::pair; - using SentACKMap = std::unordered_map; + using ACKListPair = std::pair; + using SentACKList = std::list; Connection(Socket* parentSocket, HifiSockAddr destination, std::unique_ptr congestionControl); ~Connection(); @@ -100,7 +102,7 @@ private: int _bandwidth { 1 }; // Exponential moving average for estimated bandwidth, in packets per second int _deliveryRate { 16 }; // Exponential moving average for receiver's receive rate, in packets per second - SentACKMap _sentACKs; // Map of ACK sub-sequence numbers to ACKed sequence number and sent time + SentACKList _sentACKs; // Map of ACK sub-sequence numbers to ACKed sequence number and sent time Socket* _parentSocket { nullptr }; HifiSockAddr _destination; From 8f54cd6f7ebc32b33b6537fa6bd73e366e74bfa9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 31 Jul 2015 18:19:15 -0700 Subject: [PATCH 223/549] Fix find_if_not --- libraries/networking/src/udt/Connection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 62336a31ae..dd34a2bad2 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -466,8 +466,8 @@ void Connection::processACK2(std::unique_ptr controlPacket) { controlPacket->readPrimitive(&subSequenceNumber); // check if we had that subsequence number in our map - auto it = std::find_if_not(_sentACKs.begin(), _sentACKs.end(), [subSequenceNumber](const ACKListPair& pair){ - return subSequenceNumber < pair.first; + auto it = std::find_if(_sentACKs.begin(), _sentACKs.end(), [subSequenceNumber](const ACKListPair& pair){ + return subSequenceNumber >= pair.first; }); if (it != _sentACKs.end()) { From 8bc94454b447c4918f1dd5ad506e8df2af96421d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 18:39:09 -0700 Subject: [PATCH 224/549] pre-increment the _currentACKSubSequenceNumber --- libraries/networking/src/udt/Connection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index dd34a2bad2..5c3e1846ce 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -129,7 +129,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { ackPacket->reset(); // We need to reset it every time. // pack in the ACK sub-sequence number - ackPacket->writePrimitive(_currentACKSubSequenceNumber++); + ackPacket->writePrimitive(++_currentACKSubSequenceNumber); // pack in the ACK number ackPacket->writePrimitive(nextACKNumber); From ca342fb3b4bbf1579a0e815b2789c94c5f08b701 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 31 Jul 2015 18:39:24 -0700 Subject: [PATCH 225/549] Fix std::find_if --- libraries/networking/src/udt/Connection.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index dd34a2bad2..18e3fb9668 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -466,8 +466,8 @@ void Connection::processACK2(std::unique_ptr controlPacket) { controlPacket->readPrimitive(&subSequenceNumber); // check if we had that subsequence number in our map - auto it = std::find_if(_sentACKs.begin(), _sentACKs.end(), [subSequenceNumber](const ACKListPair& pair){ - return subSequenceNumber >= pair.first; + auto it = std::find_if_not(_sentACKs.begin(), _sentACKs.end(), [&subSequenceNumber](const ACKListPair& pair){ + return pair.first < subSequenceNumber; }); if (it != _sentACKs.end()) { @@ -487,14 +487,14 @@ void Connection::processACK2(std::unique_ptr controlPacket) { if (it->second.first > _lastReceivedAcknowledgedACK) { _lastReceivedAcknowledgedACK = it->second.first; } - - // erase this sub-sequence number and anything below it now that we've gotten our timing information - _sentACKs.erase(_sentACKs.begin(), it); - } else { + } else if (it->first < subSequenceNumber) { Q_UNREACHABLE(); } } + // erase this sub-sequence number and anything below it now that we've gotten our timing information + _sentACKs.erase(_sentACKs.begin(), it); + _stats.recordReceivedACK2(); } From 3833623cfe87b9cfeca20eb7bd69ec6345a7b120 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 18:41:46 -0700 Subject: [PATCH 226/549] fix assert for control packet type --- libraries/networking/src/udt/ControlPacket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index 30bf8d452e..b8407d42a4 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -100,7 +100,7 @@ void ControlPacket::readType() { Q_ASSERT_X(bitAndType & CONTROL_BIT_MASK, "ControlPacket::readHeader()", "This should be a control packet"); uint16_t packetType = (bitAndType & ~CONTROL_BIT_MASK) >> (8 * sizeof(Type)); - Q_ASSERT_X(packetType < ControlPacket::Type::TimeoutNAK, "ControlPacket::readType()", "Received a control packet with wrong type"); + Q_ASSERT_X(packetType <= ControlPacket::Type::TimeoutNAK, "ControlPacket::readType()", "Received a control packet with wrong type"); // read the type _type = (Type) packetType; From 74a2d985ebb1fd6a985d1d516e79b67102557a43 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 19:17:02 -0700 Subject: [PATCH 227/549] tell the send queue about ACKs on light ACK --- libraries/networking/src/udt/Connection.cpp | 13 ++++++++----- tools/udt-test/src/UDTTest.cpp | 5 +++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 24911d04cb..8ad7259347 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -102,7 +102,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { if (nextACKNumber == _lastSentACK) { // We already sent this ACK, but check if we should re-send it. - if (nextACKNumber <= _lastReceivedAcknowledgedACK) { + if (nextACKNumber < _lastReceivedAcknowledgedACK) { // we already got an ACK2 for this ACK we would be sending, don't bother return; } @@ -375,11 +375,11 @@ void Connection::processACK(std::unique_ptr controlPacket) { // read the ACKed sequence number SequenceNumber ack; controlPacket->readPrimitive(&ack); - + // validate that this isn't a BS ACK if (ack > getSendQueue().getCurrentSequenceNumber()) { // in UDT they specifically break the connection here - do we want to do anything? - Q_ASSERT_X(true, "Connection::processACK", "ACK recieved higher than largest sent sequence number"); + Q_ASSERT_X(false, "Connection::processACK", "ACK recieved higher than largest sent sequence number"); return; } @@ -388,7 +388,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { controlPacket->readPrimitive(&rtt); if (ack < _lastReceivedACK) { - // Bail + // this is an out of order ACK, bail return; } @@ -396,7 +396,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { controlPacket->readPrimitive(&_flowWindowSize); if (ack == _lastReceivedACK) { - // Bail + // processing an already received ACK, bail return; } @@ -455,6 +455,9 @@ void Connection::processLightACK(std::unique_ptr controlPacket) { // update the last received ACK to the this one _lastReceivedACK = ack; + + // send light ACK to the send queue + getSendQueue().ack(ack); } _stats.recordReceivedLightACK(); diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index d0c7b159df..97de033dfe 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -42,7 +42,7 @@ const QCommandLineOption UNRELIABLE_PACKETS { }; const QStringList STATS_TABLE_HEADERS { - "Send Rate (P/s)", "RTT(ms)", "CW (P)", "Send Period (us)", "Received ACK", "Received NAK", "Sent ACK2" + "Send Rate (P/s)", "RTT(ms)", "CW (P)", "Send Period (us)", "Received ACK", "Received NAK", "Sent ACK2", "Re-sent Packets" }; UDTTest::UDTTest(int& argc, char** argv) : @@ -228,7 +228,8 @@ void UDTTest::sampleStats() { QString::number(stats.packetSendPeriod).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.receivedACKs).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.receivedNAKs).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.sentACK2s).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()) + QString::number(stats.sentACK2s).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.retransmissions).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()) }; // output this line of values From 7f8c993bd7726090db7fea914615d7f325ea169e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 19:42:24 -0700 Subject: [PATCH 228/549] make send rate actually send rate, don't sync as sender --- libraries/networking/src/udt/Connection.cpp | 27 +++++++++++-------- libraries/networking/src/udt/Connection.h | 2 ++ .../networking/src/udt/ConnectionStats.cpp | 5 ++++ .../networking/src/udt/ConnectionStats.h | 2 ++ libraries/networking/src/udt/SendQueue.cpp | 2 ++ tools/udt-test/src/UDTTest.cpp | 2 +- 6 files changed, 28 insertions(+), 12 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 8ad7259347..c27d5d5bed 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -72,16 +72,18 @@ void Connection::sendReliablePacket(unique_ptr packet) { } void Connection::sync() { - // we send out a periodic ACK every rate control interval - sendACK(); - - // check if we need to re-transmit a loss list - // we do this if it has been longer than the current nakInterval since we last sent - auto now = high_resolution_clock::now(); - - if (duration_cast(now - _lastNAKTime).count() >= _nakInterval) { - // Send a timeout NAK packet - sendTimeoutNAK(); + if (_hasReceivedFirstPacket) { + // we send out a periodic ACK every rate control interval + sendACK(); + + // check if we need to re-transmit a loss list + // we do this if it has been longer than the current nakInterval since we last sent + auto now = high_resolution_clock::now(); + + if (duration_cast(now - _lastNAKTime).count() >= _nakInterval) { + // Send a timeout NAK packet + sendTimeoutNAK(); + } } } @@ -265,6 +267,9 @@ SequenceNumber Connection::nextACK() const { } bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, int packetSize, int payloadSize) { + + _hasReceivedFirstPacket = true; + // check if this is a packet pair we should estimate bandwidth from, or just a regular packet if (((uint32_t) sequenceNumber & 0xF) == 0) { _receiveWindow.onProbePair1Arrival(); @@ -424,7 +429,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { static const int EMWA_ALPHA_NUMERATOR = 8; // record these samples in connection stats - _stats.recordReceiveRate(receiveRate); + _stats.recordSendRate(receiveRate); _stats.recordEstimatedBandwidth(bandwidth); _deliveryRate = (_deliveryRate * (EMWA_ALPHA_NUMERATOR - 1) + receiveRate) / EMWA_ALPHA_NUMERATOR; diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index dd86f9bc5b..0876a814e3 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -86,6 +86,8 @@ private: int _minNAKInterval { 100000 }; // NAK timeout interval lower bound, default of 100ms std::chrono::high_resolution_clock::time_point _lastNAKTime; + bool _hasReceivedFirstPacket { false }; + LossList _lossList; // List of all missing packets SequenceNumber _lastReceivedSequenceNumber; // The largest sequence number received from the peer SequenceNumber _lastReceivedACK; // The last ACK received diff --git a/libraries/networking/src/udt/ConnectionStats.cpp b/libraries/networking/src/udt/ConnectionStats.cpp index 62497ab496..1f8308bf5d 100644 --- a/libraries/networking/src/udt/ConnectionStats.cpp +++ b/libraries/networking/src/udt/ConnectionStats.cpp @@ -139,6 +139,11 @@ void ConnectionStats::recordDuplicates() { static const double EWMA_CURRENT_SAMPLE_WEIGHT = 0.125; static const double EWMA_PREVIOUS_SAMPLES_WEIGHT = 1 - 0.125; +void ConnectionStats::recordSendRate(int sample) { + _currentSample.sendRate = sample; + _total.sendRate = (_total.sendRate * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT); +} + void ConnectionStats::recordReceiveRate(int sample) { _currentSample.receiveRate = sample; _total.receiveRate = (_total.receiveRate * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT); diff --git a/libraries/networking/src/udt/ConnectionStats.h b/libraries/networking/src/udt/ConnectionStats.h index f4b912ace5..27d8bbd7a1 100644 --- a/libraries/networking/src/udt/ConnectionStats.h +++ b/libraries/networking/src/udt/ConnectionStats.h @@ -52,6 +52,7 @@ public: int duplicates { 0 }; // the following stats are trailing averages in the result, not totals + int sendRate { 0 }; int receiveRate { 0 }; int estimatedBandwith { 0 }; int rtt { 0 }; @@ -84,6 +85,7 @@ public: void recordRetransmission(); void recordDuplicates(); + void recordSendRate(int sample); void recordReceiveRate(int sample); void recordEstimatedBandwidth(int sample); void recordRTT(int sample); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index f271a1c685..508e674278 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -108,6 +108,8 @@ void SendQueue::overrideNAKListFromPacket(ControlPacket& packet) { packet.readPrimitive(&first); packet.readPrimitive(&second); + qDebug() << "NAK" << (uint32_t) first << (uint32_t) second; + if (first == second) { _naks.append(first); } else { diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 97de033dfe..780e035a89 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -222,7 +222,7 @@ void UDTTest::sampleStats() { // setup a list of left justified values QStringList values { - QString::number(stats.receiveRate).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.sendRate).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.rtt / USECS_PER_MSEC).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.congestionWindowSize).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.packetSendPeriod).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), From 0c44fc53ded8d4560820c2fe1cef1e50d7b6a8de Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 19:45:43 -0700 Subject: [PATCH 229/549] fix for process of timeout NAKs --- libraries/networking/src/udt/SendQueue.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 508e674278..7186316bc0 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -104,12 +104,10 @@ void SendQueue::overrideNAKListFromPacket(ControlPacket& packet) { _naks.clear(); SequenceNumber first, second; - while (packet.bytesLeftToRead() > (qint64)(2 * sizeof(SequenceNumber))) { + while (packet.bytesLeftToRead() >= (qint64)(2 * sizeof(SequenceNumber))) { packet.readPrimitive(&first); packet.readPrimitive(&second); - qDebug() << "NAK" << (uint32_t) first << (uint32_t) second; - if (first == second) { _naks.append(first); } else { From 826c8d5150a1457be57f04380ea21f814edbe86e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 19:52:20 -0700 Subject: [PATCH 230/549] more stats in UDTTest for sender --- tools/udt-test/src/UDTTest.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 780e035a89..eaa7530989 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -42,7 +42,9 @@ const QCommandLineOption UNRELIABLE_PACKETS { }; const QStringList STATS_TABLE_HEADERS { - "Send Rate (P/s)", "RTT(ms)", "CW (P)", "Send Period (us)", "Received ACK", "Received NAK", "Sent ACK2", "Re-sent Packets" + "Send Rate (P/s)", "RTT(ms)", "CW (P)", "Send Period (us)", + "Received ACK", "Received L-ACK", "Received NAK", "Received TNAK", + "Sent ACK2", "Re-sent Packets" }; UDTTest::UDTTest(int& argc, char** argv) : @@ -227,7 +229,9 @@ void UDTTest::sampleStats() { QString::number(stats.congestionWindowSize).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.packetSendPeriod).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.receivedACKs).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.receivedLightACKs).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.receivedNAKs).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.receivedTimeoutNAKs).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.sentACK2s).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.retransmissions).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()) }; From bc5ddd38374776e72909711ede5c3f3bf41867af Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jul 2015 20:12:48 -0700 Subject: [PATCH 231/549] send a light ACK every 64, not each after 64 --- libraries/networking/src/udt/Connection.cpp | 7 ++++++- libraries/networking/src/udt/Connection.h | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index c27d5d5bed..41bdb36c98 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -73,6 +73,9 @@ void Connection::sendReliablePacket(unique_ptr packet) { void Connection::sync() { if (_hasReceivedFirstPacket) { + // reset the number of light ACKS during this sync interval + _lightACKsDuringSYN = 1; + // we send out a periodic ACK every rate control interval sendACK(); @@ -322,8 +325,10 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in // check if we need to send an ACK, according to CC params if (_congestionControl->_ackInterval > 0 && _packetsSinceACK >= _congestionControl->_ackInterval) { sendACK(false); - } else if (_congestionControl->_lightACKInterval > 0 && _packetsSinceACK >= _congestionControl->_lightACKInterval) { + } else if (_congestionControl->_lightACKInterval > 0 + && _packetsSinceACK >= _congestionControl->_lightACKInterval * _lightACKsDuringSYN) { sendLightACK(); + ++_lightACKsDuringSYN; } if (wasDuplicate) { diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 0876a814e3..99328d601f 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -97,6 +97,8 @@ private: SequenceNumber _lastSentACK; // The last sent ACK SequenceNumber _lastSentACK2; // The last sent ACK sub-sequence number in an ACK2 + int _lightACKsDuringSYN { 1 }; // The number of lite ACKs sent during SYN interval + int32_t _rtt; // RTT, in microseconds int32_t _rttVariance; // RTT variance int _flowWindowSize { udt::MAX_PACKETS_IN_FLIGHT }; // Flow control window size From ffb5fcee7b9c273a9098a016b6e9f6d2ad83db0d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 3 Aug 2015 10:25:40 -0700 Subject: [PATCH 232/549] use nth element for median in PacketTimeWindow --- .../networking/src/udt/PacketTimeWindow.cpp | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/libraries/networking/src/udt/PacketTimeWindow.cpp b/libraries/networking/src/udt/PacketTimeWindow.cpp index e28b276ed9..269d158b7d 100644 --- a/libraries/networking/src/udt/PacketTimeWindow.cpp +++ b/libraries/networking/src/udt/PacketTimeWindow.cpp @@ -11,6 +11,7 @@ #include "PacketTimeWindow.h" +#include #include #include @@ -30,22 +31,32 @@ PacketTimeWindow::PacketTimeWindow(int numPacketIntervals, int numProbeIntervals } -int32_t meanOfMedianFilteredValues(std::vector intervals, int numValues, int valuesRequired = 0) { - // sort the intervals from smallest to largest - std::sort(intervals.begin(), intervals.end()); +template +int median(Iterator begin, Iterator end) { + // use std::nth_element to grab the middle - for an even number of elements this is the upper middle + Iterator middle = begin + (end - begin) / 2; + std::nth_element(begin, middle, end); - int median = 0; - if (numValues % 2 == 0) { - median = intervals[numValues / 2]; + if ((end - begin) % 2 != 0) { + // odd number of elements, just return the middle + return *middle; } else { - median = (intervals[(numValues / 2) - 1] + intervals[numValues / 2]) / 2; + // even number of elements, return the mean of the upper middle and the lower middle + Iterator lowerMiddle = std::max_element(begin, middle); + return (*middle + *lowerMiddle) / 2; } +} + +int32_t meanOfMedianFilteredValues(std::vector intervals, int numValues, int valuesRequired = 0) { + // grab the median value of the intervals vector + int intervalsMedian = median(intervals.begin(), intervals.end()); - int count = 0; - int sum = 0; static const int MEDIAN_FILTERING_BOUND_MULTIPLIER = 8; - int upperBound = median * MEDIAN_FILTERING_BOUND_MULTIPLIER; - int lowerBound = median / MEDIAN_FILTERING_BOUND_MULTIPLIER; + int upperBound = intervalsMedian * MEDIAN_FILTERING_BOUND_MULTIPLIER; + int lowerBound = intervalsMedian / MEDIAN_FILTERING_BOUND_MULTIPLIER; + + int sum = 0; + int count = 0; for (auto& interval : intervals) { if ((interval < upperBound) && (interval > lowerBound)) { From 4230d021848a40f1e1218c709e07f12db9357bc5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 3 Aug 2015 11:06:48 -0700 Subject: [PATCH 233/549] rename col for light ACKs --- tools/udt-test/src/UDTTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index eaa7530989..babf4b8c25 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -43,7 +43,7 @@ const QCommandLineOption UNRELIABLE_PACKETS { const QStringList STATS_TABLE_HEADERS { "Send Rate (P/s)", "RTT(ms)", "CW (P)", "Send Period (us)", - "Received ACK", "Received L-ACK", "Received NAK", "Received TNAK", + "Received ACK", "Received LACK", "Received NAK", "Received TNAK", "Sent ACK2", "Re-sent Packets" }; From f513a28953da79aa1f770038b9aecbeceb63027f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 3 Aug 2015 11:06:57 -0700 Subject: [PATCH 234/549] Added better assert in LossList --- libraries/networking/src/udt/LossList.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp index 90399e319d..bf9c081943 100644 --- a/libraries/networking/src/udt/LossList.cpp +++ b/libraries/networking/src/udt/LossList.cpp @@ -17,7 +17,8 @@ using namespace udt; using namespace std; void LossList::append(SequenceNumber seq) { - assert(_lossList.empty() || _lossList.back().second < seq); + Q_ASSERT_X(_lossList.empty() || (_lossList.back().second < seq), "LossList::append(SequenceNumber)", + "SequenceNumber appended is not greater than the last SequenceNumber in the list"); if (getLength() > 0 && _lossList.back().second + 1 == seq) { ++_lossList.back().second; @@ -28,6 +29,12 @@ void LossList::append(SequenceNumber seq) { } void LossList::append(SequenceNumber start, SequenceNumber end) { + Q_ASSERT_X(_lossList.empty() || (_lossList.back().second < start), + "LossList::append(SequenceNumber, SequenceNumber)", + "SequenceNumber range appended is not greater than the last SequenceNumber in the list"); + Q_ASSERT_X(start <= end, + "LossList::append(SequenceNumber, SequenceNumber)", "Range start greater than range end"); + if (getLength() > 0 && _lossList.back().second + 1 == start) { _lossList.back().second = end; } else { @@ -37,6 +44,9 @@ void LossList::append(SequenceNumber start, SequenceNumber end) { } void LossList::insert(SequenceNumber start, SequenceNumber end) { + Q_ASSERT_X(start <= end, + "LossList::insert(SequenceNumber, SequenceNumber)", "Range start greater than range end"); + auto it = find_if_not(_lossList.begin(), _lossList.end(), [&start](pair pair){ return pair.second < start; }); @@ -109,6 +119,8 @@ bool LossList::remove(SequenceNumber seq) { } void LossList::remove(SequenceNumber start, SequenceNumber end) { + Q_ASSERT_X(start <= end, + "LossList::remove(SequenceNumber, SequenceNumber)", "Range start greater than range end"); // Find the first segment sharing sequence numbers auto it = find_if(_lossList.begin(), _lossList.end(), [&start, &end](pair pair) { return (pair.first <= start && start <= pair.second) || (start <= pair.first && pair.first <= end); @@ -151,7 +163,7 @@ void LossList::remove(SequenceNumber start, SequenceNumber end) { } SequenceNumber LossList::getFirstSequenceNumber() const { - assert(getLength() > 0); + Q_ASSERT_X(getLength() > 0, "LossList::getFirstSequenceNumber()", "Trying to get first element of an empty list"); return _lossList.front().first; } From de8f730f784fce7e91e412bc0d59173579b1118d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 3 Aug 2015 11:07:58 -0700 Subject: [PATCH 235/549] Fix connection stats error --- libraries/networking/src/udt/ConnectionStats.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/ConnectionStats.cpp b/libraries/networking/src/udt/ConnectionStats.cpp index 1f8308bf5d..26112eb24f 100644 --- a/libraries/networking/src/udt/ConnectionStats.cpp +++ b/libraries/networking/src/udt/ConnectionStats.cpp @@ -100,7 +100,7 @@ void ConnectionStats::recordReceivedPackets(int payload, int total) { _currentSample.recievedUtilBytes += payload; _total.recievedUtilBytes += payload; - _currentSample.sentBytes += total; + _currentSample.recievedBytes += total; _total.recievedBytes += total; } From 62d4467f416026d94ff054843eb26df673f2d946 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 3 Aug 2015 12:09:25 -0700 Subject: [PATCH 236/549] use a vector for events in ConnectionStats --- libraries/networking/src/udt/Connection.cpp | 28 +++++---- .../networking/src/udt/ConnectionStats.cpp | 62 +------------------ .../networking/src/udt/ConnectionStats.h | 48 +++++++------- tools/udt-test/src/UDTTest.cpp | 15 ++--- 4 files changed, 47 insertions(+), 106 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 41bdb36c98..1786f7558e 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -95,7 +95,7 @@ void Connection::recordSentPackets(int dataSize, int payloadSize) { } void Connection::recordRetransmission() { - _stats.recordRetransmission(); + _stats.record(ConnectionStats::Stats::Retransmission); } void Connection::sendACK(bool wasCausedBySyncTimeout) { @@ -175,7 +175,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { // reset the number of data packets received since last ACK _packetsSinceACK = 0; - _stats.recordSentACK(); + _stats.record(ConnectionStats::Stats::SentACK); } void Connection::sendLightACK() { @@ -199,7 +199,7 @@ void Connection::sendLightACK() { // have the socket send off our packet immediately _parentSocket->writeBasePacket(*lightACKPacket, _destination); - _stats.recordSentLightACK(); + _stats.record(ConnectionStats::Stats::SentLightACK); } void Connection::sendACK2(SequenceNumber currentACKSubSequenceNumber) { @@ -219,7 +219,7 @@ void Connection::sendACK2(SequenceNumber currentACKSubSequenceNumber) { // update the last sent ACK2 and the last ACK2 send time _lastSentACK2 = currentACKSubSequenceNumber; - _stats.recordSentACK2(); + _stats.record(ConnectionStats::Stats::SentACK2); } void Connection::sendNAK(SequenceNumber sequenceNumberRecieved) { @@ -240,7 +240,7 @@ void Connection::sendNAK(SequenceNumber sequenceNumberRecieved) { // record our last NAK time _lastNAKTime = high_resolution_clock::now(); - _stats.recordSentNAK(); + _stats.record(ConnectionStats::Stats::SentNAK); } void Connection::sendTimeoutNAK() { @@ -257,7 +257,7 @@ void Connection::sendTimeoutNAK() { // record this as the last NAK time _lastNAKTime = high_resolution_clock::now(); - _stats.recordSentTimeoutNAK(); + _stats.record(ConnectionStats::Stats::SentTimeoutNAK); } } @@ -332,7 +332,7 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in } if (wasDuplicate) { - _stats.recordDuplicates(); + _stats.record(ConnectionStats::Stats::Duplicate); } else { _stats.recordReceivedPackets(payloadSize, packetSize); } @@ -386,6 +386,9 @@ void Connection::processACK(std::unique_ptr controlPacket) { SequenceNumber ack; controlPacket->readPrimitive(&ack); + // update the total count of received ACKs + _stats.record(ConnectionStats::Stats::ReceivedACK); + // validate that this isn't a BS ACK if (ack > getSendQueue().getCurrentSequenceNumber()) { // in UDT they specifically break the connection here - do we want to do anything? @@ -449,8 +452,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { _congestionControl->onACK(ack); }); - // update the total count of received ACKs - _stats.recordReceivedACK(); + _stats.record(ConnectionStats::Stats::ProcessedACK); } void Connection::processLightACK(std::unique_ptr controlPacket) { @@ -470,7 +472,7 @@ void Connection::processLightACK(std::unique_ptr controlPacket) { getSendQueue().ack(ack); } - _stats.recordReceivedLightACK(); + _stats.record(ConnectionStats::Stats::ReceivedLightACK); } void Connection::processACK2(std::unique_ptr controlPacket) { @@ -508,7 +510,7 @@ void Connection::processACK2(std::unique_ptr controlPacket) { // erase this sub-sequence number and anything below it now that we've gotten our timing information _sentACKs.erase(_sentACKs.begin(), it); - _stats.recordReceivedACK2(); + _stats.record(ConnectionStats::Stats::ReceivedACK2); } void Connection::processNAK(std::unique_ptr controlPacket) { @@ -530,7 +532,7 @@ void Connection::processNAK(std::unique_ptr controlPacket) { _congestionControl->onLoss(start, end); }); - _stats.recordReceivedNAK(); + _stats.record(ConnectionStats::Stats::ReceivedNAK); } void Connection::processTimeoutNAK(std::unique_ptr controlPacket) { @@ -540,7 +542,7 @@ void Connection::processTimeoutNAK(std::unique_ptr controlPacket) // we don't tell the congestion control object there was loss here - this matches UDTs implementation // a possible improvement would be to tell it which new loss this timeout packet told us about - _stats.recordReceivedTimeoutNAK(); + _stats.record(ConnectionStats::Stats::ReceivedTimeoutNAK); } void Connection::updateRTT(int rtt) { diff --git a/libraries/networking/src/udt/ConnectionStats.cpp b/libraries/networking/src/udt/ConnectionStats.cpp index 26112eb24f..91eeb6d49c 100644 --- a/libraries/networking/src/udt/ConnectionStats.cpp +++ b/libraries/networking/src/udt/ConnectionStats.cpp @@ -31,57 +31,11 @@ ConnectionStats::Stats ConnectionStats::sample() { return sample; } -void ConnectionStats::recordSentACK() { - ++_currentSample.sentACKs; - ++_total.sentACKs; +void ConnectionStats::record(Stats::Event event) { + ++_currentSample.events[(int) event]; + ++_total.events[(int) event]; } -void ConnectionStats::recordReceivedACK() { - ++_currentSample.receivedACKs; - ++_total.receivedACKs; -} - -void ConnectionStats::recordSentLightACK() { - ++_currentSample.sentLightACKs; - ++_total.sentLightACKs; -} - -void ConnectionStats::recordReceivedLightACK() { - ++_currentSample.receivedLightACKs; - ++_total.receivedLightACKs; -} - -void ConnectionStats::recordSentACK2() { - ++_currentSample.sentACK2s; - ++_total.sentACK2s; -} - -void ConnectionStats::recordReceivedACK2() { - ++_currentSample.receivedACK2s; - ++_total.receivedACK2s; -} - -void ConnectionStats::recordSentNAK() { - ++_currentSample.sentNAKs; - ++_total.sentNAKs; -} - -void ConnectionStats::recordReceivedNAK() { - ++_currentSample.receivedNAKs; - ++_total.receivedNAKs; -} - -void ConnectionStats::recordSentTimeoutNAK() { - ++_currentSample.sentTimeoutNAKs; - ++_total.sentTimeoutNAKs; -} - -void ConnectionStats::recordReceivedTimeoutNAK() { - ++_currentSample.receivedTimeoutNAKs; - ++_total.receivedTimeoutNAKs; -} - - void ConnectionStats::recordSentPackets(int payload, int total) { ++_currentSample.sentPackets; ++_total.sentPackets; @@ -126,16 +80,6 @@ void ConnectionStats::recordUnreliableReceivedPackets(int payload, int total) { _total.recievedUnreliableBytes += total; } -void ConnectionStats::recordRetransmission() { - ++_currentSample.retransmissions; - ++_total.retransmissions; -} - -void ConnectionStats::recordDuplicates() { - ++_currentSample.duplicates; - ++_total.duplicates; -} - static const double EWMA_CURRENT_SAMPLE_WEIGHT = 0.125; static const double EWMA_PREVIOUS_SAMPLES_WEIGHT = 1 - 0.125; diff --git a/libraries/networking/src/udt/ConnectionStats.h b/libraries/networking/src/udt/ConnectionStats.h index 27d8bbd7a1..2800db7720 100644 --- a/libraries/networking/src/udt/ConnectionStats.h +++ b/libraries/networking/src/udt/ConnectionStats.h @@ -13,6 +13,7 @@ #define hifi_ConnectionStats_h #include +#include namespace udt { @@ -22,18 +23,26 @@ public: std::chrono::microseconds startTime; std::chrono::microseconds endTime; - // Control Packet stat collection - int sentACKs { 0 }; - int receivedACKs { 0 }; - int sentLightACKs { 0 }; - int receivedLightACKs { 0 }; - int sentACK2s { 0 }; - int receivedACK2s { 0 }; - int sentNAKs { 0 }; - int receivedNAKs { 0 }; - int sentTimeoutNAKs { 0 }; - int receivedTimeoutNAKs { 0 }; + enum Event { + SentACK, + ReceivedACK, + ProcessedACK, + SentLightACK, + ReceivedLightACK, + SentACK2, + ReceivedACK2, + SentNAK, + ReceivedNAK, + SentTimeoutNAK, + ReceivedTimeoutNAK, + Retransmission, + Duplicate + }; + // construct a vector for the events of the size of our Enum - default value is zero + std::vector events = std::vector((int) Event::Duplicate + 1, 0); + + // packet counts and sizes int sentPackets { 0 }; int recievedPackets { 0 }; int sentUtilBytes { 0 }; @@ -47,9 +56,6 @@ public: int recievedUnreliableUtilBytes { 0 }; int sentUnreliableBytes { 0 }; int recievedUnreliableBytes { 0 }; - - int retransmissions { 0 }; - int duplicates { 0 }; // the following stats are trailing averages in the result, not totals int sendRate { 0 }; @@ -65,16 +71,7 @@ public: Stats sample(); Stats getTotalStats(); - void recordSentACK(); - void recordReceivedACK(); - void recordSentLightACK(); - void recordReceivedLightACK(); - void recordSentACK2(); - void recordReceivedACK2(); - void recordSentNAK(); - void recordReceivedNAK(); - void recordSentTimeoutNAK(); - void recordReceivedTimeoutNAK(); + void record(Stats::Event event); void recordSentPackets(int payload, int total); void recordReceivedPackets(int payload, int total); @@ -82,9 +79,6 @@ public: void recordUnreliableSentPackets(int payload, int total); void recordUnreliableReceivedPackets(int payload, int total); - void recordRetransmission(); - void recordDuplicates(); - void recordSendRate(int sample); void recordReceiveRate(int sample); void recordEstimatedBandwidth(int sample); diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index babf4b8c25..340c6a16a4 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -43,7 +43,7 @@ const QCommandLineOption UNRELIABLE_PACKETS { const QStringList STATS_TABLE_HEADERS { "Send Rate (P/s)", "RTT(ms)", "CW (P)", "Send Period (us)", - "Received ACK", "Received LACK", "Received NAK", "Received TNAK", + "Received ACK", "Processed ACK", "Received LACK", "Received NAK", "Received TNAK", "Sent ACK2", "Re-sent Packets" }; @@ -228,12 +228,13 @@ void UDTTest::sampleStats() { QString::number(stats.rtt / USECS_PER_MSEC).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.congestionWindowSize).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.packetSendPeriod).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.receivedACKs).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.receivedLightACKs).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.receivedNAKs).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.receivedTimeoutNAKs).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.sentACK2s).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.retransmissions).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()) + QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedACK]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::ProcessedACK]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedLightACK]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedNAK]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedTimeoutNAK]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::SentACK2]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::Retransmission]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()) }; // output this line of values From 00ab4a58f308ad5e60e5b40d8733b68b37cc4b8e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 3 Aug 2015 12:12:21 -0700 Subject: [PATCH 237/549] Fix LossList::insert --- libraries/networking/src/udt/LossList.cpp | 40 ++++++++++------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp index bf9c081943..488ac6610f 100644 --- a/libraries/networking/src/udt/LossList.cpp +++ b/libraries/networking/src/udt/LossList.cpp @@ -51,10 +51,10 @@ void LossList::insert(SequenceNumber start, SequenceNumber end) { return pair.second < start; }); - if (it == _lossList.end()) { + if (it == _lossList.end() || end < it->first) { // No overlap, simply insert - _lossList.insert(it, make_pair(start, end)); _length += seqlen(start, end); + _lossList.insert(it, make_pair(start, end)); } else { // If it starts before segment, extend segment if (start < it->first) { @@ -62,31 +62,25 @@ void LossList::insert(SequenceNumber start, SequenceNumber end) { it->first = start; } + // If it ends after segment, extend segment if (end > it->second) { - // If it goes further, find the actual end - auto it2 = find_if_not(it, _lossList.end(), [&end](pair pair){ - return end <= pair.second; - }); - --it2; - - // If it ends inside a segment, change end (segment will be deleted) - // Or backup iterator so segment doesn't get deleted - if (it2->first <= end) { - end = it2->second; - } else { - --it2; - } - - // Change the end of the original segment _length += seqlen(it->second + 1, end); it->second = end; - - // remove all underlapping segments - ++it; ++it2; - while (it != it2) { - _length -= seqlen(it->first, it->second); - it = _lossList.erase(it); + } + + auto it2 = it; + ++it2; + // For all ranges touching the current range + while (it2 != _lossList.end() && it->second >= it2->first - 1) { + // extend current range if necessary + if (it->second < it2->second) { + _length += seqlen(it->second + 1, it2->second); + it->second = it2->second; } + + // Remove overlapping range + _length -= seqlen(it2->first, it2->second); + it2 = _lossList.erase(it2); } } } From 51b47a12120ffd65b16079585f5101a5e62fec06 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 3 Aug 2015 13:27:00 -0700 Subject: [PATCH 238/549] change stats sampling to 100ms --- tools/udt-test/src/UDTTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 340c6a16a4..f6ce1cc5ac 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -123,8 +123,8 @@ UDTTest::UDTTest(int& argc, char** argv) : if (!_target.isNull()) { sendInitialPackets(); - // the sender reports stats every 1 second - static const int STATS_SAMPLE_INTERVAL = 1000; + // the sender reports stats every 100ms + static const int STATS_SAMPLE_INTERVAL = 100; QTimer* statsTimer = new QTimer(this); connect(statsTimer, &QTimer::timeout, this, &UDTTest::sampleStats); From f2b6db584a13d03fabee8ae6ac0e73e81e52e24c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 3 Aug 2015 13:34:40 -0700 Subject: [PATCH 239/549] Fix list insert --- libraries/networking/src/udt/LossList.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp index 488ac6610f..4cb182c2f7 100644 --- a/libraries/networking/src/udt/LossList.cpp +++ b/libraries/networking/src/udt/LossList.cpp @@ -100,7 +100,7 @@ bool LossList::remove(SequenceNumber seq) { } else { auto temp = it->second; it->second = seq - 1; - _lossList.insert(it, make_pair(seq + 1, temp)); + it = _lossList.insert(++it, make_pair(seq + 1, temp)); } _length -= 1; @@ -150,7 +150,7 @@ void LossList::remove(SequenceNumber start, SequenceNumber end) { _length -= seqlen(start, end); auto temp = it->second; it->second = start - 1; - _lossList.insert(it, make_pair(end + 1, temp)); + _lossList.insert(++it, make_pair(end + 1, temp)); } } } From 20f33b3b64f40349e7dbca4ce4e66aae55aa5011 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 3 Aug 2015 14:34:12 -0700 Subject: [PATCH 240/549] fix sendqueue sleep timing to use microseconds --- libraries/networking/src/udt/SendQueue.cpp | 2 +- tools/udt-test/src/UDTTest.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 7186316bc0..3aeeec4d4a 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -250,7 +250,7 @@ void SendQueue::run() { // sleep as long as we need until next packet send, if we can auto now = high_resolution_clock::now(); - auto microsecondDuration = (_lastSendTimestamp + microseconds(_packetSendPeriod)) - now; + auto microsecondDuration = duration_cast((_lastSendTimestamp + microseconds(_packetSendPeriod)) - now); if (microsecondDuration.count() > 0) { usleep(microsecondDuration.count()); diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index f6ce1cc5ac..5bc020c370 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -44,7 +44,7 @@ const QCommandLineOption UNRELIABLE_PACKETS { const QStringList STATS_TABLE_HEADERS { "Send Rate (P/s)", "RTT(ms)", "CW (P)", "Send Period (us)", "Received ACK", "Processed ACK", "Received LACK", "Received NAK", "Received TNAK", - "Sent ACK2", "Re-sent Packets" + "Sent ACK2", "Sent Packets", "Re-sent Packets" }; UDTTest::UDTTest(int& argc, char** argv) : @@ -234,6 +234,7 @@ void UDTTest::sampleStats() { QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedNAK]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedTimeoutNAK]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.events[udt::ConnectionStats::Stats::SentACK2]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.sentPackets).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.events[udt::ConnectionStats::Stats::Retransmission]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()) }; From a1bd558d71545115a9ca823302a61af1b4a15950 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 3 Aug 2015 14:39:51 -0700 Subject: [PATCH 241/549] Safe locks --- libraries/networking/src/udt/SendQueue.cpp | 23 ++++++++-------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 3aeeec4d4a..111b676499 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -151,16 +151,15 @@ void SendQueue::run() { while (!resentPacket) { // prioritize a loss retransmission - _naksLock.lockForWrite(); + QWriteLocker naksLocker(&_naksLock); if (_naks.getLength() > 0) { - // pull the sequence number we need to re-send SequenceNumber resendNumber = _naks.popFirstSequenceNumber(); - _naksLock.unlock(); + naksLocker.unlock(); // pull the packet to re-send from the sent packets list - _sentLock.lockForRead(); + QReadLocker sentLocker(&_sentLock); // see if we can find the packet to re-send auto it = _sentPackets.find(resendNumber); @@ -170,7 +169,7 @@ void SendQueue::run() { auto& resendPacket = *(it->second); // unlock the sent packets - _sentLock.unlock(); + sentLocker.unlock(); // send it off sendPacket(resendPacket); @@ -184,18 +183,12 @@ void SendQueue::run() { } else { // we didn't find this packet in the sentPackets queue - assume this means it was ACKed // we'll fire the loop again to see if there is another to re-send - - // unlock the sent packets - _sentLock.unlock(); + continue; } - - } else { - // unlock the loss list, it's empty - _naksLock.unlock(); - - // break from the while, we didn't resend a packet - break; } + + // break from the while, we didn't resend a packet + break; } if (!resentPacket From 8704f058127546bed0ad89c297168683be446f1c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 3 Aug 2015 14:40:18 -0700 Subject: [PATCH 242/549] Added UDTTest server stats --- libraries/networking/src/udt/Socket.cpp | 9 ++ libraries/networking/src/udt/Socket.h | 1 + tools/udt-test/src/UDTTest.cpp | 111 ++++++++++++++++-------- 3 files changed, 87 insertions(+), 34 deletions(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 2056957ef1..6a3a3d619f 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -229,3 +229,12 @@ ConnectionStats::Stats Socket::sampleStatsForConnection(const HifiSockAddr& dest return ConnectionStats::Stats(); } } + +std::vector Socket::getSockAddr() { + std::vector addr; + addr.reserve(_connectionsHash.size()); + for (const auto& connectionPair : _connectionsHash) { + addr.push_back(connectionPair.first); + } + return std::move(addr); +} diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 0fee52e755..602cfaf8ec 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -65,6 +65,7 @@ public: void connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* receiver, const char* slot); ConnectionStats::Stats sampleStatsForConnection(const HifiSockAddr& destination); + std::vector getSockAddr(); private slots: void readPendingDatagrams(); diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 5bc020c370..312beffa05 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -41,12 +41,18 @@ const QCommandLineOption UNRELIABLE_PACKETS { "unreliable", "send unreliable packets (default is reliable)" }; -const QStringList STATS_TABLE_HEADERS { +const QStringList CLIENT_STATS_TABLE_HEADERS { "Send Rate (P/s)", "RTT(ms)", "CW (P)", "Send Period (us)", "Received ACK", "Processed ACK", "Received LACK", "Received NAK", "Received TNAK", "Sent ACK2", "Sent Packets", "Re-sent Packets" }; +const QStringList SERVER_STATS_TABLE_HEADERS { + "Recieve Rate (P/s)", "Total Bytes", "Util Bytes", "Ratio (%)", + "Sent ACK", "Sent LACK", "Sent NAK", "Sent TNAK", + "Recieved ACK2", "Duplicate Packets" +}; + UDTTest::UDTTest(int& argc, char** argv) : QCoreApplication(argc, argv) { @@ -122,17 +128,14 @@ UDTTest::UDTTest(int& argc, char** argv) : if (!_target.isNull()) { sendInitialPackets(); - - // the sender reports stats every 100ms - static const int STATS_SAMPLE_INTERVAL = 100; - - QTimer* statsTimer = new QTimer(this); - connect(statsTimer, &QTimer::timeout, this, &UDTTest::sampleStats); - statsTimer->start(STATS_SAMPLE_INTERVAL); - - // output the headers for stats for our table - qDebug() << qPrintable(STATS_TABLE_HEADERS.join(" | ")); } + + // the sender reports stats every 100 milliseconds + static const int STATS_SAMPLE_INTERVAL = 100; + + QTimer* statsTimer = new QTimer(this); + connect(statsTimer, &QTimer::timeout, this, &UDTTest::sampleStats); + statsTimer->start(STATS_SAMPLE_INTERVAL); } void UDTTest::parseArguments() { @@ -216,28 +219,68 @@ void UDTTest::sendPacket() { } void UDTTest::sampleStats() { - udt::ConnectionStats::Stats stats = _socket.sampleStatsForConnection(_target); + static bool first = true; - int headerIndex = -1; - - static const double USECS_PER_MSEC = 1000.0; - - // setup a list of left justified values - QStringList values { - QString::number(stats.sendRate).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.rtt / USECS_PER_MSEC).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.congestionWindowSize).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.packetSendPeriod).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedACK]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::ProcessedACK]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedLightACK]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedNAK]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedTimeoutNAK]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::SentACK2]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.sentPackets).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::Retransmission]).leftJustified(STATS_TABLE_HEADERS[++headerIndex].size()) - }; - - // output this line of values - qDebug() << qPrintable(values.join(" | ")); + if (!_target.isNull()) { + if (first) { + // output the headers for stats for our table + qDebug() << qPrintable(CLIENT_STATS_TABLE_HEADERS.join(" | ")); + first = false; + } + + udt::ConnectionStats::Stats stats = _socket.sampleStatsForConnection(_target); + + int headerIndex = -1; + + static const double USECS_PER_MSEC = 1000.0; + + // setup a list of left justified values + QStringList values { + QString::number(stats.sendRate).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.rtt / USECS_PER_MSEC).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.congestionWindowSize).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.packetSendPeriod).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedACK]).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::ProcessedACK]).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedLightACK]).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedNAK]).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedTimeoutNAK]).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::SentACK2]).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.sentPackets).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::Retransmission]).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()) + }; + + // output this line of values + qDebug() << qPrintable(values.join(" | ")); + } else { + if (first) { + // output the headers for stats for our table + qDebug() << qPrintable(SERVER_STATS_TABLE_HEADERS.join(" | ")); + first = false; + } + + auto sockets = _socket.getSockAddr(); + if (sockets.size() > 0) { + udt::ConnectionStats::Stats stats = _socket.sampleStatsForConnection(sockets.front()); + + int headerIndex = -1; + + // setup a list of left justified values + QStringList values { + QString::number(stats.receiveRate).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.recievedBytes).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.recievedUtilBytes).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(100 * (double)stats.recievedUtilBytes / (double)stats.recievedBytes).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::SentACK]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::SentLightACK]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::SentNAK]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::SentTimeoutNAK]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedACK2]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::Duplicate]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()) + }; + + // output this line of values + qDebug() << qPrintable(values.join(" | ")); + } + } } From d937cf1cc7b78338830893a3f0b4dd5b3a3542d4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 3 Aug 2015 15:05:41 -0700 Subject: [PATCH 243/549] set RTT on congestion control in ctor --- libraries/networking/src/udt/Connection.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 1786f7558e..1fb4a7db9c 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -37,8 +37,12 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination, unique_pt // setup default SYN, RTT and RTT Variance based on the SYN interval in CongestionControl object _synInterval = _congestionControl->synInterval(); + _rtt = _synInterval * 10; _rttVariance = _rtt / 2; + + // set the initial RTT on congestion control object + _congestionControl->setRTT(_rtt); } Connection::~Connection() { @@ -375,7 +379,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { microseconds sinceLastACK2 = duration_cast(currentTime - lastACK2SendTime); - if (sinceLastACK2.count() > _synInterval || currentACKSubSequenceNumber == _lastSentACK2) { + if (sinceLastACK2.count() >= _synInterval || currentACKSubSequenceNumber == _lastSentACK2) { // Send ACK2 packet sendACK2(currentACKSubSequenceNumber); From b5ec02bd014d15cf08a5a46ba403dccfb92d9f06 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 3 Aug 2015 15:36:08 -0700 Subject: [PATCH 244/549] go back to previous PacketTimeWindow code --- libraries/networking/src/udt/Connection.cpp | 6 ++++-- libraries/networking/src/udt/Connection.h | 3 ++- libraries/networking/src/udt/PacketTimeWindow.cpp | 12 ++++++++---- tools/udt-test/src/UDTTest.cpp | 3 ++- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 1fb4a7db9c..4f9b7a38f7 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -77,8 +77,9 @@ void Connection::sendReliablePacket(unique_ptr packet) { void Connection::sync() { if (_hasReceivedFirstPacket) { - // reset the number of light ACKS during this sync interval + // reset the number of light ACKs or non SYN ACKs during this sync interval _lightACKsDuringSYN = 1; + _acksDuringSYN = 1; // we send out a periodic ACK every rate control interval sendACK(); @@ -327,7 +328,8 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in ++_packetsSinceACK; // check if we need to send an ACK, according to CC params - if (_congestionControl->_ackInterval > 0 && _packetsSinceACK >= _congestionControl->_ackInterval) { + if (_congestionControl->_ackInterval > 0 && _packetsSinceACK >= _congestionControl->_ackInterval * _acksDuringSYN) { + _acksDuringSYN++; sendACK(false); } else if (_congestionControl->_lightACKInterval > 0 && _packetsSinceACK >= _congestionControl->_lightACKInterval * _lightACKsDuringSYN) { diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 99328d601f..9bdc6baf24 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -96,7 +96,8 @@ private: SequenceNumber _lastSentACK; // The last sent ACK SequenceNumber _lastSentACK2; // The last sent ACK sub-sequence number in an ACK2 - + + int _acksDuringSYN { 1 }; // The number of non-SYN ACKs sent during SYN int _lightACKsDuringSYN { 1 }; // The number of lite ACKs sent during SYN interval int32_t _rtt; // RTT, in microseconds diff --git a/libraries/networking/src/udt/PacketTimeWindow.cpp b/libraries/networking/src/udt/PacketTimeWindow.cpp index 269d158b7d..67aa61bc78 100644 --- a/libraries/networking/src/udt/PacketTimeWindow.cpp +++ b/libraries/networking/src/udt/PacketTimeWindow.cpp @@ -11,7 +11,6 @@ #include "PacketTimeWindow.h" -#include #include #include @@ -49,11 +48,16 @@ int median(Iterator begin, Iterator end) { int32_t meanOfMedianFilteredValues(std::vector intervals, int numValues, int valuesRequired = 0) { // grab the median value of the intervals vector - int intervalsMedian = median(intervals.begin(), intervals.end()); + int median = 0; + if (numValues % 2 == 0) { + median = intervals[numValues / 2]; + } else { + median = (intervals[(numValues / 2) - 1] + intervals[numValues / 2]) / 2; + } static const int MEDIAN_FILTERING_BOUND_MULTIPLIER = 8; - int upperBound = intervalsMedian * MEDIAN_FILTERING_BOUND_MULTIPLIER; - int lowerBound = intervalsMedian / MEDIAN_FILTERING_BOUND_MULTIPLIER; + int upperBound = median * MEDIAN_FILTERING_BOUND_MULTIPLIER; + int lowerBound = median / MEDIAN_FILTERING_BOUND_MULTIPLIER; int sum = 0; int count = 0; diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 312beffa05..6344860442 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -42,7 +42,7 @@ const QCommandLineOption UNRELIABLE_PACKETS { }; const QStringList CLIENT_STATS_TABLE_HEADERS { - "Send Rate (P/s)", "RTT(ms)", "CW (P)", "Send Period (us)", + "Send Rate (P/s)", "Bandwidth (P/s)", "RTT(ms)", "CW (P)", "Send Period (us)", "Received ACK", "Processed ACK", "Received LACK", "Received NAK", "Received TNAK", "Sent ACK2", "Sent Packets", "Re-sent Packets" }; @@ -237,6 +237,7 @@ void UDTTest::sampleStats() { // setup a list of left justified values QStringList values { QString::number(stats.sendRate).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.estimatedBandwith).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.rtt / USECS_PER_MSEC).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.congestionWindowSize).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.packetSendPeriod).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), From acd7a7a732d390a1d91b9a9d6bba9de25f331106 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 3 Aug 2015 16:04:08 -0700 Subject: [PATCH 245/549] fix send/process for ACK packets --- libraries/networking/src/udt/Connection.cpp | 13 ++++++++++--- libraries/networking/src/udt/PacketTimeWindow.cpp | 12 ++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 4f9b7a38f7..dab6c5b934 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -134,7 +134,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { // setup the ACK packet, make it static so we can re-use it static const int ACK_PACKET_PAYLOAD_BYTES = sizeof(_lastSentACK) + sizeof(_currentACKSubSequenceNumber) - + sizeof(_rtt) + sizeof(int32_t) + sizeof(int32_t); + + sizeof(_rtt) + sizeof(int32_t) + sizeof(int32_t) + sizeof(int32_t); static auto ackPacket = ControlPacket::create(ControlPacket::ACK, ACK_PACKET_PAYLOAD_BYTES); ackPacket->reset(); // We need to reset it every time. @@ -412,7 +412,10 @@ void Connection::processACK(std::unique_ptr controlPacket) { } // this is a valid ACKed sequence number - update the flow window size and the last received ACK - controlPacket->readPrimitive(&_flowWindowSize); + int32_t packedFlowWindow; + controlPacket->readPrimitive(&packedFlowWindow); + + _flowWindowSize = packedFlowWindow; if (ack == _lastReceivedACK) { // processing an already received ACK, bail @@ -433,8 +436,12 @@ void Connection::processACK(std::unique_ptr controlPacket) { // set the RTT for congestion control _congestionControl->setRTT(_rtt); - if (controlPacket->getPayloadSize() > (qint64) (sizeof(SequenceNumber) + sizeof(SequenceNumber) + sizeof(rtt))) { + if (controlPacket->bytesLeftToRead() > 0) { int32_t receiveRate, bandwidth; + + Q_ASSERT_X(controlPacket->bytesLeftToRead() == sizeof(receiveRate) + sizeof(bandwidth), + "Connection::processACK", "sync interval ACK packet does not contain expected data"); + controlPacket->readPrimitive(&receiveRate); controlPacket->readPrimitive(&bandwidth); diff --git a/libraries/networking/src/udt/PacketTimeWindow.cpp b/libraries/networking/src/udt/PacketTimeWindow.cpp index 67aa61bc78..269d158b7d 100644 --- a/libraries/networking/src/udt/PacketTimeWindow.cpp +++ b/libraries/networking/src/udt/PacketTimeWindow.cpp @@ -11,6 +11,7 @@ #include "PacketTimeWindow.h" +#include #include #include @@ -48,16 +49,11 @@ int median(Iterator begin, Iterator end) { int32_t meanOfMedianFilteredValues(std::vector intervals, int numValues, int valuesRequired = 0) { // grab the median value of the intervals vector - int median = 0; - if (numValues % 2 == 0) { - median = intervals[numValues / 2]; - } else { - median = (intervals[(numValues / 2) - 1] + intervals[numValues / 2]) / 2; - } + int intervalsMedian = median(intervals.begin(), intervals.end()); static const int MEDIAN_FILTERING_BOUND_MULTIPLIER = 8; - int upperBound = median * MEDIAN_FILTERING_BOUND_MULTIPLIER; - int lowerBound = median / MEDIAN_FILTERING_BOUND_MULTIPLIER; + int upperBound = intervalsMedian * MEDIAN_FILTERING_BOUND_MULTIPLIER; + int lowerBound = intervalsMedian / MEDIAN_FILTERING_BOUND_MULTIPLIER; int sum = 0; int count = 0; From 36a0ef50d4b681875775614c58457b6a9180ccf9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 3 Aug 2015 16:21:17 -0700 Subject: [PATCH 246/549] add assert for BasePacket write, fix time in Connection --- libraries/networking/src/udt/BasePacket.cpp | 6 +++--- libraries/networking/src/udt/Connection.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/udt/BasePacket.cpp b/libraries/networking/src/udt/BasePacket.cpp index 80564143d4..2bfa2b6805 100644 --- a/libraries/networking/src/udt/BasePacket.cpp +++ b/libraries/networking/src/udt/BasePacket.cpp @@ -156,13 +156,13 @@ bool BasePacket::reset() { } qint64 BasePacket::writeData(const char* data, qint64 maxSize) { + + Q_ASSERT_X(maxSize <= bytesAvailableForWrite(), "BasePacket::writeData", "not enough space for write"); // make sure we have the space required to write this block if (maxSize <= bytesAvailableForWrite()) { qint64 currentPos = pos(); - - Q_ASSERT(currentPos < _payloadCapacity); - + // good to go - write the data memcpy(_payloadStart + currentPos, data, maxSize); diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index dab6c5b934..082de32204 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -283,10 +283,10 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in _receiveWindow.onProbePair1Arrival(); } else if (((uint32_t) sequenceNumber & 0xF) == 1) { _receiveWindow.onProbePair2Arrival(); - } else { - _receiveWindow.onPacketArrival(); } + _receiveWindow.onPacketArrival(); + // If this is not the next sequence number, report loss if (sequenceNumber > _lastReceivedSequenceNumber + 1) { if (_lastReceivedSequenceNumber + 1 == sequenceNumber - 1) { From 260404f1fb30348b90e031b4a1d558d059fa55aa Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 3 Aug 2015 16:23:57 -0700 Subject: [PATCH 247/549] Add AssetRequest --- libraries/networking/src/AssetRequest.cpp | 78 ++++++++++++++++++++++ libraries/networking/src/AssetRequest.h | 80 +++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 libraries/networking/src/AssetRequest.cpp create mode 100644 libraries/networking/src/AssetRequest.h diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp new file mode 100644 index 0000000000..d3863a5882 --- /dev/null +++ b/libraries/networking/src/AssetRequest.cpp @@ -0,0 +1,78 @@ +// +// AssetRequest.cpp +// +// Created by Ryan Huffman on 2015/07/24 +// Copyright 2015 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 "AssetRequest.h" + +#include + +#include + +#include "AssetClient.h" +#include "NodeList.h" + + +AssetRequest::AssetRequest(QObject* parent, QString hash) : + QObject(parent), + _hash(hash) +{ +} + +void AssetRequest::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + //(&AssetRequest::start) + return; + } + + if (_state == NOT_STARTED) { + _state = WAITING_FOR_INFO; + + auto assetClient = DependencyManager::get(); + assetClient->getAssetInfo(_hash, [this](bool success, AssetInfo info) { + _info = info; + _data.resize(info.size); + const DataOffset CHUNK_SIZE = 1024; + + qDebug() << "Got size of " << _hash << " : " << info.size << " bytes"; + + // Round up + int numChunks = (info.size + CHUNK_SIZE - 1) / CHUNK_SIZE; + auto assetClient = DependencyManager::get(); + for (int i = 0; i < numChunks; ++i) { + ++_numPendingRequests; + auto start = i * CHUNK_SIZE; + auto end = std::min((i + 1) * CHUNK_SIZE, info.size); + assetClient->getAsset(_hash, start, end, [this, start, end](bool success, QByteArray data) { + Q_ASSERT(data.size() == (end - start)); + + if (success) { + _result = Success; + memcpy((_data.data() + start), data.constData(), end - start); + _totalReceived += data.size(); + emit progress(_totalReceived, _info.size); + } else { + _result = Error; + qDebug() << "Got error retrieving asset"; + } + + --_numPendingRequests; + if (_numPendingRequests == 0) { + _state = FINISHED; + emit finished(this); + } + }); + } + }); + } +} + +const QByteArray& AssetRequest::getData() { + return _data; +} diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h new file mode 100644 index 0000000000..402aacad09 --- /dev/null +++ b/libraries/networking/src/AssetRequest.h @@ -0,0 +1,80 @@ +// +// AssetRequest.h +// +// Created by Ryan Huffman on 2015/07/24 +// Copyright 2015 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 +// + +#ifndef hifi_AssetRequest_h +#define hifi_AssetRequest_h + +#include +#include +#include + +#include "AssetClient.h" + +#include "AssetUtils.h" + +// You should be able to get an asset from any thread, and handle the responses in a safe way +// on your own thread. Everything should happen on AssetClient's thread, the caller should +// receive events by connecting to signals on an object that lives on AssetClient's threads. + +// Receives parts of an asset and puts them together +// Emits signals: +// Progress +// Completion, success or error +// On finished, the AssetClient is effectively immutable and can be read from +// any thread safely +// +// Will often make multiple requests to the AssetClient to get data +class AssetRequest : public QObject { + Q_OBJECT +public: + enum State { + NOT_STARTED = 0, + WAITING_FOR_INFO, + WAITING_FOR_DATA, + FINISHED + }; + + enum Result { + Success = 0, + Timeout, + NotFound, + Error, + }; + + AssetRequest(QObject* parent, QString hash); + + Q_INVOKABLE void start(); + //AssetRequest* requestAsset(QString hash); + // Create AssetRequest + // Start request for hash + // Store messageID -> AssetRequest + // When complete: + // Update AssetRequest + // AssetRequest emits signal + + void receiveData(DataOffset start, DataOffset end, QByteArray data); + const QByteArray& getData(); + +signals: + void finished(AssetRequest*); + void progress(uint64_t totalReceived, uint64_t total); + +private: + State _state = NOT_STARTED; + Result _result; + AssetInfo _info; + uint64_t _totalReceived { 0 }; + QString _hash; + QByteArray _data; + int _numPendingRequests { 0 }; + // Timeout +}; + +#endif From 86c82a2b2da559068240a64551b47f0dde4021fe Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 3 Aug 2015 16:24:11 -0700 Subject: [PATCH 248/549] Add generalized ResourceRequest --- libraries/networking/src/ResourceManager.cpp | 138 +++++++++++++++++++ libraries/networking/src/ResourceManager.h | 97 +++++++++++++ 2 files changed, 235 insertions(+) create mode 100644 libraries/networking/src/ResourceManager.cpp create mode 100644 libraries/networking/src/ResourceManager.h diff --git a/libraries/networking/src/ResourceManager.cpp b/libraries/networking/src/ResourceManager.cpp new file mode 100644 index 0000000000..7fdac3028a --- /dev/null +++ b/libraries/networking/src/ResourceManager.cpp @@ -0,0 +1,138 @@ +// +// ResourceManager.cpp +// +// Created by Ryan Huffman on 2015/07/23 +// Copyright 2015 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 "ResourceManager.h" + +#include +#include +#include + +#include "AssetClient.h" +#include "AssetRequest.h" +#include "NetworkAccessManager.h" + +#include + +const QString URL_SCHEME_FILE = "file"; +const QString URL_SCHEME_HTTP = "http"; +const QString URL_SCHEME_HTTPS = "https"; +const QString URL_SCHEME_FTP = "ftp"; +const QString URL_SCHEME_ATP = "atp"; + +ResourceRequest::ResourceRequest(QObject* parent, const QUrl& url) : + QObject(parent), + _url(url) { +} + +void HTTPResourceRequest::doSend() { + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkRequest networkRequest = QNetworkRequest(_url); + networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + + if (!_cacheEnabled) { + networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); + } + + QNetworkReply* reply = networkAccessManager.get(networkRequest); + QObject::connect(reply, &QNetworkReply::finished, [=]() { + if (_state != IN_PROGRESS) return; + + _state = FINISHED; + auto error = reply->error(); + qDebug() << "Loaded " << _url; + if (error == QNetworkReply::NoError) { + _data = reply->readAll(); + _result = ResourceRequest::SUCCESS; + emit finished(); + } else if (error == QNetworkReply::TimeoutError) { + _result = ResourceRequest::TIMEOUT; + emit finished(); + } else { + _result = ResourceRequest::ERROR; + emit finished(); + } + reply->deleteLater(); + }); +} + +void FileResourceRequest::doSend() { + QString filename = _url.toLocalFile(); + QFile file(filename); + _state = FINISHED; + if (file.open(QFile::ReadOnly)) { + _data = file.readAll(); + _result = ResourceRequest::SUCCESS; + emit finished(); + } else { + _result = ResourceRequest::ERROR; + emit finished(); + } +} + +void ATPResourceRequest::doSend() { + // Make request to atp + auto assetClient = DependencyManager::get(); + auto hash = _url.path(); + + auto request = assetClient->create(hash); + + if (!request) { + return; + } + + QObject::connect(request, &AssetRequest::finished, [this](AssetRequest* req) mutable { + if (_state != IN_PROGRESS) return; + _state = FINISHED; + if (true) { + _data = req->getData(); + _result = ResourceRequest::SUCCESS; + emit finished(); + } else { + _result = ResourceRequest::ERROR; + emit finished(); + } + }); + + request->start(); +} + +const int TIMEOUT_MS = 2000; +void ResourceRequest::send() { + connect(&_sendTimer, &QTimer::timeout, this, &ResourceRequest::timeout); + _sendTimer.setSingleShot(true); + _sendTimer.start(TIMEOUT_MS); + _state = IN_PROGRESS; + doSend(); +} + +void ResourceRequest::timeout() { + // TIMEOUT!! + if (_state == UNSENT) { + qDebug() << "TImed out loading " << _url; + _state = FINISHED; + _result = TIMEOUT; + emit finished(); + } +} + +ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const QUrl& url) { + auto scheme = url.scheme(); + if (scheme == URL_SCHEME_FILE) { + return new FileResourceRequest(parent, url); + } else if (scheme == URL_SCHEME_HTTP || scheme == URL_SCHEME_HTTPS || scheme == URL_SCHEME_FTP) { + return new HTTPResourceRequest(parent, url); + } else if (scheme == URL_SCHEME_ATP) { + return new ATPResourceRequest(parent, url); + } + + qDebug() << "Failed to load: " << url.url(); + + return nullptr; +} diff --git a/libraries/networking/src/ResourceManager.h b/libraries/networking/src/ResourceManager.h new file mode 100644 index 0000000000..4050b5f390 --- /dev/null +++ b/libraries/networking/src/ResourceManager.h @@ -0,0 +1,97 @@ +// +// ResourceManager.h +// +// Created by Ryan Huffman on 2015/07/23 +// Copyright 2015 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 +// + + +#ifndef hifi_ResourceManager_h +#define hifi_ResourceManager_h + +#include + +#include +#include +#include + +class ResourceRequest : public QObject { + Q_OBJECT +public: + ResourceRequest(QObject* parent, const QUrl& url); + + enum State { + UNSENT = 0, + IN_PROGRESS, + FINISHED + }; + + enum Result { + SUCCESS, + ERROR, + TIMEOUT, + NOT_FOUND + }; + + void send(); + QByteArray moveData() { return _data; } + State getState() const { return _state; } + Result getResult() const { return _result; } + QUrl getUrl() const { return _url; } + + void setCacheEnabled(bool value) { _cacheEnabled = value; } + +signals: + void progress(uint64_t bytesReceived, uint64_t bytesTotal); + void finished(); + +protected: + virtual void doSend() = 0; + + QUrl _url; + State _state = UNSENT; + Result _result; + QTimer _sendTimer; + QByteArray _data; + bool _cacheEnabled { true }; + +private slots: + void timeout(); +}; + +class HTTPResourceRequest : public ResourceRequest { + Q_OBJECT +public: + HTTPResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } + +protected: + virtual void doSend() override; +}; + +class FileResourceRequest : public ResourceRequest { + Q_OBJECT +public: + FileResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } + +protected: + virtual void doSend() override; +}; + +class ATPResourceRequest : public ResourceRequest { + Q_OBJECT +public: + ATPResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } + +protected: + virtual void doSend() override; +}; + +class ResourceManager { +public: + static ResourceRequest* createResourceRequest(QObject* parent, const QUrl& url); +}; + +#endif From 5258474f98b64c0a2c8256ff6e29c7811d73deb2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 3 Aug 2015 16:24:34 -0700 Subject: [PATCH 249/549] Update AssetServer with GetInfo packet --- assignment-client/src/assets/AssetServer.cpp | 117 +++++++++++++++---- assignment-client/src/assets/AssetServer.h | 9 +- 2 files changed, 100 insertions(+), 26 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 1a384271e0..6ac106191f 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -22,12 +22,11 @@ #include const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server"; -const int HASH_HEX_LENGTH = 32; -using MessageID = int; AssetServer::AssetServer(NLPacket& packet) : ThreadedAssignment(packet) { auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(PacketType::AssetGet, this, "handleAssetGet"); + packetReceiver.registerListener(PacketType::AssetGetInfo, this, "handleAssetGetInfo"); packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload"); } @@ -59,6 +58,17 @@ void AssetServer::run() { qDebug() << "\tCan't open file for reading: " << filename; continue; } + + // Read file + QFile file { fileInfo.absoluteFilePath() }; + file.open(QFile::ReadOnly); + QByteArray data = file.readAll(); + + auto hash = hashData(data); + + qDebug() << "\tMoving " << filename << " to " << hash; + + file.rename(_resourcesDirectory.absoluteFilePath(hash)); } } @@ -68,39 +78,97 @@ void AssetServer::run() { } } -void AssetServer::handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode) { - QByteArray assetHash; +void AssetServer::writeError(NLPacket* packet, AssetServerError error) { + packet->writePrimitive(error); +} +void AssetServer::handleAssetGetInfo(QSharedPointer packet, SharedNodePointer senderNode) { if (packet->getPayloadSize() < HASH_HEX_LENGTH) { qDebug() << "ERROR bad file request"; return; } + QByteArray assetHash; + MessageID messageID; + packet->readPrimitive(&messageID); assetHash = packet->read(HASH_HEX_LENGTH); - qDebug() << "Got a request for the file: " << assetHash; - // We need to reply... - QFile file { _resourcesDirectory.filePath(QString(assetHash)) }; + auto replyPacket = NLPacket::create(PacketType::AssetGetInfoReply); + + replyPacket->writePrimitive(messageID); + replyPacket->write(assetHash, HASH_HEX_LENGTH); + + QFileInfo fileInfo { _resourcesDirectory.filePath(QString(assetHash)) }; qDebug() << "Opening file: " << QString(QFileInfo(assetHash).fileName()); - bool found = file.open(QIODevice::ReadOnly); - auto assetPacket = NLPacket::create(PacketType::AssetGetReply); - - assetPacket->write(assetHash, HASH_HEX_LENGTH); - assetPacket->writePrimitive(found); - - const int MAX_LENGTH = 1024; - - if (found) { - QByteArray data = file.read(MAX_LENGTH); - assetPacket->writePrimitive(data.size()); - assetPacket->write(data, data.size()); + if (fileInfo.exists() && fileInfo.isReadable()) { + replyPacket->writePrimitive(AssetServerError::NO_ERROR); + replyPacket->writePrimitive(fileInfo.size()); } else { - qDebug() << "File not found"; + qDebug() << "Asset not found: " << assetHash; + replyPacket->writePrimitive(AssetServerError::ASSET_NOT_FOUND); } auto nodeList = DependencyManager::get(); - nodeList->sendPacket(std::move(assetPacket), *senderNode); + nodeList->sendPacket(std::move(replyPacket), *senderNode); +} + +void AssetServer::handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode) { + if (packet->getPayloadSize() < HASH_HEX_LENGTH) { + qDebug() << "ERROR bad file request"; + return; + } + + MessageID messageID; + packet->readPrimitive(&messageID); + + QByteArray assetHash; + assetHash = packet->read(HASH_HEX_LENGTH); + + DataOffset start; + packet->readPrimitive(&start); + + DataOffset end; + packet->readPrimitive(&end); + + qDebug() << "Received a request for the file: " << assetHash << " from " << start << " to " << end; + + // We need to reply... + auto replyPacket = NLPacket::create(PacketType::AssetGetReply); + + replyPacket->write(assetHash, HASH_HEX_LENGTH); + + replyPacket->writePrimitive(messageID); + + const int64_t MAX_LENGTH = 1024; + + if (end <= start) { + writeError(replyPacket.get(), AssetServerError::INVALID_BYTE_RANGE); + } else if (end - start > MAX_LENGTH) { + writeError(replyPacket.get(), AssetServerError::INVALID_BYTE_RANGE); + } else { + QFile file { _resourcesDirectory.filePath(QString(assetHash)) }; + qDebug() << "Opening file: " << QString(QFileInfo(assetHash).fileName()); + + if (file.open(QIODevice::ReadOnly)) { + if (file.size() < end) { + writeError(replyPacket.get(), AssetServerError::INVALID_BYTE_RANGE); + } else { + auto size = end - start; + file.seek(start); + QByteArray data = file.read(size); + replyPacket->writePrimitive(AssetServerError::NO_ERROR); + replyPacket->writePrimitive(size); + replyPacket->write(data, size); + } + } else { + qDebug() << "Asset not found"; + writeError(replyPacket.get(), AssetServerError::ASSET_NOT_FOUND); + } + } + + auto nodeList = DependencyManager::get(); + nodeList->sendPacket(std::move(replyPacket), *senderNode); } void AssetServer::handleAssetUpload(QSharedPointer packet, SharedNodePointer senderNode) { @@ -124,7 +192,7 @@ void AssetServer::handleAssetUpload(QSharedPointer packet, SharedNodeP QByteArray data = packet->read(fileSize); - QString hash = QString(QCryptographicHash::hash(data, QCryptographicHash::Md5).toHex()); + QString hash = hashData(data); qDebug() << "Got data: (" << hash << ") " << data; @@ -147,3 +215,8 @@ void AssetServer::handleAssetUpload(QSharedPointer packet, SharedNodeP auto nodeList = DependencyManager::get(); nodeList->sendPacket(std::move(replyPacket), *senderNode); } + +QString AssetServer::hashData(const QByteArray& data) { + return QString(QCryptographicHash::hash(data, QCryptographicHash::Md5).toHex()); +} + diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index ef658fae4a..585ecaa259 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -15,25 +15,26 @@ #include +#include "AssetUtils.h" + class AssetServer : public ThreadedAssignment { Q_OBJECT public: AssetServer(NLPacket& packet); ~AssetServer(); - enum ServerResponse { - ASSET_NOT_FOUND = 0, - ASSET_UPLOADED = 1, - }; + static QString hashData(const QByteArray& data); public slots: void run(); private slots: + void handleAssetGetInfo(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetUpload(QSharedPointer packet, SharedNodePointer senderNode); private: + static void writeError(NLPacket* packet, AssetServerError error); QDir _resourcesDirectory; }; From 4e1b52a0222e6dd85f7dc4b71e0187dfb37584a5 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 3 Aug 2015 16:25:07 -0700 Subject: [PATCH 250/549] Add thread for AssetClient --- interface/src/Application.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 137f3ffa83..ee785642b1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -428,6 +428,17 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : audioThread->start(); + + QThread* assetThread = new QThread(); + + assetThread->setObjectName("Asset Thread"); + auto assetClient = DependencyManager::get(); + + assetClient->moveToThread(assetThread); + + assetThread->start(); + + const DomainHandler& domainHandler = nodeList->getDomainHandler(); connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&))); From fc9cd836cef234911821f3672a5f1ba25c40bd50 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 3 Aug 2015 16:25:37 -0700 Subject: [PATCH 251/549] Update AssetScriptingInterface --- interface/src/AssetScriptingInterface.cpp | 30 +++++++++++++++++------ 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/interface/src/AssetScriptingInterface.cpp b/interface/src/AssetScriptingInterface.cpp index c03e9ee8c2..267f0cc25e 100644 --- a/interface/src/AssetScriptingInterface.cpp +++ b/interface/src/AssetScriptingInterface.cpp @@ -13,25 +13,41 @@ #include #include +#include #include #include #include #include -#include - -const int HASH_HEX_LENGTH = 32; +#include AssetScriptingInterface::AssetScriptingInterface() { } QScriptValue AssetScriptingInterface::getAsset(QString url, QScriptValue callback) { - bool success = AssetManager::getAsset(QUrl(url), [callback](AssetRequestUpdateType type, QByteArray data) mutable { - auto result = callback.engine()->newVariant(data); - QList arguments { type == AssetRequestUpdateType::COMPLETE, result }; + + auto assetClient = DependencyManager::get(); + // auto request = assetClient->requestAsset(url); + auto request = assetClient->create(url); + + if (!request) { + return false; + } + + connect(request, &AssetRequest::finished, [callback](AssetRequest* req) mutable { + auto result = callback.engine()->newVariant(req->getData()); + QList arguments { true, result }; callback.call(QScriptValue(), arguments); }); - return success; + + request->start(); + + // bool success = AssetManager::getAsset(QUrl(url), [callback](AssetRequestUpdateType type, QByteArray data) mutable { + // auto result = callback.engine()->newVariant(data); + // QList arguments { type == AssetRequestUpdateType::COMPLETE, result }; + // callback.call(QScriptValue(), arguments); + // }); + return true; } QScriptValue AssetScriptingInterface::uploadAsset(QString data, QString extension, QScriptValue callback) { From ccc0000fd0cee4ec5eb1feaaf26fe1de94c6e243 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 3 Aug 2015 16:26:16 -0700 Subject: [PATCH 252/549] Update ResourceCache to use ResourceRequest --- libraries/networking/src/ResourceCache.cpp | 266 ++++++++++++--------- libraries/networking/src/ResourceCache.h | 17 +- 2 files changed, 157 insertions(+), 126 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index e127380630..2903e810f2 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -155,6 +155,7 @@ void ResourceCache::clearUnusedResource() { void ResourceCache::attemptRequest(Resource* resource) { auto sharedItems = DependencyManager::get(); if (_requestLimit <= 0) { + qDebug() << "REQUEST LIMIT REACHED, queueing: " << resource->getURL(); // wait until a slot becomes available sharedItems->_pendingRequests.append(resource); return; @@ -187,6 +188,7 @@ void ResourceCache::requestCompleted(Resource* resource) { i++; } if (highestIndex >= 0) { + qDebug() << "trying to attempt a pending request"; attemptRequest(sharedItems->_pendingRequests.takeAt(highestIndex)); } } @@ -196,24 +198,22 @@ int ResourceCache::_requestLimit = DEFAULT_REQUEST_LIMIT; Resource::Resource(const QUrl& url, bool delayLoad) : _url(url), - _request(url) { + _request(nullptr) { init(); - _request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); - _request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); - // start loading immediately unless instructed otherwise if (!(_startedLoading || delayLoad)) { - attemptRequest(); + QTimer::singleShot(1, this, &Resource::attemptRequest); + //attemptRequest(); } } Resource::~Resource() { - if (_reply) { + if (_request) { ResourceCache::requestCompleted(this); - delete _reply; - _reply = nullptr; + _request->deleteLater(); + _request = nullptr; } } @@ -259,21 +259,20 @@ float Resource::getLoadPriority() { } void Resource::refresh() { - if (_reply && !(_loaded || _failedToLoad)) { + if (_request && !(_loaded || _failedToLoad)) { return; } - if (_reply) { + if (_request) { + _request->disconnect(this); + // _requestTimer->disconnect(this); + _request->deleteLater(); + _request = nullptr; + // _requestTimer->deleteLater(); + // _requestTimer = nullptr; ResourceCache::requestCompleted(this); - _reply->disconnect(this); - _replyTimer->disconnect(this); - _reply->deleteLater(); - _reply = nullptr; - _replyTimer->deleteLater(); - _replyTimer = nullptr; } init(); - _request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); ensureLoading(); emit onRefresh(); } @@ -331,34 +330,34 @@ void Resource::reinsert() { _cache->_resources.insert(_url, _self); } -static const int REPLY_TIMEOUT_MS = 5000; -void Resource::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { - if (!_reply->isFinished()) { - _bytesReceived = bytesReceived; - _bytesTotal = bytesTotal; - _replyTimer->start(REPLY_TIMEOUT_MS); - return; - } - _reply->disconnect(this); - _replyTimer->disconnect(this); - QNetworkReply* reply = _reply; - _reply = nullptr; - _replyTimer->deleteLater(); - _replyTimer = nullptr; - ResourceCache::requestCompleted(this); - - downloadFinished(reply); -} - -void Resource::handleReplyError() { - handleReplyError(_reply->error(), qDebug() << _reply->errorString()); -} - -void Resource::handleReplyTimeout() { - handleReplyError(QNetworkReply::TimeoutError, qDebug() << "Timed out loading" << _reply->url() << - "received" << _bytesReceived << "total" << _bytesTotal); -} - +// static const int REPLY_TIMEOUT_MS = 5000; +// void Resource::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { +// if (!_reply->isFinished()) { +// _bytesReceived = bytesReceived; +// _bytesTotal = bytesTotal; +// _replyTimer->start(REPLY_TIMEOUT_MS); +// return; +// } +// _reply->disconnect(this); +// _replyTimer->disconnect(this); +// QNetworkReply* reply = _reply; +// _reply = nullptr; +// _replyTimer->deleteLater(); +// _replyTimer = nullptr; +// ResourceCache::requestCompleted(this); +// +// // downloadFinished(reply); +// } +// +// void Resource::handleReplyError() { +// handleReplyError(_reply->error(), qDebug() << _reply->errorString()); +// } +// +// void Resource::handleReplyTimeout() { +// handleReplyError(QNetworkReply::TimeoutError, qDebug() << "Timed out loading" << _reply->url() << +// "received" << _bytesReceived << "total" << _bytesTotal); +// } +// void Resource::maybeRefresh() { if (Q_LIKELY(NetworkAccessManager::getInstance().cache())) { QNetworkReply* reply = qobject_cast(sender()); @@ -383,87 +382,116 @@ void Resource::maybeRefresh() { } } +// #include "AssetManager.h" void Resource::makeRequest() { - _reply = NetworkAccessManager::getInstance().get(_request); - - connect(_reply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(handleDownloadProgress(qint64,qint64))); - connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleReplyError())); - connect(_reply, SIGNAL(finished()), SLOT(handleReplyFinished())); - - if (_reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool()) { - // If the file as been updated since it was cached, refresh it - QNetworkRequest request(_request); - request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); - request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false); - QNetworkReply* reply = NetworkAccessManager::getInstance().head(request); - connect(reply, &QNetworkReply::finished, this, &Resource::maybeRefresh); - } else { - if (Q_LIKELY(NetworkAccessManager::getInstance().cache())) { - QNetworkCacheMetaData metaData = NetworkAccessManager::getInstance().cache()->metaData(_url); - bool needUpdate = false; - if (metaData.expirationDate().isNull() || metaData.expirationDate() <= QDateTime::currentDateTime()) { - // If the expiration date is NULL or in the past, - // put one far enough away that it won't be an issue. - metaData.setExpirationDate(QDateTime::currentDateTime().addYears(100)); - needUpdate = true; - } - if (metaData.lastModified().isNull()) { - // If the lastModified date is NULL, set it to now. - metaData.setLastModified(QDateTime::currentDateTime()); - needUpdate = true; - } - if (needUpdate) { - NetworkAccessManager::getInstance().cache()->updateMetaData(metaData); - } - } + auto request = ResourceManager::createResourceRequest(this, _url); + _request = request; + if (!_request) { + qDebug() << "Failed to get request for " << _url; + return; } - _replyTimer = new QTimer(this); - connect(_replyTimer, SIGNAL(timeout()), SLOT(handleReplyTimeout())); - _replyTimer->setSingleShot(true); - _replyTimer->start(REPLY_TIMEOUT_MS); + qDebug() << "Starting request for: " << _url; + + connect(request, &ResourceRequest::finished, this, &Resource::handleReplyFinished); + // connect(_reply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(handleDownloadProgress(qint64,qint64))); + // connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleReplyError())); + // connect(_reply, SIGNAL(finished()), SLOT(handleReplyFinished())); + + // AssetManager::getAsset(_url, [this](AssetRequestUpdateType type, QByteArray data) { + // if (type == AssetRequestUpdateType::COMPLETE) { + // downloadFinished(data); + // } else { + // handleReplyError(QNetworkReply::TimeoutError, qDebug()); + // } + // }); + // + request->send(); + + // if (_reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool()) { + // // If the file as been updated since it was cached, refresh it + // QNetworkRequest request(_request); + // request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); + // request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false); + // QNetworkReply* reply = NetworkAccessManager::getInstance().head(request); + // connect(reply, &QNetworkReply::finished, this, &Resource::maybeRefresh); + // } else { + // if (Q_LIKELY(NetworkAccessManager::getInstance().cache())) { + // QNetworkCacheMetaData metaData = NetworkAccessManager::getInstance().cache()->metaData(_url); + // bool needUpdate = false; + // if (metaData.expirationDate().isNull() || metaData.expirationDate() <= QDateTime::currentDateTime()) { + // // If the expiration date is NULL or in the past, + // // put one far enough away that it won't be an issue. + // metaData.setExpirationDate(QDateTime::currentDateTime().addYears(100)); + // needUpdate = true; + // } + // if (metaData.lastModified().isNull()) { + // // If the lastModified date is NULL, set it to now. + // metaData.setLastModified(QDateTime::currentDateTime()); + // needUpdate = true; + // } + // if (needUpdate) { + // NetworkAccessManager::getInstance().cache()->updateMetaData(metaData); + // } + // } + // } + + // _replyTimer = new QTimer(this); + // connect(_replyTimer, SIGNAL(timeout()), SLOT(handleReplyTimeout())); + // _replyTimer->setSingleShot(true); + // _replyTimer->start(REPLY_TIMEOUT_MS); _bytesReceived = _bytesTotal = 0; } -void Resource::handleReplyError(QNetworkReply::NetworkError error, QDebug debug) { - _reply->disconnect(this); - _replyTimer->disconnect(this); - _reply->deleteLater(); - _reply = nullptr; - _replyTimer->deleteLater(); - _replyTimer = nullptr; - ResourceCache::requestCompleted(this); - - // retry for certain types of failures - switch (error) { - case QNetworkReply::RemoteHostClosedError: - case QNetworkReply::TimeoutError: - case QNetworkReply::TemporaryNetworkFailureError: - case QNetworkReply::ProxyConnectionClosedError: - case QNetworkReply::ProxyTimeoutError: - case QNetworkReply::UnknownNetworkError: - case QNetworkReply::UnknownProxyError: - case QNetworkReply::UnknownContentError: - case QNetworkReply::ProtocolFailure: { - // retry with increasing delays - const int MAX_ATTEMPTS = 8; - const int BASE_DELAY_MS = 1000; - if (++_attempts < MAX_ATTEMPTS) { - QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(attemptRequest())); - debug << "-- retrying..."; - return; - } - // fall through to final failure - } - default: - finishedLoading(false); - break; - } -} - +// void Resource::handleReplyError(QNetworkReply::NetworkError error, QDebug debug) { +// _reply->disconnect(this); +// _replyTimer->disconnect(this); +// _reply->deleteLater(); +// _reply = nullptr; +// _replyTimer->deleteLater(); +// _replyTimer = nullptr; +// ResourceCache::requestCompleted(this); +// +// // retry for certain types of failures +// switch (error) { +// case QNetworkReply::RemoteHostClosedError: +// case QNetworkReply::TimeoutError: +// case QNetworkReply::TemporaryNetworkFailureError: +// case QNetworkReply::ProxyConnectionClosedError: +// case QNetworkReply::ProxyTimeoutError: +// case QNetworkReply::UnknownNetworkError: +// case QNetworkReply::UnknownProxyError: +// case QNetworkReply::UnknownContentError: +// case QNetworkReply::ProtocolFailure: { +// // retry with increasing delays +// const int MAX_ATTEMPTS = 8; +// const int BASE_DELAY_MS = 1000; +// if (++_attempts < MAX_ATTEMPTS) { +// QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(attemptRequest())); +// debug << "-- retrying..."; +// return; +// } +// // fall through to final failure +// } +// default: +// finishedLoading(false); +// break; +// } +// } +// void Resource::handleReplyFinished() { - qCDebug(networking) << "Got finished without download progress/error?" << _url; - handleDownloadProgress(0, 0); + // _request->disconnect(this); + // _request->deleteLater(); + // _request = nullptr; + Q_ASSERT(_request); + if (_request->getResult() == ResourceRequest::SUCCESS) { + _data = _request->moveData(); + _request->disconnect(this); + _request->deleteLater(); + _request = nullptr; + downloadFinished(_data); + } + ResourceCache::requestCompleted(this); } uint qHash(const QPointer& value, uint seed) { diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 93ddfe77be..59192449b8 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -26,6 +26,8 @@ #include +#include "ResourceManager.h" + class QNetworkReply; class QTimer; @@ -102,7 +104,7 @@ protected: void reserveUnusedResource(qint64 resourceSize); void clearUnusedResource(); - static void attemptRequest(Resource* resource); + Q_INVOKABLE static void attemptRequest(Resource* resource); static void requestCompleted(Resource* resource); private: @@ -188,7 +190,7 @@ protected: virtual void init(); /// Called when the download has finished. The recipient should delete the reply when done with it. - virtual void downloadFinished(QNetworkReply* reply) = 0; + virtual void downloadFinished(const QByteArray& data) = 0; /// Should be called by subclasses when all the loading that will be done has been done. Q_INVOKABLE void finishedLoading(bool success); @@ -197,19 +199,21 @@ protected: virtual void reinsert(); QUrl _url; - QNetworkRequest _request; + ResourceRequest* _request = nullptr; + //QNetworkRequest _request; bool _startedLoading = false; bool _failedToLoad = false; bool _loaded = false; QHash, float> _loadPriorities; QWeakPointer _self; QPointer _cache; + QByteArray _data; private slots: - void handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); - void handleReplyError(); + // void handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); + // void handleReplyError(); void handleReplyFinished(); - void handleReplyTimeout(); + // void handleReplyTimeout(); private: void setLRUKey(int lruKey) { _lruKey = lruKey; } @@ -221,7 +225,6 @@ private: friend class ResourceCache; int _lruKey = 0; - QNetworkReply* _reply = nullptr; QTimer* _replyTimer = nullptr; qint64 _bytesReceived = 0; qint64 _bytesTotal = 0; From 3a2ef35a3b76817ca5ccda49b23df995e95a97aa Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 3 Aug 2015 16:26:51 -0700 Subject: [PATCH 253/549] Update Geometry and Texture caches to use updated ResourceCache --- libraries/render-utils/src/GeometryCache.cpp | 44 +++++++++++--------- libraries/render-utils/src/GeometryCache.h | 2 +- libraries/render-utils/src/TextureCache.cpp | 26 ++++-------- libraries/render-utils/src/TextureCache.h | 2 +- 4 files changed, 35 insertions(+), 39 deletions(-) diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 6c03d57de3..2e76b97551 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -2030,7 +2030,7 @@ class GeometryReader : public QRunnable { public: GeometryReader(const QWeakPointer& geometry, const QUrl& url, - QNetworkReply* reply, const QVariantHash& mapping); + QByteArray data, const QVariantHash& mapping); virtual void run(); @@ -2038,28 +2038,25 @@ private: QWeakPointer _geometry; QUrl _url; - QNetworkReply* _reply; + QByteArray _data; QVariantHash _mapping; }; GeometryReader::GeometryReader(const QWeakPointer& geometry, const QUrl& url, - QNetworkReply* reply, const QVariantHash& mapping) : + QByteArray data, const QVariantHash& mapping) : _geometry(geometry), _url(url), - _reply(reply), + _data(data), _mapping(mapping) { } void GeometryReader::run() { QSharedPointer geometry = _geometry.toStrongRef(); if (geometry.isNull()) { - _reply->deleteLater(); + // _reply->deleteLater(); return; } try { - if (!_reply) { - throw QString("Reply is NULL ?!"); - } QString urlname = _url.path().toLower(); bool urlValid = true; urlValid &= !urlname.isEmpty(); @@ -2082,9 +2079,11 @@ void GeometryReader::run() { } else if (_url.path().toLower().endsWith("palaceoforinthilian4.fbx")) { lightmapLevel = 3.5f; } - fbxgeo = readFBX(_reply, _mapping, grabLightmaps, lightmapLevel); + fbxgeo = readFBX(_data, _mapping, grabLightmaps, lightmapLevel); } else if (_url.path().toLower().endsWith(".obj")) { - fbxgeo = OBJReader().readOBJ(_reply, _mapping, &_url); + auto d = QByteArray(_data); + QBuffer buffer { &d }; + fbxgeo = OBJReader().readOBJ(&buffer, _mapping, &_url); } QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo)); } else { @@ -2095,7 +2094,6 @@ void GeometryReader::run() { qCDebug(renderutils) << "Error reading " << _url << ": " << error; QMetaObject::invokeMethod(geometry.data(), "finishedLoading", Q_ARG(bool, false)); } - _reply->deleteLater(); } void NetworkGeometry::init() { @@ -2104,16 +2102,15 @@ void NetworkGeometry::init() { _meshes.clear(); _lods.clear(); _pendingTextureChanges.clear(); - _request.setUrl(_url); + //_request.setUrl(_url); Resource::init(); } -void NetworkGeometry::downloadFinished(QNetworkReply* reply) { - QUrl url = reply->url(); +void NetworkGeometry::downloadFinished(const QByteArray& data) { + QUrl url = getURL(); if (url.path().toLower().endsWith(".fst")) { // it's a mapping file; parse it and get the mesh filename - _mapping = FSTReader::readMapping(reply->readAll()); - reply->deleteLater(); + _mapping = FSTReader::readMapping(data); QString filename = _mapping.value("filename").toString(); if (filename.isNull()) { qCDebug(renderutils) << "Mapping file " << url << " has no filename."; @@ -2135,19 +2132,28 @@ void NetworkGeometry::downloadFinished(QNetworkReply* reply) { geometry->setLODParent(_lodParent); _lods.insert(it.value().toFloat(), geometry); } - _request.setUrl(url.resolved(filename)); - + // make the request immediately only if we have no LODs to switch between + // TODO reimplement using ResourceRequest + _url = url.resolved(filename); _startedLoading = false; if (_lods.isEmpty()) { attemptRequest(); } + + // _request.setUrl(url.resolved(filename)); + + // make the request immediately only if we have no LODs to switch between + // _startedLoading = false; + // if (_lods.isEmpty()) { + // attemptRequest(); + // } } return; } // send the reader off to the thread pool - QThreadPool::globalInstance()->start(new GeometryReader(_self, url, reply, _mapping)); + QThreadPool::globalInstance()->start(new GeometryReader(_self, url, data, _mapping)); } void NetworkGeometry::reinsert() { diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 147b4f8093..31bdcd16bf 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -380,7 +380,7 @@ public: protected: virtual void init(); - virtual void downloadFinished(QNetworkReply* reply); + virtual void downloadFinished(const QByteArray& reply) override; virtual void reinsert(); Q_INVOKABLE void setGeometry(const FBXGeometry& geometry); diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index f86d15079d..0694bf45d4 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -206,8 +206,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, TextureType type, const QByteArr class ImageReader : public QRunnable { public: - ImageReader(const QWeakPointer& texture, TextureType type, QNetworkReply* reply, const QUrl& url = QUrl(), - const QByteArray& content = QByteArray()); + ImageReader(const QWeakPointer& texture, TextureType type, const QByteArray& data, const QUrl& url = QUrl()); virtual void run(); @@ -215,27 +214,25 @@ private: QWeakPointer _texture; TextureType _type; - QNetworkReply* _reply; QUrl _url; QByteArray _content; }; -void NetworkTexture::downloadFinished(QNetworkReply* reply) { +void NetworkTexture::downloadFinished(const QByteArray& data) { // send the reader off to the thread pool - QThreadPool::globalInstance()->start(new ImageReader(_self, _type, reply)); + QThreadPool::globalInstance()->start(new ImageReader(_self, _type, data, _url)); } void NetworkTexture::loadContent(const QByteArray& content) { - QThreadPool::globalInstance()->start(new ImageReader(_self, _type, NULL, _url, content)); + QThreadPool::globalInstance()->start(new ImageReader(_self, _type, content)); } -ImageReader::ImageReader(const QWeakPointer& texture, TextureType type, QNetworkReply* reply, - const QUrl& url, const QByteArray& content) : +ImageReader::ImageReader(const QWeakPointer& texture, TextureType type, const QByteArray& data, + const QUrl& url) : _texture(texture), _type(type), - _reply(reply), _url(url), - _content(content) { + _content(data) { } std::once_flag onceListSupportedFormatsflag; @@ -288,16 +285,9 @@ public: void ImageReader::run() { QSharedPointer texture = _texture.toStrongRef(); if (texture.isNull()) { - if (_reply) { - _reply->deleteLater(); - } + qDebug() << "TEXTURE IS NULL"; return; } - if (_reply) { - _url = _reply->url(); - _content = _reply->readAll(); - _reply->deleteLater(); - } listSupportedImageFormats(); diff --git a/libraries/render-utils/src/TextureCache.h b/libraries/render-utils/src/TextureCache.h index 8f60382e9b..c5e8a756a0 100644 --- a/libraries/render-utils/src/TextureCache.h +++ b/libraries/render-utils/src/TextureCache.h @@ -119,7 +119,7 @@ public: TextureType getType() const { return _type; } protected: - virtual void downloadFinished(QNetworkReply* reply); + virtual void downloadFinished(const QByteArray& data) override; Q_INVOKABLE void loadContent(const QByteArray& content); // FIXME: This void* should be a gpu::Texture* but i cannot get it to work for now, moving on... From 3843e642e56327f54b5d2c3201b8bc9190c3aa2d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 3 Aug 2015 16:27:17 -0700 Subject: [PATCH 254/549] Move shared Asset code to AssetUtils.h --- libraries/networking/src/AssetUtils.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 libraries/networking/src/AssetUtils.h diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h new file mode 100644 index 0000000000..61def81ea8 --- /dev/null +++ b/libraries/networking/src/AssetUtils.h @@ -0,0 +1,25 @@ +// +// AssetUtils.h +// +// Created by Ryan Huffman on 2015/07/30 +// Copyright 2015 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 +// + +#ifndef hifi_AssetUtils_h +#define hifi_AssetUtils_h + +using MessageID = uint32_t; +using DataOffset = int64_t; + +const int HASH_HEX_LENGTH = 32; + +enum AssetServerError : uint8_t { + NO_ERROR = 0, + ASSET_NOT_FOUND, + INVALID_BYTE_RANGE, +}; + +#endif From ae93d74d8b4e06e862abafed8114a99bf8550c40 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 3 Aug 2015 16:27:34 -0700 Subject: [PATCH 255/549] Update Sound to use new ResourceCache --- libraries/audio/src/Sound.cpp | 17 +++++++++-------- libraries/audio/src/Sound.h | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 7dc6010f8f..5ff0f55f7f 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -56,16 +56,17 @@ Sound::Sound(const QUrl& url, bool isStereo) : } -void Sound::downloadFinished(QNetworkReply* reply) { +void Sound::downloadFinished(const QByteArray& data) { // replace our byte array with the downloaded data - QByteArray rawAudioByteArray = reply->readAll(); - QString fileName = reply->url().fileName(); + QByteArray rawAudioByteArray = QByteArray(data); + QString fileName = getURL().fileName(); const QString WAV_EXTENSION = ".wav"; - if (reply->hasRawHeader("Content-Type") || fileName.endsWith(WAV_EXTENSION)) { + if (fileName.endsWith(WAV_EXTENSION)) { - QByteArray headerContentType = reply->rawHeader("Content-Type"); + QString headerContentType = "audio/x-wav"; + //QByteArray headerContentType = reply->rawHeader("Content-Type"); // WAV audio file encountered if (headerContentType == "audio/x-wav" @@ -80,9 +81,9 @@ void Sound::downloadFinished(QNetworkReply* reply) { } else { // check if this was a stereo raw file // since it's raw the only way for us to know that is if the file was called .stereo.raw - if (reply->url().fileName().toLower().endsWith("stereo.raw")) { + if (fileName.toLower().endsWith("stereo.raw")) { _isStereo = true; - qCDebug(audio) << "Processing sound of" << rawAudioByteArray.size() << "bytes from" << reply->url() << "as stereo audio file."; + qCDebug(audio) << "Processing sound of" << rawAudioByteArray.size() << "bytes from" << getURL() << "as stereo audio file."; } // Process as RAW file @@ -94,7 +95,7 @@ void Sound::downloadFinished(QNetworkReply* reply) { } _isReady = true; - reply->deleteLater(); + _request->deleteLater(); } void Sound::downSample(const QByteArray& rawAudioByteArray) { diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 9aa92feea1..842c395a7d 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -39,7 +39,7 @@ private: void downSample(const QByteArray& rawAudioByteArray); void interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray); - virtual void downloadFinished(QNetworkReply* reply); + virtual void downloadFinished(const QByteArray& data) override; }; typedef QSharedPointer SharedSoundPointer; From 2d938f2d0a98f1f47cf9386470330337908b134e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 3 Aug 2015 16:27:48 -0700 Subject: [PATCH 256/549] Update AnimationCache to use new ResourceCache --- libraries/animation/src/AnimationCache.cpp | 15 +++++++-------- libraries/animation/src/AnimationCache.h | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/libraries/animation/src/AnimationCache.cpp b/libraries/animation/src/AnimationCache.cpp index 99224f7dce..5ac89f5a7e 100644 --- a/libraries/animation/src/AnimationCache.cpp +++ b/libraries/animation/src/AnimationCache.cpp @@ -43,28 +43,27 @@ Animation::Animation(const QUrl& url) : Resource(url) {} class AnimationReader : public QRunnable { public: - AnimationReader(const QWeakPointer& animation, QNetworkReply* reply); + AnimationReader(const QWeakPointer& animation, QByteArray data); virtual void run(); private: QWeakPointer _animation; - QNetworkReply* _reply; + QByteArray _data; }; -AnimationReader::AnimationReader(const QWeakPointer& animation, QNetworkReply* reply) : +AnimationReader::AnimationReader(const QWeakPointer& animation, QByteArray data) : _animation(animation), - _reply(reply) { + _data(data) { } void AnimationReader::run() { QSharedPointer animation = _animation.toStrongRef(); if (!animation.isNull()) { QMetaObject::invokeMethod(animation.data(), "setGeometry", - Q_ARG(const FBXGeometry&, readFBX(_reply->readAll(), QVariantHash()))); + Q_ARG(const FBXGeometry&, readFBX(QByteArray(_data), QVariantHash()))); } - _reply->deleteLater(); } QStringList Animation::getJointNames() const { @@ -96,9 +95,9 @@ void Animation::setGeometry(const FBXGeometry& geometry) { finishedLoading(true); } -void Animation::downloadFinished(QNetworkReply* reply) { +void Animation::downloadFinished(const QByteArray& data) { // send the reader off to the thread pool - QThreadPool::globalInstance()->start(new AnimationReader(_self, reply)); + QThreadPool::globalInstance()->start(new AnimationReader(_self, data)); } diff --git a/libraries/animation/src/AnimationCache.h b/libraries/animation/src/AnimationCache.h index c90c4c9225..2509585fb0 100644 --- a/libraries/animation/src/AnimationCache.h +++ b/libraries/animation/src/AnimationCache.h @@ -62,7 +62,7 @@ protected: Q_INVOKABLE void setGeometry(const FBXGeometry& geometry); - virtual void downloadFinished(QNetworkReply* reply); + virtual void downloadFinished(const QByteArray& data) override; private: From 6b839488492f05b8ad0f1ec366c3afb421168bc4 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 3 Aug 2015 16:28:04 -0700 Subject: [PATCH 257/549] Add new packet headers --- libraries/networking/src/udt/PacketHeaders.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index b133319a57..9e29498706 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -78,6 +78,8 @@ namespace PacketType { AssetGetReply, AssetUpload, AssetUploadReply, + AssetGetInfo, + AssetGetInfoReply, }; }; From acff31ee2dcd2101f41e38bfc2f680d4d2528a56 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 3 Aug 2015 16:28:21 -0700 Subject: [PATCH 258/549] Update script loaders to use ResourceRequest --- libraries/script-engine/src/BatchLoader.cpp | 93 ++++++++++++--------- libraries/script-engine/src/ScriptCache.cpp | 31 +++---- 2 files changed, 65 insertions(+), 59 deletions(-) diff --git a/libraries/script-engine/src/BatchLoader.cpp b/libraries/script-engine/src/BatchLoader.cpp index db0743808f..99916310f4 100644 --- a/libraries/script-engine/src/BatchLoader.cpp +++ b/libraries/script-engine/src/BatchLoader.cpp @@ -17,9 +17,7 @@ #include "BatchLoader.h" #include #include - - - +#include "ResourceManager.h" BatchLoader::BatchLoader(const QList& urls) : QObject(), @@ -27,6 +25,7 @@ BatchLoader::BatchLoader(const QList& urls) _finished(false), _urls(urls.toSet()), _data() { + qRegisterMetaType>("QMap"); } void BatchLoader::start() { @@ -35,45 +34,63 @@ void BatchLoader::start() { } _started = true; - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + // QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); for (QUrl url : _urls) { - if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") { - QNetworkRequest request = QNetworkRequest(url); - request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); - QNetworkReply* reply = networkAccessManager.get(request); - - qCDebug(scriptengine) << "Downloading file at" << url; - - connect(reply, &QNetworkReply::finished, [=]() { - if (reply->error()) { - _data.insert(url, QString()); - } else { - _data.insert(url, reply->readAll()); - } - reply->deleteLater(); - checkFinished(); - }); - - // If we end up being destroyed before the reply finishes, clean it up - connect(this, &QObject::destroyed, reply, &QObject::deleteLater); - - } else { -#ifdef _WIN32 - QString fileName = url.toString(); -#else - QString fileName = url.toLocalFile(); -#endif - - qCDebug(scriptengine) << "Reading file at " << fileName; - - QFile scriptFile(fileName); - if (scriptFile.open(QFile::ReadOnly | QFile::Text)) { - QTextStream in(&scriptFile); - _data.insert(url, in.readAll()); + auto request = ResourceManager::createResourceRequest(this, url); + if (!request) { + continue; + } + connect(request, &ResourceRequest::finished, [=]() { + if (request->getResult() == ResourceRequest::SUCCESS) { + _data.insert(url, request->moveData()); } else { _data.insert(url, QString()); } - } + request->deleteLater(); + checkFinished(); + }); + + qCDebug(scriptengine) << "Loading script at " << url; + + request->send(); + +// if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") { +// QNetworkRequest request = QNetworkRequest(url); +// request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); +// QNetworkReply* reply = networkAccessManager.get(request); +// +// qCDebug(scriptengine) << "Downloading file at" << url; +// +// connect(reply, &QNetworkReply::finished, [=]() { +// if (reply->error()) { +// _data.insert(url, QString()); +// } else { +// _data.insert(url, reply->readAll()); +// } +// reply->deleteLater(); +// checkFinished(); +// }); +// +// // If we end up being destroyed before the reply finishes, clean it up +// connect(this, &QObject::destroyed, reply, &QObject::deleteLater); +// +// } else { +// #ifdef _WIN32 +// QString fileName = url.toString(); +// #else +// QString fileName = url.toLocalFile(); +// #endif +// +// qCDebug(scriptengine) << "Reading file at " << fileName; +// +// QFile scriptFile(fileName); +// if (scriptFile.open(QFile::ReadOnly | QFile::Text)) { +// QTextStream in(&scriptFile); +// _data.insert(url, in.readAll()); +// } else { +// _data.insert(url, QString()); +// } +// } } checkFinished(); } diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index 2047442ce6..87cdae0026 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include "ScriptCache.h" @@ -44,18 +43,10 @@ QString ScriptCache::getScript(const QUrl& url, ScriptUser* scriptUser, bool& is if (alreadyWaiting) { qCDebug(scriptengine) << "Already downloading script at:" << url.toString(); } else { - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - QNetworkRequest networkRequest = QNetworkRequest(url); - networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); - if (reload) { - networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); - qCDebug(scriptengine) << "Redownloading script at:" << url.toString(); - } else { - qCDebug(scriptengine) << "Downloading script at:" << url.toString(); - } - - QNetworkReply* reply = networkAccessManager.get(networkRequest); - connect(reply, &QNetworkReply::finished, this, &ScriptCache::scriptDownloaded); + auto request = ResourceManager::createResourceRequest(this, url); + request->setCacheEnabled(!reload); + connect(request, &ResourceRequest::finished, this, &ScriptCache::scriptDownloaded); + request->send(); } } return scriptContents; @@ -69,27 +60,25 @@ void ScriptCache::deleteScript(const QUrl& url) { } void ScriptCache::scriptDownloaded() { - QNetworkReply* reply = qobject_cast(sender()); - QUrl url = reply->url(); + ResourceRequest* req = qobject_cast(sender()); + QUrl url = req->getUrl(); QList scriptUsers = _scriptUsers.values(url); _scriptUsers.remove(url); - if (reply->error() == QNetworkReply::NoError && reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 200) { - _scriptCache[url] = reply->readAll(); + if (req->getResult() == ResourceRequest::SUCCESS) { + _scriptCache[url] = req->moveData(); qCDebug(scriptengine) << "Done downloading script at:" << url.toString(); foreach(ScriptUser* user, scriptUsers) { user->scriptContentsAvailable(url, _scriptCache[url]); } } else { - qCWarning(scriptengine) << "Error loading script from URL " << reply->url().toString() - << "- HTTP status code is" << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() - << "and error from QNetworkReply is" << reply->errorString(); + qCWarning(scriptengine) << "Error loading script from URL " << url; foreach(ScriptUser* user, scriptUsers) { user->errorInLoadingScript(url); } } - reply->deleteLater(); + req->deleteLater(); } From a6665612fcbd359f746cdb1ce60a7b9ec69b4f61 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 3 Aug 2015 16:30:22 -0700 Subject: [PATCH 259/549] Add GetInfo packets to AssetClient --- libraries/networking/src/AssetClient.cpp | 110 +++++++++++++++++++---- libraries/networking/src/AssetClient.h | 28 +++--- 2 files changed, 112 insertions(+), 26 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index e8131a40f2..cf8231abeb 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -10,20 +10,52 @@ #include "AssetClient.h" +#include + +#include "AssetRequest.h" #include "NodeList.h" #include "PacketReceiver.h" -const int HASH_HEX_LENGTH = 32; MessageID AssetClient::_currentID = 0; + AssetClient::AssetClient() { auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); + packetReceiver.registerListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply"); packetReceiver.registerListener(PacketType::AssetGetReply, this, "handleAssetGetReply"); packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); } -bool AssetClient::getAsset(QString hash, ReceivedAssetCallback callback) { +AssetRequest* AssetClient::create(QString hash) { + if (QThread::currentThread() != thread()) { + AssetRequest* req; + QMetaObject::invokeMethod(this, "create", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(AssetRequest*, req), + Q_ARG(QString, hash)); + return req; + } + if (hash.length() != 32) { + qDebug() << "Invalid hash size"; + return nullptr; + } + + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + + if (assetServer) { + auto assetClient = DependencyManager::get(); + auto request = new AssetRequest(assetClient.data(), hash); + + return request; + } + + return nullptr; +} + +bool AssetClient::getAsset(QString hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback) { + if (hash.length() != HASH_HEX_LENGTH) { qDebug() << "Invalid hash size"; return false; } @@ -33,10 +65,16 @@ bool AssetClient::getAsset(QString hash, ReceivedAssetCallback callback) { if (assetServer) { auto packet = NLPacket::create(PacketType::AssetGet); + + auto messageID = ++_currentID; + packet->writePrimitive(messageID); packet->write(hash.toLatin1().constData(), 32); + packet->writePrimitive(start); + packet->writePrimitive(end); + nodeList->sendPacket(std::move(packet), *assetServer); - _pendingRequests[hash] = callback; + _pendingRequests[messageID] = callback; return true; } @@ -44,28 +82,70 @@ bool AssetClient::getAsset(QString hash, ReceivedAssetCallback callback) { return false; } +bool AssetClient::getAssetInfo(QString hash, GetInfoCallback callback) { + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + + if (assetServer) { + auto packet = NLPacket::create(PacketType::AssetGetInfo); + + auto messageID = ++_currentID; + packet->writePrimitive(messageID); + packet->write(hash.toLatin1().constData(), 32); + + nodeList->sendPacket(std::move(packet), *assetServer); + + _pendingInfoRequests[messageID] = callback; + + return true; + } + + return false; +} + +void AssetClient::handleAssetGetInfoReply(QSharedPointer packet, SharedNodePointer senderNode) { + MessageID messageID; + packet->readPrimitive(&messageID); + auto assetHash = QString(packet->read(HASH_HEX_LENGTH)); + + AssetServerError error; + packet->readPrimitive(&error); + + AssetInfo info; + + if (!error) { + packet->readPrimitive(&info.size); + } + + if (_pendingInfoRequests.contains(messageID)) { + auto callback = _pendingInfoRequests.take(messageID); + callback(error != NO_ERROR, info); + } +} + void AssetClient::handleAssetGetReply(QSharedPointer packet, SharedNodePointer senderNode) { auto assetHash = packet->read(HASH_HEX_LENGTH); qDebug() << "Got reply for asset: " << assetHash; - bool success; - packet->readPrimitive(&success); + MessageID messageID; + packet->readPrimitive(&messageID); + + AssetServerError error; + packet->readPrimitive(&error); QByteArray data; - if (success) { - int length; + if (!error) { + DataOffset length; packet->readPrimitive(&length); - char assetData[length]; - packet->read(assetData, length); - - data = QByteArray(assetData, length); + data = packet->read(length); + qDebug() << "Got data: " << length << ", " << data.toHex(); } else { - qDebug() << "Failure getting asset"; + qDebug() << "Failure getting asset: " << error; } - if (_pendingRequests.contains(assetHash)) { - auto callback = _pendingRequests.take(assetHash); - callback(success, data); + if (_pendingRequests.contains(messageID)) { + auto callback = _pendingRequests.take(messageID); + callback(!error, data); } } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 87da601563..7ad9c1a638 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -13,39 +13,45 @@ #define hifi_AssetClient_h #include -#include #include +#include "AssetUtils.h" #include "LimitedNodeList.h" #include "NLPacket.h" +class AssetRequest; + +struct AssetInfo { + QString hash; + int64_t size; +}; + using ReceivedAssetCallback = std::function; +using GetInfoCallback = std::function; using UploadResultCallback = std::function; -using MessageID = int; class AssetClient : public QObject, public Dependency { Q_OBJECT public: AssetClient(); - enum RequestResult { - SUCCESS = 0, - FAILURE, - TIMEOUT - }; - - bool getAsset(QString hash, ReceivedAssetCallback callback); + Q_INVOKABLE AssetRequest* create(QString hash); + bool getAssetInfo(QString hash, GetInfoCallback callback); + bool getAsset(QString hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback); bool uploadAsset(QByteArray data, QString extension, UploadResultCallback callback); + bool abortDataRequest(MessageID messageID); private slots: + void handleAssetGetInfoReply(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetGetReply(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetUploadReply(QSharedPointer packet, SharedNodePointer senderNode); private: static MessageID _currentID; - QMap _pendingRequests; - QMap _pendingUploads; + QHash _pendingRequests; + QHash _pendingInfoRequests; + QHash _pendingUploads; }; #endif From c0852f0eb25dc9b8aa39fd3e1ecdf8e9dd0f2d1a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 3 Aug 2015 17:14:42 -0700 Subject: [PATCH 260/549] Remove call to has pending datagrams --- libraries/networking/src/udt/Connection.cpp | 3 +-- libraries/networking/src/udt/Socket.cpp | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index dab6c5b934..8bf3501590 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -283,9 +283,8 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in _receiveWindow.onProbePair1Arrival(); } else if (((uint32_t) sequenceNumber & 0xF) == 1) { _receiveWindow.onProbePair2Arrival(); - } else { - _receiveWindow.onPacketArrival(); } + _receiveWindow.onPacketArrival(); // If this is not the next sequence number, report loss if (sequenceNumber > _lastReceivedSequenceNumber + 1) { diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 6a3a3d619f..dafe50d5c8 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -129,12 +129,12 @@ Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { } void Socket::readPendingDatagrams() { - while (_udpSocket.hasPendingDatagrams()) { + int packetSizeWithHeader = -1; + while ((packetSizeWithHeader = _udpSocket.pendingDatagramSize()) != -1) { // setup a HifiSockAddr to read into HifiSockAddr senderSockAddr; // setup a buffer to read the packet into - int packetSizeWithHeader = _udpSocket.pendingDatagramSize(); auto buffer = std::unique_ptr(new char[packetSizeWithHeader]); // pull the datagram From 40520c204ff099eb2e67c24f6846042bb89d8320 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 3 Aug 2015 17:39:09 -0700 Subject: [PATCH 261/549] Stats improvement --- libraries/networking/src/udt/Connection.cpp | 2 ++ libraries/networking/src/udt/PacketTimeWindow.cpp | 4 ++-- tools/udt-test/src/UDTTest.cpp | 6 ++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 85f103f438..2219de6fd6 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -508,6 +508,8 @@ void Connection::processACK2(std::unique_ptr controlPacket) { int rtt = duration_cast(now - it->second.second).count(); updateRTT(rtt); + // write this RTT to stats + _stats.recordRTT(rtt); // set the RTT for congestion control _congestionControl->setRTT(_rtt); diff --git a/libraries/networking/src/udt/PacketTimeWindow.cpp b/libraries/networking/src/udt/PacketTimeWindow.cpp index 269d158b7d..9193e8e0af 100644 --- a/libraries/networking/src/udt/PacketTimeWindow.cpp +++ b/libraries/networking/src/udt/PacketTimeWindow.cpp @@ -19,8 +19,8 @@ using namespace udt; using namespace std::chrono; -static const int DEFAULT_PACKET_INTERVAL_MICROSECONDS = 1000000; -static const int DEFAULT_PROBE_INTERVAL_MICROSECONDS = 1000; +static const int DEFAULT_PACKET_INTERVAL_MICROSECONDS = 1000000; // 1s +static const int DEFAULT_PROBE_INTERVAL_MICROSECONDS = 1000; // 1ms PacketTimeWindow::PacketTimeWindow(int numPacketIntervals, int numProbeIntervals) : _numPacketIntervals(numPacketIntervals), diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 6344860442..8cc141c83f 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -220,6 +220,7 @@ void UDTTest::sendPacket() { void UDTTest::sampleStats() { static bool first = true; + static const double USECS_PER_MSEC = 1000.0; if (!_target.isNull()) { if (first) { @@ -232,8 +233,6 @@ void UDTTest::sampleStats() { int headerIndex = -1; - static const double USECS_PER_MSEC = 1000.0; - // setup a list of left justified values QStringList values { QString::number(stats.sendRate).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), @@ -269,6 +268,9 @@ void UDTTest::sampleStats() { // setup a list of left justified values QStringList values { QString::number(stats.receiveRate).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.estimatedBandwith).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.rtt / USECS_PER_MSEC).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.congestionWindowSize).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.recievedBytes).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.recievedUtilBytes).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(100 * (double)stats.recievedUtilBytes / (double)stats.recievedBytes).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), From a10746a448307a3cb1dc77df4f4256c8b97919f1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 3 Aug 2015 19:12:37 -0700 Subject: [PATCH 262/549] set the max window size, correct a typo --- libraries/networking/src/udt/Connection.cpp | 3 ++- tools/udt-test/src/UDTTest.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 2219de6fd6..1fce27ee5a 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -41,8 +41,9 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination, unique_pt _rtt = _synInterval * 10; _rttVariance = _rtt / 2; - // set the initial RTT on congestion control object + // set the initial RTT and flow window size on congestion control object _congestionControl->setRTT(_rtt); + _congestionControl->setMaxCongestionWindowSize(_flowWindowSize); } Connection::~Connection() { diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 8cc141c83f..d13c82e8f1 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -48,7 +48,7 @@ const QStringList CLIENT_STATS_TABLE_HEADERS { }; const QStringList SERVER_STATS_TABLE_HEADERS { - "Recieve Rate (P/s)", "Total Bytes", "Util Bytes", "Ratio (%)", + "Receive Rate (P/s)", "Total Bytes", "Util Bytes", "Ratio (%)", "Sent ACK", "Sent LACK", "Sent NAK", "Sent TNAK", "Recieved ACK2", "Duplicate Packets" }; From 924a4d3c21a65190c85ee8b60c9cf51e77101946 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 3 Aug 2015 19:12:58 -0700 Subject: [PATCH 263/549] Change connection stats --- tools/udt-test/src/UDTTest.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 8cc141c83f..db3b483889 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -48,7 +48,8 @@ const QStringList CLIENT_STATS_TABLE_HEADERS { }; const QStringList SERVER_STATS_TABLE_HEADERS { - "Recieve Rate (P/s)", "Total Bytes", "Util Bytes", "Ratio (%)", + "Recieve Rate (P/s)", "Bandwidth (P/s)", "RTT(ms)", "CW (P)", + //"Total Bytes", "Util Bytes", "Ratio (%)", "Sent ACK", "Sent LACK", "Sent NAK", "Sent TNAK", "Recieved ACK2", "Duplicate Packets" }; @@ -271,9 +272,9 @@ void UDTTest::sampleStats() { QString::number(stats.estimatedBandwith).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.rtt / USECS_PER_MSEC).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.congestionWindowSize).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.recievedBytes).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.recievedUtilBytes).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(100 * (double)stats.recievedUtilBytes / (double)stats.recievedBytes).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), +// QString::number(stats.recievedBytes).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), +// QString::number(stats.recievedUtilBytes).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), +// QString::number(100 * (double)stats.recievedUtilBytes / (double)stats.recievedBytes).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.events[udt::ConnectionStats::Stats::SentACK]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.events[udt::ConnectionStats::Stats::SentLightACK]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.events[udt::ConnectionStats::Stats::SentNAK]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), From 3d0c71d95c644f5353c8d7aad0e1297021f65b16 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Aug 2015 12:29:22 -0700 Subject: [PATCH 264/549] remove a double on arrival time record --- libraries/networking/src/udt/Connection.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 1fce27ee5a..0817c23e8d 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -285,7 +285,6 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in } else if (((uint32_t) sequenceNumber & 0xF) == 1) { _receiveWindow.onProbePair2Arrival(); } - _receiveWindow.onPacketArrival(); _receiveWindow.onPacketArrival(); From 925cb4bd566002ab2d52ec555d3b7856cfba2f68 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Aug 2015 12:48:58 -0700 Subject: [PATCH 265/549] fix for slow start algo on loss --- .../networking/src/udt/CongestionControl.cpp | 16 +++++++++++----- libraries/networking/src/udt/CongestionControl.h | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 16ee9a0c75..d338e648fe 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -131,6 +131,11 @@ void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) { // stop the slow start if we haven't yet if (_slowStart) { stopSlowStart(); + + // if the change to send rate was driven by a known receive rate, then we don't continue with the decrease + if (_receiveRate > 0) { + return; + } } _loss = true; @@ -187,13 +192,14 @@ void DefaultCC::onTimeout() { void DefaultCC::stopSlowStart() { _slowStart = false; + if (_receiveRate > 0) { // Set the sending rate to the receiving rate. _packetSendPeriod = USECS_PER_SECOND / _receiveRate; - return; + } else { + // If no receiving rate is observed, we have to compute the sending + // rate according to the current window size, and decrease it + // using the method below. + _packetSendPeriod = _congestionWindowSize / (_rtt + synInterval()); } - // If no receiving rate is observed, we have to compute the sending - // rate according to the current window size, and decrease it - // using the method below. - _packetSendPeriod = _congestionWindowSize / (_rtt + synInterval()); } diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index 81ade13b41..3aac2dd54e 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -106,7 +106,7 @@ public: virtual void onTimeout(); private: - void stopSlowStart(); // stops the slow start on loss or timeout, if it's still on + void stopSlowStart(); // stops the slow start on loss or timeout std::chrono::high_resolution_clock::time_point _lastRCTime; // last rate increase time bool _slowStart { true }; // if in slow start phase From 4b21581b3686c3d6d30f12c1ecc3885ca4202efb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Aug 2015 14:32:48 -0700 Subject: [PATCH 266/549] fix for min NAK interval in Connection --- libraries/networking/src/udt/Connection.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 0817c23e8d..9e5bcc3dde 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -300,8 +300,6 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in sendNAK(sequenceNumber); // figure out when we should send the next loss report, if we haven't heard anything back - _nakInterval = (_rtt + 4 * _rttVariance); - int receivedPacketsPerSecond = _receiveWindow.getPacketReceiveSpeed(); if (receivedPacketsPerSecond > 0) { @@ -582,7 +580,7 @@ void Connection::updateRTT(int rtt) { } int Connection::estimatedTimeout() const { - return _congestionControl->_userDefinedRto ? _rtt + _rttVariance * 4 : _congestionControl->_rto; + return _congestionControl->_userDefinedRto ? _congestionControl->_rto : _rtt + _rttVariance * 4; } void Connection::updateCongestionControlAndSendQueue(std::function congestionCallback) { From 01749ad0de09df8e541d12d1901ea7ee69f3c327 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 4 Aug 2015 15:07:04 -0700 Subject: [PATCH 267/549] TimeoutNAK fixes --- libraries/networking/src/udt/Connection.cpp | 16 +++++++--------- libraries/networking/src/udt/ConnectionStats.cpp | 2 +- libraries/networking/src/udt/LossList.cpp | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 0817c23e8d..56f76d2f5b 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -285,7 +285,6 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in } else if (((uint32_t) sequenceNumber & 0xF) == 1) { _receiveWindow.onProbePair2Arrival(); } - _receiveWindow.onPacketArrival(); // If this is not the next sequence number, report loss @@ -300,19 +299,18 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in sendNAK(sequenceNumber); // figure out when we should send the next loss report, if we haven't heard anything back - _nakInterval = (_rtt + 4 * _rttVariance); + _nakInterval = estimatedTimeout(); int receivedPacketsPerSecond = _receiveWindow.getPacketReceiveSpeed(); - if (receivedPacketsPerSecond > 0) { // the NAK interval is at least the _minNAKInterval // but might be the time required for all lost packets to be retransmitted - _nakInterval = std::max((int) (_lossList.getLength() * (USECS_PER_SECOND / receivedPacketsPerSecond)), - _minNAKInterval); - } else { - // the NAK interval is at least the _minNAKInterval but might be the estimated timeout - _nakInterval = std::max(estimatedTimeout(), _minNAKInterval); + _nakInterval += (int) (_lossList.getLength() * (USECS_PER_SECOND / receivedPacketsPerSecond)); } + + // the NAK interval is at least the _minNAKInterval but might be the estimated timeout + _nakInterval = std::max(_nakInterval, _minNAKInterval); + } bool wasDuplicate = false; @@ -582,7 +580,7 @@ void Connection::updateRTT(int rtt) { } int Connection::estimatedTimeout() const { - return _congestionControl->_userDefinedRto ? _rtt + _rttVariance * 4 : _congestionControl->_rto; + return _congestionControl->_userDefinedRto ? _congestionControl->_rto : _rtt + _rttVariance * 4; } void Connection::updateCongestionControlAndSendQueue(std::function congestionCallback) { diff --git a/libraries/networking/src/udt/ConnectionStats.cpp b/libraries/networking/src/udt/ConnectionStats.cpp index 91eeb6d49c..8c36750782 100644 --- a/libraries/networking/src/udt/ConnectionStats.cpp +++ b/libraries/networking/src/udt/ConnectionStats.cpp @@ -81,7 +81,7 @@ void ConnectionStats::recordUnreliableReceivedPackets(int payload, int total) { } static const double EWMA_CURRENT_SAMPLE_WEIGHT = 0.125; -static const double EWMA_PREVIOUS_SAMPLES_WEIGHT = 1 - 0.125; +static const double EWMA_PREVIOUS_SAMPLES_WEIGHT = 1.0 - EWMA_CURRENT_SAMPLE_WEIGHT; void ConnectionStats::recordSendRate(int sample) { _currentSample.sendRate = sample; diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp index 4cb182c2f7..ab860a768d 100644 --- a/libraries/networking/src/udt/LossList.cpp +++ b/libraries/networking/src/udt/LossList.cpp @@ -100,7 +100,7 @@ bool LossList::remove(SequenceNumber seq) { } else { auto temp = it->second; it->second = seq - 1; - it = _lossList.insert(++it, make_pair(seq + 1, temp)); + _lossList.insert(++it, make_pair(seq + 1, temp)); } _length -= 1; From 23e1ee71ccc3d67f3ab9c19eb2181be8f01fa3ad Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Aug 2015 16:18:12 -0700 Subject: [PATCH 268/549] suppress writeDatagram errors for saturated links --- libraries/networking/src/udt/Socket.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index dafe50d5c8..9bef5ca6e5 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -13,6 +13,8 @@ #include +#include + #include "../NetworkLogging.h" #include "Connection.h" #include "ControlPacket.h" @@ -111,7 +113,12 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc qint64 bytesWritten = _udpSocket.writeDatagram(datagram, sockAddr.getAddress(), sockAddr.getPort()); if (bytesWritten < 0) { - qCDebug(networking) << "ERROR in writeDatagram:" << _udpSocket.error() << "-" << _udpSocket.errorString(); + // when saturating a link this isn't an uncommon message - suppress it so it doesn't bomb the debug + static const QString WRITE_ERROR_REGEX = "writeDatagram error: QAbstractSocket::NetworkError - Unable to send a message"; + static QString repeatedMessage + = LogHandler::getInstance().addRepeatedMessageRegex(WRITE_ERROR_REGEX); + + qCDebug(networking) << "writeDatagram error:" << _udpSocket.error() << "-" << qPrintable(_udpSocket.errorString()); } return bytesWritten; From 7b8ca2c0f2626c9f50839a8f25c731bfee3fe69e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Aug 2015 16:29:53 -0700 Subject: [PATCH 269/549] fix suppression of link saturation messages --- libraries/networking/src/udt/Socket.cpp | 4 ++-- tools/udt-test/CMakeLists.txt | 2 +- tools/udt-test/src/UDTTest.cpp | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 9bef5ca6e5..a7dd6377ba 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -114,11 +114,11 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc if (bytesWritten < 0) { // when saturating a link this isn't an uncommon message - suppress it so it doesn't bomb the debug - static const QString WRITE_ERROR_REGEX = "writeDatagram error: QAbstractSocket::NetworkError - Unable to send a message"; + static const QString WRITE_ERROR_REGEX = "Socket::writeDatagram QAbstractSocket::NetworkError - Unable to send a message"; static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex(WRITE_ERROR_REGEX); - qCDebug(networking) << "writeDatagram error:" << _udpSocket.error() << "-" << qPrintable(_udpSocket.errorString()); + qCDebug(networking) << "Socket::writeDatagram" << _udpSocket.error() << "-" << qPrintable(_udpSocket.errorString()); } return bytesWritten; diff --git a/tools/udt-test/CMakeLists.txt b/tools/udt-test/CMakeLists.txt index 7f47677269..648ef6f00c 100644 --- a/tools/udt-test/CMakeLists.txt +++ b/tools/udt-test/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME udt-test) setup_hifi_project() -link_hifi_libraries(networking) +link_hifi_libraries(networking shared) copy_dlls_beside_windows_executable() \ No newline at end of file diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 83f5ba1751..7508263429 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -16,6 +16,8 @@ #include #include +#include + const QCommandLineOption PORT_OPTION { "p", "listening port for socket (defaults to random)", "port", 0 }; const QCommandLineOption TARGET_OPTION { "target", "target for sent packets (default is listen only)", From 5124fc1ea0ae86443560c20813352f13b3840ceb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Aug 2015 16:31:40 -0700 Subject: [PATCH 270/549] add LogHandler to UDTTest --- tools/udt-test/src/UDTTest.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 7508263429..6c163a726e 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -59,6 +59,8 @@ const QStringList SERVER_STATS_TABLE_HEADERS { UDTTest::UDTTest(int& argc, char** argv) : QCoreApplication(argc, argv) { + qInstallMessageHandler(LogHandler::verboseMessageHandler); + parseArguments(); // randomize the seed for packet size randomization From 5d7dac9b8ecca1b67268b4074d6d1245138adc8c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 7 Aug 2015 17:33:33 -0700 Subject: [PATCH 271/549] do DefaultCC setup in constructor --- libraries/networking/src/udt/CongestionControl.cpp | 11 +++++------ libraries/networking/src/udt/CongestionControl.h | 3 +-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index d338e648fe..307ef528a9 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -30,14 +30,13 @@ void CongestionControl::setPacketSendPeriod(double newSendPeriod) { } } -void DefaultCC::init() { - _lastRCTime = high_resolution_clock::now(); - +DefaultCC::DefaultCC() : + _lastRCTime(high_resolution_clock::now()), + _slowStartLastAck(_sendCurrSeqNum), + _lastDecreaseMaxSeq(SequenceNumber {SequenceNumber::MAX }) +{ _mss = udt::MAX_PACKET_SIZE_WITH_UDP_HEADER; - _slowStartLastAck = _sendCurrSeqNum; - _lastDecreaseMaxSeq = SequenceNumber { SequenceNumber::MAX }; - _congestionWindowSize = 16.0; _packetSendPeriod = 1.0; } diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index 3aac2dd54e..f131324acb 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -97,10 +97,9 @@ public: class DefaultCC: public CongestionControl { public: - DefaultCC() {} + DefaultCC(); public: - virtual void init(); virtual void onACK(SequenceNumber ackNum); virtual void onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd); virtual void onTimeout(); From 9ac760aed63108cf16796d8b44f903641644ce57 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 10 Aug 2015 09:59:34 -0700 Subject: [PATCH 272/549] use c++11 number randomization for NAK --- libraries/networking/src/udt/CongestionControl.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 307ef528a9..ccb904f67e 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -10,6 +10,9 @@ // #include "CongestionControl.h" + +#include + #include "Packet.h" using namespace udt; @@ -160,12 +163,11 @@ void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) { _lastDecreaseMaxSeq = _sendCurrSeqNum; // avoid synchronous rate decrease across connections using randomization - srand((unsigned) _lastDecreaseMaxSeq); - _randomDecreaseThreshold = (int) ceil(_avgNAKNum * (double(rand()) / RAND_MAX)); + std::random_device rd; + std::mt19937 generator(rd()); + std::uniform_int_distribution<> distribution(1, _avgNAKNum); - if (_randomDecreaseThreshold < 1) { - _randomDecreaseThreshold = 1; - } + _randomDecreaseThreshold = distribution(generator); } else if ((_decreaseCount++ < MAX_DECREASES_PER_CONGESTION_EPOCH) && ((++_nakCount % _randomDecreaseThreshold) == 0)) { // there have been fewer than MAX_DECREASES_PER_CONGESTION_EPOCH AND this NAK matches the random count at which we From 5e3d3fc06ba418a4cdd54a6a36f7fab714cf1af2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 10 Aug 2015 10:03:53 -0700 Subject: [PATCH 273/549] fix for indentation in BandwidthDialog --- interface/src/ui/BandwidthDialog.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/interface/src/ui/BandwidthDialog.cpp b/interface/src/ui/BandwidthDialog.cpp index 6272ddf76a..e086005783 100644 --- a/interface/src/ui/BandwidthDialog.cpp +++ b/interface/src/ui/BandwidthDialog.cpp @@ -89,10 +89,11 @@ BandwidthDialog::BandwidthDialog(QWidget* parent) : _allChannelDisplays[4] = _otherChannelDisplay = new BandwidthChannelDisplay({NodeType::Unassigned}, form, "Other", "Kbps", 1.0, COLOR2); _allChannelDisplays[5] = _totalChannelDisplay = - new BandwidthChannelDisplay({NodeType::DomainServer, NodeType::EntityServer, - NodeType::AudioMixer, NodeType::Agent, - NodeType::AvatarMixer, NodeType::Unassigned}, - form, "Total", "Kbps", 1.0, COLOR2); + new BandwidthChannelDisplay({ + NodeType::DomainServer, NodeType::EntityServer, + NodeType::AudioMixer, NodeType::Agent, + NodeType::AvatarMixer, NodeType::Unassigned + }, form, "Total", "Kbps", 1.0, COLOR2); connect(averageUpdateTimer, SIGNAL(timeout()), this, SLOT(updateTimerTimeout())); averageUpdateTimer->start(1000); From 04c1d154ab0e680e9b660da0f68fb80719a44e9a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 10 Aug 2015 10:10:43 -0700 Subject: [PATCH 274/549] fix header size for NLPacket writeTypeAndVersion --- libraries/networking/src/NLPacket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index cba73fa6cf..2ca794f7b9 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -164,7 +164,7 @@ QByteArray NLPacket::hashForPacketAndSecret(const udt::Packet& packet, const QUu } void NLPacket::writeTypeAndVersion() { - auto headerOffset = Packet::localHeaderSize(isPartOfMessage()); + auto headerOffset = Packet::totalHeaderSize(isPartOfMessage()); // Pack the packet type memcpy(_packet.get() + headerOffset, &_type, sizeof(PacketType)); From 6d9504935de5e3569fb2ef102a74f92e0b65acd2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 10 Aug 2015 10:12:24 -0700 Subject: [PATCH 275/549] add a comment for onTimeout in CongestionControl --- libraries/networking/src/udt/CongestionControl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index ccb904f67e..555f48cfd6 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -178,6 +178,7 @@ void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) { } } +// Note: This isn't currently being called by anything since we, unlike UDT, don't have TTL on our packets void DefaultCC::onTimeout() { if (_slowStart) { stopSlowStart(); From eb17ddc04fd45dfdbfe67c5fc32eb75f6438411d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 10 Aug 2015 10:13:50 -0700 Subject: [PATCH 276/549] fix capitalization of RTO for CongestionControl --- libraries/networking/src/udt/CongestionControl.h | 4 ++-- libraries/networking/src/udt/Connection.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index f131324acb..a8a4ba3342 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -42,7 +42,7 @@ public: protected: void setAckInterval(int ackInterval) { _ackInterval = ackInterval; } - void setRto(int rto) { _userDefinedRto = true; _rto = rto; } + void setRTO(int rto) { _userDefinedRTO = true; _rto = rto; } void setMSS(int mss) { _mss = mss; } void setMaxCongestionWindowSize(int window) { _maxCongestionWindowSize = window; } @@ -74,7 +74,7 @@ private: int _synInterval { DEFAULT_SYN_INTERVAL }; - bool _userDefinedRto { false }; // if the RTO value is defined by users + bool _userDefinedRTO { false }; // if the RTO value is defined by users int _rto { -1 }; // RTO value, microseconds }; diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 56f76d2f5b..ba3ae29e98 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -580,7 +580,7 @@ void Connection::updateRTT(int rtt) { } int Connection::estimatedTimeout() const { - return _congestionControl->_userDefinedRto ? _congestionControl->_rto : _rtt + _rttVariance * 4; + return _congestionControl->_userDefinedRTO ? _congestionControl->_rto : _rtt + _rttVariance * 4; } void Connection::updateCongestionControlAndSendQueue(std::function congestionCallback) { From d9254aa2e98f7cff8ccdb03383096ec072793d76 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 10 Aug 2015 10:14:50 -0700 Subject: [PATCH 277/549] remove comment that won't come into play until ordering --- libraries/networking/src/udt/Connection.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index ba3ae29e98..149b8a478e 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -130,9 +130,6 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { // update the last sent ACK _lastSentACK = nextACKNumber; - // remove the ACKed packets from the receive queue - // TODO? - // setup the ACK packet, make it static so we can re-use it static const int ACK_PACKET_PAYLOAD_BYTES = sizeof(_lastSentACK) + sizeof(_currentACKSubSequenceNumber) + sizeof(_rtt) + sizeof(int32_t) + sizeof(int32_t) + sizeof(int32_t); From 42b5b37b96fba13aea0957e039a3bd9ba296b267 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 17 Aug 2015 15:47:43 -0700 Subject: [PATCH 278/549] force timeout NAK to fit MTU --- libraries/networking/src/udt/Connection.cpp | 8 ++++++-- libraries/networking/src/udt/LossList.cpp | 10 +++++++++- libraries/networking/src/udt/LossList.h | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 149b8a478e..273bb36378 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -248,11 +248,15 @@ void Connection::sendNAK(SequenceNumber sequenceNumberRecieved) { void Connection::sendTimeoutNAK() { if (_lossList.getLength() > 0) { + + int timeoutPayloadSize = std::min((int) (_lossList.getLength() * 2 * sizeof(SequenceNumber)), + ControlPacket::maxPayloadSize()); + // construct a NAK packet that will hold all of the lost sequence numbers - auto lossListPacket = ControlPacket::create(ControlPacket::TimeoutNAK, 2 * _lossList.getLength() * sizeof(SequenceNumber)); + auto lossListPacket = ControlPacket::create(ControlPacket::TimeoutNAK, timeoutPayloadSize); // Pack in the lost sequence numbers - _lossList.write(*lossListPacket); + _lossList.write(*lossListPacket, timeoutPayloadSize / 2); // have our parent socket send off this control packet _parentSocket->writeBasePacket(*lossListPacket, _destination); diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp index ab860a768d..c02d12c34a 100644 --- a/libraries/networking/src/udt/LossList.cpp +++ b/libraries/networking/src/udt/LossList.cpp @@ -167,9 +167,17 @@ SequenceNumber LossList::popFirstSequenceNumber() { return front; } -void LossList::write(ControlPacket& packet) { +void LossList::write(ControlPacket& packet, int maxPairs) { + int writtenPairs = 0; for(const auto& pair : _lossList) { packet.writePrimitive(pair.first); packet.writePrimitive(pair.second); + + ++writtenPairs; + + // check if we've written the maximum number we were told to write + if (maxPairs != -1 && writtenPairs >= maxPairs) { + break; + } } } diff --git a/libraries/networking/src/udt/LossList.h b/libraries/networking/src/udt/LossList.h index fc97206282..d3cbef7ebe 100644 --- a/libraries/networking/src/udt/LossList.h +++ b/libraries/networking/src/udt/LossList.h @@ -40,7 +40,7 @@ public: SequenceNumber getFirstSequenceNumber() const; SequenceNumber popFirstSequenceNumber(); - void write(ControlPacket& packet); + void write(ControlPacket& packet, int maxPairs = -1); private: std::list> _lossList; From ec82e65aec02ae914bf486576c4eebc083fcd97a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 17 Aug 2015 16:07:07 -0700 Subject: [PATCH 279/549] comment flow window size changes for light ACK --- libraries/networking/src/udt/Connection.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 273bb36378..ae4d04e930 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -475,8 +475,12 @@ void Connection::processLightACK(std::unique_ptr controlPacket) { // must be larger than the last received ACK to be processed if (ack > _lastReceivedACK) { + // NOTE: the following makes sense in UDT where there is a dynamic receive buffer. + // Since we have a receive buffer that is always of a default size, we don't use this light ACK to + // drop the flow window size. + // decrease the flow window size by the offset between the last received ACK and this ACK - _flowWindowSize -= seqoff(_lastReceivedACK, ack); + // _flowWindowSize -= seqoff(_lastReceivedACK, ack); // update the last received ACK to the this one _lastReceivedACK = ack; From 8c22627f3248727175f843ec4a4cbd35fe9a5e32 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 17 Aug 2015 16:07:29 -0700 Subject: [PATCH 280/549] fix a typo in comment --- libraries/networking/src/udt/Connection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index ae4d04e930..c26e758050 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -595,7 +595,7 @@ void Connection::updateCongestionControlAndSendQueue(std::function cong // fire congestion control callback congestionCallback(); - // now that we've update the congestion control, update the packet send period and flow window size + // now that we've updated the congestion control, update the packet send period and flow window size getSendQueue().setPacketSendPeriod(_congestionControl->_packetSendPeriod); getSendQueue().setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); From bc6846e08cbb73a40aa0349a81a85565b3505381 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 17 Aug 2015 16:07:55 -0700 Subject: [PATCH 281/549] fix a typo in Connection header --- libraries/networking/src/udt/Connection.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 9bdc6baf24..65e7fe74f0 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -46,7 +46,7 @@ public: void sync(); // rate control method, fired by Socket for all connections on SYN interval - // returns indicates if this packet was a duplicate + // return indicates if this packet was a duplicate bool processReceivedSequenceNumber(SequenceNumber sequenceNumber, int packetSize, int payloadSize); void processControl(std::unique_ptr controlPacket); From 71b2d90c64ca3dba30cf7f482ef73959dc2984de Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 17 Aug 2015 16:08:34 -0700 Subject: [PATCH 282/549] clarify comment in LossList header --- libraries/networking/src/udt/LossList.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/LossList.h b/libraries/networking/src/udt/LossList.h index d3cbef7ebe..f0f2b92988 100644 --- a/libraries/networking/src/udt/LossList.h +++ b/libraries/networking/src/udt/LossList.h @@ -26,11 +26,11 @@ public: void clear() { _length = 0; _lossList.clear(); } - // Should always add at the end + // must always add at the end - faster than insert void append(SequenceNumber seq); void append(SequenceNumber start, SequenceNumber end); - // Inserts anywhere - MUCH slower + // inserts anywhere - MUCH slower void insert(SequenceNumber start, SequenceNumber end); bool remove(SequenceNumber seq); From 1c176e55ed6570e4c668dac96024837fd7fe278c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 17 Aug 2015 16:13:14 -0700 Subject: [PATCH 283/549] add some comments to PacketTimeWindow --- libraries/networking/src/udt/PacketTimeWindow.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/networking/src/udt/PacketTimeWindow.cpp b/libraries/networking/src/udt/PacketTimeWindow.cpp index 9193e8e0af..5c389f6d26 100644 --- a/libraries/networking/src/udt/PacketTimeWindow.cpp +++ b/libraries/networking/src/udt/PacketTimeWindow.cpp @@ -51,6 +51,7 @@ int32_t meanOfMedianFilteredValues(std::vector intervals, int numValues, in // grab the median value of the intervals vector int intervalsMedian = median(intervals.begin(), intervals.end()); + // figure out our bounds for median filtering static const int MEDIAN_FILTERING_BOUND_MULTIPLIER = 8; int upperBound = intervalsMedian * MEDIAN_FILTERING_BOUND_MULTIPLIER; int lowerBound = intervalsMedian / MEDIAN_FILTERING_BOUND_MULTIPLIER; @@ -58,6 +59,7 @@ int32_t meanOfMedianFilteredValues(std::vector intervals, int numValues, in int sum = 0; int count = 0; + // sum the values that are inside the median filtered bounds for (auto& interval : intervals) { if ((interval < upperBound) && (interval > lowerBound)) { ++count; @@ -65,7 +67,9 @@ int32_t meanOfMedianFilteredValues(std::vector intervals, int numValues, in } } + // make sure we hit our threshold of values required if (count >= valuesRequired) { + // return the frequency (per second) for the mean interval static const double USECS_PER_SEC = 1000000.0; return (int32_t) ceil(USECS_PER_SEC / (((double) sum) / ((double) count))); } else { From feddb613e2736f3b4805dc2423d232c85e36ef85 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 17 Aug 2015 16:28:33 -0700 Subject: [PATCH 284/549] add comments, use scoped locker in SendQueue --- libraries/networking/src/udt/SendQueue.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 111b676499..d004deea2f 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -149,8 +149,8 @@ void SendQueue::run() { bool resentPacket = false; + // the following while makes sure that we find a packet to re-send, if there is one while (!resentPacket) { - // prioritize a loss retransmission QWriteLocker naksLocker(&_naksLock); if (_naks.getLength() > 0) { @@ -191,11 +191,13 @@ void SendQueue::run() { break; } + // if we didn't find a packet to re-send AND we think we can fit a new packet on the wire + // (this is according to the current flow window size) then we send out a new packet if (!resentPacket && seqlen(SequenceNumber { (uint32_t) _lastACKSequenceNumber }, _currentSequenceNumber) <= _flowWindowSize) { // we didn't re-send a packet, so time to send a new one - _packetsLock.lockForWrite(); + QWriteLocker locker(&_packetsLock); if (_packets.size() > 0) { SequenceNumber nextNumber = getNextSequenceNumber(); @@ -217,7 +219,7 @@ void SendQueue::run() { } // unlock the packets, we're done pulling - _packetsLock.unlock(); + locker.unlock(); // definitely send the first packet sendNewPacketAndAddToSentList(move(firstPacket), nextNumber); @@ -229,7 +231,7 @@ void SendQueue::run() { } } else { - _packetsLock.unlock(); + locker.unlock(); } } From fe100695f0f0be0632c531dd3deef5bcffd119f5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 17 Aug 2015 16:29:21 -0700 Subject: [PATCH 285/549] rename dest to destination for SendQueue --- libraries/networking/src/udt/SendQueue.cpp | 6 +++--- libraries/networking/src/udt/SendQueue.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index d004deea2f..d3095bff15 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -25,14 +25,14 @@ using namespace udt; using namespace std::chrono; -std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr dest) { - auto queue = std::unique_ptr(new SendQueue(socket, dest)); +std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr destination) { + auto queue = std::unique_ptr(new SendQueue(socket, destination)); Q_ASSERT_X(socket, "SendQueue::create", "Must be called with a valid Socket*"); // Setup queue private thread QThread* thread = new QThread(); - thread->setObjectName("Networking: SendQueue " + dest.objectName()); // Name thread for easier debug + thread->setObjectName("Networking: SendQueue " + destination.objectName()); // Name thread for easier debug connect(thread, &QThread::started, queue.get(), &SendQueue::run); diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 004938051e..bbb1dc3798 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -37,7 +37,7 @@ class SendQueue : public QObject { Q_OBJECT public: - static std::unique_ptr create(Socket* socket, HifiSockAddr dest); + static std::unique_ptr create(Socket* socket, HifiSockAddr destination); void queuePacket(std::unique_ptr packet); int getQueueSize() const { QReadLocker locker(&_packetsLock); return _packets.size(); } From d89c54112dadc7440fbcb7cca7b8f6467b6678bb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 17 Aug 2015 16:35:23 -0700 Subject: [PATCH 286/549] cleanup indentation in Socket --- libraries/networking/src/udt/Socket.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index a7dd6377ba..a280a68716 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -128,8 +128,8 @@ Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { auto it = _connectionsHash.find(sockAddr); if (it == _connectionsHash.end()) { - it = _connectionsHash.insert(it, std::make_pair(sockAddr, - std::unique_ptr(new Connection(this, sockAddr, _ccFactory->create())))); + auto connection = std::unique_ptr(new Connection(this, sockAddr, _ccFactory->create())); + it = _connectionsHash.insert(it, std::make_pair(sockAddr, std::move(connection))); } return *it->second; From 2ec4d8ff3cd3634e15f719c358f6716291a865db Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 17 Aug 2015 16:38:59 -0700 Subject: [PATCH 287/549] rename return of HifiSockAddr objects for connections --- libraries/networking/src/udt/Socket.cpp | 2 +- libraries/networking/src/udt/Socket.h | 4 ++-- tools/udt-test/src/UDTTest.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index a280a68716..a55a129c0a 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -237,7 +237,7 @@ ConnectionStats::Stats Socket::sampleStatsForConnection(const HifiSockAddr& dest } } -std::vector Socket::getSockAddr() { +std::vector Socket::getConnectionSockAddrs() { std::vector addr; addr.reserve(_connectionsHash.size()); for (const auto& connectionPair : _connectionsHash) { diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 602cfaf8ec..e3cf347905 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -65,7 +65,7 @@ public: void connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* receiver, const char* slot); ConnectionStats::Stats sampleStatsForConnection(const HifiSockAddr& destination); - std::vector getSockAddr(); + std::vector getConnectionSockAddrs(); private slots: void readPendingDatagrams(); @@ -83,7 +83,7 @@ private: std::unordered_map _unreliableSequenceNumbers; std::unordered_map> _connectionsHash; - int32_t _synInterval = 10; // 10ms + int _synInterval = 10; // 10ms QTimer _synTimer; std::unique_ptr _ccFactory { new CongestionControlFactory() }; diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 6c163a726e..d24a9282e9 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -264,7 +264,7 @@ void UDTTest::sampleStats() { first = false; } - auto sockets = _socket.getSockAddr(); + auto sockets = _socket.getConnectionSockAddrs(); if (sockets.size() > 0) { udt::ConnectionStats::Stats stats = _socket.sampleStatsForConnection(sockets.front()); From 47d17102082ac707cf82c9837154f85156662d59 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 17 Aug 2015 16:39:29 -0700 Subject: [PATCH 288/549] remove msecTimestampNow that is not used --- libraries/shared/src/SharedUtil.cpp | 4 ---- libraries/shared/src/SharedUtil.h | 1 - 2 files changed, 5 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index d73e8f446e..f78c8c47e0 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -39,10 +39,6 @@ void usecTimestampNowForceClockSkew(int clockSkew) { ::usecTimestampNowAdjust = clockSkew; } -quint64 msecTimestampNow(bool wantDebug) { - return usecTimestampNow() / 1000; -} - quint64 usecTimestampNow(bool wantDebug) { static bool usecTimestampNowIsInitialized = false; static qint64 TIME_REFERENCE = 0; // in usec diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index a60c0defd0..17a32e7910 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -64,7 +64,6 @@ inline bool operator!=(const xColor& lhs, const xColor& rhs) // Use a custom User-Agent to avoid ModSecurity filtering, e.g. by hosting providers. const QByteArray HIGH_FIDELITY_USER_AGENT = "Mozilla/5.0 (HighFidelityInterface)"; -quint64 msecTimestampNow(bool wantDebug = false); quint64 usecTimestampNow(bool wantDebug = false); void usecTimestampNowForceClockSkew(int clockSkew); From abf07dc06df1c0c339c3edd9dcb65fef4eecfa06 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 17 Aug 2015 16:39:52 -0700 Subject: [PATCH 289/549] move hasher for UUID to UUID.h --- libraries/networking/src/UUID.h | 6 ++++++ libraries/octree/src/OctreeEditPacketSender.h | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/UUID.h b/libraries/networking/src/UUID.h index 7e7048486f..b8cb1b56ca 100644 --- a/libraries/networking/src/UUID.h +++ b/libraries/networking/src/UUID.h @@ -18,4 +18,10 @@ const int NUM_BYTES_RFC4122_UUID = 16; QString uuidStringWithoutCurlyBraces(const QUuid& uuid); +template <> struct std::hash { + size_t operator()(const QUuid& uuid) const { + return qHash(uuid); + } +}; + #endif // hifi_UUID_h diff --git a/libraries/octree/src/OctreeEditPacketSender.h b/libraries/octree/src/OctreeEditPacketSender.h index d10870a221..d8761e6161 100644 --- a/libraries/octree/src/OctreeEditPacketSender.h +++ b/libraries/octree/src/OctreeEditPacketSender.h @@ -20,12 +20,6 @@ #include "JurisdictionMap.h" #include "SentPacketHistory.h" -template <> struct std::hash { - size_t operator()(const QUuid& uuid) const { - return qHash(uuid); - } -}; - /// Utility for processing, packing, queueing and sending of outbound edit messages. class OctreeEditPacketSender : public PacketSender { Q_OBJECT From d9f445d5f69001a306f1862dad2d00a721d397c0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 17 Aug 2015 16:45:15 -0700 Subject: [PATCH 290/549] put custom hashing for UUID in UUIDHasher --- assignment-client/src/avatars/AvatarMixerClientData.h | 2 +- libraries/networking/src/UUID.h | 6 ------ libraries/networking/src/UUIDHasher.h | 10 +++++++--- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index fd0971294c..3dbe917ee2 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -81,7 +81,7 @@ private: AvatarData _avatar; uint16_t _lastReceivedSequenceNumber { 0 }; - std::unordered_map _lastBroadcastSequenceNumbers; + std::unordered_map _lastBroadcastSequenceNumbers; bool _hasReceivedFirstPackets = false; quint64 _billboardChangeTimestamp = 0; diff --git a/libraries/networking/src/UUID.h b/libraries/networking/src/UUID.h index b8cb1b56ca..7e7048486f 100644 --- a/libraries/networking/src/UUID.h +++ b/libraries/networking/src/UUID.h @@ -18,10 +18,4 @@ const int NUM_BYTES_RFC4122_UUID = 16; QString uuidStringWithoutCurlyBraces(const QUuid& uuid); -template <> struct std::hash { - size_t operator()(const QUuid& uuid) const { - return qHash(uuid); - } -}; - #endif // hifi_UUID_h diff --git a/libraries/networking/src/UUIDHasher.h b/libraries/networking/src/UUIDHasher.h index 3ece236812..b05e517841 100644 --- a/libraries/networking/src/UUIDHasher.h +++ b/libraries/networking/src/UUIDHasher.h @@ -20,9 +20,13 @@ class UUIDHasher { public: size_t operator()(const QUuid& uuid) const { - return uuid.data1 ^ uuid.data2 ^ (uuid.data3 << 16) - ^ ((uuid.data4[0] << 24) | (uuid.data4[1] << 16) | (uuid.data4[2] << 8) | uuid.data4[3]) - ^ ((uuid.data4[4] << 24) | (uuid.data4[5] << 16) | (uuid.data4[6] << 8) | uuid.data4[7]); + return qHash(uuid); + } +}; + +template <> struct std::hash { + size_t operator()(const QUuid& uuid) const { + return qHash(uuid); } }; From 75e7de3019831a0dc45b3c6194074399ac82df81 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 17 Aug 2015 16:49:08 -0700 Subject: [PATCH 291/549] remove getConnectionSockAddrs vector move --- libraries/networking/src/udt/Socket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index a55a129c0a..530d268425 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -243,5 +243,5 @@ std::vector Socket::getConnectionSockAddrs() { for (const auto& connectionPair : _connectionsHash) { addr.push_back(connectionPair.first); } - return std::move(addr); + return addr; } From f039851f13546d877d4179e386282419d6a3b452 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 17 Aug 2015 16:57:42 -0700 Subject: [PATCH 292/549] remove std namespacing from Connection --- libraries/networking/src/udt/Connection.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index c26e758050..e07d987c4a 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -22,10 +22,9 @@ #include "Socket.h" using namespace udt; -using namespace std; using namespace std::chrono; -Connection::Connection(Socket* parentSocket, HifiSockAddr destination, unique_ptr congestionControl) : +Connection::Connection(Socket* parentSocket, HifiSockAddr destination, std::unique_ptr congestionControl) : _parentSocket(parentSocket), _destination(destination), _congestionControl(move(congestionControl)) @@ -71,7 +70,7 @@ SendQueue& Connection::getSendQueue() { return *_sendQueue; } -void Connection::sendReliablePacket(unique_ptr packet) { +void Connection::sendReliablePacket(std::unique_ptr packet) { Q_ASSERT_X(packet->isReliable(), "Connection::send", "Trying to send an unreliable packet reliably."); getSendQueue().queuePacket(move(packet)); } @@ -346,7 +345,7 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in return wasDuplicate; } -void Connection::processControl(unique_ptr controlPacket) { +void Connection::processControl(std::unique_ptr controlPacket) { // Simple dispatch to control packets processing methods based on their type switch (controlPacket->getType()) { case ControlPacket::ACK: From 4e540828bd3a7e17fd93e053f6da0a7d83072a40 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 09:33:22 -0700 Subject: [PATCH 293/549] use mod in place of branching for SequenceNumber --- libraries/networking/src/udt/SequenceNumber.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/SequenceNumber.h b/libraries/networking/src/udt/SequenceNumber.h index d0bea86777..9827fc79b2 100644 --- a/libraries/networking/src/udt/SequenceNumber.h +++ b/libraries/networking/src/udt/SequenceNumber.h @@ -39,11 +39,11 @@ public: explicit operator UType() { return static_cast(_value); } inline SequenceNumber& operator++() { - _value = (_value == MAX) ? 0 : ++_value; + _value = (_value + 1) % (MAX + 1); return *this; } inline SequenceNumber& operator--() { - _value = (_value == 0) ? MAX : --_value; + _value = (_value - 1) % (MAX + 1); return *this; } inline SequenceNumber operator++(int) { From 426a8909e19b45d217e5ba35e62fd5a434f20c63 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 09:40:13 -0700 Subject: [PATCH 294/549] wait on the SendQueue thread in Connection --- libraries/networking/src/udt/Connection.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index e07d987c4a..d8aee60432 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -47,9 +47,16 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination, std::uniq Connection::~Connection() { if (_sendQueue) { + // grab the send queue thread so we can wait on it + QThread* sendQueueThread = _sendQueue->thread(); + + // tell the send queue to stop and be deleted _sendQueue->stop(); _sendQueue->deleteLater(); _sendQueue.release(); + + // wait on the send queue thread so we know the send queue is gone + sendQueueThread->wait(); } } From ffa2070a46365d7f26721adaace830e608684161 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 09:44:56 -0700 Subject: [PATCH 295/549] remove commented stats in UDTTest --- tools/udt-test/src/UDTTest.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index d24a9282e9..1780231b99 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -276,9 +276,6 @@ void UDTTest::sampleStats() { QString::number(stats.estimatedBandwith).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.rtt / USECS_PER_MSEC).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.congestionWindowSize).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), -// QString::number(stats.recievedBytes).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), -// QString::number(stats.recievedUtilBytes).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), -// QString::number(100 * (double)stats.recievedUtilBytes / (double)stats.recievedBytes).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.events[udt::ConnectionStats::Stats::SentACK]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.events[udt::ConnectionStats::Stats::SentLightACK]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.events[udt::ConnectionStats::Stats::SentNAK]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), From 5c2348cf0d8bc44e59878be48608ff85c048a747 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 09:49:39 -0700 Subject: [PATCH 296/549] remove header for commented stats --- tools/udt-test/src/UDTTest.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 1780231b99..1f55fd1665 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -51,7 +51,6 @@ const QStringList CLIENT_STATS_TABLE_HEADERS { const QStringList SERVER_STATS_TABLE_HEADERS { "Receive Rate (P/s)", "Bandwidth (P/s)", "RTT(ms)", "CW (P)", - //"Total Bytes", "Util Bytes", "Ratio (%)", "Sent ACK", "Sent LACK", "Sent NAK", "Sent TNAK", "Recieved ACK2", "Duplicate Packets" }; From b7d779bb25b35b31f8e571cf40cc0f198c9c2cac Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 09:56:00 -0700 Subject: [PATCH 297/549] put back branching for signed Type --- libraries/networking/src/udt/SequenceNumber.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/SequenceNumber.h b/libraries/networking/src/udt/SequenceNumber.h index 9827fc79b2..fae5a7bb01 100644 --- a/libraries/networking/src/udt/SequenceNumber.h +++ b/libraries/networking/src/udt/SequenceNumber.h @@ -43,7 +43,7 @@ public: return *this; } inline SequenceNumber& operator--() { - _value = (_value - 1) % (MAX + 1); + _value = (_value == 0) ? MAX : --_value; return *this; } inline SequenceNumber operator++(int) { From bf919f105a5c96bbf6c6df1fbd607b1260cacca2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 11:29:07 -0700 Subject: [PATCH 298/549] add a simple container-test, speed HifiSockAddr hashing --- libraries/networking/src/HifiSockAddr.h | 18 +++++- tools/CMakeLists.txt | 3 + tools/container-test/CMakeLists.txt | 4 ++ tools/container-test/src/main.cpp | 84 +++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 tools/container-test/CMakeLists.txt create mode 100644 tools/container-test/src/main.cpp diff --git a/libraries/networking/src/HifiSockAddr.h b/libraries/networking/src/HifiSockAddr.h index 25f7ad2194..e6f018413f 100644 --- a/libraries/networking/src/HifiSockAddr.h +++ b/libraries/networking/src/HifiSockAddr.h @@ -70,10 +70,24 @@ uint qHash(const HifiSockAddr& key, uint seed); template <> struct std::hash { + // NOTE: this hashing specifically ignores IPv6 addresses - if we begin to support those we will need + // to conditionally hash the bytes that represent an IPv6 address std::size_t operator()(const HifiSockAddr& sockAddr) const { // use XOR of implemented std::hash templates for new hash - return std::hash()(sockAddr.getAddress().toString().toStdString()) - ^ std::hash()((uint16_t) sockAddr.getPort()); + // depending on the type of address we're looking at + + if (sockAddr.getAddress().protocol() == QAbstractSocket::IPv4Protocol) { + return std::hash()((uint32_t) sockAddr.getAddress().toIPv4Address()) + ^ std::hash()((uint16_t) sockAddr.getPort()); + } else if (sockAddr.getAddress().protocol() == QAbstractSocket::IPv6Protocol) { + // use XOR of implemented std::hash templates for new hash + return std::hash()(reinterpret_cast(sockAddr.getAddress().toIPv6Address().c)) + ^ std::hash()((uint16_t) sockAddr.getPort()); + } else { + return std::hash()(sockAddr.getAddress().toString().toStdString()) + ^ std::hash()((uint16_t) sockAddr.getPort()); + + } } }; diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 2056044a4b..7ab4525707 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -8,5 +8,8 @@ set_target_properties(scribe PROPERTIES FOLDER "Tools") add_subdirectory(udt-test) set_target_properties(udt-test PROPERTIES FOLDER "Tools") +add_subdirectory(container-test) +set_target_properties(container-test PROPERTIES FOLDER "Tools") + add_subdirectory(vhacd-util) set_target_properties(vhacd-util PROPERTIES FOLDER "Tools") diff --git a/tools/container-test/CMakeLists.txt b/tools/container-test/CMakeLists.txt new file mode 100644 index 0000000000..0eea7ddd84 --- /dev/null +++ b/tools/container-test/CMakeLists.txt @@ -0,0 +1,4 @@ +set(TARGET_NAME container-test) +setup_hifi_project() + +link_hifi_libraries(networking) \ No newline at end of file diff --git a/tools/container-test/src/main.cpp b/tools/container-test/src/main.cpp new file mode 100644 index 0000000000..7b570b4172 --- /dev/null +++ b/tools/container-test/src/main.cpp @@ -0,0 +1,84 @@ +// +// main.cpp +// tools/container-test/src +// +// Created by Stephen Birarda on 8/18/15. +// Copyright 2015 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 +#include +#include +#include +#include + +#include + +using namespace std::chrono; + +int main(int argc, char* argv[]) { + static const int NUM_ELEMENTS = 50; + + std::random_device rd; + std::mt19937 generator(rd()); + std::uniform_int_distribution<> ipDistribution(1, UINT32_MAX); + std::uniform_int_distribution<> portDistribution(1, UINT16_MAX); + + // from 1 to NUM_ELEMENTS, create a vector and unordered map with that many elements and compare how long it takes to pull the last value + for (int i = 1; i <= NUM_ELEMENTS; ++i) { + // create our vector with i elements + std::vector> vectorElements(i); + + // create our unordered map with i elements + std::unordered_map hashElements; + + HifiSockAddr lastAddress; + + // fill the structures with HifiSockAddr + for (int j = 0; j < i; ++j) { + // create a random IP address + quint32 randomNumber = ipDistribution(generator); + quint32 randomIP = (randomNumber >> 24 & 0xFF) << 24 | + (randomNumber >> 16 & 0xFF) << 16 | + (randomNumber >> 8 & 0xFF) << 8 | + (randomNumber & 0xFF); + + HifiSockAddr randomAddress(QHostAddress(randomIP), portDistribution(generator)); + + vectorElements.push_back({ randomAddress, 12 }); + hashElements.insert({ randomAddress, 12 }); + + if (j == i - 1) { + // this is the last element - store it for lookup purposes + lastAddress = randomAddress; + } + } + + // time how long it takes to get the value for the key lastAddress, for each container + auto before = high_resolution_clock::now(); + int vectorResult; + + for (auto& vi : vectorElements) { + if (vi.first == lastAddress) { + vectorResult = vi.second;; + break; + } + } + + auto vectorDuration = duration_cast(high_resolution_clock::now() - before); + + Q_UNUSED(vectorResult); + + before = high_resolution_clock::now(); + auto mi = hashElements.find(lastAddress); + int mapResult = mi->second; + auto mapDuration = duration_cast(high_resolution_clock::now() - before); + + Q_UNUSED(mapResult); + + qDebug() << i << QString("v: %1ns").arg(vectorDuration.count()) << QString("m: %2ns").arg(mapDuration.count()); + } +} + From c6467f7fbc4a7be03d22d96f78a0b50b02077f87 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 11:31:11 -0700 Subject: [PATCH 299/549] rename the container-test to container-profile --- tools/CMakeLists.txt | 4 ++-- tools/{container-test => container-profile}/CMakeLists.txt | 2 +- tools/{container-test => container-profile}/src/main.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename tools/{container-test => container-profile}/CMakeLists.txt (60%) rename tools/{container-test => container-profile}/src/main.cpp (98%) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 7ab4525707..3dcd7aab57 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -8,8 +8,8 @@ set_target_properties(scribe PROPERTIES FOLDER "Tools") add_subdirectory(udt-test) set_target_properties(udt-test PROPERTIES FOLDER "Tools") -add_subdirectory(container-test) -set_target_properties(container-test PROPERTIES FOLDER "Tools") +add_subdirectory(container-profile) +set_target_properties(container-profile PROPERTIES FOLDER "Tools") add_subdirectory(vhacd-util) set_target_properties(vhacd-util PROPERTIES FOLDER "Tools") diff --git a/tools/container-test/CMakeLists.txt b/tools/container-profile/CMakeLists.txt similarity index 60% rename from tools/container-test/CMakeLists.txt rename to tools/container-profile/CMakeLists.txt index 0eea7ddd84..9c0adb99f2 100644 --- a/tools/container-test/CMakeLists.txt +++ b/tools/container-profile/CMakeLists.txt @@ -1,4 +1,4 @@ -set(TARGET_NAME container-test) +set(TARGET_NAME container-profile) setup_hifi_project() link_hifi_libraries(networking) \ No newline at end of file diff --git a/tools/container-test/src/main.cpp b/tools/container-profile/src/main.cpp similarity index 98% rename from tools/container-test/src/main.cpp rename to tools/container-profile/src/main.cpp index 7b570b4172..3cde3b2a23 100644 --- a/tools/container-test/src/main.cpp +++ b/tools/container-profile/src/main.cpp @@ -1,6 +1,6 @@ // // main.cpp -// tools/container-test/src +// tools/container-profile/src // // Created by Stephen Birarda on 8/18/15. // Copyright 2015 High Fidelity, Inc. From 972cf8cb02594375c37e65d01c65ff617f6a35e1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 11:32:00 -0700 Subject: [PATCH 300/549] remove the container-profile tool --- tools/CMakeLists.txt | 3 - tools/container-profile/CMakeLists.txt | 4 -- tools/container-profile/src/main.cpp | 84 -------------------------- 3 files changed, 91 deletions(-) delete mode 100644 tools/container-profile/CMakeLists.txt delete mode 100644 tools/container-profile/src/main.cpp diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 3dcd7aab57..2056044a4b 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -8,8 +8,5 @@ set_target_properties(scribe PROPERTIES FOLDER "Tools") add_subdirectory(udt-test) set_target_properties(udt-test PROPERTIES FOLDER "Tools") -add_subdirectory(container-profile) -set_target_properties(container-profile PROPERTIES FOLDER "Tools") - add_subdirectory(vhacd-util) set_target_properties(vhacd-util PROPERTIES FOLDER "Tools") diff --git a/tools/container-profile/CMakeLists.txt b/tools/container-profile/CMakeLists.txt deleted file mode 100644 index 9c0adb99f2..0000000000 --- a/tools/container-profile/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -set(TARGET_NAME container-profile) -setup_hifi_project() - -link_hifi_libraries(networking) \ No newline at end of file diff --git a/tools/container-profile/src/main.cpp b/tools/container-profile/src/main.cpp deleted file mode 100644 index 3cde3b2a23..0000000000 --- a/tools/container-profile/src/main.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// -// main.cpp -// tools/container-profile/src -// -// Created by Stephen Birarda on 8/18/15. -// Copyright 2015 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 -#include -#include -#include -#include - -#include - -using namespace std::chrono; - -int main(int argc, char* argv[]) { - static const int NUM_ELEMENTS = 50; - - std::random_device rd; - std::mt19937 generator(rd()); - std::uniform_int_distribution<> ipDistribution(1, UINT32_MAX); - std::uniform_int_distribution<> portDistribution(1, UINT16_MAX); - - // from 1 to NUM_ELEMENTS, create a vector and unordered map with that many elements and compare how long it takes to pull the last value - for (int i = 1; i <= NUM_ELEMENTS; ++i) { - // create our vector with i elements - std::vector> vectorElements(i); - - // create our unordered map with i elements - std::unordered_map hashElements; - - HifiSockAddr lastAddress; - - // fill the structures with HifiSockAddr - for (int j = 0; j < i; ++j) { - // create a random IP address - quint32 randomNumber = ipDistribution(generator); - quint32 randomIP = (randomNumber >> 24 & 0xFF) << 24 | - (randomNumber >> 16 & 0xFF) << 16 | - (randomNumber >> 8 & 0xFF) << 8 | - (randomNumber & 0xFF); - - HifiSockAddr randomAddress(QHostAddress(randomIP), portDistribution(generator)); - - vectorElements.push_back({ randomAddress, 12 }); - hashElements.insert({ randomAddress, 12 }); - - if (j == i - 1) { - // this is the last element - store it for lookup purposes - lastAddress = randomAddress; - } - } - - // time how long it takes to get the value for the key lastAddress, for each container - auto before = high_resolution_clock::now(); - int vectorResult; - - for (auto& vi : vectorElements) { - if (vi.first == lastAddress) { - vectorResult = vi.second;; - break; - } - } - - auto vectorDuration = duration_cast(high_resolution_clock::now() - before); - - Q_UNUSED(vectorResult); - - before = high_resolution_clock::now(); - auto mi = hashElements.find(lastAddress); - int mapResult = mi->second; - auto mapDuration = duration_cast(high_resolution_clock::now() - before); - - Q_UNUSED(mapResult); - - qDebug() << i << QString("v: %1ns").arg(vectorDuration.count()) << QString("m: %2ns").arg(mapDuration.count()); - } -} - From 1c3543febc2ff3a4c39740e995369bb1e7028fb4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 11:39:04 -0700 Subject: [PATCH 301/549] use string style hashing for IPv6 addresses --- libraries/networking/src/HifiSockAddr.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/HifiSockAddr.h b/libraries/networking/src/HifiSockAddr.h index e6f018413f..c66579eca1 100644 --- a/libraries/networking/src/HifiSockAddr.h +++ b/libraries/networking/src/HifiSockAddr.h @@ -79,14 +79,11 @@ struct std::hash { if (sockAddr.getAddress().protocol() == QAbstractSocket::IPv4Protocol) { return std::hash()((uint32_t) sockAddr.getAddress().toIPv4Address()) ^ std::hash()((uint16_t) sockAddr.getPort()); - } else if (sockAddr.getAddress().protocol() == QAbstractSocket::IPv6Protocol) { - // use XOR of implemented std::hash templates for new hash - return std::hash()(reinterpret_cast(sockAddr.getAddress().toIPv6Address().c)) - ^ std::hash()((uint16_t) sockAddr.getPort()); } else { + // NOTE: if we start to use IPv6 addresses, it's possible their hashing + // can be faster by XORing the hash for each 64 bits in the address return std::hash()(sockAddr.getAddress().toString().toStdString()) ^ std::hash()((uint16_t) sockAddr.getPort()); - } } }; From 3d09f405ed41adb0b31cf1a2b44446989b2938ae Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 11:50:23 -0700 Subject: [PATCH 302/549] fix bad merge for State.h --- libraries/gpu/src/gpu/State.h | 714 +++++++++++++++++----------------- 1 file changed, 357 insertions(+), 357 deletions(-) diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index 8f09669f64..5f2a78690b 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -22,387 +22,387 @@ // Because some of the fields are bool packed tightly in the State::Cache class // and it s just not good anymore for template T& variable manipulation... #define SET_FIELD(field, defaultValue, value, dest) {\ - dest = value;\ - if (value == defaultValue) {\ - _signature.reset(field);\ - } else {\ - _signature.set(field);\ - }\ - _stamp++;\ +dest = value;\ +if (value == defaultValue) {\ +_signature.reset(field);\ +} else {\ +_signature.set(field);\ +}\ +_stamp++;\ }\ namespace gpu { - -class GPUObject; - -class State { -public: - State(); - virtual ~State(); - - Stamp getStamp() const { return _stamp; } - - typedef ::gpu::ComparisonFunction ComparisonFunction; - - enum FillMode { - FILL_POINT = 0, - FILL_LINE, - FILL_FACE, - - NUM_FILL_MODES, - }; - - enum CullMode { - CULL_NONE = 0, - CULL_FRONT, - CULL_BACK, - - NUM_CULL_MODES, - }; - - enum StencilOp { - STENCIL_OP_KEEP = 0, - STENCIL_OP_ZERO, - STENCIL_OP_REPLACE, - STENCIL_OP_INCR_SAT, - STENCIL_OP_DECR_SAT, - STENCIL_OP_INVERT, - STENCIL_OP_INCR, - STENCIL_OP_DECR, - - NUM_STENCIL_OPS, - }; - - enum BlendArg { - ZERO = 0, - ONE, - SRC_COLOR, - INV_SRC_COLOR, - SRC_ALPHA, - INV_SRC_ALPHA, - DEST_ALPHA, - INV_DEST_ALPHA, - DEST_COLOR, - INV_DEST_COLOR, - SRC_ALPHA_SAT, - FACTOR_COLOR, - INV_FACTOR_COLOR, - FACTOR_ALPHA, - INV_FACTOR_ALPHA, - - NUM_BLEND_ARGS, - }; - - enum BlendOp { - BLEND_OP_ADD = 0, - BLEND_OP_SUBTRACT, - BLEND_OP_REV_SUBTRACT, - BLEND_OP_MIN, - BLEND_OP_MAX, - - NUM_BLEND_OPS, - }; - - enum ColorMask - { - WRITE_NONE = 0, - WRITE_RED = 1, - WRITE_GREEN = 2, - WRITE_BLUE = 4, - WRITE_ALPHA = 8, - WRITE_ALL = (WRITE_RED | WRITE_GREEN | WRITE_BLUE | WRITE_ALPHA ), - }; - - class DepthTest { - uint8 _function = LESS; - uint8 _writeMask = true; - uint8 _enabled = false; - uint8 _spare = 0; + + class GPUObject; + + class State { public: - DepthTest(bool enabled = false, bool writeMask = true, ComparisonFunction func = LESS) : + State(); + virtual ~State(); + + Stamp getStamp() const { return _stamp; } + + typedef ::gpu::ComparisonFunction ComparisonFunction; + + enum FillMode { + FILL_POINT = 0, + FILL_LINE, + FILL_FACE, + + NUM_FILL_MODES, + }; + + enum CullMode { + CULL_NONE = 0, + CULL_FRONT, + CULL_BACK, + + NUM_CULL_MODES, + }; + + enum StencilOp { + STENCIL_OP_KEEP = 0, + STENCIL_OP_ZERO, + STENCIL_OP_REPLACE, + STENCIL_OP_INCR_SAT, + STENCIL_OP_DECR_SAT, + STENCIL_OP_INVERT, + STENCIL_OP_INCR, + STENCIL_OP_DECR, + + NUM_STENCIL_OPS, + }; + + enum BlendArg { + ZERO = 0, + ONE, + SRC_COLOR, + INV_SRC_COLOR, + SRC_ALPHA, + INV_SRC_ALPHA, + DEST_ALPHA, + INV_DEST_ALPHA, + DEST_COLOR, + INV_DEST_COLOR, + SRC_ALPHA_SAT, + FACTOR_COLOR, + INV_FACTOR_COLOR, + FACTOR_ALPHA, + INV_FACTOR_ALPHA, + + NUM_BLEND_ARGS, + }; + + enum BlendOp { + BLEND_OP_ADD = 0, + BLEND_OP_SUBTRACT, + BLEND_OP_REV_SUBTRACT, + BLEND_OP_MIN, + BLEND_OP_MAX, + + NUM_BLEND_OPS, + }; + + enum ColorMask + { + WRITE_NONE = 0, + WRITE_RED = 1, + WRITE_GREEN = 2, + WRITE_BLUE = 4, + WRITE_ALPHA = 8, + WRITE_ALL = (WRITE_RED | WRITE_GREEN | WRITE_BLUE | WRITE_ALPHA ), + }; + + class DepthTest { + uint8 _function = LESS; + uint8 _writeMask = true; + uint8 _enabled = false; + uint8 _spare = 0; + public: + DepthTest(bool enabled = false, bool writeMask = true, ComparisonFunction func = LESS) : _function(func), _writeMask(writeMask), _enabled(enabled) {} - - bool isEnabled() const { return _enabled != 0; } - ComparisonFunction getFunction() const { return ComparisonFunction(_function); } - uint8 getWriteMask() const { return _writeMask; } - - int32 getRaw() const { return *(reinterpret_cast(this)); } - DepthTest(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const DepthTest& right) const { return getRaw() == right.getRaw(); } - bool operator!= (const DepthTest& right) const { return getRaw() != right.getRaw(); } - }; - - class StencilTest { - static const int FUNC_MASK = 0x000f; - static const int FAIL_OP_MASK = 0x00f0; - static const int DEPTH_FAIL_OP_MASK = 0x0f00; - static const int PASS_OP_MASK = 0xf000; - static const int FAIL_OP_OFFSET = 4; - static const int DEPTH_FAIL_OP_OFFSET = 8; - static const int PASS_OP_OFFSET = 12; - - uint16 _functionAndOperations; - uint8 _reference = 0; - uint8 _readMask = 0xff; - public: - - StencilTest(uint8 reference = 0, uint8 readMask =0xFF, ComparisonFunction func = ALWAYS, StencilOp failOp = STENCIL_OP_KEEP, StencilOp depthFailOp = STENCIL_OP_KEEP, StencilOp passOp = STENCIL_OP_KEEP) : - _functionAndOperations(func | (failOp << FAIL_OP_OFFSET) | (depthFailOp << DEPTH_FAIL_OP_OFFSET) | (passOp << PASS_OP_OFFSET)), + + bool isEnabled() const { return _enabled != 0; } + ComparisonFunction getFunction() const { return ComparisonFunction(_function); } + uint8 getWriteMask() const { return _writeMask; } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + DepthTest(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const DepthTest& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const DepthTest& right) const { return getRaw() != right.getRaw(); } + }; + + class StencilTest { + static const int FUNC_MASK = 0x000f; + static const int FAIL_OP_MASK = 0x00f0; + static const int DEPTH_FAIL_OP_MASK = 0x0f00; + static const int PASS_OP_MASK = 0xf000; + static const int FAIL_OP_OFFSET = 4; + static const int DEPTH_FAIL_OP_OFFSET = 8; + static const int PASS_OP_OFFSET = 12; + + uint16 _functionAndOperations; + uint8 _reference = 0; + uint8 _readMask = 0xff; + public: + + StencilTest(uint8 reference = 0, uint8 readMask =0xFF, ComparisonFunction func = ALWAYS, StencilOp failOp = STENCIL_OP_KEEP, StencilOp depthFailOp = STENCIL_OP_KEEP, StencilOp passOp = STENCIL_OP_KEEP) : + _functionAndOperations(func | (failOp << FAIL_OP_OFFSET) | (depthFailOp << DEPTH_FAIL_OP_OFFSET) | (passOp << PASS_OP_OFFSET)), _reference(reference), _readMask(readMask) {} - - ComparisonFunction getFunction() const { return ComparisonFunction(_functionAndOperations & FUNC_MASK); } - StencilOp getFailOp() const { return StencilOp((_functionAndOperations & FAIL_OP_MASK) >> FAIL_OP_OFFSET); } - StencilOp getDepthFailOp() const { return StencilOp((_functionAndOperations & DEPTH_FAIL_OP_MASK) >> DEPTH_FAIL_OP_OFFSET); } - StencilOp getPassOp() const { return StencilOp((_functionAndOperations & PASS_OP_MASK) >> PASS_OP_OFFSET); } - - uint8 getReference() const { return _reference; } - uint8 getReadMask() const { return _readMask; } - - int32 getRaw() const { return *(reinterpret_cast(this)); } - StencilTest(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const StencilTest& right) const { return getRaw() == right.getRaw(); } - bool operator!= (const StencilTest& right) const { return getRaw() != right.getRaw(); } - }; - - class StencilActivation { - uint8 _frontWriteMask = 0xFF; - uint8 _backWriteMask = 0xFF; - uint16 _enabled = 0; - public: - - StencilActivation(bool enabled, uint8 frontWriteMask = 0xFF, uint8 backWriteMask = 0xFF) : + + ComparisonFunction getFunction() const { return ComparisonFunction(_functionAndOperations & FUNC_MASK); } + StencilOp getFailOp() const { return StencilOp((_functionAndOperations & FAIL_OP_MASK) >> FAIL_OP_OFFSET); } + StencilOp getDepthFailOp() const { return StencilOp((_functionAndOperations & DEPTH_FAIL_OP_MASK) >> DEPTH_FAIL_OP_OFFSET); } + StencilOp getPassOp() const { return StencilOp((_functionAndOperations & PASS_OP_MASK) >> PASS_OP_OFFSET); } + + uint8 getReference() const { return _reference; } + uint8 getReadMask() const { return _readMask; } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + StencilTest(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const StencilTest& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const StencilTest& right) const { return getRaw() != right.getRaw(); } + }; + + class StencilActivation { + uint8 _frontWriteMask = 0xFF; + uint8 _backWriteMask = 0xFF; + uint16 _enabled = 0; + public: + + StencilActivation(bool enabled, uint8 frontWriteMask = 0xFF, uint8 backWriteMask = 0xFF) : _frontWriteMask(frontWriteMask), _backWriteMask(backWriteMask), _enabled(enabled) {} - - bool isEnabled() const { return (_enabled != 0); } - uint8 getWriteMaskFront() const { return _frontWriteMask; } - uint8 getWriteMaskBack() const { return _backWriteMask; } - - int32 getRaw() const { return *(reinterpret_cast(this)); } - StencilActivation(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const StencilActivation& right) const { return getRaw() == right.getRaw(); } - bool operator!= (const StencilActivation& right) const { return getRaw() != right.getRaw(); } - }; - - class BlendFunction { - static const int COLOR_MASK = 0x0f; - static const int ALPHA_MASK = 0xf0; - static const int ALPHA_OFFSET = 4; - - uint8 _enabled; - uint8 _source; - uint8 _destination; - uint8 _operation; - public: - - BlendFunction(bool enabled, - BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, - BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) : + + bool isEnabled() const { return (_enabled != 0); } + uint8 getWriteMaskFront() const { return _frontWriteMask; } + uint8 getWriteMaskBack() const { return _backWriteMask; } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + StencilActivation(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const StencilActivation& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const StencilActivation& right) const { return getRaw() != right.getRaw(); } + }; + + class BlendFunction { + static const int COLOR_MASK = 0x0f; + static const int ALPHA_MASK = 0xf0; + static const int ALPHA_OFFSET = 4; + + uint8 _enabled; + uint8 _source; + uint8 _destination; + uint8 _operation; + public: + + BlendFunction(bool enabled, + BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, + BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) : _enabled(enabled), _source(sourceColor | (sourceAlpha << ALPHA_OFFSET)), _destination(destinationColor | (destinationAlpha << ALPHA_OFFSET)), _operation(operationColor | (operationAlpha << ALPHA_OFFSET)) {} - - BlendFunction(bool enabled, BlendArg source = ONE, BlendOp operation = BLEND_OP_ADD, BlendArg destination = ZERO) : + + BlendFunction(bool enabled, BlendArg source = ONE, BlendOp operation = BLEND_OP_ADD, BlendArg destination = ZERO) : _enabled(enabled), _source(source | (source << ALPHA_OFFSET)), _destination(destination | (destination << ALPHA_OFFSET)), _operation(operation | (operation << ALPHA_OFFSET)) {} - - bool isEnabled() const { return (_enabled != 0); } - - BlendArg getSourceColor() const { return BlendArg(_source & COLOR_MASK); } - BlendArg getDestinationColor() const { return BlendArg(_destination & COLOR_MASK); } - BlendOp getOperationColor() const { return BlendOp(_operation & COLOR_MASK); } - - BlendArg getSourceAlpha() const { return BlendArg((_source & ALPHA_MASK) >> ALPHA_OFFSET); } - BlendArg getDestinationAlpha() const { return BlendArg((_destination & ALPHA_MASK) >> ALPHA_OFFSET); } - BlendOp getOperationAlpha() const { return BlendOp((_operation & ALPHA_MASK) >> ALPHA_OFFSET); } - - int32 getRaw() const { return *(reinterpret_cast(this)); } - BlendFunction(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const BlendFunction& right) const { return getRaw() == right.getRaw(); } - bool operator!= (const BlendFunction& right) const { return getRaw() != right.getRaw(); } - }; - - // The Data class is the full explicit description of the State class fields value. - // Useful for having one const static called Default for reference or for the gpu::Backend to keep track of the current value - class Data { - public: - float depthBias = 0.0f; - float depthBiasSlopeScale = 0.0f; - - DepthTest depthTest = DepthTest(false, true, LESS); - - StencilActivation stencilActivation = StencilActivation(false); - StencilTest stencilTestFront = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); - StencilTest stencilTestBack = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); - - uint32 sampleMask = 0xFFFFFFFF; - - BlendFunction blendFunction = BlendFunction(false); - - uint8 fillMode = FILL_FACE; - uint8 cullMode = CULL_NONE; - - uint8 colorWriteMask = WRITE_ALL; - - bool frontFaceClockwise : 1; - bool depthClampEnable : 1; - bool scissorEnable : 1; - bool multisampleEnable : 1; - bool antialisedLineEnable : 1; - bool alphaToCoverageEnable : 1; - - Data() : + + bool isEnabled() const { return (_enabled != 0); } + + BlendArg getSourceColor() const { return BlendArg(_source & COLOR_MASK); } + BlendArg getDestinationColor() const { return BlendArg(_destination & COLOR_MASK); } + BlendOp getOperationColor() const { return BlendOp(_operation & COLOR_MASK); } + + BlendArg getSourceAlpha() const { return BlendArg((_source & ALPHA_MASK) >> ALPHA_OFFSET); } + BlendArg getDestinationAlpha() const { return BlendArg((_destination & ALPHA_MASK) >> ALPHA_OFFSET); } + BlendOp getOperationAlpha() const { return BlendOp((_operation & ALPHA_MASK) >> ALPHA_OFFSET); } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + BlendFunction(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const BlendFunction& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const BlendFunction& right) const { return getRaw() != right.getRaw(); } + }; + + // The Data class is the full explicit description of the State class fields value. + // Useful for having one const static called Default for reference or for the gpu::Backend to keep track of the current value + class Data { + public: + float depthBias = 0.0f; + float depthBiasSlopeScale = 0.0f; + + DepthTest depthTest = DepthTest(false, true, LESS); + + StencilActivation stencilActivation = StencilActivation(false); + StencilTest stencilTestFront = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); + StencilTest stencilTestBack = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); + + uint32 sampleMask = 0xFFFFFFFF; + + BlendFunction blendFunction = BlendFunction(false); + + uint8 fillMode = FILL_FACE; + uint8 cullMode = CULL_NONE; + + uint8 colorWriteMask = WRITE_ALL; + + bool frontFaceClockwise : 1; + bool depthClampEnable : 1; + bool scissorEnable : 1; + bool multisampleEnable : 1; + bool antialisedLineEnable : 1; + bool alphaToCoverageEnable : 1; + + Data() : frontFaceClockwise(false), depthClampEnable(false), scissorEnable(false), multisampleEnable(false), antialisedLineEnable(true), alphaToCoverageEnable(false) - {} + {} + }; + + // The unique default values for all the fields + static const Data DEFAULT; + void setFillMode(FillMode fill) { SET_FIELD(FILL_MODE, DEFAULT.fillMode, fill, _values.fillMode); } + FillMode getFillMode() const { return FillMode(_values.fillMode); } + + void setCullMode(CullMode cull) { SET_FIELD(CULL_MODE, DEFAULT.cullMode, cull, _values.cullMode); } + CullMode getCullMode() const { return CullMode(_values.cullMode); } + + void setFrontFaceClockwise(bool isClockwise) { SET_FIELD(FRONT_FACE_CLOCKWISE, DEFAULT.frontFaceClockwise, isClockwise, _values.frontFaceClockwise); } + bool isFrontFaceClockwise() const { return _values.frontFaceClockwise; } + + void setDepthClampEnable(bool enable) { SET_FIELD(DEPTH_CLAMP_ENABLE, DEFAULT.depthClampEnable, enable, _values.depthClampEnable); } + bool isDepthClampEnable() const { return _values.depthClampEnable; } + + void setScissorEnable(bool enable) { SET_FIELD(SCISSOR_ENABLE, DEFAULT.scissorEnable, enable, _values.scissorEnable); } + bool isScissorEnable() const { return _values.scissorEnable; } + + void setMultisampleEnable(bool enable) { SET_FIELD(MULTISAMPLE_ENABLE, DEFAULT.multisampleEnable, enable, _values.multisampleEnable); } + bool isMultisampleEnable() const { return _values.multisampleEnable; } + + void setAntialiasedLineEnable(bool enable) { SET_FIELD(ANTIALISED_LINE_ENABLE, DEFAULT.antialisedLineEnable, enable, _values.antialisedLineEnable); } + bool isAntialiasedLineEnable() const { return _values.antialisedLineEnable; } + + // Depth Bias + void setDepthBias(float bias) { SET_FIELD(DEPTH_BIAS, DEFAULT.depthBias, bias, _values.depthBias); } + float getDepthBias() const { return _values.depthBias; } + + void setDepthBiasSlopeScale(float scale) { SET_FIELD(DEPTH_BIAS_SLOPE_SCALE, DEFAULT.depthBiasSlopeScale, scale, _values.depthBiasSlopeScale); } + float getDepthBiasSlopeScale() const { return _values.depthBiasSlopeScale; } + + // Depth Test + void setDepthTest(DepthTest depthTest) { SET_FIELD(DEPTH_TEST, DEFAULT.depthTest, depthTest, _values.depthTest); } + void setDepthTest(bool enable, bool writeMask, ComparisonFunction func) { setDepthTest(DepthTest(enable, writeMask, func)); } + DepthTest getDepthTest() const { return _values.depthTest; } + + bool isDepthTestEnabled() const { return getDepthTest().isEnabled(); } + uint8 getDepthTestWriteMask() const { return getDepthTest().getWriteMask(); } + ComparisonFunction getDepthTestFunc() const { return getDepthTest().getFunction(); } + + // Stencil test + void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest, uint8 backWriteMask, StencilTest backTest) { + SET_FIELD(STENCIL_ACTIVATION, DEFAULT.stencilActivation, StencilActivation(enabled, frontWriteMask, backWriteMask), _values.stencilActivation); + SET_FIELD(STENCIL_TEST_FRONT, DEFAULT.stencilTestFront, frontTest, _values.stencilTestFront); + SET_FIELD(STENCIL_TEST_BACK, DEFAULT.stencilTestBack, backTest, _values.stencilTestBack); } + void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest) { + setStencilTest(enabled, frontWriteMask, frontTest, frontWriteMask, frontTest); } + + StencilActivation getStencilActivation() const { return _values.stencilActivation; } + StencilTest getStencilTestFront() const { return _values.stencilTestFront; } + StencilTest getStencilTestBack() const { return _values.stencilTestBack; } + + bool isStencilEnabled() const { return getStencilActivation().isEnabled(); } + uint8 getStencilWriteMaskFront() const { return getStencilActivation().getWriteMaskFront(); } + uint8 getStencilWriteMaskBack() const { return getStencilActivation().getWriteMaskBack(); } + + // Alpha to coverage + void setAlphaToCoverageEnable(bool enable) { SET_FIELD(ALPHA_TO_COVERAGE_ENABLE, DEFAULT.alphaToCoverageEnable, enable, _values.alphaToCoverageEnable); } + bool isAlphaToCoverageEnabled() const { return _values.alphaToCoverageEnable; } + + // Sample mask + void setSampleMask(uint32 mask) { SET_FIELD(SAMPLE_MASK, DEFAULT.sampleMask, mask, _values.sampleMask); } + uint32 getSampleMask() const { return _values.sampleMask; } + + // Blend Function + void setBlendFunction(BlendFunction function) { SET_FIELD(BLEND_FUNCTION, DEFAULT.blendFunction, function, _values.blendFunction); } + BlendFunction getBlendFunction() const { return _values.blendFunction; } + + void setBlendFunction(bool enabled, BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) { + setBlendFunction(BlendFunction(enabled, sourceColor, operationColor, destinationColor, sourceAlpha, operationAlpha, destinationAlpha)); } + void setBlendFunction(bool enabled, BlendArg source, BlendOp operation, BlendArg destination) { + setBlendFunction(BlendFunction(enabled, source, operation, destination)); } + + bool isBlendEnabled() const { return getBlendFunction().isEnabled(); } + + // Color write mask + void setColorWriteMask(uint8 mask) { SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, mask, _values.colorWriteMask); } + void setColorWriteMask(bool red, bool green, bool blue, bool alpha) { uint32 value = ((WRITE_RED * red) | (WRITE_GREEN * green) | (WRITE_BLUE * blue) | (WRITE_ALPHA * alpha)); SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, value, _values.colorWriteMask); } + uint8 getColorWriteMask() const { return _values.colorWriteMask; } + + // All the possible fields + enum Field { + FILL_MODE, + CULL_MODE, + FRONT_FACE_CLOCKWISE, + DEPTH_CLAMP_ENABLE, + SCISSOR_ENABLE, + MULTISAMPLE_ENABLE, + ANTIALISED_LINE_ENABLE, + + DEPTH_BIAS, + DEPTH_BIAS_SLOPE_SCALE, + + DEPTH_TEST, + + STENCIL_ACTIVATION, + STENCIL_TEST_FRONT, + STENCIL_TEST_BACK, + + SAMPLE_MASK, + ALPHA_TO_COVERAGE_ENABLE, + + BLEND_FUNCTION, + + COLOR_WRITE_MASK, + + NUM_FIELDS, // not a valid field, just the count + }; + + // The signature of the state tells which fields of the state are not default + // this way during rendering the Backend can compare it's current state and try to minimize the job to do + typedef std::bitset Signature; + + Signature getSignature() const { return _signature; } + + static Signature evalSignature(const Data& state); + + // For convenience, create a State from the values directly + State(const Data& values); + const Data& getValues() const { return _values; } + + protected: + State(const State& state); + State& operator=(const State& state); + + Data _values; + Signature _signature{0}; + Stamp _stamp{0}; + + // This shouldn't be used by anything else than the Backend class with the proper casting. + mutable GPUObject* _gpuObject = nullptr; + void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } + GPUObject* getGPUObject() const { return _gpuObject; } + friend class Backend; }; - - // The unique default values for all the fields - static const Data DEFAULT; - void setFillMode(FillMode fill) { SET_FIELD(FILL_MODE, DEFAULT.fillMode, fill, _values.fillMode); } - FillMode getFillMode() const { return FillMode(_values.fillMode); } - - void setCullMode(CullMode cull) { SET_FIELD(CULL_MODE, DEFAULT.cullMode, cull, _values.cullMode); } - CullMode getCullMode() const { return CullMode(_values.cullMode); } - - void setFrontFaceClockwise(bool isClockwise) { SET_FIELD(FRONT_FACE_CLOCKWISE, DEFAULT.frontFaceClockwise, isClockwise, _values.frontFaceClockwise); } - bool isFrontFaceClockwise() const { return _values.frontFaceClockwise; } - - void setDepthClampEnable(bool enable) { SET_FIELD(DEPTH_CLAMP_ENABLE, DEFAULT.depthClampEnable, enable, _values.depthClampEnable); } - bool isDepthClampEnable() const { return _values.depthClampEnable; } - - void setScissorEnable(bool enable) { SET_FIELD(SCISSOR_ENABLE, DEFAULT.scissorEnable, enable, _values.scissorEnable); } - bool isScissorEnable() const { return _values.scissorEnable; } - - void setMultisampleEnable(bool enable) { SET_FIELD(MULTISAMPLE_ENABLE, DEFAULT.multisampleEnable, enable, _values.multisampleEnable); } - bool isMultisampleEnable() const { return _values.multisampleEnable; } - - void setAntialiasedLineEnable(bool enable) { SET_FIELD(ANTIALISED_LINE_ENABLE, DEFAULT.antialisedLineEnable, enable, _values.antialisedLineEnable); } - bool isAntialiasedLineEnable() const { return _values.antialisedLineEnable; } - - // Depth Bias - void setDepthBias(float bias) { SET_FIELD(DEPTH_BIAS, DEFAULT.depthBias, bias, _values.depthBias); } - float getDepthBias() const { return _values.depthBias; } - - void setDepthBiasSlopeScale(float scale) { SET_FIELD(DEPTH_BIAS_SLOPE_SCALE, DEFAULT.depthBiasSlopeScale, scale, _values.depthBiasSlopeScale); } - float getDepthBiasSlopeScale() const { return _values.depthBiasSlopeScale; } - - // Depth Test - void setDepthTest(DepthTest depthTest) { SET_FIELD(DEPTH_TEST, DEFAULT.depthTest, depthTest, _values.depthTest); } - void setDepthTest(bool enable, bool writeMask, ComparisonFunction func) { setDepthTest(DepthTest(enable, writeMask, func)); } - DepthTest getDepthTest() const { return _values.depthTest; } - - bool isDepthTestEnabled() const { return getDepthTest().isEnabled(); } - uint8 getDepthTestWriteMask() const { return getDepthTest().getWriteMask(); } - ComparisonFunction getDepthTestFunc() const { return getDepthTest().getFunction(); } - - // Stencil test - void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest, uint8 backWriteMask, StencilTest backTest) { - SET_FIELD(STENCIL_ACTIVATION, DEFAULT.stencilActivation, StencilActivation(enabled, frontWriteMask, backWriteMask), _values.stencilActivation); - SET_FIELD(STENCIL_TEST_FRONT, DEFAULT.stencilTestFront, frontTest, _values.stencilTestFront); - SET_FIELD(STENCIL_TEST_BACK, DEFAULT.stencilTestBack, backTest, _values.stencilTestBack); } - void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest) { - setStencilTest(enabled, frontWriteMask, frontTest, frontWriteMask, frontTest); } - - StencilActivation getStencilActivation() const { return _values.stencilActivation; } - StencilTest getStencilTestFront() const { return _values.stencilTestFront; } - StencilTest getStencilTestBack() const { return _values.stencilTestBack; } - - bool isStencilEnabled() const { return getStencilActivation().isEnabled(); } - uint8 getStencilWriteMaskFront() const { return getStencilActivation().getWriteMaskFront(); } - uint8 getStencilWriteMaskBack() const { return getStencilActivation().getWriteMaskBack(); } - - // Alpha to coverage - void setAlphaToCoverageEnable(bool enable) { SET_FIELD(ALPHA_TO_COVERAGE_ENABLE, DEFAULT.alphaToCoverageEnable, enable, _values.alphaToCoverageEnable); } - bool isAlphaToCoverageEnabled() const { return _values.alphaToCoverageEnable; } - - // Sample mask - void setSampleMask(uint32 mask) { SET_FIELD(SAMPLE_MASK, DEFAULT.sampleMask, mask, _values.sampleMask); } - uint32 getSampleMask() const { return _values.sampleMask; } - - // Blend Function - void setBlendFunction(BlendFunction function) { SET_FIELD(BLEND_FUNCTION, DEFAULT.blendFunction, function, _values.blendFunction); } - BlendFunction getBlendFunction() const { return _values.blendFunction; } - - void setBlendFunction(bool enabled, BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) { - setBlendFunction(BlendFunction(enabled, sourceColor, operationColor, destinationColor, sourceAlpha, operationAlpha, destinationAlpha)); } - void setBlendFunction(bool enabled, BlendArg source, BlendOp operation, BlendArg destination) { - setBlendFunction(BlendFunction(enabled, source, operation, destination)); } - - bool isBlendEnabled() const { return getBlendFunction().isEnabled(); } - - // Color write mask - void setColorWriteMask(uint8 mask) { SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, mask, _values.colorWriteMask); } - void setColorWriteMask(bool red, bool green, bool blue, bool alpha) { uint32 value = ((WRITE_RED * red) | (WRITE_GREEN * green) | (WRITE_BLUE * blue) | (WRITE_ALPHA * alpha)); SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, value, _values.colorWriteMask); } - uint8 getColorWriteMask() const { return _values.colorWriteMask; } - - // All the possible fields - enum Field { - FILL_MODE, - CULL_MODE, - FRONT_FACE_CLOCKWISE, - DEPTH_CLAMP_ENABLE, - SCISSOR_ENABLE, - MULTISAMPLE_ENABLE, - ANTIALISED_LINE_ENABLE, - - DEPTH_BIAS, - DEPTH_BIAS_SLOPE_SCALE, - - DEPTH_TEST, - - STENCIL_ACTIVATION, - STENCIL_TEST_FRONT, - STENCIL_TEST_BACK, - - SAMPLE_MASK, - ALPHA_TO_COVERAGE_ENABLE, - - BLEND_FUNCTION, - - COLOR_WRITE_MASK, - - NUM_FIELDS, // not a valid field, just the count - }; - - // The signature of the state tells which fields of the state are not default - // this way during rendering the Backend can compare it's current state and try to minimize the job to do - typedef std::bitset Signature; - - Signature getSignature() const { return _signature; } - - static Signature evalSignature(const Data& state); - - // For convenience, create a State from the values directly - State(const Data& values); - const Data& getValues() const { return _values; } - -protected: - State(const State& state); - State& operator=(const State& state); - - Data _values; - Signature _signature{0}; - Stamp _stamp{0}; - - // This shouldn't be used by anything else than the Backend class with the proper casting. - mutable GPUObject* _gpuObject = nullptr; - void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } - GPUObject* getGPUObject() const { return _gpuObject; } - friend class Backend; -}; - -typedef std::shared_ptr< State > StatePointer; -typedef std::vector< StatePointer > States; - + + typedef std::shared_ptr< State > StatePointer; + typedef std::vector< StatePointer > States; + }; #endif From aa1c36e61a8472d49abc891be3653f88b985ee23 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 11:51:23 -0700 Subject: [PATCH 303/549] fix State.h after bad merge --- libraries/gpu/src/gpu/State.h | 714 +++++++++++++++++----------------- 1 file changed, 357 insertions(+), 357 deletions(-) diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index 5500f20e06..1c338865db 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -22,387 +22,387 @@ // Because some of the fields are bool packed tightly in the State::Cache class // and it s just not good anymore for template T& variable manipulation... #define SET_FIELD(field, defaultValue, value, dest) {\ - dest = value;\ - if (value == defaultValue) {\ - _signature.reset(field);\ - } else {\ - _signature.set(field);\ - }\ - _stamp++;\ +dest = value;\ +if (value == defaultValue) {\ +_signature.reset(field);\ +} else {\ +_signature.set(field);\ +}\ +_stamp++;\ }\ namespace gpu { - -class GPUObject; - -class State { -public: - State(); - virtual ~State(); - - Stamp getStamp() const { return _stamp; } - - typedef ::gpu::ComparisonFunction ComparisonFunction; - - enum FillMode { - FILL_POINT = 0, - FILL_LINE, - FILL_FACE, - - NUM_FILL_MODES, - }; - - enum CullMode { - CULL_NONE = 0, - CULL_FRONT, - CULL_BACK, - - NUM_CULL_MODES, - }; - - enum StencilOp { - STENCIL_OP_KEEP = 0, - STENCIL_OP_ZERO, - STENCIL_OP_REPLACE, - STENCIL_OP_INCR_SAT, - STENCIL_OP_DECR_SAT, - STENCIL_OP_INVERT, - STENCIL_OP_INCR, - STENCIL_OP_DECR, - - NUM_STENCIL_OPS, - }; - - enum BlendArg { - ZERO = 0, - ONE, - SRC_COLOR, - INV_SRC_COLOR, - SRC_ALPHA, - INV_SRC_ALPHA, - DEST_ALPHA, - INV_DEST_ALPHA, - DEST_COLOR, - INV_DEST_COLOR, - SRC_ALPHA_SAT, - FACTOR_COLOR, - INV_FACTOR_COLOR, - FACTOR_ALPHA, - INV_FACTOR_ALPHA, - - NUM_BLEND_ARGS, - }; - - enum BlendOp { - BLEND_OP_ADD = 0, - BLEND_OP_SUBTRACT, - BLEND_OP_REV_SUBTRACT, - BLEND_OP_MIN, - BLEND_OP_MAX, - - NUM_BLEND_OPS, - }; - - enum ColorMask - { - WRITE_NONE = 0, - WRITE_RED = 1, - WRITE_GREEN = 2, - WRITE_BLUE = 4, - WRITE_ALPHA = 8, - WRITE_ALL = (WRITE_RED | WRITE_GREEN | WRITE_BLUE | WRITE_ALPHA ), - }; - - class DepthTest { - uint8 _function = LESS; - uint8 _writeMask = true; - uint8 _enabled = false; - uint8 _spare = 0; + + class GPUObject; + + class State { public: - DepthTest(bool enabled = false, bool writeMask = true, ComparisonFunction func = LESS) : + State(); + virtual ~State(); + + Stamp getStamp() const { return _stamp; } + + typedef ::gpu::ComparisonFunction ComparisonFunction; + + enum FillMode { + FILL_POINT = 0, + FILL_LINE, + FILL_FACE, + + NUM_FILL_MODES, + }; + + enum CullMode { + CULL_NONE = 0, + CULL_FRONT, + CULL_BACK, + + NUM_CULL_MODES, + }; + + enum StencilOp { + STENCIL_OP_KEEP = 0, + STENCIL_OP_ZERO, + STENCIL_OP_REPLACE, + STENCIL_OP_INCR_SAT, + STENCIL_OP_DECR_SAT, + STENCIL_OP_INVERT, + STENCIL_OP_INCR, + STENCIL_OP_DECR, + + NUM_STENCIL_OPS, + }; + + enum BlendArg { + ZERO = 0, + ONE, + SRC_COLOR, + INV_SRC_COLOR, + SRC_ALPHA, + INV_SRC_ALPHA, + DEST_ALPHA, + INV_DEST_ALPHA, + DEST_COLOR, + INV_DEST_COLOR, + SRC_ALPHA_SAT, + FACTOR_COLOR, + INV_FACTOR_COLOR, + FACTOR_ALPHA, + INV_FACTOR_ALPHA, + + NUM_BLEND_ARGS, + }; + + enum BlendOp { + BLEND_OP_ADD = 0, + BLEND_OP_SUBTRACT, + BLEND_OP_REV_SUBTRACT, + BLEND_OP_MIN, + BLEND_OP_MAX, + + NUM_BLEND_OPS, + }; + + enum ColorMask + { + WRITE_NONE = 0, + WRITE_RED = 1, + WRITE_GREEN = 2, + WRITE_BLUE = 4, + WRITE_ALPHA = 8, + WRITE_ALL = (WRITE_RED | WRITE_GREEN | WRITE_BLUE | WRITE_ALPHA ), + }; + + class DepthTest { + uint8 _function = LESS; + uint8 _writeMask = true; + uint8 _enabled = false; + uint8 _spare = 0; + public: + DepthTest(bool enabled = false, bool writeMask = true, ComparisonFunction func = LESS) : _function(func), _writeMask(writeMask), _enabled(enabled) {} - - bool isEnabled() const { return _enabled != 0; } - ComparisonFunction getFunction() const { return ComparisonFunction(_function); } - uint8 getWriteMask() const { return _writeMask; } - - int32 getRaw() const { return *(reinterpret_cast(this)); } - DepthTest(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const DepthTest& right) const { return getRaw() == right.getRaw(); } - bool operator!= (const DepthTest& right) const { return getRaw() != right.getRaw(); } - }; - - class StencilTest { - static const int FUNC_MASK = 0x000f; - static const int FAIL_OP_MASK = 0x00f0; - static const int DEPTH_FAIL_OP_MASK = 0x0f00; - static const int PASS_OP_MASK = 0xf000; - static const int FAIL_OP_OFFSET = 4; - static const int DEPTH_FAIL_OP_OFFSET = 8; - static const int PASS_OP_OFFSET = 12; - - uint16 _functionAndOperations; - uint8 _reference = 0; - uint8 _readMask = 0xff; - public: - - StencilTest(uint8 reference = 0, uint8 readMask =0xFF, ComparisonFunction func = ALWAYS, StencilOp failOp = STENCIL_OP_KEEP, StencilOp depthFailOp = STENCIL_OP_KEEP, StencilOp passOp = STENCIL_OP_KEEP) : - _functionAndOperations(func | (failOp << FAIL_OP_OFFSET) | (depthFailOp << DEPTH_FAIL_OP_OFFSET) | (passOp << PASS_OP_OFFSET)), + + bool isEnabled() const { return _enabled != 0; } + ComparisonFunction getFunction() const { return ComparisonFunction(_function); } + uint8 getWriteMask() const { return _writeMask; } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + DepthTest(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const DepthTest& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const DepthTest& right) const { return getRaw() != right.getRaw(); } + }; + + class StencilTest { + static const int FUNC_MASK = 0x000f; + static const int FAIL_OP_MASK = 0x00f0; + static const int DEPTH_FAIL_OP_MASK = 0x0f00; + static const int PASS_OP_MASK = 0xf000; + static const int FAIL_OP_OFFSET = 4; + static const int DEPTH_FAIL_OP_OFFSET = 8; + static const int PASS_OP_OFFSET = 12; + + uint16 _functionAndOperations; + uint8 _reference = 0; + uint8 _readMask = 0xff; + public: + + StencilTest(uint8 reference = 0, uint8 readMask =0xFF, ComparisonFunction func = ALWAYS, StencilOp failOp = STENCIL_OP_KEEP, StencilOp depthFailOp = STENCIL_OP_KEEP, StencilOp passOp = STENCIL_OP_KEEP) : + _functionAndOperations(func | (failOp << FAIL_OP_OFFSET) | (depthFailOp << DEPTH_FAIL_OP_OFFSET) | (passOp << PASS_OP_OFFSET)), _reference(reference), _readMask(readMask) {} - - ComparisonFunction getFunction() const { return ComparisonFunction(_functionAndOperations & FUNC_MASK); } - StencilOp getFailOp() const { return StencilOp((_functionAndOperations & FAIL_OP_MASK) >> FAIL_OP_OFFSET); } - StencilOp getDepthFailOp() const { return StencilOp((_functionAndOperations & DEPTH_FAIL_OP_MASK) >> DEPTH_FAIL_OP_OFFSET); } - StencilOp getPassOp() const { return StencilOp((_functionAndOperations & PASS_OP_MASK) >> PASS_OP_OFFSET); } - - uint8 getReference() const { return _reference; } - uint8 getReadMask() const { return _readMask; } - - int32 getRaw() const { return *(reinterpret_cast(this)); } - StencilTest(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const StencilTest& right) const { return getRaw() == right.getRaw(); } - bool operator!= (const StencilTest& right) const { return getRaw() != right.getRaw(); } - }; - - class StencilActivation { - uint8 _frontWriteMask = 0xFF; - uint8 _backWriteMask = 0xFF; - uint16 _enabled = 0; - public: - - StencilActivation(bool enabled, uint8 frontWriteMask = 0xFF, uint8 backWriteMask = 0xFF) : + + ComparisonFunction getFunction() const { return ComparisonFunction(_functionAndOperations & FUNC_MASK); } + StencilOp getFailOp() const { return StencilOp((_functionAndOperations & FAIL_OP_MASK) >> FAIL_OP_OFFSET); } + StencilOp getDepthFailOp() const { return StencilOp((_functionAndOperations & DEPTH_FAIL_OP_MASK) >> DEPTH_FAIL_OP_OFFSET); } + StencilOp getPassOp() const { return StencilOp((_functionAndOperations & PASS_OP_MASK) >> PASS_OP_OFFSET); } + + uint8 getReference() const { return _reference; } + uint8 getReadMask() const { return _readMask; } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + StencilTest(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const StencilTest& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const StencilTest& right) const { return getRaw() != right.getRaw(); } + }; + + class StencilActivation { + uint8 _frontWriteMask = 0xFF; + uint8 _backWriteMask = 0xFF; + uint16 _enabled = 0; + public: + + StencilActivation(bool enabled, uint8 frontWriteMask = 0xFF, uint8 backWriteMask = 0xFF) : _frontWriteMask(frontWriteMask), _backWriteMask(backWriteMask), _enabled(enabled) {} - - bool isEnabled() const { return (_enabled != 0); } - uint8 getWriteMaskFront() const { return _frontWriteMask; } - uint8 getWriteMaskBack() const { return _backWriteMask; } - - int32 getRaw() const { return *(reinterpret_cast(this)); } - StencilActivation(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const StencilActivation& right) const { return getRaw() == right.getRaw(); } - bool operator!= (const StencilActivation& right) const { return getRaw() != right.getRaw(); } - }; - - class BlendFunction { - static const int COLOR_MASK = 0x0f; - static const int ALPHA_MASK = 0xf0; - static const int ALPHA_OFFSET = 4; - - uint8 _enabled; - uint8 _source; - uint8 _destination; - uint8 _operation; - public: - - BlendFunction(bool enabled, - BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, - BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) : + + bool isEnabled() const { return (_enabled != 0); } + uint8 getWriteMaskFront() const { return _frontWriteMask; } + uint8 getWriteMaskBack() const { return _backWriteMask; } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + StencilActivation(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const StencilActivation& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const StencilActivation& right) const { return getRaw() != right.getRaw(); } + }; + + class BlendFunction { + static const int COLOR_MASK = 0x0f; + static const int ALPHA_MASK = 0xf0; + static const int ALPHA_OFFSET = 4; + + uint8 _enabled; + uint8 _source; + uint8 _destination; + uint8 _operation; + public: + + BlendFunction(bool enabled, + BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, + BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) : _enabled(enabled), _source(sourceColor | (sourceAlpha << ALPHA_OFFSET)), _destination(destinationColor | (destinationAlpha << ALPHA_OFFSET)), _operation(operationColor | (operationAlpha << ALPHA_OFFSET)) {} - - BlendFunction(bool enabled, BlendArg source = ONE, BlendOp operation = BLEND_OP_ADD, BlendArg destination = ZERO) : + + BlendFunction(bool enabled, BlendArg source = ONE, BlendOp operation = BLEND_OP_ADD, BlendArg destination = ZERO) : _enabled(enabled), _source(source | (source << ALPHA_OFFSET)), _destination(destination | (destination << ALPHA_OFFSET)), _operation(operation | (operation << ALPHA_OFFSET)) {} - - bool isEnabled() const { return (_enabled != 0); } - - BlendArg getSourceColor() const { return BlendArg(_source & COLOR_MASK); } - BlendArg getDestinationColor() const { return BlendArg(_destination & COLOR_MASK); } - BlendOp getOperationColor() const { return BlendOp(_operation & COLOR_MASK); } - - BlendArg getSourceAlpha() const { return BlendArg((_source & ALPHA_MASK) >> ALPHA_OFFSET); } - BlendArg getDestinationAlpha() const { return BlendArg((_destination & ALPHA_MASK) >> ALPHA_OFFSET); } - BlendOp getOperationAlpha() const { return BlendOp((_operation & ALPHA_MASK) >> ALPHA_OFFSET); } - - int32 getRaw() const { return *(reinterpret_cast(this)); } - BlendFunction(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const BlendFunction& right) const { return getRaw() == right.getRaw(); } - bool operator!= (const BlendFunction& right) const { return getRaw() != right.getRaw(); } - }; - - // The Data class is the full explicit description of the State class fields value. - // Useful for having one const static called Default for reference or for the gpu::Backend to keep track of the current value - class Data { - public: - float depthBias = 0.0f; - float depthBiasSlopeScale = 0.0f; - - DepthTest depthTest = DepthTest(false, true, LESS); - - StencilActivation stencilActivation = StencilActivation(false); - StencilTest stencilTestFront = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); - StencilTest stencilTestBack = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); - - uint32 sampleMask = 0xFFFFFFFF; - - BlendFunction blendFunction = BlendFunction(false); - - uint8 fillMode = FILL_FACE; - uint8 cullMode = CULL_NONE; - - uint8 colorWriteMask = WRITE_ALL; - - bool frontFaceClockwise : 1; - bool depthClampEnable : 1; - bool scissorEnable : 1; - bool multisampleEnable : 1; - bool antialisedLineEnable : 1; - bool alphaToCoverageEnable : 1; - - Data() : + + bool isEnabled() const { return (_enabled != 0); } + + BlendArg getSourceColor() const { return BlendArg(_source & COLOR_MASK); } + BlendArg getDestinationColor() const { return BlendArg(_destination & COLOR_MASK); } + BlendOp getOperationColor() const { return BlendOp(_operation & COLOR_MASK); } + + BlendArg getSourceAlpha() const { return BlendArg((_source & ALPHA_MASK) >> ALPHA_OFFSET); } + BlendArg getDestinationAlpha() const { return BlendArg((_destination & ALPHA_MASK) >> ALPHA_OFFSET); } + BlendOp getOperationAlpha() const { return BlendOp((_operation & ALPHA_MASK) >> ALPHA_OFFSET); } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + BlendFunction(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const BlendFunction& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const BlendFunction& right) const { return getRaw() != right.getRaw(); } + }; + + // The Data class is the full explicit description of the State class fields value. + // Useful for having one const static called Default for reference or for the gpu::Backend to keep track of the current value + class Data { + public: + float depthBias = 0.0f; + float depthBiasSlopeScale = 0.0f; + + DepthTest depthTest = DepthTest(false, true, LESS); + + StencilActivation stencilActivation = StencilActivation(false); + StencilTest stencilTestFront = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); + StencilTest stencilTestBack = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); + + uint32 sampleMask = 0xFFFFFFFF; + + BlendFunction blendFunction = BlendFunction(false); + + uint8 fillMode = FILL_FACE; + uint8 cullMode = CULL_NONE; + + uint8 colorWriteMask = WRITE_ALL; + + bool frontFaceClockwise : 1; + bool depthClampEnable : 1; + bool scissorEnable : 1; + bool multisampleEnable : 1; + bool antialisedLineEnable : 1; + bool alphaToCoverageEnable : 1; + + Data() : frontFaceClockwise(false), depthClampEnable(false), scissorEnable(false), multisampleEnable(false), antialisedLineEnable(true), alphaToCoverageEnable(false) - {} + {} + }; + + // The unique default values for all the fields + static const Data DEFAULT; + void setFillMode(FillMode fill) { SET_FIELD(FILL_MODE, DEFAULT.fillMode, fill, _values.fillMode); } + FillMode getFillMode() const { return FillMode(_values.fillMode); } + + void setCullMode(CullMode cull) { SET_FIELD(CULL_MODE, DEFAULT.cullMode, cull, _values.cullMode); } + CullMode getCullMode() const { return CullMode(_values.cullMode); } + + void setFrontFaceClockwise(bool isClockwise) { SET_FIELD(FRONT_FACE_CLOCKWISE, DEFAULT.frontFaceClockwise, isClockwise, _values.frontFaceClockwise); } + bool isFrontFaceClockwise() const { return _values.frontFaceClockwise; } + + void setDepthClampEnable(bool enable) { SET_FIELD(DEPTH_CLAMP_ENABLE, DEFAULT.depthClampEnable, enable, _values.depthClampEnable); } + bool isDepthClampEnable() const { return _values.depthClampEnable; } + + void setScissorEnable(bool enable) { SET_FIELD(SCISSOR_ENABLE, DEFAULT.scissorEnable, enable, _values.scissorEnable); } + bool isScissorEnable() const { return _values.scissorEnable; } + + void setMultisampleEnable(bool enable) { SET_FIELD(MULTISAMPLE_ENABLE, DEFAULT.multisampleEnable, enable, _values.multisampleEnable); } + bool isMultisampleEnable() const { return _values.multisampleEnable; } + + void setAntialiasedLineEnable(bool enable) { SET_FIELD(ANTIALISED_LINE_ENABLE, DEFAULT.antialisedLineEnable, enable, _values.antialisedLineEnable); } + bool isAntialiasedLineEnable() const { return _values.antialisedLineEnable; } + + // Depth Bias + void setDepthBias(float bias) { SET_FIELD(DEPTH_BIAS, DEFAULT.depthBias, bias, _values.depthBias); } + float getDepthBias() const { return _values.depthBias; } + + void setDepthBiasSlopeScale(float scale) { SET_FIELD(DEPTH_BIAS_SLOPE_SCALE, DEFAULT.depthBiasSlopeScale, scale, _values.depthBiasSlopeScale); } + float getDepthBiasSlopeScale() const { return _values.depthBiasSlopeScale; } + + // Depth Test + void setDepthTest(DepthTest depthTest) { SET_FIELD(DEPTH_TEST, DEFAULT.depthTest, depthTest, _values.depthTest); } + void setDepthTest(bool enable, bool writeMask, ComparisonFunction func) { setDepthTest(DepthTest(enable, writeMask, func)); } + DepthTest getDepthTest() const { return _values.depthTest; } + + bool isDepthTestEnabled() const { return getDepthTest().isEnabled(); } + uint8 getDepthTestWriteMask() const { return getDepthTest().getWriteMask(); } + ComparisonFunction getDepthTestFunc() const { return getDepthTest().getFunction(); } + + // Stencil test + void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest, uint8 backWriteMask, StencilTest backTest) { + SET_FIELD(STENCIL_ACTIVATION, DEFAULT.stencilActivation, StencilActivation(enabled, frontWriteMask, backWriteMask), _values.stencilActivation); + SET_FIELD(STENCIL_TEST_FRONT, DEFAULT.stencilTestFront, frontTest, _values.stencilTestFront); + SET_FIELD(STENCIL_TEST_BACK, DEFAULT.stencilTestBack, backTest, _values.stencilTestBack); } + void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest) { + setStencilTest(enabled, frontWriteMask, frontTest, frontWriteMask, frontTest); } + + StencilActivation getStencilActivation() const { return _values.stencilActivation; } + StencilTest getStencilTestFront() const { return _values.stencilTestFront; } + StencilTest getStencilTestBack() const { return _values.stencilTestBack; } + + bool isStencilEnabled() const { return getStencilActivation().isEnabled(); } + uint8 getStencilWriteMaskFront() const { return getStencilActivation().getWriteMaskFront(); } + uint8 getStencilWriteMaskBack() const { return getStencilActivation().getWriteMaskBack(); } + + // Alpha to coverage + void setAlphaToCoverageEnable(bool enable) { SET_FIELD(ALPHA_TO_COVERAGE_ENABLE, DEFAULT.alphaToCoverageEnable, enable, _values.alphaToCoverageEnable); } + bool isAlphaToCoverageEnabled() const { return _values.alphaToCoverageEnable; } + + // Sample mask + void setSampleMask(uint32 mask) { SET_FIELD(SAMPLE_MASK, DEFAULT.sampleMask, mask, _values.sampleMask); } + uint32 getSampleMask() const { return _values.sampleMask; } + + // Blend Function + void setBlendFunction(BlendFunction function) { SET_FIELD(BLEND_FUNCTION, DEFAULT.blendFunction, function, _values.blendFunction); } + BlendFunction getBlendFunction() const { return _values.blendFunction; } + + void setBlendFunction(bool enabled, BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) { + setBlendFunction(BlendFunction(enabled, sourceColor, operationColor, destinationColor, sourceAlpha, operationAlpha, destinationAlpha)); } + void setBlendFunction(bool enabled, BlendArg source, BlendOp operation, BlendArg destination) { + setBlendFunction(BlendFunction(enabled, source, operation, destination)); } + + bool isBlendEnabled() const { return getBlendFunction().isEnabled(); } + + // Color write mask + void setColorWriteMask(uint8 mask) { SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, mask, _values.colorWriteMask); } + void setColorWriteMask(bool red, bool green, bool blue, bool alpha) { uint32 value = ((WRITE_RED * red) | (WRITE_GREEN * green) | (WRITE_BLUE * blue) | (WRITE_ALPHA * alpha)); SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, value, _values.colorWriteMask); } + uint8 getColorWriteMask() const { return _values.colorWriteMask; } + + // All the possible fields + enum Field { + FILL_MODE, + CULL_MODE, + FRONT_FACE_CLOCKWISE, + DEPTH_CLAMP_ENABLE, + SCISSOR_ENABLE, + MULTISAMPLE_ENABLE, + ANTIALISED_LINE_ENABLE, + + DEPTH_BIAS, + DEPTH_BIAS_SLOPE_SCALE, + + DEPTH_TEST, + + STENCIL_ACTIVATION, + STENCIL_TEST_FRONT, + STENCIL_TEST_BACK, + + SAMPLE_MASK, + ALPHA_TO_COVERAGE_ENABLE, + + BLEND_FUNCTION, + + COLOR_WRITE_MASK, + + NUM_FIELDS, // not a valid field, just the count + }; + + // The signature of the state tells which fields of the state are not default + // this way during rendering the Backend can compare it's current state and try to minimize the job to do + typedef std::bitset Signature; + + Signature getSignature() const { return _signature; } + + static Signature evalSignature(const Data& state); + + // For convenience, create a State from the values directly + State(const Data& values); + const Data& getValues() const { return _values; } + + protected: + State(const State& state); + State& operator=(const State& state); + + Data _values; + Signature _signature{0}; + Stamp _stamp{0}; + + // This shouldn't be used by anything else than the Backend class with the proper casting. + mutable GPUObject* _gpuObject = nullptr; + void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } + GPUObject* getGPUObject() const { return _gpuObject; } + friend class Backend; }; - - // The unique default values for all the fields - static const Data DEFAULT; - void setFillMode(FillMode fill) { SET_FIELD(FILL_MODE, DEFAULT.fillMode, fill, _values.fillMode); } - FillMode getFillMode() const { return FillMode(_values.fillMode); } - - void setCullMode(CullMode cull) { SET_FIELD(CULL_MODE, DEFAULT.cullMode, cull, _values.cullMode); } - CullMode getCullMode() const { return CullMode(_values.cullMode); } - - void setFrontFaceClockwise(bool isClockwise) { SET_FIELD(FRONT_FACE_CLOCKWISE, DEFAULT.frontFaceClockwise, isClockwise, _values.frontFaceClockwise); } - bool isFrontFaceClockwise() const { return _values.frontFaceClockwise; } - - void setDepthClampEnable(bool enable) { SET_FIELD(DEPTH_CLAMP_ENABLE, DEFAULT.depthClampEnable, enable, _values.depthClampEnable); } - bool isDepthClampEnable() const { return _values.depthClampEnable; } - - void setScissorEnable(bool enable) { SET_FIELD(SCISSOR_ENABLE, DEFAULT.scissorEnable, enable, _values.scissorEnable); } - bool isScissorEnable() const { return _values.scissorEnable; } - - void setMultisampleEnable(bool enable) { SET_FIELD(MULTISAMPLE_ENABLE, DEFAULT.multisampleEnable, enable, _values.multisampleEnable); } - bool isMultisampleEnable() const { return _values.multisampleEnable; } - - void setAntialiasedLineEnable(bool enable) { SET_FIELD(ANTIALISED_LINE_ENABLE, DEFAULT.antialisedLineEnable, enable, _values.antialisedLineEnable); } - bool isAntialiasedLineEnable() const { return _values.antialisedLineEnable; } - - // Depth Bias - void setDepthBias(float bias) { SET_FIELD(DEPTH_BIAS, DEFAULT.depthBias, bias, _values.depthBias); } - float getDepthBias() const { return _values.depthBias; } - - void setDepthBiasSlopeScale(float scale) { SET_FIELD(DEPTH_BIAS_SLOPE_SCALE, DEFAULT.depthBiasSlopeScale, scale, _values.depthBiasSlopeScale); } - float getDepthBiasSlopeScale() const { return _values.depthBiasSlopeScale; } - - // Depth Test - void setDepthTest(DepthTest depthTest) { SET_FIELD(DEPTH_TEST, DEFAULT.depthTest, depthTest, _values.depthTest); } - void setDepthTest(bool enable, bool writeMask, ComparisonFunction func) { setDepthTest(DepthTest(enable, writeMask, func)); } - DepthTest getDepthTest() const { return _values.depthTest; } - - bool isDepthTestEnabled() const { return getDepthTest().isEnabled(); } - uint8 getDepthTestWriteMask() const { return getDepthTest().getWriteMask(); } - ComparisonFunction getDepthTestFunc() const { return getDepthTest().getFunction(); } - - // Stencil test - void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest, uint8 backWriteMask, StencilTest backTest) { - SET_FIELD(STENCIL_ACTIVATION, DEFAULT.stencilActivation, StencilActivation(enabled, frontWriteMask, backWriteMask), _values.stencilActivation); - SET_FIELD(STENCIL_TEST_FRONT, DEFAULT.stencilTestFront, frontTest, _values.stencilTestFront); - SET_FIELD(STENCIL_TEST_BACK, DEFAULT.stencilTestBack, backTest, _values.stencilTestBack); } - void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest) { - setStencilTest(enabled, frontWriteMask, frontTest, frontWriteMask, frontTest); } - - StencilActivation getStencilActivation() const { return _values.stencilActivation; } - StencilTest getStencilTestFront() const { return _values.stencilTestFront; } - StencilTest getStencilTestBack() const { return _values.stencilTestBack; } - - bool isStencilEnabled() const { return getStencilActivation().isEnabled(); } - uint8 getStencilWriteMaskFront() const { return getStencilActivation().getWriteMaskFront(); } - uint8 getStencilWriteMaskBack() const { return getStencilActivation().getWriteMaskBack(); } - - // Alpha to coverage - void setAlphaToCoverageEnable(bool enable) { SET_FIELD(ALPHA_TO_COVERAGE_ENABLE, DEFAULT.alphaToCoverageEnable, enable, _values.alphaToCoverageEnable); } - bool isAlphaToCoverageEnabled() const { return _values.alphaToCoverageEnable; } - - // Sample mask - void setSampleMask(uint32 mask) { SET_FIELD(SAMPLE_MASK, DEFAULT.sampleMask, mask, _values.sampleMask); } - uint32 getSampleMask() const { return _values.sampleMask; } - - // Blend Function - void setBlendFunction(BlendFunction function) { SET_FIELD(BLEND_FUNCTION, DEFAULT.blendFunction, function, _values.blendFunction); } - BlendFunction getBlendFunction() const { return _values.blendFunction; } - - void setBlendFunction(bool enabled, BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) { - setBlendFunction(BlendFunction(enabled, sourceColor, operationColor, destinationColor, sourceAlpha, operationAlpha, destinationAlpha)); } - void setBlendFunction(bool enabled, BlendArg source, BlendOp operation, BlendArg destination) { - setBlendFunction(BlendFunction(enabled, source, operation, destination)); } - - bool isBlendEnabled() const { return getBlendFunction().isEnabled(); } - - // Color write mask - void setColorWriteMask(uint8 mask) { SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, mask, _values.colorWriteMask); } - void setColorWriteMask(bool red, bool green, bool blue, bool alpha) { uint32 value = ((WRITE_RED * red) | (WRITE_GREEN * green) | (WRITE_BLUE * blue) | (WRITE_ALPHA * alpha)); SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, value, _values.colorWriteMask); } - uint8 getColorWriteMask() const { return _values.colorWriteMask; } - - // All the possible fields - enum Field { - FILL_MODE, - CULL_MODE, - FRONT_FACE_CLOCKWISE, - DEPTH_CLAMP_ENABLE, - SCISSOR_ENABLE, - MULTISAMPLE_ENABLE, - ANTIALISED_LINE_ENABLE, - - DEPTH_BIAS, - DEPTH_BIAS_SLOPE_SCALE, - - DEPTH_TEST, - - STENCIL_ACTIVATION, - STENCIL_TEST_FRONT, - STENCIL_TEST_BACK, - - SAMPLE_MASK, - ALPHA_TO_COVERAGE_ENABLE, - - BLEND_FUNCTION, - - COLOR_WRITE_MASK, - - NUM_FIELDS, // not a valid field, just the count - }; - - // The signature of the state tells which fields of the state are not default - // this way during rendering the Backend can compare it's current state and try to minimize the job to do - typedef std::bitset Signature; - - Signature getSignature() const { return _signature; } - - static Signature evalSignature(const Data& state); - - // For convenience, create a State from the values directly - State(const Data& values); - const Data& getValues() const { return _values; } - -protected: - State(const State& state); - State& operator=(const State& state); - - Data _values; - Signature _signature{0}; - Stamp _stamp{0}; - - // This shouldn't be used by anything else than the Backend class with the proper casting. - mutable GPUObject* _gpuObject = nullptr; - void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } - GPUObject* getGPUObject() const { return _gpuObject; } - friend class Backend; -}; - -typedef std::shared_ptr< State > StatePointer; -typedef std::vector< StatePointer > States; - + + typedef std::shared_ptr< State > StatePointer; + typedef std::vector< StatePointer > States; + }; #endif From f8e2d511547bb517fecccd39a02c66033f163ad5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 11:55:49 -0700 Subject: [PATCH 304/549] fix indentation changes in State.h --- libraries/gpu/src/gpu/State.h | 760 ++++++++++++++++++---------------- 1 file changed, 395 insertions(+), 365 deletions(-) diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index 1c338865db..d6d987b520 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -8,6 +8,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + #ifndef hifi_gpu_State_h #define hifi_gpu_State_h @@ -23,6 +24,35 @@ // and it s just not good anymore for template T& variable manipulation... #define SET_FIELD(field, defaultValue, value, dest) {\ dest = value;\ +if (value == defaultValue) {\ + _signature.reset(field);\ +} else {\ + _signature. + // + // State + // libraries/gpu/src/gpu + // + // Created by Sam Gateau on 3/8/2015. + // Copyright 2014 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 + // +#ifndef hifi_gpu_State_h +#define hifi_gpu_State_h + +#include "Format.h" + +#include +#include +#include +#include + + // Why a macro and not a fancy template you will ask me ? + // Because some of the fields are bool packed tightly in the State::Cache class + // and it s just not good anymore for template T& variable manipulation... +#define SET_FIELD(field, defaultValue, value, dest) {\ +dest = value;\ if (value == defaultValue) {\ _signature.reset(field);\ } else {\ @@ -31,378 +61,378 @@ _signature.set(field);\ _stamp++;\ }\ - + namespace gpu { - class GPUObject; +class GPUObject; + +class State { +public: + State(); + virtual ~State(); - class State { - public: - State(); - virtual ~State(); + Stamp getStamp() const { return _stamp; } + + typedef ::gpu::ComparisonFunction ComparisonFunction; + + enum FillMode { + FILL_POINT = 0, + FILL_LINE, + FILL_FACE, - Stamp getStamp() const { return _stamp; } - - typedef ::gpu::ComparisonFunction ComparisonFunction; - - enum FillMode { - FILL_POINT = 0, - FILL_LINE, - FILL_FACE, - - NUM_FILL_MODES, - }; - - enum CullMode { - CULL_NONE = 0, - CULL_FRONT, - CULL_BACK, - - NUM_CULL_MODES, - }; - - enum StencilOp { - STENCIL_OP_KEEP = 0, - STENCIL_OP_ZERO, - STENCIL_OP_REPLACE, - STENCIL_OP_INCR_SAT, - STENCIL_OP_DECR_SAT, - STENCIL_OP_INVERT, - STENCIL_OP_INCR, - STENCIL_OP_DECR, - - NUM_STENCIL_OPS, - }; - - enum BlendArg { - ZERO = 0, - ONE, - SRC_COLOR, - INV_SRC_COLOR, - SRC_ALPHA, - INV_SRC_ALPHA, - DEST_ALPHA, - INV_DEST_ALPHA, - DEST_COLOR, - INV_DEST_COLOR, - SRC_ALPHA_SAT, - FACTOR_COLOR, - INV_FACTOR_COLOR, - FACTOR_ALPHA, - INV_FACTOR_ALPHA, - - NUM_BLEND_ARGS, - }; - - enum BlendOp { - BLEND_OP_ADD = 0, - BLEND_OP_SUBTRACT, - BLEND_OP_REV_SUBTRACT, - BLEND_OP_MIN, - BLEND_OP_MAX, - - NUM_BLEND_OPS, - }; - - enum ColorMask - { - WRITE_NONE = 0, - WRITE_RED = 1, - WRITE_GREEN = 2, - WRITE_BLUE = 4, - WRITE_ALPHA = 8, - WRITE_ALL = (WRITE_RED | WRITE_GREEN | WRITE_BLUE | WRITE_ALPHA ), - }; - - class DepthTest { - uint8 _function = LESS; - uint8 _writeMask = true; - uint8 _enabled = false; - uint8 _spare = 0; - public: - DepthTest(bool enabled = false, bool writeMask = true, ComparisonFunction func = LESS) : - _function(func), _writeMask(writeMask), _enabled(enabled) {} - - bool isEnabled() const { return _enabled != 0; } - ComparisonFunction getFunction() const { return ComparisonFunction(_function); } - uint8 getWriteMask() const { return _writeMask; } - - int32 getRaw() const { return *(reinterpret_cast(this)); } - DepthTest(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const DepthTest& right) const { return getRaw() == right.getRaw(); } - bool operator!= (const DepthTest& right) const { return getRaw() != right.getRaw(); } - }; - - class StencilTest { - static const int FUNC_MASK = 0x000f; - static const int FAIL_OP_MASK = 0x00f0; - static const int DEPTH_FAIL_OP_MASK = 0x0f00; - static const int PASS_OP_MASK = 0xf000; - static const int FAIL_OP_OFFSET = 4; - static const int DEPTH_FAIL_OP_OFFSET = 8; - static const int PASS_OP_OFFSET = 12; - - uint16 _functionAndOperations; - uint8 _reference = 0; - uint8 _readMask = 0xff; - public: - - StencilTest(uint8 reference = 0, uint8 readMask =0xFF, ComparisonFunction func = ALWAYS, StencilOp failOp = STENCIL_OP_KEEP, StencilOp depthFailOp = STENCIL_OP_KEEP, StencilOp passOp = STENCIL_OP_KEEP) : - _functionAndOperations(func | (failOp << FAIL_OP_OFFSET) | (depthFailOp << DEPTH_FAIL_OP_OFFSET) | (passOp << PASS_OP_OFFSET)), - _reference(reference), _readMask(readMask) - {} - - ComparisonFunction getFunction() const { return ComparisonFunction(_functionAndOperations & FUNC_MASK); } - StencilOp getFailOp() const { return StencilOp((_functionAndOperations & FAIL_OP_MASK) >> FAIL_OP_OFFSET); } - StencilOp getDepthFailOp() const { return StencilOp((_functionAndOperations & DEPTH_FAIL_OP_MASK) >> DEPTH_FAIL_OP_OFFSET); } - StencilOp getPassOp() const { return StencilOp((_functionAndOperations & PASS_OP_MASK) >> PASS_OP_OFFSET); } - - uint8 getReference() const { return _reference; } - uint8 getReadMask() const { return _readMask; } - - int32 getRaw() const { return *(reinterpret_cast(this)); } - StencilTest(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const StencilTest& right) const { return getRaw() == right.getRaw(); } - bool operator!= (const StencilTest& right) const { return getRaw() != right.getRaw(); } - }; - - class StencilActivation { - uint8 _frontWriteMask = 0xFF; - uint8 _backWriteMask = 0xFF; - uint16 _enabled = 0; - public: - - StencilActivation(bool enabled, uint8 frontWriteMask = 0xFF, uint8 backWriteMask = 0xFF) : - _frontWriteMask(frontWriteMask), _backWriteMask(backWriteMask), _enabled(enabled) {} - - bool isEnabled() const { return (_enabled != 0); } - uint8 getWriteMaskFront() const { return _frontWriteMask; } - uint8 getWriteMaskBack() const { return _backWriteMask; } - - int32 getRaw() const { return *(reinterpret_cast(this)); } - StencilActivation(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const StencilActivation& right) const { return getRaw() == right.getRaw(); } - bool operator!= (const StencilActivation& right) const { return getRaw() != right.getRaw(); } - }; - - class BlendFunction { - static const int COLOR_MASK = 0x0f; - static const int ALPHA_MASK = 0xf0; - static const int ALPHA_OFFSET = 4; - - uint8 _enabled; - uint8 _source; - uint8 _destination; - uint8 _operation; - public: - - BlendFunction(bool enabled, - BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, - BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) : - _enabled(enabled), - _source(sourceColor | (sourceAlpha << ALPHA_OFFSET)), - _destination(destinationColor | (destinationAlpha << ALPHA_OFFSET)), - _operation(operationColor | (operationAlpha << ALPHA_OFFSET)) {} - - BlendFunction(bool enabled, BlendArg source = ONE, BlendOp operation = BLEND_OP_ADD, BlendArg destination = ZERO) : - _enabled(enabled), - _source(source | (source << ALPHA_OFFSET)), - _destination(destination | (destination << ALPHA_OFFSET)), - _operation(operation | (operation << ALPHA_OFFSET)) {} - - bool isEnabled() const { return (_enabled != 0); } - - BlendArg getSourceColor() const { return BlendArg(_source & COLOR_MASK); } - BlendArg getDestinationColor() const { return BlendArg(_destination & COLOR_MASK); } - BlendOp getOperationColor() const { return BlendOp(_operation & COLOR_MASK); } - - BlendArg getSourceAlpha() const { return BlendArg((_source & ALPHA_MASK) >> ALPHA_OFFSET); } - BlendArg getDestinationAlpha() const { return BlendArg((_destination & ALPHA_MASK) >> ALPHA_OFFSET); } - BlendOp getOperationAlpha() const { return BlendOp((_operation & ALPHA_MASK) >> ALPHA_OFFSET); } - - int32 getRaw() const { return *(reinterpret_cast(this)); } - BlendFunction(int32 raw) { *(reinterpret_cast(this)) = raw; } - bool operator== (const BlendFunction& right) const { return getRaw() == right.getRaw(); } - bool operator!= (const BlendFunction& right) const { return getRaw() != right.getRaw(); } - }; - - // The Data class is the full explicit description of the State class fields value. - // Useful for having one const static called Default for reference or for the gpu::Backend to keep track of the current value - class Data { - public: - float depthBias = 0.0f; - float depthBiasSlopeScale = 0.0f; - - DepthTest depthTest = DepthTest(false, true, LESS); - - StencilActivation stencilActivation = StencilActivation(false); - StencilTest stencilTestFront = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); - StencilTest stencilTestBack = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); - - uint32 sampleMask = 0xFFFFFFFF; - - BlendFunction blendFunction = BlendFunction(false); - - uint8 fillMode = FILL_FACE; - uint8 cullMode = CULL_NONE; - - uint8 colorWriteMask = WRITE_ALL; - - bool frontFaceClockwise : 1; - bool depthClampEnable : 1; - bool scissorEnable : 1; - bool multisampleEnable : 1; - bool antialisedLineEnable : 1; - bool alphaToCoverageEnable : 1; - - Data() : - frontFaceClockwise(false), - depthClampEnable(false), - scissorEnable(false), - multisampleEnable(false), - antialisedLineEnable(true), - alphaToCoverageEnable(false) - {} - }; - - // The unique default values for all the fields - static const Data DEFAULT; - void setFillMode(FillMode fill) { SET_FIELD(FILL_MODE, DEFAULT.fillMode, fill, _values.fillMode); } - FillMode getFillMode() const { return FillMode(_values.fillMode); } - - void setCullMode(CullMode cull) { SET_FIELD(CULL_MODE, DEFAULT.cullMode, cull, _values.cullMode); } - CullMode getCullMode() const { return CullMode(_values.cullMode); } - - void setFrontFaceClockwise(bool isClockwise) { SET_FIELD(FRONT_FACE_CLOCKWISE, DEFAULT.frontFaceClockwise, isClockwise, _values.frontFaceClockwise); } - bool isFrontFaceClockwise() const { return _values.frontFaceClockwise; } - - void setDepthClampEnable(bool enable) { SET_FIELD(DEPTH_CLAMP_ENABLE, DEFAULT.depthClampEnable, enable, _values.depthClampEnable); } - bool isDepthClampEnable() const { return _values.depthClampEnable; } - - void setScissorEnable(bool enable) { SET_FIELD(SCISSOR_ENABLE, DEFAULT.scissorEnable, enable, _values.scissorEnable); } - bool isScissorEnable() const { return _values.scissorEnable; } - - void setMultisampleEnable(bool enable) { SET_FIELD(MULTISAMPLE_ENABLE, DEFAULT.multisampleEnable, enable, _values.multisampleEnable); } - bool isMultisampleEnable() const { return _values.multisampleEnable; } - - void setAntialiasedLineEnable(bool enable) { SET_FIELD(ANTIALISED_LINE_ENABLE, DEFAULT.antialisedLineEnable, enable, _values.antialisedLineEnable); } - bool isAntialiasedLineEnable() const { return _values.antialisedLineEnable; } - - // Depth Bias - void setDepthBias(float bias) { SET_FIELD(DEPTH_BIAS, DEFAULT.depthBias, bias, _values.depthBias); } - float getDepthBias() const { return _values.depthBias; } - - void setDepthBiasSlopeScale(float scale) { SET_FIELD(DEPTH_BIAS_SLOPE_SCALE, DEFAULT.depthBiasSlopeScale, scale, _values.depthBiasSlopeScale); } - float getDepthBiasSlopeScale() const { return _values.depthBiasSlopeScale; } - - // Depth Test - void setDepthTest(DepthTest depthTest) { SET_FIELD(DEPTH_TEST, DEFAULT.depthTest, depthTest, _values.depthTest); } - void setDepthTest(bool enable, bool writeMask, ComparisonFunction func) { setDepthTest(DepthTest(enable, writeMask, func)); } - DepthTest getDepthTest() const { return _values.depthTest; } - - bool isDepthTestEnabled() const { return getDepthTest().isEnabled(); } - uint8 getDepthTestWriteMask() const { return getDepthTest().getWriteMask(); } - ComparisonFunction getDepthTestFunc() const { return getDepthTest().getFunction(); } - - // Stencil test - void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest, uint8 backWriteMask, StencilTest backTest) { - SET_FIELD(STENCIL_ACTIVATION, DEFAULT.stencilActivation, StencilActivation(enabled, frontWriteMask, backWriteMask), _values.stencilActivation); - SET_FIELD(STENCIL_TEST_FRONT, DEFAULT.stencilTestFront, frontTest, _values.stencilTestFront); - SET_FIELD(STENCIL_TEST_BACK, DEFAULT.stencilTestBack, backTest, _values.stencilTestBack); } - void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest) { - setStencilTest(enabled, frontWriteMask, frontTest, frontWriteMask, frontTest); } - - StencilActivation getStencilActivation() const { return _values.stencilActivation; } - StencilTest getStencilTestFront() const { return _values.stencilTestFront; } - StencilTest getStencilTestBack() const { return _values.stencilTestBack; } - - bool isStencilEnabled() const { return getStencilActivation().isEnabled(); } - uint8 getStencilWriteMaskFront() const { return getStencilActivation().getWriteMaskFront(); } - uint8 getStencilWriteMaskBack() const { return getStencilActivation().getWriteMaskBack(); } - - // Alpha to coverage - void setAlphaToCoverageEnable(bool enable) { SET_FIELD(ALPHA_TO_COVERAGE_ENABLE, DEFAULT.alphaToCoverageEnable, enable, _values.alphaToCoverageEnable); } - bool isAlphaToCoverageEnabled() const { return _values.alphaToCoverageEnable; } - - // Sample mask - void setSampleMask(uint32 mask) { SET_FIELD(SAMPLE_MASK, DEFAULT.sampleMask, mask, _values.sampleMask); } - uint32 getSampleMask() const { return _values.sampleMask; } - - // Blend Function - void setBlendFunction(BlendFunction function) { SET_FIELD(BLEND_FUNCTION, DEFAULT.blendFunction, function, _values.blendFunction); } - BlendFunction getBlendFunction() const { return _values.blendFunction; } - - void setBlendFunction(bool enabled, BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) { - setBlendFunction(BlendFunction(enabled, sourceColor, operationColor, destinationColor, sourceAlpha, operationAlpha, destinationAlpha)); } - void setBlendFunction(bool enabled, BlendArg source, BlendOp operation, BlendArg destination) { - setBlendFunction(BlendFunction(enabled, source, operation, destination)); } - - bool isBlendEnabled() const { return getBlendFunction().isEnabled(); } - - // Color write mask - void setColorWriteMask(uint8 mask) { SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, mask, _values.colorWriteMask); } - void setColorWriteMask(bool red, bool green, bool blue, bool alpha) { uint32 value = ((WRITE_RED * red) | (WRITE_GREEN * green) | (WRITE_BLUE * blue) | (WRITE_ALPHA * alpha)); SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, value, _values.colorWriteMask); } - uint8 getColorWriteMask() const { return _values.colorWriteMask; } - - // All the possible fields - enum Field { - FILL_MODE, - CULL_MODE, - FRONT_FACE_CLOCKWISE, - DEPTH_CLAMP_ENABLE, - SCISSOR_ENABLE, - MULTISAMPLE_ENABLE, - ANTIALISED_LINE_ENABLE, - - DEPTH_BIAS, - DEPTH_BIAS_SLOPE_SCALE, - - DEPTH_TEST, - - STENCIL_ACTIVATION, - STENCIL_TEST_FRONT, - STENCIL_TEST_BACK, - - SAMPLE_MASK, - ALPHA_TO_COVERAGE_ENABLE, - - BLEND_FUNCTION, - - COLOR_WRITE_MASK, - - NUM_FIELDS, // not a valid field, just the count - }; - - // The signature of the state tells which fields of the state are not default - // this way during rendering the Backend can compare it's current state and try to minimize the job to do - typedef std::bitset Signature; - - Signature getSignature() const { return _signature; } - - static Signature evalSignature(const Data& state); - - // For convenience, create a State from the values directly - State(const Data& values); - const Data& getValues() const { return _values; } - - protected: - State(const State& state); - State& operator=(const State& state); - - Data _values; - Signature _signature{0}; - Stamp _stamp{0}; - - // This shouldn't be used by anything else than the Backend class with the proper casting. - mutable GPUObject* _gpuObject = nullptr; - void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } - GPUObject* getGPUObject() const { return _gpuObject; } - friend class Backend; + NUM_FILL_MODES, }; - typedef std::shared_ptr< State > StatePointer; - typedef std::vector< StatePointer > States; + enum CullMode { + CULL_NONE = 0, + CULL_FRONT, + CULL_BACK, + + NUM_CULL_MODES, + }; + enum StencilOp { + STENCIL_OP_KEEP = 0, + STENCIL_OP_ZERO, + STENCIL_OP_REPLACE, + STENCIL_OP_INCR_SAT, + STENCIL_OP_DECR_SAT, + STENCIL_OP_INVERT, + STENCIL_OP_INCR, + STENCIL_OP_DECR, + + NUM_STENCIL_OPS, + }; + + enum BlendArg { + ZERO = 0, + ONE, + SRC_COLOR, + INV_SRC_COLOR, + SRC_ALPHA, + INV_SRC_ALPHA, + DEST_ALPHA, + INV_DEST_ALPHA, + DEST_COLOR, + INV_DEST_COLOR, + SRC_ALPHA_SAT, + FACTOR_COLOR, + INV_FACTOR_COLOR, + FACTOR_ALPHA, + INV_FACTOR_ALPHA, + + NUM_BLEND_ARGS, + }; + + enum BlendOp { + BLEND_OP_ADD = 0, + BLEND_OP_SUBTRACT, + BLEND_OP_REV_SUBTRACT, + BLEND_OP_MIN, + BLEND_OP_MAX, + + NUM_BLEND_OPS, + }; + + enum ColorMask + { + WRITE_NONE = 0, + WRITE_RED = 1, + WRITE_GREEN = 2, + WRITE_BLUE = 4, + WRITE_ALPHA = 8, + WRITE_ALL = (WRITE_RED | WRITE_GREEN | WRITE_BLUE | WRITE_ALPHA ), + }; + + class DepthTest { + uint8 _function = LESS; + uint8 _writeMask = true; + uint8 _enabled = false; + uint8 _spare = 0; + public: + DepthTest(bool enabled = false, bool writeMask = true, ComparisonFunction func = LESS) : + _function(func), _writeMask(writeMask), _enabled(enabled) {} + + bool isEnabled() const { return _enabled != 0; } + ComparisonFunction getFunction() const { return ComparisonFunction(_function); } + uint8 getWriteMask() const { return _writeMask; } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + DepthTest(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const DepthTest& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const DepthTest& right) const { return getRaw() != right.getRaw(); } + }; + + class StencilTest { + static const int FUNC_MASK = 0x000f; + static const int FAIL_OP_MASK = 0x00f0; + static const int DEPTH_FAIL_OP_MASK = 0x0f00; + static const int PASS_OP_MASK = 0xf000; + static const int FAIL_OP_OFFSET = 4; + static const int DEPTH_FAIL_OP_OFFSET = 8; + static const int PASS_OP_OFFSET = 12; + + uint16 _functionAndOperations; + uint8 _reference = 0; + uint8 _readMask = 0xff; + public: + + StencilTest(uint8 reference = 0, uint8 readMask =0xFF, ComparisonFunction func = ALWAYS, StencilOp failOp = STENCIL_OP_KEEP, StencilOp depthFailOp = STENCIL_OP_KEEP, StencilOp passOp = STENCIL_OP_KEEP) : + _functionAndOperations(func | (failOp << FAIL_OP_OFFSET) | (depthFailOp << DEPTH_FAIL_OP_OFFSET) | (passOp << PASS_OP_OFFSET)), + _reference(reference), _readMask(readMask) + {} + + ComparisonFunction getFunction() const { return ComparisonFunction(_functionAndOperations & FUNC_MASK); } + StencilOp getFailOp() const { return StencilOp((_functionAndOperations & FAIL_OP_MASK) >> FAIL_OP_OFFSET); } + StencilOp getDepthFailOp() const { return StencilOp((_functionAndOperations & DEPTH_FAIL_OP_MASK) >> DEPTH_FAIL_OP_OFFSET); } + StencilOp getPassOp() const { return StencilOp((_functionAndOperations & PASS_OP_MASK) >> PASS_OP_OFFSET); } + + uint8 getReference() const { return _reference; } + uint8 getReadMask() const { return _readMask; } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + StencilTest(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const StencilTest& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const StencilTest& right) const { return getRaw() != right.getRaw(); } + }; + + class StencilActivation { + uint8 _frontWriteMask = 0xFF; + uint8 _backWriteMask = 0xFF; + uint16 _enabled = 0; + public: + + StencilActivation(bool enabled, uint8 frontWriteMask = 0xFF, uint8 backWriteMask = 0xFF) : + _frontWriteMask(frontWriteMask), _backWriteMask(backWriteMask), _enabled(enabled) {} + + bool isEnabled() const { return (_enabled != 0); } + uint8 getWriteMaskFront() const { return _frontWriteMask; } + uint8 getWriteMaskBack() const { return _backWriteMask; } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + StencilActivation(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const StencilActivation& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const StencilActivation& right) const { return getRaw() != right.getRaw(); } + }; + + class BlendFunction { + static const int COLOR_MASK = 0x0f; + static const int ALPHA_MASK = 0xf0; + static const int ALPHA_OFFSET = 4; + + uint8 _enabled; + uint8 _source; + uint8 _destination; + uint8 _operation; + public: + + BlendFunction(bool enabled, + BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, + BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) : + _enabled(enabled), + _source(sourceColor | (sourceAlpha << ALPHA_OFFSET)), + _destination(destinationColor | (destinationAlpha << ALPHA_OFFSET)), + _operation(operationColor | (operationAlpha << ALPHA_OFFSET)) {} + + BlendFunction(bool enabled, BlendArg source = ONE, BlendOp operation = BLEND_OP_ADD, BlendArg destination = ZERO) : + _enabled(enabled), + _source(source | (source << ALPHA_OFFSET)), + _destination(destination | (destination << ALPHA_OFFSET)), + _operation(operation | (operation << ALPHA_OFFSET)) {} + + bool isEnabled() const { return (_enabled != 0); } + + BlendArg getSourceColor() const { return BlendArg(_source & COLOR_MASK); } + BlendArg getDestinationColor() const { return BlendArg(_destination & COLOR_MASK); } + BlendOp getOperationColor() const { return BlendOp(_operation & COLOR_MASK); } + + BlendArg getSourceAlpha() const { return BlendArg((_source & ALPHA_MASK) >> ALPHA_OFFSET); } + BlendArg getDestinationAlpha() const { return BlendArg((_destination & ALPHA_MASK) >> ALPHA_OFFSET); } + BlendOp getOperationAlpha() const { return BlendOp((_operation & ALPHA_MASK) >> ALPHA_OFFSET); } + + int32 getRaw() const { return *(reinterpret_cast(this)); } + BlendFunction(int32 raw) { *(reinterpret_cast(this)) = raw; } + bool operator== (const BlendFunction& right) const { return getRaw() == right.getRaw(); } + bool operator!= (const BlendFunction& right) const { return getRaw() != right.getRaw(); } + }; + + // The Data class is the full explicit description of the State class fields value. + // Useful for having one const static called Default for reference or for the gpu::Backend to keep track of the current value + class Data { + public: + float depthBias = 0.0f; + float depthBiasSlopeScale = 0.0f; + + DepthTest depthTest = DepthTest(false, true, LESS); + + StencilActivation stencilActivation = StencilActivation(false); + StencilTest stencilTestFront = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); + StencilTest stencilTestBack = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); + + uint32 sampleMask = 0xFFFFFFFF; + + BlendFunction blendFunction = BlendFunction(false); + + uint8 fillMode = FILL_FACE; + uint8 cullMode = CULL_NONE; + + uint8 colorWriteMask = WRITE_ALL; + + bool frontFaceClockwise : 1; + bool depthClampEnable : 1; + bool scissorEnable : 1; + bool multisampleEnable : 1; + bool antialisedLineEnable : 1; + bool alphaToCoverageEnable : 1; + + Data() : + frontFaceClockwise(false), + depthClampEnable(false), + scissorEnable(false), + multisampleEnable(false), + antialisedLineEnable(true), + alphaToCoverageEnable(false) + {} + }; + + // The unique default values for all the fields + static const Data DEFAULT; + void setFillMode(FillMode fill) { SET_FIELD(FILL_MODE, DEFAULT.fillMode, fill, _values.fillMode); } + FillMode getFillMode() const { return FillMode(_values.fillMode); } + + void setCullMode(CullMode cull) { SET_FIELD(CULL_MODE, DEFAULT.cullMode, cull, _values.cullMode); } + CullMode getCullMode() const { return CullMode(_values.cullMode); } + + void setFrontFaceClockwise(bool isClockwise) { SET_FIELD(FRONT_FACE_CLOCKWISE, DEFAULT.frontFaceClockwise, isClockwise, _values.frontFaceClockwise); } + bool isFrontFaceClockwise() const { return _values.frontFaceClockwise; } + + void setDepthClampEnable(bool enable) { SET_FIELD(DEPTH_CLAMP_ENABLE, DEFAULT.depthClampEnable, enable, _values.depthClampEnable); } + bool isDepthClampEnable() const { return _values.depthClampEnable; } + + void setScissorEnable(bool enable) { SET_FIELD(SCISSOR_ENABLE, DEFAULT.scissorEnable, enable, _values.scissorEnable); } + bool isScissorEnable() const { return _values.scissorEnable; } + + void setMultisampleEnable(bool enable) { SET_FIELD(MULTISAMPLE_ENABLE, DEFAULT.multisampleEnable, enable, _values.multisampleEnable); } + bool isMultisampleEnable() const { return _values.multisampleEnable; } + + void setAntialiasedLineEnable(bool enable) { SET_FIELD(ANTIALISED_LINE_ENABLE, DEFAULT.antialisedLineEnable, enable, _values.antialisedLineEnable); } + bool isAntialiasedLineEnable() const { return _values.antialisedLineEnable; } + + // Depth Bias + void setDepthBias(float bias) { SET_FIELD(DEPTH_BIAS, DEFAULT.depthBias, bias, _values.depthBias); } + float getDepthBias() const { return _values.depthBias; } + + void setDepthBiasSlopeScale(float scale) { SET_FIELD(DEPTH_BIAS_SLOPE_SCALE, DEFAULT.depthBiasSlopeScale, scale, _values.depthBiasSlopeScale); } + float getDepthBiasSlopeScale() const { return _values.depthBiasSlopeScale; } + + // Depth Test + void setDepthTest(DepthTest depthTest) { SET_FIELD(DEPTH_TEST, DEFAULT.depthTest, depthTest, _values.depthTest); } + void setDepthTest(bool enable, bool writeMask, ComparisonFunction func) { setDepthTest(DepthTest(enable, writeMask, func)); } + DepthTest getDepthTest() const { return _values.depthTest; } + + bool isDepthTestEnabled() const { return getDepthTest().isEnabled(); } + uint8 getDepthTestWriteMask() const { return getDepthTest().getWriteMask(); } + ComparisonFunction getDepthTestFunc() const { return getDepthTest().getFunction(); } + + // Stencil test + void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest, uint8 backWriteMask, StencilTest backTest) { + SET_FIELD(STENCIL_ACTIVATION, DEFAULT.stencilActivation, StencilActivation(enabled, frontWriteMask, backWriteMask), _values.stencilActivation); + SET_FIELD(STENCIL_TEST_FRONT, DEFAULT.stencilTestFront, frontTest, _values.stencilTestFront); + SET_FIELD(STENCIL_TEST_BACK, DEFAULT.stencilTestBack, backTest, _values.stencilTestBack); } + void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest) { + setStencilTest(enabled, frontWriteMask, frontTest, frontWriteMask, frontTest); } + + StencilActivation getStencilActivation() const { return _values.stencilActivation; } + StencilTest getStencilTestFront() const { return _values.stencilTestFront; } + StencilTest getStencilTestBack() const { return _values.stencilTestBack; } + + bool isStencilEnabled() const { return getStencilActivation().isEnabled(); } + uint8 getStencilWriteMaskFront() const { return getStencilActivation().getWriteMaskFront(); } + uint8 getStencilWriteMaskBack() const { return getStencilActivation().getWriteMaskBack(); } + + // Alpha to coverage + void setAlphaToCoverageEnable(bool enable) { SET_FIELD(ALPHA_TO_COVERAGE_ENABLE, DEFAULT.alphaToCoverageEnable, enable, _values.alphaToCoverageEnable); } + bool isAlphaToCoverageEnabled() const { return _values.alphaToCoverageEnable; } + + // Sample mask + void setSampleMask(uint32 mask) { SET_FIELD(SAMPLE_MASK, DEFAULT.sampleMask, mask, _values.sampleMask); } + uint32 getSampleMask() const { return _values.sampleMask; } + + // Blend Function + void setBlendFunction(BlendFunction function) { SET_FIELD(BLEND_FUNCTION, DEFAULT.blendFunction, function, _values.blendFunction); } + BlendFunction getBlendFunction() const { return _values.blendFunction; } + + void setBlendFunction(bool enabled, BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) { + setBlendFunction(BlendFunction(enabled, sourceColor, operationColor, destinationColor, sourceAlpha, operationAlpha, destinationAlpha)); } + void setBlendFunction(bool enabled, BlendArg source, BlendOp operation, BlendArg destination) { + setBlendFunction(BlendFunction(enabled, source, operation, destination)); } + + bool isBlendEnabled() const { return getBlendFunction().isEnabled(); } + + // Color write mask + void setColorWriteMask(uint8 mask) { SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, mask, _values.colorWriteMask); } + void setColorWriteMask(bool red, bool green, bool blue, bool alpha) { uint32 value = ((WRITE_RED * red) | (WRITE_GREEN * green) | (WRITE_BLUE * blue) | (WRITE_ALPHA * alpha)); SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, value, _values.colorWriteMask); } + uint8 getColorWriteMask() const { return _values.colorWriteMask; } + + // All the possible fields + enum Field { + FILL_MODE, + CULL_MODE, + FRONT_FACE_CLOCKWISE, + DEPTH_CLAMP_ENABLE, + SCISSOR_ENABLE, + MULTISAMPLE_ENABLE, + ANTIALISED_LINE_ENABLE, + + DEPTH_BIAS, + DEPTH_BIAS_SLOPE_SCALE, + + DEPTH_TEST, + + STENCIL_ACTIVATION, + STENCIL_TEST_FRONT, + STENCIL_TEST_BACK, + + SAMPLE_MASK, + ALPHA_TO_COVERAGE_ENABLE, + + BLEND_FUNCTION, + + COLOR_WRITE_MASK, + + NUM_FIELDS, // not a valid field, just the count + }; + + // The signature of the state tells which fields of the state are not default + // this way during rendering the Backend can compare it's current state and try to minimize the job to do + typedef std::bitset Signature; + + Signature getSignature() const { return _signature; } + + static Signature evalSignature(const Data& state); + + // For convenience, create a State from the values directly + State(const Data& values); + const Data& getValues() const { return _values; } + +protected: + State(const State& state); + State& operator=(const State& state); + + Data _values; + Signature _signature{0}; + Stamp _stamp{0}; + + // This shouldn't be used by anything else than the Backend class with the proper casting. + mutable GPUObject* _gpuObject = nullptr; + void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } + GPUObject* getGPUObject() const { return _gpuObject; } + friend class Backend; }; +typedef std::shared_ptr< State > StatePointer; +typedef std::vector< StatePointer > States; + +}; + #endif From df41ce1e0e696dd8e087e0d7a950b55d3b2f7857 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 11:58:54 -0700 Subject: [PATCH 305/549] revert State.h to state in upstream/master --- libraries/gpu/src/gpu/State.h | 262 +++++++++++++++------------------- 1 file changed, 116 insertions(+), 146 deletions(-) diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index d6d987b520..5500f20e06 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -8,7 +8,6 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - #ifndef hifi_gpu_State_h #define hifi_gpu_State_h @@ -23,74 +22,45 @@ // Because some of the fields are bool packed tightly in the State::Cache class // and it s just not good anymore for template T& variable manipulation... #define SET_FIELD(field, defaultValue, value, dest) {\ -dest = value;\ -if (value == defaultValue) {\ - _signature.reset(field);\ -} else {\ - _signature. - // - // State - // libraries/gpu/src/gpu - // - // Created by Sam Gateau on 3/8/2015. - // Copyright 2014 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 - // -#ifndef hifi_gpu_State_h -#define hifi_gpu_State_h - -#include "Format.h" - -#include -#include -#include -#include - - // Why a macro and not a fancy template you will ask me ? - // Because some of the fields are bool packed tightly in the State::Cache class - // and it s just not good anymore for template T& variable manipulation... -#define SET_FIELD(field, defaultValue, value, dest) {\ -dest = value;\ -if (value == defaultValue) {\ -_signature.reset(field);\ -} else {\ -_signature.set(field);\ -}\ -_stamp++;\ + dest = value;\ + if (value == defaultValue) {\ + _signature.reset(field);\ + } else {\ + _signature.set(field);\ + }\ + _stamp++;\ }\ - + namespace gpu { - + class GPUObject; class State { public: State(); virtual ~State(); - + Stamp getStamp() const { return _stamp; } - + typedef ::gpu::ComparisonFunction ComparisonFunction; - + enum FillMode { FILL_POINT = 0, FILL_LINE, FILL_FACE, - + NUM_FILL_MODES, }; - + enum CullMode { CULL_NONE = 0, CULL_FRONT, CULL_BACK, - + NUM_CULL_MODES, }; - + enum StencilOp { STENCIL_OP_KEEP = 0, STENCIL_OP_ZERO, @@ -100,10 +70,10 @@ public: STENCIL_OP_INVERT, STENCIL_OP_INCR, STENCIL_OP_DECR, - + NUM_STENCIL_OPS, }; - + enum BlendArg { ZERO = 0, ONE, @@ -120,20 +90,20 @@ public: INV_FACTOR_COLOR, FACTOR_ALPHA, INV_FACTOR_ALPHA, - + NUM_BLEND_ARGS, }; - + enum BlendOp { BLEND_OP_ADD = 0, BLEND_OP_SUBTRACT, BLEND_OP_REV_SUBTRACT, BLEND_OP_MIN, BLEND_OP_MAX, - + NUM_BLEND_OPS, }; - + enum ColorMask { WRITE_NONE = 0, @@ -143,7 +113,7 @@ public: WRITE_ALPHA = 8, WRITE_ALL = (WRITE_RED | WRITE_GREEN | WRITE_BLUE | WRITE_ALPHA ), }; - + class DepthTest { uint8 _function = LESS; uint8 _writeMask = true; @@ -151,19 +121,19 @@ public: uint8 _spare = 0; public: DepthTest(bool enabled = false, bool writeMask = true, ComparisonFunction func = LESS) : - _function(func), _writeMask(writeMask), _enabled(enabled) {} - + _function(func), _writeMask(writeMask), _enabled(enabled) {} + bool isEnabled() const { return _enabled != 0; } ComparisonFunction getFunction() const { return ComparisonFunction(_function); } uint8 getWriteMask() const { return _writeMask; } - + int32 getRaw() const { return *(reinterpret_cast(this)); } DepthTest(int32 raw) { *(reinterpret_cast(this)) = raw; } bool operator== (const DepthTest& right) const { return getRaw() == right.getRaw(); } bool operator!= (const DepthTest& right) const { return getRaw() != right.getRaw(); } - }; - - class StencilTest { + }; + + class StencilTest { static const int FUNC_MASK = 0x000f; static const int FAIL_OP_MASK = 0x00f0; static const int DEPTH_FAIL_OP_MASK = 0x0f00; @@ -171,169 +141,169 @@ public: static const int FAIL_OP_OFFSET = 4; static const int DEPTH_FAIL_OP_OFFSET = 8; static const int PASS_OP_OFFSET = 12; - + uint16 _functionAndOperations; uint8 _reference = 0; uint8 _readMask = 0xff; - public: - + public: + StencilTest(uint8 reference = 0, uint8 readMask =0xFF, ComparisonFunction func = ALWAYS, StencilOp failOp = STENCIL_OP_KEEP, StencilOp depthFailOp = STENCIL_OP_KEEP, StencilOp passOp = STENCIL_OP_KEEP) : - _functionAndOperations(func | (failOp << FAIL_OP_OFFSET) | (depthFailOp << DEPTH_FAIL_OP_OFFSET) | (passOp << PASS_OP_OFFSET)), - _reference(reference), _readMask(readMask) - {} - + _functionAndOperations(func | (failOp << FAIL_OP_OFFSET) | (depthFailOp << DEPTH_FAIL_OP_OFFSET) | (passOp << PASS_OP_OFFSET)), + _reference(reference), _readMask(readMask) + {} + ComparisonFunction getFunction() const { return ComparisonFunction(_functionAndOperations & FUNC_MASK); } StencilOp getFailOp() const { return StencilOp((_functionAndOperations & FAIL_OP_MASK) >> FAIL_OP_OFFSET); } StencilOp getDepthFailOp() const { return StencilOp((_functionAndOperations & DEPTH_FAIL_OP_MASK) >> DEPTH_FAIL_OP_OFFSET); } StencilOp getPassOp() const { return StencilOp((_functionAndOperations & PASS_OP_MASK) >> PASS_OP_OFFSET); } - + uint8 getReference() const { return _reference; } uint8 getReadMask() const { return _readMask; } - + int32 getRaw() const { return *(reinterpret_cast(this)); } StencilTest(int32 raw) { *(reinterpret_cast(this)) = raw; } bool operator== (const StencilTest& right) const { return getRaw() == right.getRaw(); } bool operator!= (const StencilTest& right) const { return getRaw() != right.getRaw(); } - }; - - class StencilActivation { + }; + + class StencilActivation { uint8 _frontWriteMask = 0xFF; uint8 _backWriteMask = 0xFF; uint16 _enabled = 0; - public: - + public: + StencilActivation(bool enabled, uint8 frontWriteMask = 0xFF, uint8 backWriteMask = 0xFF) : - _frontWriteMask(frontWriteMask), _backWriteMask(backWriteMask), _enabled(enabled) {} - + _frontWriteMask(frontWriteMask), _backWriteMask(backWriteMask), _enabled(enabled) {} + bool isEnabled() const { return (_enabled != 0); } uint8 getWriteMaskFront() const { return _frontWriteMask; } uint8 getWriteMaskBack() const { return _backWriteMask; } - + int32 getRaw() const { return *(reinterpret_cast(this)); } StencilActivation(int32 raw) { *(reinterpret_cast(this)) = raw; } bool operator== (const StencilActivation& right) const { return getRaw() == right.getRaw(); } bool operator!= (const StencilActivation& right) const { return getRaw() != right.getRaw(); } }; - + class BlendFunction { static const int COLOR_MASK = 0x0f; static const int ALPHA_MASK = 0xf0; static const int ALPHA_OFFSET = 4; - + uint8 _enabled; uint8 _source; uint8 _destination; uint8 _operation; public: - + BlendFunction(bool enabled, - BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, - BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) : - _enabled(enabled), - _source(sourceColor | (sourceAlpha << ALPHA_OFFSET)), - _destination(destinationColor | (destinationAlpha << ALPHA_OFFSET)), - _operation(operationColor | (operationAlpha << ALPHA_OFFSET)) {} - + BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, + BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) : + _enabled(enabled), + _source(sourceColor | (sourceAlpha << ALPHA_OFFSET)), + _destination(destinationColor | (destinationAlpha << ALPHA_OFFSET)), + _operation(operationColor | (operationAlpha << ALPHA_OFFSET)) {} + BlendFunction(bool enabled, BlendArg source = ONE, BlendOp operation = BLEND_OP_ADD, BlendArg destination = ZERO) : - _enabled(enabled), - _source(source | (source << ALPHA_OFFSET)), - _destination(destination | (destination << ALPHA_OFFSET)), - _operation(operation | (operation << ALPHA_OFFSET)) {} - + _enabled(enabled), + _source(source | (source << ALPHA_OFFSET)), + _destination(destination | (destination << ALPHA_OFFSET)), + _operation(operation | (operation << ALPHA_OFFSET)) {} + bool isEnabled() const { return (_enabled != 0); } - + BlendArg getSourceColor() const { return BlendArg(_source & COLOR_MASK); } BlendArg getDestinationColor() const { return BlendArg(_destination & COLOR_MASK); } BlendOp getOperationColor() const { return BlendOp(_operation & COLOR_MASK); } - + BlendArg getSourceAlpha() const { return BlendArg((_source & ALPHA_MASK) >> ALPHA_OFFSET); } BlendArg getDestinationAlpha() const { return BlendArg((_destination & ALPHA_MASK) >> ALPHA_OFFSET); } BlendOp getOperationAlpha() const { return BlendOp((_operation & ALPHA_MASK) >> ALPHA_OFFSET); } - + int32 getRaw() const { return *(reinterpret_cast(this)); } BlendFunction(int32 raw) { *(reinterpret_cast(this)) = raw; } bool operator== (const BlendFunction& right) const { return getRaw() == right.getRaw(); } bool operator!= (const BlendFunction& right) const { return getRaw() != right.getRaw(); } }; - + // The Data class is the full explicit description of the State class fields value. // Useful for having one const static called Default for reference or for the gpu::Backend to keep track of the current value class Data { public: float depthBias = 0.0f; float depthBiasSlopeScale = 0.0f; - + DepthTest depthTest = DepthTest(false, true, LESS); - + StencilActivation stencilActivation = StencilActivation(false); StencilTest stencilTestFront = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); StencilTest stencilTestBack = StencilTest(0, 0xff, ALWAYS, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); - + uint32 sampleMask = 0xFFFFFFFF; - + BlendFunction blendFunction = BlendFunction(false); - + uint8 fillMode = FILL_FACE; uint8 cullMode = CULL_NONE; - + uint8 colorWriteMask = WRITE_ALL; - + bool frontFaceClockwise : 1; bool depthClampEnable : 1; bool scissorEnable : 1; bool multisampleEnable : 1; bool antialisedLineEnable : 1; bool alphaToCoverageEnable : 1; - + Data() : - frontFaceClockwise(false), - depthClampEnable(false), - scissorEnable(false), - multisampleEnable(false), - antialisedLineEnable(true), - alphaToCoverageEnable(false) + frontFaceClockwise(false), + depthClampEnable(false), + scissorEnable(false), + multisampleEnable(false), + antialisedLineEnable(true), + alphaToCoverageEnable(false) {} }; - + // The unique default values for all the fields static const Data DEFAULT; void setFillMode(FillMode fill) { SET_FIELD(FILL_MODE, DEFAULT.fillMode, fill, _values.fillMode); } FillMode getFillMode() const { return FillMode(_values.fillMode); } - + void setCullMode(CullMode cull) { SET_FIELD(CULL_MODE, DEFAULT.cullMode, cull, _values.cullMode); } CullMode getCullMode() const { return CullMode(_values.cullMode); } - + void setFrontFaceClockwise(bool isClockwise) { SET_FIELD(FRONT_FACE_CLOCKWISE, DEFAULT.frontFaceClockwise, isClockwise, _values.frontFaceClockwise); } bool isFrontFaceClockwise() const { return _values.frontFaceClockwise; } - + void setDepthClampEnable(bool enable) { SET_FIELD(DEPTH_CLAMP_ENABLE, DEFAULT.depthClampEnable, enable, _values.depthClampEnable); } bool isDepthClampEnable() const { return _values.depthClampEnable; } - + void setScissorEnable(bool enable) { SET_FIELD(SCISSOR_ENABLE, DEFAULT.scissorEnable, enable, _values.scissorEnable); } bool isScissorEnable() const { return _values.scissorEnable; } - + void setMultisampleEnable(bool enable) { SET_FIELD(MULTISAMPLE_ENABLE, DEFAULT.multisampleEnable, enable, _values.multisampleEnable); } bool isMultisampleEnable() const { return _values.multisampleEnable; } - + void setAntialiasedLineEnable(bool enable) { SET_FIELD(ANTIALISED_LINE_ENABLE, DEFAULT.antialisedLineEnable, enable, _values.antialisedLineEnable); } bool isAntialiasedLineEnable() const { return _values.antialisedLineEnable; } - + // Depth Bias void setDepthBias(float bias) { SET_FIELD(DEPTH_BIAS, DEFAULT.depthBias, bias, _values.depthBias); } float getDepthBias() const { return _values.depthBias; } - + void setDepthBiasSlopeScale(float scale) { SET_FIELD(DEPTH_BIAS_SLOPE_SCALE, DEFAULT.depthBiasSlopeScale, scale, _values.depthBiasSlopeScale); } float getDepthBiasSlopeScale() const { return _values.depthBiasSlopeScale; } - + // Depth Test void setDepthTest(DepthTest depthTest) { SET_FIELD(DEPTH_TEST, DEFAULT.depthTest, depthTest, _values.depthTest); } void setDepthTest(bool enable, bool writeMask, ComparisonFunction func) { setDepthTest(DepthTest(enable, writeMask, func)); } DepthTest getDepthTest() const { return _values.depthTest; } - + bool isDepthTestEnabled() const { return getDepthTest().isEnabled(); } uint8 getDepthTestWriteMask() const { return getDepthTest().getWriteMask(); } ComparisonFunction getDepthTestFunc() const { return getDepthTest().getFunction(); } - + // Stencil test void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest, uint8 backWriteMask, StencilTest backTest) { SET_FIELD(STENCIL_ACTIVATION, DEFAULT.stencilActivation, StencilActivation(enabled, frontWriteMask, backWriteMask), _values.stencilActivation); @@ -341,39 +311,39 @@ public: SET_FIELD(STENCIL_TEST_BACK, DEFAULT.stencilTestBack, backTest, _values.stencilTestBack); } void setStencilTest(bool enabled, uint8 frontWriteMask, StencilTest frontTest) { setStencilTest(enabled, frontWriteMask, frontTest, frontWriteMask, frontTest); } - + StencilActivation getStencilActivation() const { return _values.stencilActivation; } StencilTest getStencilTestFront() const { return _values.stencilTestFront; } StencilTest getStencilTestBack() const { return _values.stencilTestBack; } - + bool isStencilEnabled() const { return getStencilActivation().isEnabled(); } uint8 getStencilWriteMaskFront() const { return getStencilActivation().getWriteMaskFront(); } uint8 getStencilWriteMaskBack() const { return getStencilActivation().getWriteMaskBack(); } - + // Alpha to coverage void setAlphaToCoverageEnable(bool enable) { SET_FIELD(ALPHA_TO_COVERAGE_ENABLE, DEFAULT.alphaToCoverageEnable, enable, _values.alphaToCoverageEnable); } bool isAlphaToCoverageEnabled() const { return _values.alphaToCoverageEnable; } - + // Sample mask void setSampleMask(uint32 mask) { SET_FIELD(SAMPLE_MASK, DEFAULT.sampleMask, mask, _values.sampleMask); } uint32 getSampleMask() const { return _values.sampleMask; } - + // Blend Function void setBlendFunction(BlendFunction function) { SET_FIELD(BLEND_FUNCTION, DEFAULT.blendFunction, function, _values.blendFunction); } BlendFunction getBlendFunction() const { return _values.blendFunction; } - + void setBlendFunction(bool enabled, BlendArg sourceColor, BlendOp operationColor, BlendArg destinationColor, BlendArg sourceAlpha, BlendOp operationAlpha, BlendArg destinationAlpha) { setBlendFunction(BlendFunction(enabled, sourceColor, operationColor, destinationColor, sourceAlpha, operationAlpha, destinationAlpha)); } void setBlendFunction(bool enabled, BlendArg source, BlendOp operation, BlendArg destination) { setBlendFunction(BlendFunction(enabled, source, operation, destination)); } - + bool isBlendEnabled() const { return getBlendFunction().isEnabled(); } - + // Color write mask void setColorWriteMask(uint8 mask) { SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, mask, _values.colorWriteMask); } void setColorWriteMask(bool red, bool green, bool blue, bool alpha) { uint32 value = ((WRITE_RED * red) | (WRITE_GREEN * green) | (WRITE_BLUE * blue) | (WRITE_ALPHA * alpha)); SET_FIELD(COLOR_WRITE_MASK, DEFAULT.colorWriteMask, value, _values.colorWriteMask); } uint8 getColorWriteMask() const { return _values.colorWriteMask; } - + // All the possible fields enum Field { FILL_MODE, @@ -383,46 +353,46 @@ public: SCISSOR_ENABLE, MULTISAMPLE_ENABLE, ANTIALISED_LINE_ENABLE, - + DEPTH_BIAS, DEPTH_BIAS_SLOPE_SCALE, - + DEPTH_TEST, - + STENCIL_ACTIVATION, STENCIL_TEST_FRONT, STENCIL_TEST_BACK, - + SAMPLE_MASK, ALPHA_TO_COVERAGE_ENABLE, - + BLEND_FUNCTION, - + COLOR_WRITE_MASK, - + NUM_FIELDS, // not a valid field, just the count }; - + // The signature of the state tells which fields of the state are not default // this way during rendering the Backend can compare it's current state and try to minimize the job to do typedef std::bitset Signature; - + Signature getSignature() const { return _signature; } - + static Signature evalSignature(const Data& state); - + // For convenience, create a State from the values directly State(const Data& values); const Data& getValues() const { return _values; } - + protected: State(const State& state); State& operator=(const State& state); - + Data _values; Signature _signature{0}; Stamp _stamp{0}; - + // This shouldn't be used by anything else than the Backend class with the proper casting. mutable GPUObject* _gpuObject = nullptr; void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } @@ -432,7 +402,7 @@ protected: typedef std::shared_ptr< State > StatePointer; typedef std::vector< StatePointer > States; - + }; - + #endif From 23c6e8bd451bb29e902f56765e9c7cea2a86e452 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 12:03:49 -0700 Subject: [PATCH 306/549] fixes for packet version bumps --- libraries/networking/src/udt/PacketHeaders.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 8c0e27db5e..1c2a38a2a6 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -32,16 +32,14 @@ const QSet NON_SOURCED_PACKETS = QSet() const QSet RELIABLE_PACKETS = QSet(); -PacketVersion versionForPacketType(PacketType::Value packetType) { +PacketVersion versionForPacketType(PacketType packetType) { switch (packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: return VERSION_ENTITIES_PROTOCOL_HEADER_SWAP; - case AvatarData: - return 13; default: - return 12; + return 14; } } From bc7d8d7029cf0b021bb01af4c3bffd41f8d2f0be Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 12:06:45 -0700 Subject: [PATCH 307/549] change UDT note comment --- libraries/networking/src/udt/CongestionControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 555f48cfd6..9dc1880df6 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -47,7 +47,7 @@ DefaultCC::DefaultCC() : void DefaultCC::onACK(SequenceNumber ackNum) { double increase = 0; - // Note: 1/24/2012 + // Note from UDT original code: // The minimum increase parameter is increased from "1.0 / _mss" to 0.01 // because the original was too small and caused sending rate to stay at low level // for long time. From a58c6b9320ff6c722e11aeb625ccd6bfeef364ea Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 12:09:28 -0700 Subject: [PATCH 308/549] remove CC close given that it is not called --- libraries/networking/src/udt/CongestionControl.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index a8a4ba3342..f1ebe9ada7 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -36,7 +36,6 @@ public: int synInterval() const { return _synInterval; } virtual void init() {} - virtual void close() {} virtual void onACK(SequenceNumber ackNum) {} virtual void onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) {} From bd56a5074d6103bc21721b9d3839548036fd6b64 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 12:10:05 -0700 Subject: [PATCH 309/549] inline a curly bracket after template --- libraries/networking/src/udt/CongestionControl.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index f1ebe9ada7..5208ff9d3b 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -87,8 +87,7 @@ public: virtual std::unique_ptr create() = 0; }; -template class CongestionControlFactory: public CongestionControlVirtualFactory -{ +template class CongestionControlFactory: public CongestionControlVirtualFactory { public: virtual ~CongestionControlFactory() {} virtual std::unique_ptr create() { return std::unique_ptr(new T()); } From e4c1de78455404d82057d8e35372946a357ef496 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Aug 2015 17:15:09 -0700 Subject: [PATCH 310/549] fix variable names for sourced/verified --- libraries/networking/src/NLPacket.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 2ca794f7b9..39f4f9c541 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -12,9 +12,9 @@ #include "NLPacket.h" int NLPacket::localHeaderSize(PacketType type) { - bool sourced = NON_SOURCED_PACKETS.contains(type); - bool verified = NON_VERIFIED_PACKETS.contains(type); - qint64 optionalSize = (sourced ? 0 : NUM_BYTES_RFC4122_UUID) + ((sourced || verified) ? 0 : NUM_BYTES_MD5_HASH); + bool nonSourced = NON_SOURCED_PACKETS.contains(type); + bool nonVerified = NON_VERIFIED_PACKETS.contains(type); + qint64 optionalSize = (nonSourced ? 0 : NUM_BYTES_RFC4122_UUID) + ((nonSourced || nonVerified) ? 0 : NUM_BYTES_MD5_HASH); return sizeof(PacketType) + sizeof(PacketVersion) + optionalSize; } int NLPacket::totalHeaderSize(PacketType type, bool isPartOfMessage) { From 9c658490378a0e8d50604098653cb59574e22f6c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 18 Aug 2015 23:04:32 -0700 Subject: [PATCH 311/549] Add ordered sending to Socket and Connection --- libraries/networking/src/udt/Connection.cpp | 64 ++++++++++++++++++++- libraries/networking/src/udt/Connection.h | 21 +++++++ libraries/networking/src/udt/Socket.cpp | 38 ++++++++++-- libraries/networking/src/udt/Socket.h | 7 +++ 4 files changed, 123 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index d8aee60432..85c3dbcbda 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -16,9 +16,12 @@ #include #include "../HifiSockAddr.h" +#include "../NetworkLogging.h" + #include "CongestionControl.h" #include "ControlPacket.h" #include "Packet.h" +#include "PacketList.h" #include "Socket.h" using namespace udt; @@ -79,7 +82,32 @@ SendQueue& Connection::getSendQueue() { void Connection::sendReliablePacket(std::unique_ptr packet) { Q_ASSERT_X(packet->isReliable(), "Connection::send", "Trying to send an unreliable packet reliably."); - getSendQueue().queuePacket(move(packet)); + getSendQueue().queuePacket(std::move(packet)); +} + +void Connection::sendReliablePacketList(std::unique_ptr packetList) { + Q_ASSERT_X(packetList->isReliable(), "Connection::send", "Trying to send an unreliable packet reliably."); + getSendQueue().queuePacketList(std::move(packetList)); +} + +void Connection::queueReceivedMessagePacket(std::unique_ptr packet) { + Q_ASSERT(packet->isPartOfMessage()); + + auto messageNumber = packet->getMessageNumber(); + PendingReceivedMessage& pendingMessage = _pendingReceivedMessages[messageNumber]; + + pendingMessage.enqueuePacket(std::move(packet)); + + if (pendingMessage.isComplete()) { + // All messages have been received, create PacketList + auto packetList = PacketList::fromReceivedPackets(std::move(pendingMessage._packets)); + + _pendingReceivedMessages.erase(messageNumber); + + if (_parentSocket) { + _parentSocket->messageReceived(std::move(packetList)); + } + } } void Connection::sync() { @@ -609,3 +637,37 @@ void Connection::updateCongestionControlAndSendQueue(std::function cong _stats.recordPacketSendPeriod(_congestionControl->_packetSendPeriod); _stats.recordCongestionWindowSize(_congestionControl->_congestionWindowSize); } + +void PendingReceivedMessage::enqueuePacket(std::unique_ptr packet) { + if (_isComplete) { + qCDebug(networking) << "UNEXPECTED: Received packet for a message that is already complete"; + return; + } + + if (packet->getPacketPosition() == Packet::PacketPosition::FIRST) { + _hasFirstSequenceNumber = true; + _firstSequenceNumber = packet->getSequenceNumber(); + } else if (packet->getPacketPosition() == Packet::PacketPosition::LAST) { + _hasLastSequenceNumber = true; + _lastSequenceNumber = packet->getSequenceNumber(); + } else if (packet->getPacketPosition() == Packet::PacketPosition::ONLY) { + _hasFirstSequenceNumber = true; + _hasLastSequenceNumber = true; + _firstSequenceNumber = packet->getSequenceNumber(); + _lastSequenceNumber = packet->getSequenceNumber(); + } + + _packets.push_back(std::move(packet)); + + if (_hasFirstSequenceNumber && _hasLastSequenceNumber) { + auto numPackets = udt::seqlen(_firstSequenceNumber, _lastSequenceNumber); + if (uint64_t(numPackets) == _packets.size()) { + _isComplete = true; + + // Sort packets by sequence number + _packets.sort([](std::unique_ptr& a, std::unique_ptr& b) { + return a->getSequenceNumber() < b->getSequenceNumber(); + }); + } + } +} diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 65e7fe74f0..307c90eda5 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -30,8 +30,24 @@ namespace udt { class CongestionControl; class ControlPacket; class Packet; +class PacketList; class Socket; +class PendingReceivedMessage { +public: + void enqueuePacket(std::unique_ptr packet); + bool isComplete() const { return _isComplete; } + + std::list> _packets; + +private: + bool _isComplete { false }; + bool _hasFirstSequenceNumber { false }; + bool _hasLastSequenceNumber { false }; + SequenceNumber _firstSequenceNumber; + SequenceNumber _lastSequenceNumber; +}; + class Connection : public QObject { Q_OBJECT public: @@ -43,12 +59,15 @@ public: ~Connection(); void sendReliablePacket(std::unique_ptr packet); + void sendReliablePacketList(std::unique_ptr packet); void sync(); // rate control method, fired by Socket for all connections on SYN interval // return indicates if this packet was a duplicate bool processReceivedSequenceNumber(SequenceNumber sequenceNumber, int packetSize, int payloadSize); void processControl(std::unique_ptr controlPacket); + + void queueReceivedMessagePacket(std::unique_ptr packet); ConnectionStats::Stats sampleStats() { return _stats.sample(); } @@ -117,6 +136,8 @@ private: std::unique_ptr _congestionControl; std::unique_ptr _sendQueue; + + std::map _pendingReceivedMessages; int _packetsSinceACK { 0 }; // The number of packets that have been received during the current ACK interval diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 530d268425..0aac7f8f99 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -20,6 +20,7 @@ #include "ControlPacket.h" #include "Packet.h" #include "../NLPacket.h" +#include "PacketList.h" using namespace udt; @@ -104,6 +105,23 @@ qint64 Socket::writePacket(std::unique_ptr packet, const HifiSockAddr& s return writePacket(*packet, sockAddr); } +qint64 Socket::writePacketList(std::unique_ptr packetList, const HifiSockAddr& sockAddr) { + if (packetList->isReliable()) { + // Reliable and Ordered + // Reliable and Unordered + findOrCreateConnection(sockAddr).sendReliablePacketList(move(packetList)); + return 0; + } + + // Unerliable and Unordered + qint64 totalBytesSent = 0; + while (!packetList->_packets.empty()) { + totalBytesSent += writePacket(packetList->takeFront(), sockAddr); + } + + return totalBytesSent; +} + qint64 Socket::writeDatagram(const char* data, qint64 size, const HifiSockAddr& sockAddr) { return writeDatagram(QByteArray::fromRawData(data, size), sockAddr); } @@ -126,7 +144,7 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { auto it = _connectionsHash.find(sockAddr); - + if (it == _connectionsHash.end()) { auto connection = std::unique_ptr(new Connection(this, sockAddr, _ccFactory->create())); it = _connectionsHash.insert(it, std::make_pair(sockAddr, std::move(connection))); @@ -135,6 +153,12 @@ Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { return *it->second; } +void Socket::messageReceived(std::unique_ptr packetList) { + if (_packetListHandler) { + _packetListHandler(std::move(packetList)); + } +} + void Socket::readPendingDatagrams() { int packetSizeWithHeader = -1; while ((packetSizeWithHeader = _udpSocket.pendingDatagramSize()) != -1) { @@ -177,16 +201,18 @@ void Socket::readPendingDatagrams() { // call our verification operator to see if this packet is verified if (!_packetFilterOperator || _packetFilterOperator(*packet)) { - if (packet->isReliable()) { // if this was a reliable packet then signal the matching connection with the sequence number auto& connection = findOrCreateConnection(senderSockAddr); connection.processReceivedSequenceNumber(packet->getSequenceNumber(), - packet->getDataSize(), - packet->getPayloadSize()); + packet->getDataSize(), + packet->getPayloadSize()); } - - if (_packetHandler) { + + if (packet->isPartOfMessage()) { + auto& connection = findOrCreateConnection(senderSockAddr); + connection.queueReceivedMessagePacket(std::move(packet)); + } else if (_packetHandler) { // call the verified packet callback to let it handle this packet _packetHandler(std::move(packet)); } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index e3cf347905..0c4276a767 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -30,12 +30,14 @@ namespace udt { class BasePacket; class ControlSender; class Packet; +class PacketList; class SequenceNumber; using PacketFilterOperator = std::function; using BasePacketHandler = std::function)>; using PacketHandler = std::function)>; +using PacketListHandler = std::function)>; class Socket : public QObject { Q_OBJECT @@ -48,6 +50,7 @@ public: qint64 writeBasePacket(const BasePacket& packet, const HifiSockAddr& sockAddr); qint64 writePacket(const Packet& packet, const HifiSockAddr& sockAddr); qint64 writePacket(std::unique_ptr packet, const HifiSockAddr& sockAddr); + qint64 writePacketList(std::unique_ptr packetList, const HifiSockAddr& sockAddr); qint64 writeDatagram(const char* data, qint64 size, const HifiSockAddr& sockAddr); qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr); @@ -56,6 +59,7 @@ public: void setPacketFilterOperator(PacketFilterOperator filterOperator) { _packetFilterOperator = filterOperator; } void setPacketHandler(PacketHandler handler) { _packetHandler = handler; } + void setPacketListHandler(PacketListHandler handler) { _packetListHandler = handler; } void addUnfilteredHandler(const HifiSockAddr& senderSockAddr, BasePacketHandler handler) { _unfilteredHandlers[senderSockAddr] = handler; } @@ -63,6 +67,8 @@ public: void setCongestionControlFactory(std::unique_ptr ccFactory); void connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* receiver, const char* slot); + + void messageReceived(std::unique_ptr packetList); ConnectionStats::Stats sampleStatsForConnection(const HifiSockAddr& destination); std::vector getConnectionSockAddrs(); @@ -78,6 +84,7 @@ private: QUdpSocket _udpSocket { this }; PacketFilterOperator _packetFilterOperator; PacketHandler _packetHandler; + PacketListHandler _packetListHandler; std::unordered_map _unfilteredHandlers; std::unordered_map _unreliableSequenceNumbers; From 5cb028cf4382d575589507f180807533e0f992bb Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 18 Aug 2015 23:05:07 -0700 Subject: [PATCH 312/549] Add support for PacketList to SendQueue --- libraries/networking/src/udt/SendQueue.cpp | 45 ++++++++++++++++++++++ libraries/networking/src/udt/SendQueue.h | 6 +++ 2 files changed, 51 insertions(+) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index d3095bff15..2c2ff7350b 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -20,6 +20,7 @@ #include "ControlPacket.h" #include "Packet.h" +#include "PacketList.h" #include "Socket.h" using namespace udt; @@ -63,6 +64,44 @@ void SendQueue::queuePacket(std::unique_ptr packet) { } } +void SendQueue::queuePacketList(std::unique_ptr packetList) { + Q_ASSERT(packetList->_packets.size() > 0); + + { + QWriteLocker locker(&_packetsLock); + + auto messageNumber = getNextMessageNumber(); + + if (packetList->_packets.size() == 1) { + auto packet = packetList->takeFront(); + packet->setPacketPosition(Packet::PacketPosition::ONLY); + + packet->writeMessageNumber(messageNumber); + _packets.push_back(std::move(packet)); + } else { + bool haveMarkedFirstPacket = false; + while (!packetList->_packets.empty()) { + auto packet = packetList->takeFront(); + if (!haveMarkedFirstPacket) { + packet->setPacketPosition(Packet::PacketPosition::FIRST); + haveMarkedFirstPacket = true; + } else if (packetList->_packets.empty()) { + packet->setPacketPosition(Packet::PacketPosition::LAST); + } else { + packet->setPacketPosition(Packet::PacketPosition::MIDDLE); + } + + packet->writeMessageNumber(messageNumber); + + _packets.push_back(std::move(packet)); + } + } + } + if (!this->thread()->isRunning()) { + this->thread()->start(); + } +} + void SendQueue::stop() { _isRunning = false; } @@ -121,6 +160,12 @@ SequenceNumber SendQueue::getNextSequenceNumber() { return _currentSequenceNumber; } +uint32_t SendQueue::getNextMessageNumber() { + static const MessageNumber MAX_MESSAGE_NUMBER = MessageNumber(1) << 30; + _currentMessageNumber = (_currentMessageNumber + 1) % MAX_MESSAGE_NUMBER; + return _currentMessageNumber; +} + void SendQueue::sendNewPacketAndAddToSentList(std::unique_ptr newPacket, SequenceNumber sequenceNumber) { // write the sequence number and send the packet newPacket->writeSequenceNumber(sequenceNumber); diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index bbb1dc3798..901a9f7a87 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -31,7 +31,10 @@ namespace udt { class BasePacket; class ControlPacket; class Packet; +class PacketList; class Socket; + +using MessageNumber = uint32_t; class SendQueue : public QObject { Q_OBJECT @@ -40,6 +43,7 @@ public: static std::unique_ptr create(Socket* socket, HifiSockAddr destination); void queuePacket(std::unique_ptr packet); + void queuePacketList(std::unique_ptr packetList); int getQueueSize() const { QReadLocker locker(&_packetsLock); return _packets.size(); } SequenceNumber getCurrentSequenceNumber() const { return SequenceNumber(_atomicCurrentSequenceNumber); } @@ -73,6 +77,7 @@ private: // Increments current sequence number and return it SequenceNumber getNextSequenceNumber(); + MessageNumber getNextMessageNumber(); mutable QReadWriteLock _packetsLock; // Protects the packets to be sent list. std::list> _packets; // List of packets to be sent @@ -82,6 +87,7 @@ private: std::atomic _lastACKSequenceNumber; // Last ACKed sequence number + MessageNumber _currentMessageNumber { 0 }; SequenceNumber _currentSequenceNumber; // Last sequence number sent out std::atomic _atomicCurrentSequenceNumber;// Atomic for last sequence number sent out From 8032f05ed6666b5878d94464ff5200b33b7772c1 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 18 Aug 2015 23:06:30 -0700 Subject: [PATCH 313/549] Add support for generating PacketList from received data --- libraries/networking/src/udt/PacketList.cpp | 54 +++++++++++++++++++-- libraries/networking/src/udt/PacketList.h | 27 +++++++++-- 2 files changed, 73 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/udt/PacketList.cpp b/libraries/networking/src/udt/PacketList.cpp index 494587971b..e5386a4cc9 100644 --- a/libraries/networking/src/udt/PacketList.cpp +++ b/libraries/networking/src/udt/PacketList.cpp @@ -13,17 +13,26 @@ #include -#include "Packet.h" +#include "../NLPacket.h" using namespace udt; -PacketList::PacketList(PacketType packetType, QByteArray extendedHeader) : +PacketList::PacketList(PacketType packetType, QByteArray extendedHeader, bool isReliable, bool isOrdered) : _packetType(packetType), + _isReliable(isReliable), + _isOrdered(isOrdered), _extendedHeader(extendedHeader) { + Q_ASSERT_X(!(!_isReliable && _isOrdered), "PacketList", "Unreliable ordered PacketLists are not currently supported"); QIODevice::open(WriteOnly); } +PacketList::PacketList(PacketList&& other) : + _packetType(other._packetType), + _packets(std::move(other._packets)) +{ +} + void PacketList::startSegment() { _segmentStartIndex = _currentPacket ? _currentPacket->pos() : _extendedHeader.size(); } @@ -32,10 +41,30 @@ void PacketList::endSegment() { _segmentStartIndex = -1; } +size_t PacketList::getDataSize() const { + size_t totalBytes = 0; + for (const auto& packet : _packets) { + totalBytes += packet->getDataSize(); + } + + if (_currentPacket) { + totalBytes += _currentPacket->getDataSize(); + } + + return totalBytes; +} + +std::unique_ptr PacketList::fromReceivedPackets(std::list>&& packets) { + auto packetList = std::unique_ptr(new PacketList(PacketType::Unknown, QByteArray(), true, true)); + packetList->_packets = std::move(packets); + return packetList; +} + std::unique_ptr PacketList::createPacket() { // use the static create method to create a new packet - // TODO: create a packet with correct reliability and messaging - return Packet::create(); + // If this packet list is supposed to be ordered then we consider this to be part of a message + bool isPartOfMessage = _isOrdered; + return Packet::create(-1, _isReliable, isPartOfMessage); } std::unique_ptr PacketList::createPacketWithExtendedHeader() { @@ -53,6 +82,23 @@ std::unique_ptr PacketList::createPacketWithExtendedHeader() { return packet; } +QByteArray PacketList::getAllData() { + size_t sizeBytes = 0; + + for (const auto& packet : _packets) { + sizeBytes += packet->size(); + } + + QByteArray data; + data.reserve(sizeBytes); + + for (auto& packet : _packets) { + data.append(packet->getPayload(), packet->getPayloadSize()); + } + + return data; +} + qint64 PacketList::writeData(const char* data, qint64 maxSize) { if (!_currentPacket) { // we don't have a current packet, time to set one up diff --git a/libraries/networking/src/udt/PacketList.h b/libraries/networking/src/udt/PacketList.h index 18acb7fa17..5596253a6c 100644 --- a/libraries/networking/src/udt/PacketList.h +++ b/libraries/networking/src/udt/PacketList.h @@ -16,6 +16,7 @@ #include +#include "Packet.h" #include "PacketHeaders.h" class LimitedNodeList; @@ -27,26 +28,44 @@ class Packet; class PacketList : public QIODevice { Q_OBJECT public: - PacketList(PacketType packetType, QByteArray extendedHeader = QByteArray()); + PacketList(PacketType packetType, QByteArray extendedHeader = QByteArray(), bool isReliable = false, bool isOrdered = false); + PacketList(PacketList&& other); + + static std::unique_ptr fromReceivedPackets(std::list>&& packets); virtual bool isSequential() const { return true; } + + bool isReliable() const { return _isReliable; } + bool isOrdered() const { return _isOrdered; } void startSegment(); void endSegment(); PacketType getType() const { return _packetType; } int getNumPackets() const { return _packets.size() + (_currentPacket ? 1 : 0); } + + QByteArray getExtendedHeader() const { return _extendedHeader; } + + size_t getDataSize() const; void closeCurrentPacket(bool shouldSendEmpty = false); - + + QByteArray getAllData(); + template qint64 readPrimitive(T* data); template qint64 writePrimitive(const T& data); + std::list> _packets; protected: virtual qint64 writeData(const char* data, qint64 maxSize); virtual qint64 readData(char* data, qint64 maxSize) { return 0; } + PacketType _packetType; + private: friend class ::LimitedNodeList; + friend class Socket; + friend class SendQueue; + friend class NLPacketList; PacketList(const PacketList& other) = delete; PacketList& operator=(const PacketList& other) = delete; @@ -58,11 +77,11 @@ private: virtual std::unique_ptr createPacket(); std::unique_ptr createPacketWithExtendedHeader(); - PacketType _packetType; + Packet::MessageNumber _messageNumber; + bool _isReliable = false; bool _isOrdered = false; std::unique_ptr _currentPacket; - std::list> _packets; int _segmentStartIndex = -1; From 46d5f73e4ebdc9715920092eb05e549cc4852f17 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 18 Aug 2015 23:07:08 -0700 Subject: [PATCH 314/549] Add support for creating NLPacketList from PacketList --- libraries/networking/src/NLPacketList.cpp | 22 +++++++++++++++++----- libraries/networking/src/NLPacketList.h | 13 +++++++++++-- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/NLPacketList.cpp b/libraries/networking/src/NLPacketList.cpp index df36228e7a..6dfd627271 100644 --- a/libraries/networking/src/NLPacketList.cpp +++ b/libraries/networking/src/NLPacketList.cpp @@ -11,15 +11,27 @@ #include "NLPacketList.h" -#include "NLPacket.h" +#include "udt/Packet.h" -NLPacketList::NLPacketList(PacketType packetType, QByteArray extendedHeader) : - PacketList(packetType, extendedHeader) +NLPacketList::NLPacketList(PacketType packetType, QByteArray extendedHeader, bool isReliable, bool isOrdered) : + PacketList(packetType, extendedHeader, isReliable, isOrdered) { +} +NLPacketList::NLPacketList(PacketList&& other) : PacketList(other.getType(), other.getExtendedHeader(), other.isReliable(), other.isOrdered()) { + // Update _packets + for (auto& packet : other._packets) { + auto nlPacket = NLPacket::fromBase(std::move(packet)); + _packets.push_back(std::move(nlPacket)); + } + + if (_packets.size() > 0) { + auto nlPacket = static_cast(_packets.front().get()); + _sourceID = nlPacket->getSourceID(); + _packetType = nlPacket->getType(); + } } std::unique_ptr NLPacketList::createPacket() { - return NLPacket::create(getType()); + return NLPacket::create(getType(), -1, isReliable(), isOrdered()); } - diff --git a/libraries/networking/src/NLPacketList.h b/libraries/networking/src/NLPacketList.h index 512ec23d22..cb48db08f2 100644 --- a/libraries/networking/src/NLPacketList.h +++ b/libraries/networking/src/NLPacketList.h @@ -12,17 +12,26 @@ #ifndef hifi_NLPacketList_h #define hifi_NLPacketList_h +#include + #include "udt/PacketList.h" +#include "NLPacket.h" + class NLPacketList : public udt::PacketList { public: - NLPacketList(PacketType packetType, QByteArray extendedHeader = QByteArray()); + NLPacketList(PacketType packetType, QByteArray extendedHeader = QByteArray(), bool isReliable = false, bool isOrdered = false); + NLPacketList(PacketList&& packetList); + + QUuid getSourceID() const { return _sourceID; } private: NLPacketList(const NLPacketList& other) = delete; NLPacketList& operator=(const NLPacketList& other) = delete; - + virtual std::unique_ptr createPacket(); + + QUuid _sourceID; }; #endif // hifi_PacketList_h From 69a2d0b5b03c30ccf933b31f3344277a36d391ef Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 18 Aug 2015 23:07:54 -0700 Subject: [PATCH 315/549] Add 32-bit message data to packet header --- libraries/networking/src/udt/Packet.cpp | 33 ++++++++++++++++++++----- libraries/networking/src/udt/Packet.h | 18 +++++++++++++- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index ae81341a1d..2cc0624f7b 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -57,7 +57,6 @@ Packet::Packet(qint64 size, bool isReliable, bool isPartOfMessage) : _isPartOfMessage(isPartOfMessage) { adjustPayloadStartAndCapacity(Packet::localHeaderSize(_isPartOfMessage)); - // set the UDT header to default values writeHeader(); } @@ -106,6 +105,12 @@ Packet& Packet::operator=(Packet&& other) { return *this; } +void Packet::writeMessageNumber(MessageNumber messageNumber) { + _isPartOfMessage = true; + _messageNumber = messageNumber; + writeHeader(); +} + void Packet::writeSequenceNumber(SequenceNumber sequenceNumber) const { _sequenceNumber = sequenceNumber; writeHeader(); @@ -115,14 +120,23 @@ static const uint32_t RELIABILITY_BIT_MASK = uint32_t(1) << (SEQUENCE_NUMBER_BIT static const uint32_t MESSAGE_BIT_MASK = uint32_t(1) << (SEQUENCE_NUMBER_BITS - 3); static const uint32_t BIT_FIELD_MASK = CONTROL_BIT_MASK | RELIABILITY_BIT_MASK | MESSAGE_BIT_MASK; +static const uint32_t PACKET_POSITION_MASK = uint32_t(0x03) << 30; +static const uint32_t MESSAGE_NUMBER_MASK = ~PACKET_POSITION_MASK; + void Packet::readHeader() const { - SequenceNumberAndBitField seqNumBitField = *reinterpret_cast(_packet.get()); + SequenceNumberAndBitField* seqNumBitField = reinterpret_cast(_packet.get()); - Q_ASSERT_X(!(seqNumBitField & CONTROL_BIT_MASK), "Packet::readHeader()", "This should be a data packet"); + Q_ASSERT_X(!(*seqNumBitField & CONTROL_BIT_MASK), "Packet::readHeader()", "This should be a data packet"); - _isReliable = (bool) (seqNumBitField & RELIABILITY_BIT_MASK); // Only keep reliability bit - _isPartOfMessage = (bool) (seqNumBitField & MESSAGE_BIT_MASK); // Only keep message bit - _sequenceNumber = SequenceNumber{ seqNumBitField & ~BIT_FIELD_MASK }; // Remove the bit field + _isReliable = (bool) (*seqNumBitField & RELIABILITY_BIT_MASK); // Only keep reliability bit + _isPartOfMessage = (bool) (*seqNumBitField & MESSAGE_BIT_MASK); // Only keep message bit + _sequenceNumber = SequenceNumber{ *seqNumBitField & ~BIT_FIELD_MASK }; // Remove the bit field + + if (_isPartOfMessage) { + MessageNumberAndBitField* messageNumberAndBitField = seqNumBitField + 1; + _messageNumber = *messageNumberAndBitField & MESSAGE_NUMBER_MASK; + _packetPosition = static_cast(*messageNumberAndBitField >> 30); + } } void Packet::writeHeader() const { @@ -140,5 +154,12 @@ void Packet::writeHeader() const { if (_isPartOfMessage) { *seqNumBitField |= MESSAGE_BIT_MASK; + + Q_ASSERT_X(!(_messageNumber & PACKET_POSITION_MASK), + "Packet::writeHeader()", "Message number is overflowing into bit field"); + + MessageNumberAndBitField* messageNumberAndBitField = seqNumBitField + 1; + *messageNumberAndBitField = _messageNumber; + *messageNumberAndBitField |= _packetPosition << 30; } } diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index 01c7fe90a1..2c57bbfc6c 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -31,6 +31,14 @@ public: // NOTE: The MessageNumber is only actually 29 bits to leave room for a bit field using MessageNumber = uint32_t; using MessageNumberAndBitField = uint32_t; + + // Use same size as MessageNumberAndBitField so we can use the enum with bitwise operations + enum PacketPosition : MessageNumberAndBitField { + ONLY = 0x0, + FIRST = 0x2, + MIDDLE = 0x3, + LAST = 0x1 + }; static std::unique_ptr create(qint64 size = -1, bool isReliable = false, bool isPartOfMessage = false); static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); @@ -48,8 +56,14 @@ public: bool isPartOfMessage() const { return _isPartOfMessage; } bool isReliable() const { return _isReliable; } SequenceNumber getSequenceNumber() const { return _sequenceNumber; } + + MessageNumber getMessageNumber() const { return _messageNumber; } + + void setPacketPosition(PacketPosition position) { _packetPosition = position; } + PacketPosition getPacketPosition() const { return _packetPosition; } - void writeSequenceNumber(SequenceNumber sequenceNumber) const; + void writeMessageNumber(MessageNumber messageNumber); + void writeSequenceNumber(SequenceNumber sequenceNumber)const; protected: Packet(qint64 size, bool isReliable = false, bool isPartOfMessage = false); @@ -70,6 +84,8 @@ private: mutable bool _isReliable { false }; mutable bool _isPartOfMessage { false }; mutable SequenceNumber _sequenceNumber; + mutable PacketPosition _packetPosition { PacketPosition::ONLY }; + mutable MessageNumber _messageNumber { 0 }; }; } // namespace udt From 9154067cfb20d04015d51fee690ac874701ad032 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 18 Aug 2015 23:08:25 -0700 Subject: [PATCH 316/549] Add PacketList interface to PacketReceiver --- libraries/networking/src/PacketReceiver.cpp | 156 +++++++++++++++++++- libraries/networking/src/PacketReceiver.h | 4 + 2 files changed, 159 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index b3d591d875..1056c54c5e 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -89,6 +89,28 @@ void PacketReceiver::registerDirectListenerForTypes(const QSet& type } } +bool PacketReceiver::registerMessageListener(PacketType type, QObject* listener, const char* slot) { + QMetaMethod matchingMethod = matchingMethodForListener(type, listener, slot); + + if (matchingMethod.isValid()) { + //registerVerifiedListener(type, listener, matchingMethod); + _packetListenerLock.lock(); + + if (_packetListListenerMap.contains(type)) { + qDebug() << "Warning: Registering a packet listener for packet type" << type + << "that will remove a previously registered listener"; + } + + // add the mapping + _packetListListenerMap[type] = ObjectMethodPair(QPointer(listener), matchingMethod); + + _packetListenerLock.unlock(); + return true; + } else { + return false; + } +} + bool PacketReceiver::registerListener(PacketType type, QObject* listener, const char* slot) { Q_ASSERT(listener); @@ -107,19 +129,25 @@ QMetaMethod PacketReceiver::matchingMethodForListener(PacketType type, QObject* // normalize the slot with the expected parameters - const QString NON_SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer"; + static const QString NON_SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer"; + static const QString NON_SOURCED_PACKETLIST_LISTENER_PARAMETERS = "QSharedPointer"; QSet possibleSignatures { QString("%1(%2)").arg(slot).arg(NON_SOURCED_PACKET_LISTENER_PARAMETERS) }; + possibleSignatures << QString("%1(%2)").arg(slot).arg(NON_SOURCED_PACKETLIST_LISTENER_PARAMETERS); if (!NON_SOURCED_PACKETS.contains(type)) { static const QString SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer,QSharedPointer"; static const QString TYPEDEF_SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer,SharedNodePointer"; + static const QString SOURCED_PACKETLIST_LISTENER_PARAMETERS = "QSharedPointer,QSharedPointer"; + static const QString TYPEDEF_SOURCED_PACKETLIST_LISTENER_PARAMETERS = "QSharedPointer,SharedNodePointer"; // a sourced packet must take the shared pointer to the packet but optionally could include // a shared pointer to the node possibleSignatures << QString("%1(%2)").arg(slot).arg(TYPEDEF_SOURCED_PACKET_LISTENER_PARAMETERS); possibleSignatures << QString("%1(%2)").arg(slot).arg(SOURCED_PACKET_LISTENER_PARAMETERS); + possibleSignatures << QString("%1(%2)").arg(slot).arg(TYPEDEF_SOURCED_PACKETLIST_LISTENER_PARAMETERS); + possibleSignatures << QString("%1(%2)").arg(slot).arg(SOURCED_PACKETLIST_LISTENER_PARAMETERS); } int methodIndex = -1; @@ -190,6 +218,132 @@ void PacketReceiver::unregisterListener(QObject* listener) { _directConnectSetMutex.unlock(); } +void PacketReceiver::handleVerifiedPacketList(std::unique_ptr packetList) { + // if we're supposed to drop this packet then break out here + if (_shouldDropPackets) { + return; + } + + // setup an NLPacketList from the PacketList we were passed + auto nlPacketList = new NLPacketList(std::move(*packetList)); + + auto nodeList = DependencyManager::get(); + + _inPacketCount += nlPacketList->getNumPackets(); + _inByteCount += nlPacketList->getDataSize(); + + SharedNodePointer matchingNode; + + if (!nlPacketList->getSourceID().isNull()) { + matchingNode = nodeList->nodeWithUUID(nlPacketList->getSourceID()); + + if (matchingNode) { + // No matter if this packet is handled or not, we update the timestamp for the last time we heard + // from this sending node + matchingNode->setLastHeardMicrostamp(usecTimestampNow()); + } + } + + _packetListenerLock.lock(); + + bool listenerIsDead = false; + + auto it = _packetListListenerMap.find(nlPacketList->getType()); + + if (it != _packetListListenerMap.end() && it->second.isValid()) { + + auto listener = it.value(); + + if (listener.first) { + + bool success = false; + + // check if this is a directly connected listener + _directConnectSetMutex.lock(); + + Qt::ConnectionType connectionType = + _directlyConnectedObjects.contains(listener.first) ? Qt::DirectConnection : Qt::AutoConnection; + + _directConnectSetMutex.unlock(); + + PacketType packetType = nlPacketList->getType(); + + if (matchingNode) { + emit dataReceived(matchingNode->getType(), nlPacketList->getDataSize()); + QMetaMethod metaMethod = listener.second; + + static const QByteArray QSHAREDPOINTER_NODE_NORMALIZED = QMetaObject::normalizedType("QSharedPointer"); + static const QByteArray SHARED_NODE_NORMALIZED = QMetaObject::normalizedType("SharedNodePointer"); + + // one final check on the QPointer before we go to invoke + if (listener.first) { + if (metaMethod.parameterTypes().contains(SHARED_NODE_NORMALIZED)) { + success = metaMethod.invoke(listener.first, + connectionType, + Q_ARG(QSharedPointer, + QSharedPointer(nlPacketList)), + Q_ARG(SharedNodePointer, matchingNode)); + + } else if (metaMethod.parameterTypes().contains(QSHAREDPOINTER_NODE_NORMALIZED)) { + success = metaMethod.invoke(listener.first, + connectionType, + Q_ARG(QSharedPointer, + QSharedPointer(nlPacketList)), + Q_ARG(QSharedPointer, matchingNode)); + + } else { + success = metaMethod.invoke(listener.first, + connectionType, + Q_ARG(QSharedPointer, + QSharedPointer(nlPacketList))); + } + } else { + listenerIsDead = true; + } + } else { + emit dataReceived(NodeType::Unassigned, nlPacketList->getDataSize()); + + // one final check on the QPointer before we invoke + if (listener.first) { + success = listener.second.invoke(listener.first, + Q_ARG(QSharedPointer, + QSharedPointer(nlPacketList))); + } else { + listenerIsDead = true; + } + + } + + if (!success) { + qDebug().nospace() << "Error delivering packet " << packetType << " to listener " + << listener.first << "::" << qPrintable(listener.second.methodSignature()); + } + + } else { + listenerIsDead = true; + } + + if (listenerIsDead) { + qDebug().nospace() << "Listener for packet " << nlPacketList->getType() + << " has been destroyed. Removing from listener map."; + it = _packetListListenerMap.erase(it); + + // if it exists, remove the listener from _directlyConnectedObjects + _directConnectSetMutex.lock(); + _directlyConnectedObjects.remove(listener.first); + _directConnectSetMutex.unlock(); + } + + } else if (it == _packetListListenerMap.end()) { + qWarning() << "No listener found for packet type" << nlPacketList->getType(); + + // insert a dummy listener so we don't print this again + _packetListListenerMap.insert(nlPacketList->getType(), { nullptr, QMetaMethod() }); + } + + _packetListenerLock.unlock(); +} + void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { // if we're supposed to drop this packet then break out here diff --git a/libraries/networking/src/PacketReceiver.h b/libraries/networking/src/PacketReceiver.h index 531a8e60be..b5a4501476 100644 --- a/libraries/networking/src/PacketReceiver.h +++ b/libraries/networking/src/PacketReceiver.h @@ -21,6 +21,7 @@ #include #include "NLPacket.h" +#include "NLPacketList.h" #include "udt/PacketHeaders.h" class EntityEditPacketSender; @@ -42,10 +43,12 @@ public: void resetCounters() { _inPacketCount = 0; _inByteCount = 0; } bool registerListenerForTypes(const QSet& types, QObject* listener, const char* slot); + bool registerMessageListener(PacketType types, QObject* listener, const char* slot); bool registerListener(PacketType type, QObject* listener, const char* slot); void unregisterListener(QObject* listener); void handleVerifiedPacket(std::unique_ptr packet); + void handleVerifiedPacketList(std::unique_ptr packetList); signals: void dataReceived(quint8 channelType, int bytes); @@ -63,6 +66,7 @@ private: QMutex _packetListenerLock; QHash _packetListenerMap; + QHash _packetListListenerMap; int _inPacketCount = 0; int _inByteCount = 0; bool _shouldDropPackets = false; From 0b3986ef9ba333da822c10ff71659b03fc923477 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 18 Aug 2015 23:09:02 -0700 Subject: [PATCH 317/549] Replace NLPacket unique_ptr ctor with && ctor --- libraries/networking/src/NLPacket.cpp | 6 +++--- libraries/networking/src/NLPacket.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 39f4f9c541..575a2c7a9c 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -54,7 +54,7 @@ std::unique_ptr NLPacket::fromBase(std::unique_ptr packet) { Q_ASSERT(packet); // call our constructor to create an NLPacket from this Packet - return std::unique_ptr(new NLPacket(std::move(packet))); + return std::unique_ptr(new NLPacket(std::move(*packet))); } std::unique_ptr NLPacket::createCopy(const NLPacket& other) { @@ -71,8 +71,8 @@ NLPacket::NLPacket(PacketType type, qint64 size, bool isReliable, bool isPartOfM writeTypeAndVersion(); } -NLPacket::NLPacket(std::unique_ptr packet) : - Packet(std::move(*packet.release())) +NLPacket::NLPacket(Packet&& packet) : + Packet(std::move(packet)) { readType(); readVersion(); diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index c25ff198a5..b5d5fc0766 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -63,10 +63,10 @@ protected: NLPacket(PacketType type, qint64 size = -1, bool forceReliable = false, bool isPartOfMessage = false); NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); - NLPacket(std::unique_ptr packet); NLPacket(const NLPacket& other); NLPacket(NLPacket&& other); + NLPacket(Packet&& other); NLPacket& operator=(const NLPacket& other); NLPacket& operator=(NLPacket&& other); From 62eaaed9e5abfe96490ff095c4b2bbf5cb0b3c90 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 18 Aug 2015 23:10:05 -0700 Subject: [PATCH 318/549] Add PacketList support to LimitedNodeList --- libraries/networking/src/LimitedNodeList.cpp | 12 ++++++++++++ libraries/networking/src/LimitedNodeList.h | 1 + 2 files changed, 13 insertions(+) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 5f547ecaf3..e2bae6b5e8 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -95,6 +95,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short // set &PacketReceiver::handleVerifiedPacket as the verified packet callback for the udt::Socket using std::placeholders::_1; _nodeSocket.setPacketHandler(std::bind(&PacketReceiver::handleVerifiedPacket, _packetReceiver, _1)); + _nodeSocket.setPacketListHandler(std::bind(&PacketReceiver::handleVerifiedPacketList, _packetReceiver, _1)); // set our isPacketVerified method as the verify operator for the udt::Socket _nodeSocket.setPacketFilterOperator(std::bind(&LimitedNodeList::isPacketVerified, this, _1)); @@ -258,6 +259,7 @@ void LimitedNodeList::fillPacketHeader(const NLPacket& packet, const QUuid& conn } qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const Node& destinationNode) { + Q_ASSERT(!packet.isPartOfMessage()); if (!destinationNode.getActiveSocket()) { return 0; } @@ -267,6 +269,7 @@ qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const Node& 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."); @@ -277,6 +280,7 @@ qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const HifiS } qint64 LimitedNodeList::sendPacket(std::unique_ptr packet, const Node& destinationNode) { + Q_ASSERT(!packet->isPartOfMessage()); if (!destinationNode.getActiveSocket()) { return 0; } @@ -286,6 +290,7 @@ qint64 LimitedNodeList::sendPacket(std::unique_ptr packet, const Node& qint64 LimitedNodeList::sendPacket(std::unique_ptr packet, const HifiSockAddr& sockAddr, const QUuid& connectionSecret) { + Q_ASSERT(!packet->isPartOfMessage()); if (packet->isReliable()) { collectPacketStats(*packet); fillPacketHeader(*packet, connectionSecret); @@ -332,6 +337,13 @@ qint64 LimitedNodeList::sendPacketList(NLPacketList& packetList, const HifiSockA return bytesSent; } +qint64 LimitedNodeList::sendPacketList(std::unique_ptr packetList, const HifiSockAddr& sockAddr) { + // close the last packet in the list + packetList->closeCurrentPacket(); + + return _nodeSocket.writePacketList(std::move(packetList), sockAddr); +} + qint64 LimitedNodeList::sendPacket(std::unique_ptr packet, const Node& destinationNode, const HifiSockAddr& overridenSockAddr) { // use the node's active socket as the destination socket if there is no overriden socket address diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 9c3ff058fc..5371831e3e 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -127,6 +127,7 @@ public: qint64 sendPacketList(NLPacketList& packetList, const Node& destinationNode); qint64 sendPacketList(NLPacketList& packetList, const HifiSockAddr& sockAddr, const QUuid& connectionSecret = QUuid()); + qint64 sendPacketList(std::unique_ptr packetList, const HifiSockAddr& sockAddr); void (*linkedDataCreateCallback)(Node *); From 63d0205d1e9093d6f24b35b577337ea7fd6d8349 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 18 Aug 2015 23:11:33 -0700 Subject: [PATCH 319/549] Move domain settings retrieval to UDT --- domain-server/src/DomainServer.cpp | 3 ++ .../src/DomainServerSettingsManager.cpp | 18 ++++++++++ .../src/DomainServerSettingsManager.h | 6 ++++ libraries/networking/src/Assignment.h | 2 +- libraries/networking/src/DomainHandler.cpp | 35 ++++++++++++------- libraries/networking/src/DomainHandler.h | 3 ++ libraries/networking/src/NodeList.cpp | 1 + .../networking/src/udt/PacketHeaders.cpp | 1 + libraries/networking/src/udt/PacketHeaders.h | 4 ++- 9 files changed, 58 insertions(+), 15 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index f15de0c458..ddbef90ef6 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -289,6 +289,9 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { packetReceiver.registerListener(PacketType::ICEPing, this, "processICEPingPacket"); packetReceiver.registerListener(PacketType::ICEPingReply, this, "processICEPingReplyPacket"); packetReceiver.registerListener(PacketType::ICEServerPeerInformation, this, "processICEPeerInformationPacket"); + + // NodeList won't be available to the settings manager when it is created, so call registerListener here + packetReceiver.registerListener(PacketType::DomainSettingsRequest, &_settingsManager, "processSettingsRequestPacket"); // add whatever static assignments that have been parsed to the queue addStaticAssignmentsToQueue(); diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 5cd5b5ef35..c9b52a17bb 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "DomainServerSettingsManager.h" @@ -66,6 +67,23 @@ DomainServerSettingsManager::DomainServerSettingsManager() : QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection); } +void DomainServerSettingsManager::processSettingsRequestPacket(QSharedPointer packet) { + qDebug() << "Got request for domain settings"; + + Assignment::Type type; + packet->readPrimitive(&type); + + QJsonObject responseObject = responseObjectForType(QString::number(type)); + auto json = QJsonDocument(responseObject).toJson(); + + auto packetList = std::unique_ptr(new NLPacketList(PacketType::DomainSettings, QByteArray(), true, true)); + + packetList->write(json); + + auto nodeList = DependencyManager::get(); + nodeList->sendPacketList(std::move(packetList), packet->getSenderSockAddr()); +} + void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList) { _configMap.loadMasterAndUserConfig(argumentList); diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index 21bf099ef0..321f7b7214 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -18,6 +18,8 @@ #include #include +#include + const QString SETTINGS_PATHS_KEY = "paths"; const QString SETTINGS_PATH = "/settings"; @@ -38,6 +40,10 @@ public: QVariantMap& getUserSettingsMap() { return _configMap.getUserConfig(); } QVariantMap& getSettingsMap() { return _configMap.getMergedConfig(); } + +private slots: + void processSettingsRequestPacket(QSharedPointer packet); + private: QJsonObject responseObjectForType(const QString& typeValue, bool isAuthenticated = false); void recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, QVariantMap& settingsVariant); diff --git a/libraries/networking/src/Assignment.h b/libraries/networking/src/Assignment.h index 67f861f850..0fadc78770 100644 --- a/libraries/networking/src/Assignment.h +++ b/libraries/networking/src/Assignment.h @@ -25,7 +25,7 @@ class Assignment : public NodeData { Q_OBJECT public: - enum Type { + enum Type : uint8_t { AudioMixerType = 0, AvatarMixerType = 1, AgentType = 2, diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 6c6c258235..81b7ee6c55 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -17,7 +17,9 @@ #include "Assignment.h" #include "HifiSockAddr.h" #include "NodeList.h" +#include "udt/Packet.h" #include "udt/PacketHeaders.h" +#include "NLPacket.h" #include "SharedUtil.h" #include "UserActivityLogger.h" #include "NetworkLogging.h" @@ -39,7 +41,7 @@ DomainHandler::DomainHandler(QObject* parent) : _failedSettingsRequests(0) { _sockAddr.setObjectName("DomainServer"); - + // if we get a socket that make sure our NetworkPeer ping timer stops connect(this, &DomainHandler::completedSocketDiscovery, &_icePeer, &NetworkPeer::stopPingTimer); } @@ -233,21 +235,15 @@ void DomainHandler::requestDomainSettings() { emit settingsReceived(_settingsObject); } else { if (_settingsObject.isEmpty()) { - // setup the URL required to grab settings JSON - QUrl settingsJSONURL; - settingsJSONURL.setScheme("http"); - settingsJSONURL.setHost(_hostname); - settingsJSONURL.setPort(DOMAIN_SERVER_HTTP_PORT); - settingsJSONURL.setPath("/settings.json"); + qCDebug(networking) << "Requesting settings from domain server"; + Assignment::Type assignmentType = Assignment::typeForNodeType(DependencyManager::get()->getOwnerType()); - settingsJSONURL.setQuery(QString("type=%1").arg(assignmentType)); - qCDebug(networking) << "Requesting domain-server settings at" << settingsJSONURL.toString(); + auto packet = NLPacket::create(PacketType::DomainSettingsRequest, sizeof(assignmentType), true, false); + packet->writePrimitive(assignmentType); - QNetworkRequest settingsRequest(settingsJSONURL); - settingsRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); - QNetworkReply* reply = NetworkAccessManager::getInstance().get(settingsRequest); - connect(reply, &QNetworkReply::finished, this, &DomainHandler::settingsRequestFinished); + auto nodeList = DependencyManager::get(); + nodeList->sendPacket(std::move(packet), _sockAddr); } } } @@ -286,6 +282,19 @@ void DomainHandler::settingsRequestFinished() { settingsReply->deleteLater(); } +void DomainHandler::processSettingsPacketList(QSharedPointer packetList) { + auto data = packetList->getAllData(); + + _settingsObject = QJsonDocument::fromJson(data).object(); + + qCDebug(networking) << "Received domain settings: \n" << QString(data); + + // reset failed settings requests to 0, we got them + _failedSettingsRequests = 0; + + emit settingsReceived(_settingsObject); +} + void DomainHandler::processICEPingReplyPacket(QSharedPointer packet) { const HifiSockAddr& senderSockAddr = packet->getSenderSockAddr(); qCDebug(networking) << "Received reply from domain-server on" << senderSockAddr; diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 7bb0582914..349b3934eb 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -22,6 +22,8 @@ #include "HifiSockAddr.h" #include "NetworkPeer.h" #include "NLPacket.h" +#include "NLPacketList.h" +#include "Node.h" const unsigned short DEFAULT_DOMAIN_SERVER_PORT = 40102; const unsigned short DEFAULT_DOMAIN_SERVER_DTLS_PORT = 40103; @@ -85,6 +87,7 @@ public slots: void setHostnameAndPort(const QString& hostname, quint16 port = DEFAULT_DOMAIN_SERVER_PORT); void setIceServerHostnameAndID(const QString& iceServerHostname, const QUuid& id); + void processSettingsPacketList(QSharedPointer packetList); void processICEPingReplyPacket(QSharedPointer packet); void processDTLSRequirementPacket(QSharedPointer dtlsRequirementPacket); void processICEResponsePacket(QSharedPointer icePacket); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index ab69d11bc3..000180cec7 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -95,6 +95,7 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned packetReceiver.registerListener(PacketType::ICEPing, this, "processICEPingPacket"); packetReceiver.registerListener(PacketType::DomainServerAddedNode, this, "processDomainServerAddedNode"); packetReceiver.registerListener(PacketType::DomainServerConnectionToken, this, "processDomainServerConnectionTokenPacket"); + packetReceiver.registerMessageListener(PacketType::DomainSettings, &_domainHandler, "processSettingsPacketList"); packetReceiver.registerListener(PacketType::ICEServerPeerInformation, &_domainHandler, "processICEResponsePacket"); packetReceiver.registerListener(PacketType::DomainServerRequireDTLS, &_domainHandler, "processDTLSRequirementPacket"); packetReceiver.registerListener(PacketType::ICEPingReply, &_domainHandler, "processICEPingReplyPacket"); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 1c2a38a2a6..819a65dc26 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -26,6 +26,7 @@ const QSet NON_SOURCED_PACKETS = QSet() << PacketType::DomainList << PacketType::DomainConnectionDenied << PacketType::DomainServerPathQuery << PacketType::DomainServerPathResponse << PacketType::DomainServerAddedNode + << PacketType::DomainSettingsRequest << PacketType::DomainSettings << PacketType::ICEServerPeerInformation << PacketType::ICEServerQuery << PacketType::ICEServerHeartbeat << PacketType::ICEPing << PacketType::ICEPingReply << PacketType::AssignmentClientStatus << PacketType::StopNode; diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 58e0832800..35898a21f5 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -71,7 +71,9 @@ enum class PacketType : uint8_t { EntityAdd, EntityErase, EntityEdit, - DomainServerConnectionToken + DomainServerConnectionToken, + DomainSettingsRequest, + DomainSettings }; const int NUM_BYTES_MD5_HASH = 16; From 97bb36add4b30ef19dc43dd055108524e1e12c4c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 18 Aug 2015 23:11:47 -0700 Subject: [PATCH 320/549] Add constant for message line size --- libraries/networking/src/udt/Constants.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/networking/src/udt/Constants.h b/libraries/networking/src/udt/Constants.h index eaad77d03e..8c73a230df 100644 --- a/libraries/networking/src/udt/Constants.h +++ b/libraries/networking/src/udt/Constants.h @@ -26,6 +26,7 @@ namespace udt { static const int UDP_RECEIVE_BUFFER_SIZE_BYTES = 1048576; static const int DEFAULT_SYN_INTERVAL_USECS = 10 * 1000; static const int SEQUENCE_NUMBER_BITS = sizeof(SequenceNumber) * 8; + static const int MESSAGE_LINE_NUMBER_BITS = 32; static const uint32_t CONTROL_BIT_MASK = uint32_t(1) << (SEQUENCE_NUMBER_BITS - 1); } From 74547777df0dd2d8698b414d99199abd688a80fe Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 18 Aug 2015 23:12:09 -0700 Subject: [PATCH 321/549] Add basic test to send packetList in udt-test --- tools/udt-test/src/UDTTest.cpp | 52 ++++++++++++++++++++++++++-------- tools/udt-test/src/UDTTest.h | 3 +- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 1f55fd1665..0b65907e29 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -15,6 +15,7 @@ #include #include +#include #include @@ -42,6 +43,9 @@ const QCommandLineOption MAX_SEND_PACKETS { const QCommandLineOption UNRELIABLE_PACKETS { "unreliable", "send unreliable packets (default is reliable)" }; +const QCommandLineOption ORDERED_PACKETS { + "ordered", "send ordered packets (default is unordered)" +}; const QStringList CLIENT_STATS_TABLE_HEADERS { "Send Rate (P/s)", "Bandwidth (P/s)", "RTT(ms)", "CW (P)", "Send Period (us)", @@ -129,6 +133,10 @@ UDTTest::UDTTest(int& argc, char** argv) : if (_argumentParser.isSet(UNRELIABLE_PACKETS)) { _sendReliable = false; } + + if (_argumentParser.isSet(ORDERED_PACKETS)) { + _sendOrdered = true; + } if (!_target.isNull()) { sendInitialPackets(); @@ -151,7 +159,7 @@ void UDTTest::parseArguments() { _argumentParser.addOptions({ PORT_OPTION, TARGET_OPTION, PACKET_SIZE, MIN_PACKET_SIZE, MAX_PACKET_SIZE, - MAX_SEND_BYTES, MAX_SEND_PACKETS, UNRELIABLE_PACKETS + MAX_SEND_BYTES, MAX_SEND_PACKETS, UNRELIABLE_PACKETS, ORDERED_PACKETS }); if (!_argumentParser.parse(arguments())) { @@ -206,20 +214,40 @@ void UDTTest::sendPacket() { int randomPacketSize = rand() % _maxPacketSize + _minPacketSize; packetPayloadSize = randomPacketSize - udt::Packet::localHeaderSize(false); } - - auto newPacket = udt::Packet::create(packetPayloadSize, _sendReliable); - newPacket->setPayloadSize(packetPayloadSize); - - _totalQueuedBytes += newPacket->getDataSize(); - - // queue or send this packet by calling write packet on the socket for our target - if (_sendReliable) { - _socket.writePacket(std::move(newPacket), _target); + + if (_sendOrdered) { + static int call = 0; + call = (call + 1) % 4; + if (call == 0) { + auto packetList = std::unique_ptr(new udt::PacketList(PacketType::BulkAvatarData, QByteArray(), true, true)); + for (int i = 0; i < 4; i++) { + packetList->writePrimitive(0x1); + packetList->writePrimitive(0x2); + packetList->writePrimitive(0x3); + packetList->writePrimitive(0x4); + packetList->closeCurrentPacket(false); + } + _totalQueuedBytes += packetList->getDataSize(); + + _socket.writePacketList(std::move(packetList), _target); + } + _totalQueuedPackets += 4; } else { - _socket.writePacket(*newPacket, _target); + auto newPacket = udt::Packet::create(packetPayloadSize, _sendReliable); + newPacket->setPayloadSize(packetPayloadSize); + + _totalQueuedBytes += newPacket->getDataSize(); + + // queue or send this packet by calling write packet on the socket for our target + // if ( + if (_sendReliable) { + _socket.writePacket(std::move(newPacket), _target); + } else { + _socket.writePacket(*newPacket, _target); + } + ++_totalQueuedPackets; } - ++_totalQueuedPackets; } void UDTTest::sampleStats() { diff --git a/tools/udt-test/src/UDTTest.h b/tools/udt-test/src/UDTTest.h index 1fd1836cf9..28aa3d340e 100644 --- a/tools/udt-test/src/UDTTest.h +++ b/tools/udt-test/src/UDTTest.h @@ -45,7 +45,8 @@ private: int _maxSendBytes { -1 }; // the number of bytes to send to the target before stopping int _maxSendPackets { -1 }; // the number of packets to send to the target before stopping - bool _sendReliable { true }; // wether packets are sent reliably or unreliably + bool _sendReliable { true }; // whether packets are sent reliably or unreliably + bool _sendOrdered { false }; // whether to send ordered packets int _totalQueuedPackets { 0 }; // keeps track of the number of packets we have already queued int _totalQueuedBytes { 0 }; // keeps track of the number of bytes we have already queued From 92dadb437c838d30a51b2fe4ec2733194f6ea8dc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 18 Aug 2015 23:15:47 -0700 Subject: [PATCH 322/549] Replace magic number '30' for number of bits in message number --- libraries/networking/src/udt/Constants.h | 1 + libraries/networking/src/udt/SendQueue.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Constants.h b/libraries/networking/src/udt/Constants.h index 8c73a230df..0152444f84 100644 --- a/libraries/networking/src/udt/Constants.h +++ b/libraries/networking/src/udt/Constants.h @@ -27,6 +27,7 @@ namespace udt { static const int DEFAULT_SYN_INTERVAL_USECS = 10 * 1000; static const int SEQUENCE_NUMBER_BITS = sizeof(SequenceNumber) * 8; static const int MESSAGE_LINE_NUMBER_BITS = 32; + static const int MESSAGE_NUMBER_BITS = 30; static const uint32_t CONTROL_BIT_MASK = uint32_t(1) << (SEQUENCE_NUMBER_BITS - 1); } diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 2c2ff7350b..650542dec5 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -161,7 +161,7 @@ SequenceNumber SendQueue::getNextSequenceNumber() { } uint32_t SendQueue::getNextMessageNumber() { - static const MessageNumber MAX_MESSAGE_NUMBER = MessageNumber(1) << 30; + static const MessageNumber MAX_MESSAGE_NUMBER = MessageNumber(1) << MESSAGE_NUMBER_BITS; _currentMessageNumber = (_currentMessageNumber + 1) % MAX_MESSAGE_NUMBER; return _currentMessageNumber; } From cda0aaf7cf4c2247b2e8a9c3ad8101cd2b0f48aa Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 08:54:24 -0700 Subject: [PATCH 323/549] Update PacketReceiver to use scoped locks --- libraries/networking/src/PacketReceiver.cpp | 29 ++++++++++----------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 1056c54c5e..adcee4e22f 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -12,6 +12,8 @@ #include "PacketReceiver.h" +#include + #include "DependencyManager.h" #include "NetworkLogging.h" #include "NodeList.h" @@ -93,8 +95,7 @@ bool PacketReceiver::registerMessageListener(PacketType type, QObject* listener, QMetaMethod matchingMethod = matchingMethodForListener(type, listener, slot); if (matchingMethod.isValid()) { - //registerVerifiedListener(type, listener, matchingMethod); - _packetListenerLock.lock(); + QMutexLocker(&_packetListenerLock); if (_packetListListenerMap.contains(type)) { qDebug() << "Warning: Registering a packet listener for packet type" << type @@ -104,7 +105,6 @@ bool PacketReceiver::registerMessageListener(PacketType type, QObject* listener, // add the mapping _packetListListenerMap[type] = ObjectMethodPair(QPointer(listener), matchingMethod); - _packetListenerLock.unlock(); return true; } else { return false; @@ -244,7 +244,7 @@ void PacketReceiver::handleVerifiedPacketList(std::unique_ptr p } } - _packetListenerLock.lock(); + QMutexLocker packetListenerLocker(&_packetListenerLock); bool listenerIsDead = false; @@ -258,13 +258,13 @@ void PacketReceiver::handleVerifiedPacketList(std::unique_ptr p bool success = false; + Qt::ConnectionType connectionType; // check if this is a directly connected listener - _directConnectSetMutex.lock(); - - Qt::ConnectionType connectionType = - _directlyConnectedObjects.contains(listener.first) ? Qt::DirectConnection : Qt::AutoConnection; - - _directConnectSetMutex.unlock(); + { + QMutexLocker directConnectLocker(&_directConnectSetMutex); + + connectionType = _directlyConnectedObjects.contains(listener.first) ? Qt::DirectConnection : Qt::AutoConnection; + } PacketType packetType = nlPacketList->getType(); @@ -329,9 +329,10 @@ void PacketReceiver::handleVerifiedPacketList(std::unique_ptr p it = _packetListListenerMap.erase(it); // if it exists, remove the listener from _directlyConnectedObjects - _directConnectSetMutex.lock(); - _directlyConnectedObjects.remove(listener.first); - _directConnectSetMutex.unlock(); + { + QMutexLocker directConnectLocker(&_directConnectSetMutex); + _directlyConnectedObjects.remove(listener.first); + } } } else if (it == _packetListListenerMap.end()) { @@ -340,8 +341,6 @@ void PacketReceiver::handleVerifiedPacketList(std::unique_ptr p // insert a dummy listener so we don't print this again _packetListListenerMap.insert(nlPacketList->getType(), { nullptr, QMetaMethod() }); } - - _packetListenerLock.unlock(); } void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { From c6a8ccd4909ccea7d53d106b3b648839a938113b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 08:56:17 -0700 Subject: [PATCH 324/549] Replace usage of qDebug with qCDebug in PacketReceiver --- libraries/networking/src/PacketReceiver.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index adcee4e22f..ed65519e5b 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -98,7 +98,7 @@ bool PacketReceiver::registerMessageListener(PacketType type, QObject* listener, QMutexLocker(&_packetListenerLock); if (_packetListListenerMap.contains(type)) { - qDebug() << "Warning: Registering a packet listener for packet type" << type + qCDebug(networking) << "Warning: Registering a packet listener for packet type" << type << "that will remove a previously registered listener"; } @@ -165,7 +165,7 @@ QMetaMethod PacketReceiver::matchingMethodForListener(PacketType type, QObject* } if (methodIndex < 0) { - qDebug() << "PacketReceiver::registerListener expected a slot with one of the following signatures:" + qCDebug(networking) << "PacketReceiver::registerListener expected a slot with one of the following signatures:" << possibleSignatures.toList() << "- but such a slot was not found." << "Could not complete listener registration for type" << type; } @@ -186,7 +186,7 @@ void PacketReceiver::registerVerifiedListener(PacketType type, QObject* object, _packetListenerLock.lock(); if (_packetListenerMap.contains(type)) { - qDebug() << "Warning: Registering a packet listener for packet type" << type + qCDebug(networking) << "Warning: Registering a packet listener for packet type" << type << "that will remove a previously registered listener"; } @@ -315,7 +315,7 @@ void PacketReceiver::handleVerifiedPacketList(std::unique_ptr p } if (!success) { - qDebug().nospace() << "Error delivering packet " << packetType << " to listener " + qCDebug(networking).nospace() << "Error delivering packet " << packetType << " to listener " << listener.first << "::" << qPrintable(listener.second.methodSignature()); } @@ -324,7 +324,7 @@ void PacketReceiver::handleVerifiedPacketList(std::unique_ptr p } if (listenerIsDead) { - qDebug().nospace() << "Listener for packet " << nlPacketList->getType() + qCDebug(networking).nospace() << "Listener for packet " << nlPacketList->getType() << " has been destroyed. Removing from listener map."; it = _packetListListenerMap.erase(it); @@ -441,7 +441,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { } if (!success) { - qDebug().nospace() << "Error delivering packet " << packetType << " to listener " + qCDebug(networking).nospace() << "Error delivering packet " << packetType << " to listener " << listener.first << "::" << qPrintable(listener.second.methodSignature()); } @@ -450,7 +450,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { } if (listenerIsDead) { - qDebug().nospace() << "Listener for packet " << nlPacket->getType() + qCDebug(networking).nospace() << "Listener for packet " << nlPacket->getType() << " has been destroyed. Removing from listener map."; it = _packetListenerMap.erase(it); From 10cd315a10b380b0b18e89c8bc6e36b6360e2375 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 08:58:53 -0700 Subject: [PATCH 325/549] Fix QMutexLocker in PacketReceiver --- libraries/networking/src/PacketReceiver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index ed65519e5b..12f9b618bb 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -95,7 +95,7 @@ bool PacketReceiver::registerMessageListener(PacketType type, QObject* listener, QMetaMethod matchingMethod = matchingMethodForListener(type, listener, slot); if (matchingMethod.isValid()) { - QMutexLocker(&_packetListenerLock); + QMutexLocker locker(&_packetListenerLock); if (_packetListListenerMap.contains(type)) { qCDebug(networking) << "Warning: Registering a packet listener for packet type" << type From 3c5483a00839d2e5acb907a27e6405dcbd288f21 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 08:59:05 -0700 Subject: [PATCH 326/549] Fix style issue with const --- libraries/networking/src/udt/Packet.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index 2c57bbfc6c..565fc24616 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -63,7 +63,7 @@ public: PacketPosition getPacketPosition() const { return _packetPosition; } void writeMessageNumber(MessageNumber messageNumber); - void writeSequenceNumber(SequenceNumber sequenceNumber)const; + void writeSequenceNumber(SequenceNumber sequenceNumber) const; protected: Packet(qint64 size, bool isReliable = false, bool isPartOfMessage = false); From f5aac5f086c81c390544ef63f546ce3f06999572 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 09:02:17 -0700 Subject: [PATCH 327/549] Remove unused include --- libraries/networking/src/udt/PacketList.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/networking/src/udt/PacketList.cpp b/libraries/networking/src/udt/PacketList.cpp index e5386a4cc9..23060fecf4 100644 --- a/libraries/networking/src/udt/PacketList.cpp +++ b/libraries/networking/src/udt/PacketList.cpp @@ -13,8 +13,6 @@ #include -#include "../NLPacket.h" - using namespace udt; PacketList::PacketList(PacketType packetType, QByteArray extendedHeader, bool isReliable, bool isOrdered) : From f2b4c0e26965397934afa44f8deaeef55694233a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 09:03:31 -0700 Subject: [PATCH 328/549] Merge listener signatures into intializer list in PacketListener --- libraries/networking/src/PacketReceiver.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 12f9b618bb..e7fff8e679 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -132,8 +132,10 @@ QMetaMethod PacketReceiver::matchingMethodForListener(PacketType type, QObject* static const QString NON_SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer"; static const QString NON_SOURCED_PACKETLIST_LISTENER_PARAMETERS = "QSharedPointer"; - QSet possibleSignatures { QString("%1(%2)").arg(slot).arg(NON_SOURCED_PACKET_LISTENER_PARAMETERS) }; - possibleSignatures << QString("%1(%2)").arg(slot).arg(NON_SOURCED_PACKETLIST_LISTENER_PARAMETERS); + QSet possibleSignatures { + QString("%1(%2)").arg(slot).arg(NON_SOURCED_PACKET_LISTENER_PARAMETERS), + QString("%1(%2)").arg(slot).arg(NON_SOURCED_PACKETLIST_LISTENER_PARAMETERS) + }; if (!NON_SOURCED_PACKETS.contains(type)) { static const QString SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer,QSharedPointer"; From 5ba3280975ab0444b08c4e5de562f92b235325c9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 10:01:16 -0700 Subject: [PATCH 329/549] Remove include in NLPacketList --- libraries/networking/src/NLPacketList.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/networking/src/NLPacketList.h b/libraries/networking/src/NLPacketList.h index cb48db08f2..4f3ba49d29 100644 --- a/libraries/networking/src/NLPacketList.h +++ b/libraries/networking/src/NLPacketList.h @@ -12,8 +12,6 @@ #ifndef hifi_NLPacketList_h #define hifi_NLPacketList_h -#include - #include "udt/PacketList.h" #include "NLPacket.h" From da7c9198c5bc962f80271518ead95ad6da92c053 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 10:01:40 -0700 Subject: [PATCH 330/549] Remove superfluous log message --- domain-server/src/DomainServerSettingsManager.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index c9b52a17bb..fc0ed95b92 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -68,8 +68,6 @@ DomainServerSettingsManager::DomainServerSettingsManager() : } void DomainServerSettingsManager::processSettingsRequestPacket(QSharedPointer packet) { - qDebug() << "Got request for domain settings"; - Assignment::Type type; packet->readPrimitive(&type); From ebf112e2003469cebc0d96b4a6163f36a5077c48 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 10:03:52 -0700 Subject: [PATCH 331/549] Replace NLPacketList::getSourceID() with const& return --- libraries/networking/src/NLPacketList.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/NLPacketList.h b/libraries/networking/src/NLPacketList.h index 4f3ba49d29..5391e49488 100644 --- a/libraries/networking/src/NLPacketList.h +++ b/libraries/networking/src/NLPacketList.h @@ -21,7 +21,7 @@ public: NLPacketList(PacketType packetType, QByteArray extendedHeader = QByteArray(), bool isReliable = false, bool isOrdered = false); NLPacketList(PacketList&& packetList); - QUuid getSourceID() const { return _sourceID; } + const QUuid& getSourceID() const { return _sourceID; } private: NLPacketList(const NLPacketList& other) = delete; From df510693058afcd0c03a559a30a47acfd0b85603 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 10:39:19 -0700 Subject: [PATCH 332/549] Rename getAllData to getMessage --- libraries/networking/src/DomainHandler.cpp | 2 +- libraries/networking/src/udt/PacketList.cpp | 2 +- libraries/networking/src/udt/PacketList.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 81b7ee6c55..62b00a8c98 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -283,7 +283,7 @@ void DomainHandler::settingsRequestFinished() { } void DomainHandler::processSettingsPacketList(QSharedPointer packetList) { - auto data = packetList->getAllData(); + auto data = packetList->getMessage(); _settingsObject = QJsonDocument::fromJson(data).object(); diff --git a/libraries/networking/src/udt/PacketList.cpp b/libraries/networking/src/udt/PacketList.cpp index 23060fecf4..2e9bef09e1 100644 --- a/libraries/networking/src/udt/PacketList.cpp +++ b/libraries/networking/src/udt/PacketList.cpp @@ -80,7 +80,7 @@ std::unique_ptr PacketList::createPacketWithExtendedHeader() { return packet; } -QByteArray PacketList::getAllData() { +QByteArray PacketList::getMessage() { size_t sizeBytes = 0; for (const auto& packet : _packets) { diff --git a/libraries/networking/src/udt/PacketList.h b/libraries/networking/src/udt/PacketList.h index 5596253a6c..37c253ac08 100644 --- a/libraries/networking/src/udt/PacketList.h +++ b/libraries/networking/src/udt/PacketList.h @@ -50,7 +50,7 @@ public: void closeCurrentPacket(bool shouldSendEmpty = false); - QByteArray getAllData(); + QByteArray getMessage(); template qint64 readPrimitive(T* data); template qint64 writePrimitive(const T& data); From fc29297d871d2589c5fcd5151e2ccbc58b342dad Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 10:55:26 -0700 Subject: [PATCH 333/549] Update SendQueue::queuePacketList to use splice --- libraries/networking/src/udt/SendQueue.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 650542dec5..0e97e9a1e0 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -68,20 +68,19 @@ void SendQueue::queuePacketList(std::unique_ptr packetList) { Q_ASSERT(packetList->_packets.size() > 0); { - QWriteLocker locker(&_packetsLock); - auto messageNumber = getNextMessageNumber(); if (packetList->_packets.size() == 1) { - auto packet = packetList->takeFront(); - packet->setPacketPosition(Packet::PacketPosition::ONLY); + auto packet = packetList->_packets.front().get(); + packet->setPacketPosition(Packet::PacketPosition::ONLY); packet->writeMessageNumber(messageNumber); - _packets.push_back(std::move(packet)); } else { bool haveMarkedFirstPacket = false; - while (!packetList->_packets.empty()) { - auto packet = packetList->takeFront(); + auto end = packetList->_packets.end(); + for (auto it = packetList->_packets.begin(); it != end; ++it) { + auto packet = it->get(); + if (!haveMarkedFirstPacket) { packet->setPacketPosition(Packet::PacketPosition::FIRST); haveMarkedFirstPacket = true; @@ -92,11 +91,14 @@ void SendQueue::queuePacketList(std::unique_ptr packetList) { } packet->writeMessageNumber(messageNumber); - - _packets.push_back(std::move(packet)); } } + + QWriteLocker locker(&_packetsLock); + + _packets.splice(_packets.end(), packetList->_packets); } + if (!this->thread()->isRunning()) { this->thread()->start(); } From 121d3a77ad6398aa4146d4ba0770965d4ef55a64 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 11:27:31 -0700 Subject: [PATCH 334/549] Fix iterator usage in SendQueue --- libraries/networking/src/udt/SendQueue.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 0e97e9a1e0..cfb969a186 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -71,20 +71,21 @@ void SendQueue::queuePacketList(std::unique_ptr packetList) { auto messageNumber = getNextMessageNumber(); if (packetList->_packets.size() == 1) { - auto packet = packetList->_packets.front().get(); + auto& packet = packetList->_packets.front(); packet->setPacketPosition(Packet::PacketPosition::ONLY); packet->writeMessageNumber(messageNumber); } else { bool haveMarkedFirstPacket = false; auto end = packetList->_packets.end(); + auto lastElement = --packetList->_packets.end(); for (auto it = packetList->_packets.begin(); it != end; ++it) { - auto packet = it->get(); + auto& packet = *it; if (!haveMarkedFirstPacket) { packet->setPacketPosition(Packet::PacketPosition::FIRST); haveMarkedFirstPacket = true; - } else if (packetList->_packets.empty()) { + } else if (it == lastElement) { packet->setPacketPosition(Packet::PacketPosition::LAST); } else { packet->setPacketPosition(Packet::PacketPosition::MIDDLE); From d18ce5066f10d2965e834d726249ff9da7ad576e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 11:55:06 -0700 Subject: [PATCH 335/549] Fix error with Assignment::Type not being hashable --- libraries/networking/src/Assignment.cpp | 7 +++++++ libraries/networking/src/Assignment.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index e8ba67c4a6..6a89bd80c4 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -159,3 +159,10 @@ QDataStream& operator>>(QDataStream &in, Assignment& assignment) { return in; } + + +uint qHash(const Assignment::Type& key, uint seed) { + // seems odd that Qt couldn't figure out this cast itself, but this fixes a compile error after switch to + // strongly typed enum for PacketType + return qHash((uint8_t) key, seed); +} diff --git a/libraries/networking/src/Assignment.h b/libraries/networking/src/Assignment.h index 0fadc78770..fc2f8620a2 100644 --- a/libraries/networking/src/Assignment.h +++ b/libraries/networking/src/Assignment.h @@ -100,4 +100,6 @@ protected: QUuid _walletUUID; /// the UUID for the wallet that should be paid for this assignment }; +uint qHash(const Assignment::Type& key, uint seed); + #endif // hifi_Assignment_h From a168a1058f8b761c54cb3b445ed71364f1a79854 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 12:09:46 -0700 Subject: [PATCH 336/549] Update filename regex in AssetServer to allow extensions --- assignment-client/src/assets/AssetServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 6ac106191f..7dd31eba5f 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -49,7 +49,7 @@ void AssetServer::run() { // Scan for new files qDebug() << "Looking for new files in asset directory"; auto files = _resourcesDirectory.entryInfoList(QDir::Files); - QRegExp filenameRegex { "^[a-f0-9]{32}$" }; + QRegExp filenameRegex { "^[a-f0-9]{32}(\\..+)?$" }; for (auto fileInfo : files) { auto filename = fileInfo.fileName(); if (!filenameRegex.exactMatch(filename)) { From 51d4cf84da9cc92518c56a4ccb0266c3b2f27054 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 12:10:47 -0700 Subject: [PATCH 337/549] Fix AnimationReader to work with new ResourceCache updates --- libraries/animation/src/AnimationCache.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/animation/src/AnimationCache.cpp b/libraries/animation/src/AnimationCache.cpp index 9fc650ecbe..7563e44178 100644 --- a/libraries/animation/src/AnimationCache.cpp +++ b/libraries/animation/src/AnimationCache.cpp @@ -43,7 +43,7 @@ Animation::Animation(const QUrl& url) : Resource(url) {} class AnimationReader : public QRunnable { public: - AnimationReader(const QWeakPointer& animation, QByteArray data); + AnimationReader(const QWeakPointer& animation, QByteArray data, QUrl url); virtual void run(); @@ -64,7 +64,7 @@ void AnimationReader::run() { QSharedPointer animation = _animation.toStrongRef(); if (!animation.isNull()) { QMetaObject::invokeMethod(animation.data(), "setGeometry", - Q_ARG(const FBXGeometry&, readFBX(QByteArray(_data), QVariantHash(), _url))); + Q_ARG(const FBXGeometry&, readFBX(QByteArray(_data), QVariantHash(), _url.path()))); } } @@ -99,7 +99,7 @@ void Animation::setGeometry(const FBXGeometry& geometry) { void Animation::downloadFinished(const QByteArray& data) { // send the reader off to the thread pool - QThreadPool::globalInstance()->start(new AnimationReader(_self, data)); + QThreadPool::globalInstance()->start(new AnimationReader(_self, data, _url)); } From 4827d326f4f7d001fc566c5b866051c4f8281b64 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 12:11:47 -0700 Subject: [PATCH 338/549] Update ResourceCache to allow multiple downloads on the same resource --- libraries/audio/src/Sound.cpp | 1 - libraries/networking/src/ResourceCache.cpp | 171 +++++++++++---------- libraries/networking/src/ResourceCache.h | 9 +- 3 files changed, 99 insertions(+), 82 deletions(-) diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 5ff0f55f7f..2457bda74a 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -95,7 +95,6 @@ void Sound::downloadFinished(const QByteArray& data) { } _isReady = true; - _request->deleteLater(); } void Sound::downSample(const QByteArray& rawAudioByteArray) { diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 2903e810f2..018f9b1c36 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -154,12 +154,13 @@ void ResourceCache::clearUnusedResource() { void ResourceCache::attemptRequest(Resource* resource) { auto sharedItems = DependencyManager::get(); - if (_requestLimit <= 0) { - qDebug() << "REQUEST LIMIT REACHED, queueing: " << resource->getURL(); - // wait until a slot becomes available - sharedItems->_pendingRequests.append(resource); - return; - } + // if (_requestLimit <= 0) { + // qDebug() << "REQUEST LIMIT REACHED (" << _requestLimit << "), queueing: " << resource->getURL(); + // // wait until a slot becomes available + // sharedItems->_pendingRequests.append(resource); + // return; + // } + qDebug() << "-- Decreasing limit for : " << resource->getURL(); _requestLimit--; sharedItems->_loadingRequests.append(resource); resource->makeRequest(); @@ -169,6 +170,7 @@ void ResourceCache::requestCompleted(Resource* resource) { auto sharedItems = DependencyManager::get(); sharedItems->_loadingRequests.removeOne(resource); + qDebug() << "++ Increasing limit after finished: " << resource->getURL(); _requestLimit++; // look for the highest priority pending request @@ -198,13 +200,14 @@ int ResourceCache::_requestLimit = DEFAULT_REQUEST_LIMIT; Resource::Resource(const QUrl& url, bool delayLoad) : _url(url), + _activeUrl(url), _request(nullptr) { init(); // start loading immediately unless instructed otherwise if (!(_startedLoading || delayLoad)) { - QTimer::singleShot(1, this, &Resource::attemptRequest); + // QTimer::singleShot(1, this, &Resource::attemptRequest); //attemptRequest(); } } @@ -264,11 +267,8 @@ void Resource::refresh() { } if (_request) { _request->disconnect(this); - // _requestTimer->disconnect(this); _request->deleteLater(); _request = nullptr; - // _requestTimer->deleteLater(); - // _requestTimer = nullptr; ResourceCache::requestCompleted(this); } @@ -302,6 +302,7 @@ void Resource::init() { _failedToLoad = false; _loaded = false; _attempts = 0; + _activeUrl = _url; if (_url.isEmpty()) { _startedLoading = _loaded = true; @@ -317,6 +318,7 @@ void Resource::attemptRequest() { } void Resource::finishedLoading(bool success) { + qDebug() << "Finished loading: " << _url; if (success) { _loaded = true; emit loaded(); @@ -349,15 +351,6 @@ void Resource::reinsert() { // // downloadFinished(reply); // } // -// void Resource::handleReplyError() { -// handleReplyError(_reply->error(), qDebug() << _reply->errorString()); -// } -// -// void Resource::handleReplyTimeout() { -// handleReplyError(QNetworkReply::TimeoutError, qDebug() << "Timed out loading" << _reply->url() << -// "received" << _bytesReceived << "total" << _bytesTotal); -// } -// void Resource::maybeRefresh() { if (Q_LIKELY(NetworkAccessManager::getInstance().cache())) { QNetworkReply* reply = qobject_cast(sender()); @@ -382,31 +375,30 @@ void Resource::maybeRefresh() { } } -// #include "AssetManager.h" void Resource::makeRequest() { - auto request = ResourceManager::createResourceRequest(this, _url); - _request = request; + QString u = _activeUrl.path(); + QString uu = _url.path(); + Q_ASSERT(!_request); + + _request = ResourceManager::createResourceRequest(this, _activeUrl); + if (!_request) { qDebug() << "Failed to get request for " << _url; + ResourceCache::requestCompleted(this); + finishedLoading(false); return; } qDebug() << "Starting request for: " << _url; - connect(request, &ResourceRequest::finished, this, &Resource::handleReplyFinished); + connect(_request, &ResourceRequest::finished, this, &Resource::handleReplyFinished); // connect(_reply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(handleDownloadProgress(qint64,qint64))); // connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleReplyError())); // connect(_reply, SIGNAL(finished()), SLOT(handleReplyFinished())); - // AssetManager::getAsset(_url, [this](AssetRequestUpdateType type, QByteArray data) { - // if (type == AssetRequestUpdateType::COMPLETE) { - // downloadFinished(data); - // } else { - // handleReplyError(QNetworkReply::TimeoutError, qDebug()); - // } - // }); - // - request->send(); + _bytesReceived = _bytesTotal = 0; + + _request->send(); // if (_reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool()) { // // If the file as been updated since it was cached, refresh it @@ -435,63 +427,88 @@ void Resource::makeRequest() { // } // } // } - - // _replyTimer = new QTimer(this); - // connect(_replyTimer, SIGNAL(timeout()), SLOT(handleReplyTimeout())); - // _replyTimer->setSingleShot(true); - // _replyTimer->start(REPLY_TIMEOUT_MS); - _bytesReceived = _bytesTotal = 0; } -// void Resource::handleReplyError(QNetworkReply::NetworkError error, QDebug debug) { -// _reply->disconnect(this); -// _replyTimer->disconnect(this); -// _reply->deleteLater(); -// _reply = nullptr; -// _replyTimer->deleteLater(); -// _replyTimer = nullptr; -// ResourceCache::requestCompleted(this); -// -// // retry for certain types of failures -// switch (error) { -// case QNetworkReply::RemoteHostClosedError: -// case QNetworkReply::TimeoutError: -// case QNetworkReply::TemporaryNetworkFailureError: -// case QNetworkReply::ProxyConnectionClosedError: -// case QNetworkReply::ProxyTimeoutError: -// case QNetworkReply::UnknownNetworkError: -// case QNetworkReply::UnknownProxyError: -// case QNetworkReply::UnknownContentError: -// case QNetworkReply::ProtocolFailure: { -// // retry with increasing delays -// const int MAX_ATTEMPTS = 8; -// const int BASE_DELAY_MS = 1000; -// if (++_attempts < MAX_ATTEMPTS) { -// QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(attemptRequest())); -// debug << "-- retrying..."; -// return; -// } -// // fall through to final failure -// } -// default: -// finishedLoading(false); -// break; -// } +// void Resource::handleReplyError(ResourceRequest::Result result, QDebug debug) { +// +// // // retry for certain types of failures +// // switch (error) { +// // case QNetworkReply::RemoteHostClosedError: +// // case QNetworkReply::TimeoutError: +// // case QNetworkReply::TemporaryNetworkFailureError: +// // case QNetworkReply::ProxyConnectionClosedError: +// // case QNetworkReply::ProxyTimeoutError: +// // case QNetworkReply::UnknownNetworkError: +// // case QNetworkReply::UnknownProxyError: +// // case QNetworkReply::UnknownContentError: +// // case QNetworkReply::ProtocolFailure: { +// // // retry with increasing delays +// // const int MAX_ATTEMPTS = 8; +// // const int BASE_DELAY_MS = 1000; +// // if (++_attempts < MAX_ATTEMPTS) { +// // QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(nttemptRequest())); +// // debug << "-- retrying..."; +// // return; +// // } +// // // fall through to final failure +// // } +// // default: +// // finishedLoading(false); +// // break; +// // } // } // void Resource::handleReplyFinished() { - // _request->disconnect(this); - // _request->deleteLater(); - // _request = nullptr; + QString u = _url.path(); Q_ASSERT(_request); - if (_request->getResult() == ResourceRequest::SUCCESS) { + + auto result = _request->getResult(); + if (result == ResourceRequest::SUCCESS) { _data = _request->moveData(); + qDebug() << "Reqeust finsihed for " << _url << ", " << _activeUrl; + _request->disconnect(this); _request->deleteLater(); _request = nullptr; + + ResourceCache::requestCompleted(this); + downloadFinished(_data); + } else { + _request->disconnect(this); + _request->deleteLater(); + _request = nullptr; + + if (result == ResourceRequest::Result::TIMEOUT) { + qDebug() << "Timed out loading" << _url << + "received" << _bytesReceived << "total" << _bytesTotal; + } else { + qDebug() << "Error loading " << _url; + } + + bool retry = false; + switch (result) { + case ResourceRequest::Result::TIMEOUT: + case ResourceRequest::Result::ERROR: { + // retry with increasing delays + const int MAX_ATTEMPTS = 8; + const int BASE_DELAY_MS = 1000; + if (++_attempts < MAX_ATTEMPTS) { + QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(attemptRequest())); + retry = true; + break; + } + // fall through to final failure + } + default: + finishedLoading(false); + break; + } + + if (!retry) { + ResourceCache::requestCompleted(this); + } } - ResourceCache::requestCompleted(this); } uint qHash(const QPointer& value, uint seed) { diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 59192449b8..e23b68416a 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -199,8 +199,7 @@ protected: virtual void reinsert(); QUrl _url; - ResourceRequest* _request = nullptr; - //QNetworkRequest _request; + QUrl _activeUrl; bool _startedLoading = false; bool _failedToLoad = false; bool _loaded = false; @@ -211,19 +210,21 @@ protected: private slots: // void handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); - // void handleReplyError(); void handleReplyFinished(); + // void handleReplyError(); // void handleReplyTimeout(); private: void setLRUKey(int lruKey) { _lruKey = lruKey; } void makeRequest(); + void retry(); - void handleReplyError(QNetworkReply::NetworkError error, QDebug debug); + // void handleReplyError(ResourceRequest::Result result, QDebug debug); friend class ResourceCache; + ResourceRequest* _request = nullptr; int _lruKey = 0; QTimer* _replyTimer = nullptr; qint64 _bytesReceived = 0; From 7305135125f09b31d2f6ba37eaf919a2a88f85e8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 12:16:34 -0700 Subject: [PATCH 339/549] Update ResourceManager --- libraries/networking/src/ResourceManager.cpp | 42 ++++++++++++++------ libraries/networking/src/ResourceManager.h | 10 ++++- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/libraries/networking/src/ResourceManager.cpp b/libraries/networking/src/ResourceManager.cpp index 7fdac3028a..00348df69b 100644 --- a/libraries/networking/src/ResourceManager.cpp +++ b/libraries/networking/src/ResourceManager.cpp @@ -12,7 +12,6 @@ #include #include -#include #include "AssetClient.h" #include "AssetRequest.h" @@ -31,24 +30,38 @@ ResourceRequest::ResourceRequest(QObject* parent, const QUrl& url) : _url(url) { } +HTTPResourceRequest::~HTTPResourceRequest() { + if (_reply) { + _reply->disconnect(this); + _reply->deleteLater(); + _reply = nullptr; + } +} + void HTTPResourceRequest::doSend() { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest networkRequest = QNetworkRequest(_url); networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); - if (!_cacheEnabled) { + if (_cacheEnabled) { + networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + } else { networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); - } + } - QNetworkReply* reply = networkAccessManager.get(networkRequest); - QObject::connect(reply, &QNetworkReply::finished, [=]() { - if (_state != IN_PROGRESS) return; + _reply = networkAccessManager.get(networkRequest); + QObject::connect(_reply, &QNetworkReply::finished, [=]() { + Q_ASSERT(_state == IN_PROGRESS); + Q_ASSERT(_reply); _state = FINISHED; - auto error = reply->error(); + auto error = _reply->error(); qDebug() << "Loaded " << _url; + QString u = _url.path(); if (error == QNetworkReply::NoError) { - _data = reply->readAll(); + _data = _reply->readAll(); + qDebug() << "!!!! " << _data.size() << " " << _url.path(); + _loadedFromCache = _reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(); _result = ResourceRequest::SUCCESS; emit finished(); } else if (error == QNetworkReply::TimeoutError) { @@ -58,7 +71,8 @@ void HTTPResourceRequest::doSend() { _result = ResourceRequest::ERROR; emit finished(); } - reply->deleteLater(); + _reply->deleteLater(); + _reply = nullptr; }); } @@ -105,16 +119,20 @@ void ATPResourceRequest::doSend() { const int TIMEOUT_MS = 2000; void ResourceRequest::send() { + Q_ASSERT(_state == UNSENT); + + _state = IN_PROGRESS; + doSend(); connect(&_sendTimer, &QTimer::timeout, this, &ResourceRequest::timeout); _sendTimer.setSingleShot(true); _sendTimer.start(TIMEOUT_MS); - _state = IN_PROGRESS; - doSend(); } void ResourceRequest::timeout() { + Q_ASSERT(_state != UNSENT); + // TIMEOUT!! - if (_state == UNSENT) { + if (_state == IN_PROGRESS) { qDebug() << "TImed out loading " << _url; _state = FINISHED; _result = TIMEOUT; diff --git a/libraries/networking/src/ResourceManager.h b/libraries/networking/src/ResourceManager.h index 4050b5f390..599399fb15 100644 --- a/libraries/networking/src/ResourceManager.h +++ b/libraries/networking/src/ResourceManager.h @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -41,6 +42,7 @@ public: State getState() const { return _state; } Result getResult() const { return _result; } QUrl getUrl() const { return _url; } + bool loadedFromCache() const { return _loadedFromCache; } void setCacheEnabled(bool value) { _cacheEnabled = value; } @@ -52,11 +54,12 @@ protected: virtual void doSend() = 0; QUrl _url; - State _state = UNSENT; + State _state { UNSENT }; Result _result; QTimer _sendTimer; QByteArray _data; bool _cacheEnabled { true }; + bool _loadedFromCache { false }; private slots: void timeout(); @@ -65,10 +68,15 @@ private slots: class HTTPResourceRequest : public ResourceRequest { Q_OBJECT public: + ~HTTPResourceRequest(); + HTTPResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } protected: virtual void doSend() override; + +private: + QNetworkReply* _reply { nullptr }; }; class FileResourceRequest : public ResourceRequest { From e1f8b6700c025b9d94ccef3f42959eb3e8c370c8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 12:17:19 -0700 Subject: [PATCH 340/549] Update GeometryCache to work with ResourceCache updates --- libraries/render-utils/src/GeometryCache.cpp | 14 +++++++++----- libraries/render-utils/src/GeometryCache.h | 2 +- libraries/render-utils/src/Model.cpp | 2 ++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 5f9de399a6..69d5da939b 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1973,10 +1973,10 @@ GeometryReader::GeometryReader(const QWeakPointer& geometry, const QUr void GeometryReader::run() { QSharedPointer geometry = _geometry.toStrongRef(); if (geometry.isNull()) { - // _reply->deleteLater(); return; } try { + auto url = _url.path(); QString urlname = _url.path().toLower(); bool urlValid = true; urlValid &= !urlname.isEmpty(); @@ -2004,8 +2004,10 @@ void GeometryReader::run() { auto d = QByteArray(_data); QBuffer buffer { &d }; fbxgeo = OBJReader().readOBJ(&buffer, _mapping, &_url); + } else { + throw QString("Unknown file type"); } - QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo)); + QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(FBXGeometry, fbxgeo)); } else { throw QString("url is invalid"); } @@ -2027,7 +2029,7 @@ void NetworkGeometry::init() { } void NetworkGeometry::downloadFinished(const QByteArray& data) { - QUrl url = getURL(); + QUrl url = _activeUrl; if (url.path().toLower().endsWith(".fst")) { // it's a mapping file; parse it and get the mesh filename _mapping = FSTReader::readMapping(data); @@ -2055,7 +2057,7 @@ void NetworkGeometry::downloadFinished(const QByteArray& data) { // make the request immediately only if we have no LODs to switch between // TODO reimplement using ResourceRequest - _url = url.resolved(filename); + _activeUrl = url.resolved(filename); _startedLoading = false; if (_lods.isEmpty()) { attemptRequest(); @@ -2072,6 +2074,8 @@ void NetworkGeometry::downloadFinished(const QByteArray& data) { return; } + QString u = url.path(); + // send the reader off to the thread pool QThreadPool::globalInstance()->start(new GeometryReader(_self, url, data, _mapping)); } @@ -2085,7 +2089,7 @@ void NetworkGeometry::reinsert() { } } -void NetworkGeometry::setGeometry(const FBXGeometry& geometry) { +void NetworkGeometry::setGeometry(FBXGeometry geometry) { _geometry = geometry; auto textureCache = DependencyManager::get(); diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 679b67ab8a..e3a1525c55 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -342,7 +342,7 @@ protected: virtual void downloadFinished(const QByteArray& reply) override; virtual void reinsert(); - Q_INVOKABLE void setGeometry(const FBXGeometry& geometry); + Q_INVOKABLE void setGeometry(FBXGeometry geometry); private slots: void replaceTexturesWithPendingChanges(); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 51f737505f..dbe1dfbe09 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1405,7 +1405,9 @@ void Model::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm: } bool Model::restoreJointPosition(int jointIndex, float fraction, float priority) { + QString url = _url.path(); const FBXGeometry& geometry = _geometry->getFBXGeometry(); + return true; const QVector& freeLineage = geometry.joints.at(jointIndex).freeLineage; return _rig->restoreJointPosition(jointIndex, fraction, priority, freeLineage); } From 330a6bb279ca771b9c367254fdf2c466c7ba4fc8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 12:17:36 -0700 Subject: [PATCH 341/549] Update TextureCache to work with ResourceCache updates --- libraries/render-utils/src/TextureCache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index 8290b7d544..16e8502340 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -223,7 +223,7 @@ void NetworkTexture::downloadFinished(const QByteArray& data) { } void NetworkTexture::loadContent(const QByteArray& content) { - QThreadPool::globalInstance()->start(new ImageReader(_self, _type, content)); + QThreadPool::globalInstance()->start(new ImageReader(_self, _type, content, _url)); } ImageReader::ImageReader(const QWeakPointer& texture, TextureType type, const QByteArray& data, From ebb4db134d4feae9d2e7f9e7a39d53441c6332f7 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Aug 2015 12:18:01 -0700 Subject: [PATCH 342/549] Temporarily disable assert in ScriptCache --- libraries/script-engine/src/ScriptCache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index 87cdae0026..94fff89c35 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -27,7 +27,7 @@ ScriptCache::ScriptCache(QObject* parent) { } QString ScriptCache::getScript(const QUrl& url, ScriptUser* scriptUser, bool& isPending, bool reload) { - assert(!_scriptCache.contains(url) || !reload); + //assert(!_scriptCache.contains(url) || !reload); QString scriptContents; if (_scriptCache.contains(url) && !reload) { From 62c76d0332baedf401eb88d75bb69f2d35c30eab Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 20 Aug 2015 14:55:51 +0200 Subject: [PATCH 343/549] registerListenerForTypes optimisations --- assignment-client/src/audio/AudioMixer.cpp | 11 ++- .../src/octree/OctreePacketProcessor.cpp | 9 +-- libraries/networking/src/PacketReceiver.cpp | 69 +++++++++---------- libraries/networking/src/PacketReceiver.h | 10 ++- 4 files changed, 48 insertions(+), 51 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 664088084d..c1d0cc2215 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -96,14 +96,11 @@ AudioMixer::AudioMixer(NLPacket& packet) : // SOON auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - - QSet nodeAudioPackets { - PacketType::MicrophoneAudioNoEcho, PacketType::MicrophoneAudioWithEcho, - PacketType::InjectAudio, PacketType::SilentAudioFrame, - PacketType::AudioStreamStats - }; - packetReceiver.registerListenerForTypes(nodeAudioPackets, this, "handleNodeAudioPacket"); + packetReceiver.registerListenerForTypes({ PacketType::MicrophoneAudioNoEcho, PacketType::MicrophoneAudioWithEcho, + PacketType::InjectAudio, PacketType::SilentAudioFrame, + PacketType::AudioStreamStats }, + this, "handleNodeAudioPacket"); packetReceiver.registerListener(PacketType::MuteEnvironment, this, "handleMuteEnvironmentPacket"); } diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index 9bf845cccd..5b8ff78fad 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -18,13 +18,10 @@ OctreePacketProcessor::OctreePacketProcessor() { auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - - QSet types { - PacketType::OctreeStats, PacketType::EntityData, - PacketType::EntityErase, PacketType::OctreeStats - }; - packetReceiver.registerDirectListenerForTypes(types, this, "handleOctreePacket"); + packetReceiver.registerDirectListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, + PacketType::EntityErase, PacketType::OctreeStats }, + this, "handleOctreePacket"); } void OctreePacketProcessor::handleOctreePacket(QSharedPointer packet, SharedNodePointer senderNode) { diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index e7fff8e679..7a9a3b1ddd 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -19,49 +19,48 @@ #include "NodeList.h" #include "SharedUtil.h" -PacketReceiver::PacketReceiver(QObject* parent) : - QObject(parent), - _packetListenerMap() -{ +PacketReceiver::PacketReceiver(QObject* parent) : QObject(parent) { qRegisterMetaType>(); } -bool PacketReceiver::registerListenerForTypes(const QSet& types, QObject* listener, const char* slot) { - QSet nonSourcedTypes; - QSet sourcedTypes; - - foreach(PacketType type, types) { - if (NON_SOURCED_PACKETS.contains(type)) { - nonSourcedTypes << type; - } else { - sourcedTypes << type; - } - } - - Q_ASSERT(listener); - - if (nonSourcedTypes.size() > 0) { - QMetaMethod nonSourcedMethod = matchingMethodForListener(*nonSourcedTypes.begin(), listener, slot); - if (nonSourcedMethod.isValid()) { - foreach(PacketType type, nonSourcedTypes) { - registerVerifiedListener(type, listener, nonSourcedMethod); - } - } else { +bool PacketReceiver::registerListenerForTypes(PacketTypeList types, QObject* listener, const char* slot) { + Q_ASSERT_X(!types.empty(), "PacketReceiver::registerListenerForTypes", "No types to register"); + Q_ASSERT_X(listener, "PacketReceiver::registerListenerForTypes", "No object to register"); + Q_ASSERT_X(slot, "PacketReceiver::registerListenerForTypes", "No slot to register"); + + // Partition types based on whether they are sourced or not (non sourced in front) + auto middle = std::partition(std::begin(types), std::end(types), [](PacketType type) { + return NON_SOURCED_PACKETS.contains(type); + }); + + QMetaMethod nonSourcedMethod, sourcedMethod; + + // Check we have a valid method for non sourced types if any + if (middle != std::begin(types)) { + nonSourcedMethod = matchingMethodForListener(*std::begin(types), listener, slot); + if (!nonSourcedMethod.isValid()) { return false; } } - - if (sourcedTypes.size() > 0) { - QMetaMethod sourcedMethod = matchingMethodForListener(*sourcedTypes.begin(), listener, slot); - if (sourcedMethod.isValid()) { - foreach(PacketType type, sourcedTypes) { - registerVerifiedListener(type, listener, sourcedMethod); - } - } else { + + // Check we have a valid method for sourced types if any + if (middle != std::end(types)) { + sourcedMethod = matchingMethodForListener(*middle, listener, slot); + if (!sourcedMethod.isValid()) { return false; } } + // Register non sourced types + std::for_each(std::begin(types), middle, [this, &listener, &nonSourcedMethod](PacketType type) { + registerVerifiedListener(type, listener, nonSourcedMethod); + }); + + // Register sourced types + std::for_each(middle, std::end(types), [this, &listener, &sourcedMethod](PacketType type) { + registerVerifiedListener(type, listener, sourcedMethod); + }); + return true; } @@ -77,10 +76,10 @@ void PacketReceiver::registerDirectListener(PacketType type, QObject* listener, } } -void PacketReceiver::registerDirectListenerForTypes(const QSet& types, +void PacketReceiver::registerDirectListenerForTypes(PacketTypeList types, QObject* listener, const char* slot) { // just call register listener for types to start - bool success = registerListenerForTypes(types, listener, slot); + bool success = registerListenerForTypes(std::move(types), listener, slot); if (success) { _directConnectSetMutex.lock(); diff --git a/libraries/networking/src/PacketReceiver.h b/libraries/networking/src/PacketReceiver.h index b5a4501476..9965eccdc2 100644 --- a/libraries/networking/src/PacketReceiver.h +++ b/libraries/networking/src/PacketReceiver.h @@ -13,6 +13,8 @@ #ifndef hifi_PacketReceiver_h #define hifi_PacketReceiver_h +#include + #include #include #include @@ -30,6 +32,8 @@ class OctreePacketProcessor; class PacketReceiver : public QObject { Q_OBJECT public: + using PacketTypeList = std::vector; + PacketReceiver(QObject* parent = 0); PacketReceiver(const PacketReceiver&) = delete; @@ -42,8 +46,8 @@ public: void resetCounters() { _inPacketCount = 0; _inByteCount = 0; } - bool registerListenerForTypes(const QSet& types, QObject* listener, const char* slot); - bool registerMessageListener(PacketType types, QObject* listener, const char* slot); + bool registerListenerForTypes(PacketTypeList types, QObject* listener, const char* slot); + bool registerMessageListener(PacketType type, QObject* listener, const char* slot); bool registerListener(PacketType type, QObject* listener, const char* slot); void unregisterListener(QObject* listener); @@ -56,7 +60,7 @@ signals: private: // these are brutal hacks for now - ideally GenericThread / ReceivedPacketProcessor // should be changed to have a true event loop and be able to handle our QMetaMethod::invoke - void registerDirectListenerForTypes(const QSet& types, QObject* listener, const char* slot); + void registerDirectListenerForTypes(PacketTypeList types, QObject* listener, const char* slot); void registerDirectListener(PacketType type, QObject* listener, const char* slot); QMetaMethod matchingMethodForListener(PacketType type, QObject* object, const char* slot) const; From f6854782a4ce3beee478170362e69a1835558c93 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 20 Aug 2015 14:57:35 +0200 Subject: [PATCH 344/549] Debug/Lock cleanup --- libraries/networking/src/PacketReceiver.cpp | 92 ++++++++++----------- 1 file changed, 44 insertions(+), 48 deletions(-) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 7a9a3b1ddd..a086949ac8 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -65,45 +65,49 @@ bool PacketReceiver::registerListenerForTypes(PacketTypeList types, QObject* lis } void PacketReceiver::registerDirectListener(PacketType type, QObject* listener, const char* slot) { + Q_ASSERT_X(listener, "PacketReceiver::registerDirectListener", "No object to register"); + Q_ASSERT_X(slot, "PacketReceiver::registerDirectListener", "No slot to register"); + bool success = registerListener(type, listener, slot); if (success) { - _directConnectSetMutex.lock(); + QMutexLocker locker(&_directConnectSetMutex); // if we successfully registered, add this object to the set of objects that are directly connected _directlyConnectedObjects.insert(listener); - - _directConnectSetMutex.unlock(); } } void PacketReceiver::registerDirectListenerForTypes(PacketTypeList types, QObject* listener, const char* slot) { + Q_ASSERT_X(listener, "PacketReceiver::registerDirectListenerForTypes", "No object to register"); + Q_ASSERT_X(slot, "PacketReceiver::registerDirectListenerForTypes", "No slot to register"); + // just call register listener for types to start bool success = registerListenerForTypes(std::move(types), listener, slot); if (success) { - _directConnectSetMutex.lock(); + QMutexLocker locker(&_directConnectSetMutex); // if we successfully registered, add this object to the set of objects that are directly connected _directlyConnectedObjects.insert(listener); - - _directConnectSetMutex.unlock(); } } bool PacketReceiver::registerMessageListener(PacketType type, QObject* listener, const char* slot) { + Q_ASSERT_X(listener, "PacketReceiver::registerMessageListener", "No object to register"); + Q_ASSERT_X(slot, "PacketReceiver::registerMessageListener", "No slot to register"); + QMetaMethod matchingMethod = matchingMethodForListener(type, listener, slot); if (matchingMethod.isValid()) { QMutexLocker locker(&_packetListenerLock); if (_packetListListenerMap.contains(type)) { - qCDebug(networking) << "Warning: Registering a packet listener for packet type" << type + qCWarning(networking) << "Registering a packet listener for packet type" << type << "that will remove a previously registered listener"; } // add the mapping _packetListListenerMap[type] = ObjectMethodPair(QPointer(listener), matchingMethod); - return true; } else { return false; @@ -111,7 +115,8 @@ bool PacketReceiver::registerMessageListener(PacketType type, QObject* listener, } bool PacketReceiver::registerListener(PacketType type, QObject* listener, const char* slot) { - Q_ASSERT(listener); + Q_ASSERT_X(listener, "PacketReceiver::registerListener", "No object to register"); + Q_ASSERT_X(slot, "PacketReceiver::registerListener", "No slot to register"); QMetaMethod matchingMethod = matchingMethodForListener(type, listener, slot); @@ -124,16 +129,18 @@ bool PacketReceiver::registerListener(PacketType type, QObject* listener, const } QMetaMethod PacketReceiver::matchingMethodForListener(PacketType type, QObject* object, const char* slot) const { - Q_ASSERT(object); + Q_ASSERT_X(object, "PacketReceiver::matchingMethodForListener", "No object to call"); + Q_ASSERT_X(slot, "PacketReceiver::matchingMethodForListener", "No slot to call"); // normalize the slot with the expected parameters - + + static const QString SIGNATURE_TEMPLATE("%1(%2)"); static const QString NON_SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer"; static const QString NON_SOURCED_PACKETLIST_LISTENER_PARAMETERS = "QSharedPointer"; QSet possibleSignatures { - QString("%1(%2)").arg(slot).arg(NON_SOURCED_PACKET_LISTENER_PARAMETERS), - QString("%1(%2)").arg(slot).arg(NON_SOURCED_PACKETLIST_LISTENER_PARAMETERS) + SIGNATURE_TEMPLATE.arg(slot, NON_SOURCED_PACKET_LISTENER_PARAMETERS), + SIGNATURE_TEMPLATE.arg(slot, NON_SOURCED_PACKETLIST_LISTENER_PARAMETERS) }; if (!NON_SOURCED_PACKETS.contains(type)) { @@ -145,10 +152,10 @@ QMetaMethod PacketReceiver::matchingMethodForListener(PacketType type, QObject* // a sourced packet must take the shared pointer to the packet but optionally could include // a shared pointer to the node - possibleSignatures << QString("%1(%2)").arg(slot).arg(TYPEDEF_SOURCED_PACKET_LISTENER_PARAMETERS); - possibleSignatures << QString("%1(%2)").arg(slot).arg(SOURCED_PACKET_LISTENER_PARAMETERS); - possibleSignatures << QString("%1(%2)").arg(slot).arg(TYPEDEF_SOURCED_PACKETLIST_LISTENER_PARAMETERS); - possibleSignatures << QString("%1(%2)").arg(slot).arg(SOURCED_PACKETLIST_LISTENER_PARAMETERS); + possibleSignatures << SIGNATURE_TEMPLATE.arg(slot, TYPEDEF_SOURCED_PACKET_LISTENER_PARAMETERS); + possibleSignatures << SIGNATURE_TEMPLATE.arg(slot, SOURCED_PACKET_LISTENER_PARAMETERS); + possibleSignatures << SIGNATURE_TEMPLATE.arg(slot, TYPEDEF_SOURCED_PACKETLIST_LISTENER_PARAMETERS); + possibleSignatures << SIGNATURE_TEMPLATE.arg(slot, SOURCED_PACKETLIST_LISTENER_PARAMETERS); } int methodIndex = -1; @@ -184,39 +191,30 @@ QMetaMethod PacketReceiver::matchingMethodForListener(PacketType type, QObject* } void PacketReceiver::registerVerifiedListener(PacketType type, QObject* object, const QMetaMethod& slot) { - _packetListenerLock.lock(); + Q_ASSERT_X(object, "PacketReceiver::registerVerifiedListener", "No object to register"); + QMutexLocker locker(&_packetListenerLock); if (_packetListenerMap.contains(type)) { - qCDebug(networking) << "Warning: Registering a packet listener for packet type" << type + qCWarning(networking) << "Registering a packet listener for packet type" << type << "that will remove a previously registered listener"; } // add the mapping _packetListenerMap[type] = ObjectMethodPair(QPointer(object), slot); - - _packetListenerLock.unlock(); - } void PacketReceiver::unregisterListener(QObject* listener) { - _packetListenerLock.lock(); - - auto it = _packetListenerMap.begin(); - - while (it != _packetListenerMap.end()) { - if (it.value().first == listener) { - // this listener matches - erase it - it = _packetListenerMap.erase(it); - } else { - ++it; - } - } - - _packetListenerLock.unlock(); + Q_ASSERT_X(listener, "PacketReceiver::unregisterListener", "No listener to unregister"); - _directConnectSetMutex.lock(); + QMutexLocker packetListenerLocker(&_packetListenerLock); + std::remove_if(std::begin(_packetListenerMap), std::end(_packetListenerMap), + [&listener](const ObjectMethodPair& pair) { + return pair.first == listener; + }); + packetListenerLocker.unlock(); + + QMutexLocker directConnectSetLocker(&_directConnectSetMutex); _directlyConnectedObjects.remove(listener); - _directConnectSetMutex.unlock(); } void PacketReceiver::handleVerifiedPacketList(std::unique_ptr packetList) { @@ -337,7 +335,7 @@ void PacketReceiver::handleVerifiedPacketList(std::unique_ptr p } } else if (it == _packetListListenerMap.end()) { - qWarning() << "No listener found for packet type" << nlPacketList->getType(); + qCWarning(networking) << "No listener found for packet type" << nlPacketList->getType(); // insert a dummy listener so we don't print this again _packetListListenerMap.insert(nlPacketList->getType(), { nullptr, QMetaMethod() }); @@ -371,7 +369,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { } } - _packetListenerLock.lock(); + QMutexLocker packetListenerLocker(&_packetListenerLock); bool listenerIsDead = false; @@ -386,12 +384,10 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { bool success = false; // check if this is a directly connected listener - _directConnectSetMutex.lock(); - + QMutexLocker directConnectSetLocker(&_directConnectSetMutex); Qt::ConnectionType connectionType = _directlyConnectedObjects.contains(listener.first) ? Qt::DirectConnection : Qt::AutoConnection; - - _directConnectSetMutex.unlock(); + directConnectSetLocker.unlock(); PacketType packetType = nlPacket->getType(); @@ -456,18 +452,18 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { it = _packetListenerMap.erase(it); // if it exists, remove the listener from _directlyConnectedObjects - _directConnectSetMutex.lock(); + QMutexLocker locker(&_directConnectSetMutex); _directlyConnectedObjects.remove(listener.first); - _directConnectSetMutex.unlock(); + locker.unlock(); } } else if (it == _packetListenerMap.end()) { - qWarning() << "No listener found for packet type" << nlPacket->getType(); + qCWarning(networking) << "No listener found for packet type" << nlPacket->getType(); // insert a dummy listener so we don't print this again _packetListenerMap.insert(nlPacket->getType(), { nullptr, QMetaMethod() }); } - _packetListenerLock.unlock(); + packetListenerLocker.unlock(); } From 74d6e5ba890186c904a767974f09f0e98bcef938 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 20 Aug 2015 10:01:12 -0700 Subject: [PATCH 345/549] make sure LNL goes down before domain-server --- domain-server/src/DomainServer.cpp | 5 +++++ domain-server/src/DomainServer.h | 3 ++- libraries/networking/src/udt/Connection.cpp | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index ddbef90ef6..410b58d17f 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -110,6 +110,11 @@ DomainServer::DomainServer(int argc, char* argv[]) : } } +DomainServer::~DomainServer() { + // destroy the LimitedNodeList before the DomainServer QCoreApplication is down + DependencyManager::destroy(); +} + void DomainServer::aboutToQuit() { // clear the log handler so that Qt doesn't call the destructor on LogHandler diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 7495e080de..c39633f62a 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -38,7 +38,8 @@ class DomainServer : public QCoreApplication, public HTTPSRequestHandler { Q_OBJECT public: DomainServer(int argc, char* argv[]); - + ~DomainServer(); + static int const EXIT_CODE_REBOOT; bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false); diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 85c3dbcbda..9f8b1eb3ee 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -58,7 +58,8 @@ Connection::~Connection() { _sendQueue->deleteLater(); _sendQueue.release(); - // wait on the send queue thread so we know the send queue is gone + // wait on the send queue thread so we know the send queue is gone + sendQueueThread->quit(); sendQueueThread->wait(); } } From 039e6121bc9c5c6b68f5c5e2b66ef094c1fac534 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 20 Aug 2015 12:44:10 -0700 Subject: [PATCH 346/549] add randomization of data for ordered test --- tools/udt-test/src/UDTTest.cpp | 82 +++++++++++++++++++++++++++------- tools/udt-test/src/UDTTest.h | 2 + 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 0b65907e29..4455ac586e 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -11,6 +11,8 @@ #include "UDTTest.h" +#include + #include #include @@ -29,16 +31,16 @@ const QCommandLineOption PACKET_SIZE { QString(udt::MAX_PACKET_SIZE_WITH_UDP_HEADER) }; const QCommandLineOption MIN_PACKET_SIZE { - "min-packet-size", "min size for sent packets in bytes", "min-bytes" + "min-packet-size", "min size for sent packets in bytes", "min bytes" }; const QCommandLineOption MAX_PACKET_SIZE { - "max-packet-size", "max size for sent packets in bytes", "max-bytes" + "max-packet-size", "max size for sent packets in bytes", "max bytes" }; const QCommandLineOption MAX_SEND_BYTES { - "max-send-bytes", "number of bytes to send before stopping (default is infinite)", "max-bytes" + "max-send-bytes", "number of bytes to send before stopping (default is infinite)", "max bytes" }; const QCommandLineOption MAX_SEND_PACKETS { - "max-send-packets", "number of packets to send before stopping (default is infinite)", "max-packets" + "max-send-packets", "number of packets to send before stopping (default is infinite)", "max packets" }; const QCommandLineOption UNRELIABLE_PACKETS { "unreliable", "send unreliable packets (default is reliable)" @@ -46,6 +48,9 @@ const QCommandLineOption UNRELIABLE_PACKETS { const QCommandLineOption ORDERED_PACKETS { "ordered", "send ordered packets (default is unordered)" }; +const QCommandLineOption MESSAGE_SIZE { + "message-size", "megabytes per message payload for ordered sending (default is 100)", "megabytes" +}; const QStringList CLIENT_STATS_TABLE_HEADERS { "Send Rate (P/s)", "Bandwidth (P/s)", "RTT(ms)", "CW (P)", "Send Period (us)", @@ -138,6 +143,17 @@ UDTTest::UDTTest(int& argc, char** argv) : _sendOrdered = true; } + if (_argumentParser.isSet(MESSAGE_SIZE)) { + if (_argumentParser.isSet(ORDERED_PACKETS)) { + static const double BYTES_PER_MEGABYTE = 1000000; + _messageSize = (int) _argumentParser.value(MESSAGE_SIZE).toInt() * BYTES_PER_MEGABYTE; + + qDebug() << "Message size for ordered packet sending is" << QString("%1MB").arg(_messageSize / BYTES_PER_MEGABYTE); + } else { + qWarning() << "message-size has no effect if not sending ordered - it will be ignored"; + } + } + if (!_target.isNull()) { sendInitialPackets(); } @@ -159,7 +175,8 @@ void UDTTest::parseArguments() { _argumentParser.addOptions({ PORT_OPTION, TARGET_OPTION, PACKET_SIZE, MIN_PACKET_SIZE, MAX_PACKET_SIZE, - MAX_SEND_BYTES, MAX_SEND_PACKETS, UNRELIABLE_PACKETS, ORDERED_PACKETS + MAX_SEND_BYTES, MAX_SEND_PACKETS, UNRELIABLE_PACKETS, ORDERED_PACKETS, + MESSAGE_SIZE }); if (!_argumentParser.parse(arguments())) { @@ -189,6 +206,8 @@ void UDTTest::sendInitialPackets() { } } +static const int FIRST_MESSAGE_SEED = 742272; + void UDTTest::sendPacket() { if (_maxSendPackets != -1 && _totalQueuedPackets > _maxSendPackets) { @@ -216,22 +235,51 @@ void UDTTest::sendPacket() { } if (_sendOrdered) { + // check if it is time to add another message - we do this every time 95% of the message size has been sent static int call = 0; - call = (call + 1) % 4; - if (call == 0) { - auto packetList = std::unique_ptr(new udt::PacketList(PacketType::BulkAvatarData, QByteArray(), true, true)); - for (int i = 0; i < 4; i++) { - packetList->writePrimitive(0x1); - packetList->writePrimitive(0x2); - packetList->writePrimitive(0x3); - packetList->writePrimitive(0x4); - packetList->closeCurrentPacket(false); + static int packetSize = udt::Packet::maxPayloadSize(true); + static int messageSizePackets = (int) ceil(_messageSize / udt::Packet::maxPayloadSize()); + + static int refillCount = (int) (messageSizePackets * 0.95); + + if (call++ % refillCount == 0) { + // construct a reliable and ordered packet list + auto packetList = std::unique_ptr({ + new udt::PacketList(PacketType::BulkAvatarData, QByteArray(), true, true) + }); + + static int currentSeed = FIRST_MESSAGE_SEED; + + std::random_device rd; + std::mt19937 generator(rd()); + + // seed the generator with a value that the receiver will also use when verifying the ordered message + generator.seed(currentSeed++); + + // setup a distribution for integer values + std::uniform_int_distribution<> dis(1, UINT64_MAX); + + // fill the packet list with random data according to the constant seed (so receiver can verify) + for (int i = 0; i < messageSizePackets; ++i) { + // setup a QByteArray full of zeros for our random padded data + QByteArray randomPaddedData { packetSize, 0 }; + + // generate a random integer for the first 8 bytes of the random data + uint64_t randomInt = dis(generator); + randomPaddedData.replace(0, sizeof(randomInt), reinterpret_cast(&randomInt)); + + // write this data to the PacketList + packetList->write(randomPaddedData); } + + packetList->closeCurrentPacket(false); + _totalQueuedBytes += packetList->getDataSize(); - + _totalQueuedPackets += packetList->getNumPackets(); + _socket.writePacketList(std::move(packetList), _target); } - _totalQueuedPackets += 4; + } else { auto newPacket = udt::Packet::create(packetPayloadSize, _sendReliable); newPacket->setPayloadSize(packetPayloadSize); @@ -239,12 +287,12 @@ void UDTTest::sendPacket() { _totalQueuedBytes += newPacket->getDataSize(); // queue or send this packet by calling write packet on the socket for our target - // if ( if (_sendReliable) { _socket.writePacket(std::move(newPacket), _target); } else { _socket.writePacket(*newPacket, _target); } + ++_totalQueuedPackets; } diff --git a/tools/udt-test/src/UDTTest.h b/tools/udt-test/src/UDTTest.h index 28aa3d340e..652a721cbc 100644 --- a/tools/udt-test/src/UDTTest.h +++ b/tools/udt-test/src/UDTTest.h @@ -48,6 +48,8 @@ private: bool _sendReliable { true }; // whether packets are sent reliably or unreliably bool _sendOrdered { false }; // whether to send ordered packets + int _messageSize { 10000000 }; // number of bytes per message while sending ordered + int _totalQueuedPackets { 0 }; // keeps track of the number of packets we have already queued int _totalQueuedBytes { 0 }; // keeps track of the number of bytes we have already queued }; From 1756e606477b64dd8922eaa04c2817d4cbc27a7f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 20 Aug 2015 14:22:05 -0700 Subject: [PATCH 347/549] complete test for ordered packets in udt-test target --- libraries/networking/src/udt/PacketList.cpp | 13 ++++ libraries/networking/src/udt/PacketList.h | 1 + tools/udt-test/src/UDTTest.cpp | 72 +++++++++++++++------ tools/udt-test/src/UDTTest.h | 8 +++ 4 files changed, 74 insertions(+), 20 deletions(-) diff --git a/libraries/networking/src/udt/PacketList.cpp b/libraries/networking/src/udt/PacketList.cpp index 2e9bef09e1..b135788985 100644 --- a/libraries/networking/src/udt/PacketList.cpp +++ b/libraries/networking/src/udt/PacketList.cpp @@ -52,6 +52,19 @@ size_t PacketList::getDataSize() const { return totalBytes; } +size_t PacketList::getMessageSize() const { + size_t totalBytes = 0; + for (const auto& packet: _packets) { + totalBytes += packet->getPayloadSize(); + } + + if (_currentPacket) { + totalBytes += _currentPacket->getPayloadSize(); + } + + return totalBytes; +} + std::unique_ptr PacketList::fromReceivedPackets(std::list>&& packets) { auto packetList = std::unique_ptr(new PacketList(PacketType::Unknown, QByteArray(), true, true)); packetList->_packets = std::move(packets); diff --git a/libraries/networking/src/udt/PacketList.h b/libraries/networking/src/udt/PacketList.h index 37c253ac08..05800a1b26 100644 --- a/libraries/networking/src/udt/PacketList.h +++ b/libraries/networking/src/udt/PacketList.h @@ -47,6 +47,7 @@ public: QByteArray getExtendedHeader() const { return _extendedHeader; } size_t getDataSize() const; + size_t getMessageSize() const; void closeCurrentPacket(bool shouldSendEmpty = false); diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 4455ac586e..234ae1e93e 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -11,8 +11,6 @@ #include "UDTTest.h" -#include - #include #include @@ -49,7 +47,10 @@ const QCommandLineOption ORDERED_PACKETS { "ordered", "send ordered packets (default is unordered)" }; const QCommandLineOption MESSAGE_SIZE { - "message-size", "megabytes per message payload for ordered sending (default is 100)", "megabytes" + "message-size", "megabytes per message payload for ordered sending (default is 20)", "megabytes" +}; +const QCommandLineOption MESSAGE_SEED { + "message-seed", "seed used for random number generation to match ordered messages (default is 742272)", "integer" }; const QStringList CLIENT_STATS_TABLE_HEADERS { @@ -154,8 +155,26 @@ UDTTest::UDTTest(int& argc, char** argv) : } } + + // in case we're an ordered sender or receiver setup our random number generator now + static const int FIRST_MESSAGE_SEED = 742272; + + int messageSeed = FIRST_MESSAGE_SEED; + + if (_argumentParser.isSet(MESSAGE_SEED)) { + messageSeed = _argumentParser.value(MESSAGE_SEED).toInt(); + } + + // seed the generator with a value that the receiver will also use when verifying the ordered message + _generator.seed(messageSeed); + if (!_target.isNull()) { sendInitialPackets(); + } else { + // this is a receiver - in case there are ordered packets (messages) being sent to us make sure that we handle them + // so that they can be verified + using std::placeholders::_1; + _socket.setPacketListHandler(std::bind(&UDTTest::handlePacketList, this, _1)); } // the sender reports stats every 100 milliseconds @@ -176,7 +195,7 @@ void UDTTest::parseArguments() { _argumentParser.addOptions({ PORT_OPTION, TARGET_OPTION, PACKET_SIZE, MIN_PACKET_SIZE, MAX_PACKET_SIZE, MAX_SEND_BYTES, MAX_SEND_PACKETS, UNRELIABLE_PACKETS, ORDERED_PACKETS, - MESSAGE_SIZE + MESSAGE_SIZE, MESSAGE_SEED }); if (!_argumentParser.parse(arguments())) { @@ -206,8 +225,6 @@ void UDTTest::sendInitialPackets() { } } -static const int FIRST_MESSAGE_SEED = 742272; - void UDTTest::sendPacket() { if (_maxSendPackets != -1 && _totalQueuedPackets > _maxSendPackets) { @@ -238,7 +255,7 @@ void UDTTest::sendPacket() { // check if it is time to add another message - we do this every time 95% of the message size has been sent static int call = 0; static int packetSize = udt::Packet::maxPayloadSize(true); - static int messageSizePackets = (int) ceil(_messageSize / udt::Packet::maxPayloadSize()); + static int messageSizePackets = (int) ceil(_messageSize / udt::Packet::maxPayloadSize(true)); static int refillCount = (int) (messageSizePackets * 0.95); @@ -248,25 +265,14 @@ void UDTTest::sendPacket() { new udt::PacketList(PacketType::BulkAvatarData, QByteArray(), true, true) }); - static int currentSeed = FIRST_MESSAGE_SEED; - - std::random_device rd; - std::mt19937 generator(rd()); - - // seed the generator with a value that the receiver will also use when verifying the ordered message - generator.seed(currentSeed++); - - // setup a distribution for integer values - std::uniform_int_distribution<> dis(1, UINT64_MAX); - // fill the packet list with random data according to the constant seed (so receiver can verify) for (int i = 0; i < messageSizePackets; ++i) { // setup a QByteArray full of zeros for our random padded data QByteArray randomPaddedData { packetSize, 0 }; // generate a random integer for the first 8 bytes of the random data - uint64_t randomInt = dis(generator); - randomPaddedData.replace(0, sizeof(randomInt), reinterpret_cast(&randomInt)); + uint64_t randomInt = _distribution(_generator); + randomPaddedData.replace(0, sizeof(randomInt), reinterpret_cast(&randomInt), sizeof(randomInt)); // write this data to the PacketList packetList->write(randomPaddedData); @@ -298,6 +304,32 @@ void UDTTest::sendPacket() { } +void UDTTest::handlePacketList(std::unique_ptr packetList) { + // generate the byte array that should match this message - using the same seed the sender did + + int packetSize = udt::Packet::maxPayloadSize(true); + int messageSize = packetList->getMessageSize(); + + QByteArray messageData(messageSize, 0); + + for (int i = 0; i < messageSize; i += packetSize) { + // generate the random 64-bit unsigned integer that should lead this packet + uint64_t randomInt = _distribution(_generator); + + messageData.replace(i, sizeof(randomInt), reinterpret_cast(&randomInt), sizeof(randomInt)); + } + + bool dataMatch = messageData == packetList->getMessage(); + + Q_ASSERT_X(dataMatch, "UDTTest::handlePacketList", + "received message did not match expected message (from seeded random number generation)."); + + if (!dataMatch) { + qCritical() << "UDTTest::handlePacketList" << "received message did not match expected message" + << "(from seeded random number generation)."; + } +} + void UDTTest::sampleStats() { static bool first = true; static const double USECS_PER_MSEC = 1000.0; diff --git a/tools/udt-test/src/UDTTest.h b/tools/udt-test/src/UDTTest.h index 652a721cbc..376dc98bf6 100644 --- a/tools/udt-test/src/UDTTest.h +++ b/tools/udt-test/src/UDTTest.h @@ -14,6 +14,9 @@ #ifndef hifi_UDTTest_h #define hifi_UDTTest_h + +#include + #include #include @@ -31,6 +34,7 @@ public slots: private: void parseArguments(); + void handlePacketList(std::unique_ptr packetList); void sendInitialPackets(); // fills the queue with packets to start void sendPacket(); // constructs and sends a packet according to the test parameters @@ -50,6 +54,10 @@ private: int _messageSize { 10000000 }; // number of bytes per message while sending ordered + std::random_device _randomDevice; + std::mt19937 _generator { _randomDevice() }; // random number generator for ordered data testing + std::uniform_int_distribution _distribution { 1, UINT64_MAX }; // producer of random integer values + int _totalQueuedPackets { 0 }; // keeps track of the number of packets we have already queued int _totalQueuedBytes { 0 }; // keeps track of the number of bytes we have already queued }; From f802f354caf5357abb22558ffc5ba5e73c527c4d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 21 Aug 2015 15:36:03 +0200 Subject: [PATCH 348/549] prefer scoped locker to unlocks --- libraries/networking/src/PacketReceiver.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index a086949ac8..74a8ef8ff1 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -206,12 +206,13 @@ void PacketReceiver::registerVerifiedListener(PacketType type, QObject* object, void PacketReceiver::unregisterListener(QObject* listener) { Q_ASSERT_X(listener, "PacketReceiver::unregisterListener", "No listener to unregister"); - QMutexLocker packetListenerLocker(&_packetListenerLock); - std::remove_if(std::begin(_packetListenerMap), std::end(_packetListenerMap), - [&listener](const ObjectMethodPair& pair) { - return pair.first == listener; - }); - packetListenerLocker.unlock(); + { + QMutexLocker packetListenerLocker(&_packetListenerLock); + std::remove_if(std::begin(_packetListenerMap), std::end(_packetListenerMap), + [&listener](const ObjectMethodPair& pair) { + return pair.first == listener; + }); + } QMutexLocker directConnectSetLocker(&_directConnectSetMutex); _directlyConnectedObjects.remove(listener); @@ -454,7 +455,6 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { // if it exists, remove the listener from _directlyConnectedObjects QMutexLocker locker(&_directConnectSetMutex); _directlyConnectedObjects.remove(listener.first); - locker.unlock(); } } else if (it == _packetListenerMap.end()) { @@ -463,7 +463,4 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { // insert a dummy listener so we don't print this again _packetListenerMap.insert(nlPacket->getType(), { nullptr, QMetaMethod() }); } - - packetListenerLocker.unlock(); - } From 4191ccd60de3924e8740839fb2e4c57cb0e872f9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 24 Aug 2015 12:16:20 -0700 Subject: [PATCH 349/549] Move *ResourceRequest objects to separate files --- .../networking/src/AssetResourceRequest.cpp | 44 +++++++ .../networking/src/AssetResourceRequest.h | 30 +++++ .../networking/src/FileResourceRequest.cpp | 27 ++++ .../networking/src/FileResourceRequest.h | 27 ++++ .../networking/src/HTTPResourceRequest.cpp | 96 ++++++++++++++ .../networking/src/HTTPResourceRequest.h | 40 ++++++ libraries/networking/src/ResourceManager.cpp | 124 +----------------- libraries/networking/src/ResourceManager.h | 84 +----------- libraries/networking/src/ResourceRequest.cpp | 23 ++++ libraries/networking/src/ResourceRequest.h | 59 +++++++++ 10 files changed, 350 insertions(+), 204 deletions(-) create mode 100644 libraries/networking/src/AssetResourceRequest.cpp create mode 100644 libraries/networking/src/AssetResourceRequest.h create mode 100644 libraries/networking/src/FileResourceRequest.cpp create mode 100644 libraries/networking/src/FileResourceRequest.h create mode 100644 libraries/networking/src/HTTPResourceRequest.cpp create mode 100644 libraries/networking/src/HTTPResourceRequest.h create mode 100644 libraries/networking/src/ResourceRequest.cpp create mode 100644 libraries/networking/src/ResourceRequest.h diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp new file mode 100644 index 0000000000..f7727336a9 --- /dev/null +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -0,0 +1,44 @@ +// +// AssetResourceRequest.cpp +// +// Created by Ryan Huffman on 2015/07/23 +// Copyright 2015 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 "AssetResourceRequest.h" + +#include "AssetClient.h" +#include "AssetRequest.h" + +void ATPResourceRequest::doSend() { + // Make request to atp + auto assetClient = DependencyManager::get(); + auto hash = _url.path(); + + auto request = assetClient->create(hash); + + if (!request) { + return; + } + + QObject::connect(request, &AssetRequest::finished, [this](AssetRequest* req) mutable { + if (_state != IN_PROGRESS) return; + _state = FINISHED; + if (true) { + _data = req->getData(); + _result = ResourceRequest::SUCCESS; + emit finished(); + } else { + _result = ResourceRequest::ERROR; + emit finished(); + } + }); + + request->start(); +} + +void ATPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { +} diff --git a/libraries/networking/src/AssetResourceRequest.h b/libraries/networking/src/AssetResourceRequest.h new file mode 100644 index 0000000000..34c1878b04 --- /dev/null +++ b/libraries/networking/src/AssetResourceRequest.h @@ -0,0 +1,30 @@ +// +// AssetResourceRequest.h +// +// Created by Ryan Huffman on 2015/07/23 +// Copyright 2015 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 +// + +#ifndef hifi_AssetResourceRequest_h +#define hifi_AssetResourceRequest_h + +#include + +#include "ResourceRequest.h" + +class ATPResourceRequest : public ResourceRequest { + Q_OBJECT +public: + ATPResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } + +protected: + virtual void doSend() override; + +private slots: + void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); +}; + +#endif diff --git a/libraries/networking/src/FileResourceRequest.cpp b/libraries/networking/src/FileResourceRequest.cpp new file mode 100644 index 0000000000..8bd7ecf94e --- /dev/null +++ b/libraries/networking/src/FileResourceRequest.cpp @@ -0,0 +1,27 @@ +// +// FileResourceRequest.cpp +// +// Created by Ryan Huffman on 2015/07/23 +// Copyright 2015 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 "FileResourceRequest.h" + +#include + +void FileResourceRequest::doSend() { + QString filename = _url.toLocalFile(); + QFile file(filename); + _state = FINISHED; + if (file.open(QFile::ReadOnly)) { + _data = file.readAll(); + _result = ResourceRequest::SUCCESS; + emit finished(); + } else { + _result = ResourceRequest::ERROR; + emit finished(); + } +} diff --git a/libraries/networking/src/FileResourceRequest.h b/libraries/networking/src/FileResourceRequest.h new file mode 100644 index 0000000000..7618311626 --- /dev/null +++ b/libraries/networking/src/FileResourceRequest.h @@ -0,0 +1,27 @@ +// +// FileResourceRequest.h +// +// Created by Ryan Huffman on 2015/07/23 +// Copyright 2015 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 +// + +#ifndef hifi_FileResourceRequest_h +#define hifi_FileResourceRequest_h + +#include + +#include "ResourceRequest.h" + +class FileResourceRequest : public ResourceRequest { + Q_OBJECT +public: + FileResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } + +protected: + virtual void doSend() override; +}; + +#endif diff --git a/libraries/networking/src/HTTPResourceRequest.cpp b/libraries/networking/src/HTTPResourceRequest.cpp new file mode 100644 index 0000000000..f684718bf1 --- /dev/null +++ b/libraries/networking/src/HTTPResourceRequest.cpp @@ -0,0 +1,96 @@ +// +// HTTPResourceRequest.cpp +// +// Created by Ryan Huffman on 2015/07/23 +// Copyright 2015 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 "HTTPResourceRequest.h" + +#include +#include +#include + +#include + +#include "NetworkAccessManager.h" +#include "NetworkLogging.h" + +HTTPResourceRequest::~HTTPResourceRequest() { + if (_reply) { + _reply->disconnect(this); + _reply->deleteLater(); + _reply = nullptr; + } +} + +void HTTPResourceRequest::doSend() { + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkRequest networkRequest = QNetworkRequest(_url); + networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + + if (_cacheEnabled) { + networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + } else { + networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); + } + + _reply = networkAccessManager.get(networkRequest); + + connect(_reply, &QNetworkReply::finished, this, &HTTPResourceRequest::onRequestFinished); + + static const int TIMEOUT_MS = 10000; + + connect(&_sendTimer, &QTimer::timeout, this, &HTTPResourceRequest::onTimeout); + _sendTimer.setSingleShot(true); + _sendTimer.start(TIMEOUT_MS); +} + +void HTTPResourceRequest::onRequestFinished() { + Q_ASSERT(_state == IN_PROGRESS); + Q_ASSERT(_reply); + + _state = FINISHED; + auto error = _reply->error(); + qDebug() << "Loaded " << _url; + QString u = _url.path(); + if (error == QNetworkReply::NoError) { + _data = _reply->readAll(); + qDebug() << "!!!! " << _data.size() << " " << _url.path(); + _loadedFromCache = _reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(); + _result = ResourceRequest::SUCCESS; + emit finished(); + } else if (error == QNetworkReply::TimeoutError) { + _result = ResourceRequest::TIMEOUT; + emit finished(); + } else { + _result = ResourceRequest::ERROR; + emit finished(); + } + _reply->deleteLater(); + _reply = nullptr; +} + +void HTTPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { + if (_state == IN_PROGRESS) { + // Restart timer + _sendTimer.start(); + } +} + +void HTTPResourceRequest::onTimeout() { + Q_ASSERT(_state != UNSENT); + + // TODO Cancel request if timed out, handle properly in + // receive callback + if (_state == IN_PROGRESS) { + qCDebug(networking) << "Timed out loading " << _url; + _state = FINISHED; + _result = TIMEOUT; + _reply->abort(); + emit finished(); + } +} diff --git a/libraries/networking/src/HTTPResourceRequest.h b/libraries/networking/src/HTTPResourceRequest.h new file mode 100644 index 0000000000..c42204f3e9 --- /dev/null +++ b/libraries/networking/src/HTTPResourceRequest.h @@ -0,0 +1,40 @@ +// +// HTTPResourceRequest.h +// +// Created by Ryan Huffman on 2015/07/23 +// Copyright 2015 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 +// + +#ifndef hifi_HTTPResourceRequest_h +#define hifi_HTTPResourceRequest_h + +#include +#include +#include + +#include "ResourceRequest.h" + +class HTTPResourceRequest : public ResourceRequest { + Q_OBJECT +public: + ~HTTPResourceRequest(); + + HTTPResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } + +protected: + virtual void doSend() override; + +private slots: + void onTimeout(); + void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); + void onRequestFinished(); + +private: + QTimer _sendTimer; + QNetworkReply* _reply { nullptr }; +}; + +#endif diff --git a/libraries/networking/src/ResourceManager.cpp b/libraries/networking/src/ResourceManager.cpp index 00348df69b..cfa7513a1a 100644 --- a/libraries/networking/src/ResourceManager.cpp +++ b/libraries/networking/src/ResourceManager.cpp @@ -10,12 +10,9 @@ #include "ResourceManager.h" -#include -#include - -#include "AssetClient.h" -#include "AssetRequest.h" -#include "NetworkAccessManager.h" +#include "AssetResourceRequest.h" +#include "FileResourceRequest.h" +#include "HTTPResourceRequest.h" #include @@ -25,121 +22,6 @@ const QString URL_SCHEME_HTTPS = "https"; const QString URL_SCHEME_FTP = "ftp"; const QString URL_SCHEME_ATP = "atp"; -ResourceRequest::ResourceRequest(QObject* parent, const QUrl& url) : - QObject(parent), - _url(url) { -} - -HTTPResourceRequest::~HTTPResourceRequest() { - if (_reply) { - _reply->disconnect(this); - _reply->deleteLater(); - _reply = nullptr; - } -} - -void HTTPResourceRequest::doSend() { - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - QNetworkRequest networkRequest = QNetworkRequest(_url); - networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); - - if (_cacheEnabled) { - networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); - } else { - networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); - } - - _reply = networkAccessManager.get(networkRequest); - QObject::connect(_reply, &QNetworkReply::finished, [=]() { - Q_ASSERT(_state == IN_PROGRESS); - Q_ASSERT(_reply); - - _state = FINISHED; - auto error = _reply->error(); - qDebug() << "Loaded " << _url; - QString u = _url.path(); - if (error == QNetworkReply::NoError) { - _data = _reply->readAll(); - qDebug() << "!!!! " << _data.size() << " " << _url.path(); - _loadedFromCache = _reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(); - _result = ResourceRequest::SUCCESS; - emit finished(); - } else if (error == QNetworkReply::TimeoutError) { - _result = ResourceRequest::TIMEOUT; - emit finished(); - } else { - _result = ResourceRequest::ERROR; - emit finished(); - } - _reply->deleteLater(); - _reply = nullptr; - }); -} - -void FileResourceRequest::doSend() { - QString filename = _url.toLocalFile(); - QFile file(filename); - _state = FINISHED; - if (file.open(QFile::ReadOnly)) { - _data = file.readAll(); - _result = ResourceRequest::SUCCESS; - emit finished(); - } else { - _result = ResourceRequest::ERROR; - emit finished(); - } -} - -void ATPResourceRequest::doSend() { - // Make request to atp - auto assetClient = DependencyManager::get(); - auto hash = _url.path(); - - auto request = assetClient->create(hash); - - if (!request) { - return; - } - - QObject::connect(request, &AssetRequest::finished, [this](AssetRequest* req) mutable { - if (_state != IN_PROGRESS) return; - _state = FINISHED; - if (true) { - _data = req->getData(); - _result = ResourceRequest::SUCCESS; - emit finished(); - } else { - _result = ResourceRequest::ERROR; - emit finished(); - } - }); - - request->start(); -} - -const int TIMEOUT_MS = 2000; -void ResourceRequest::send() { - Q_ASSERT(_state == UNSENT); - - _state = IN_PROGRESS; - doSend(); - connect(&_sendTimer, &QTimer::timeout, this, &ResourceRequest::timeout); - _sendTimer.setSingleShot(true); - _sendTimer.start(TIMEOUT_MS); -} - -void ResourceRequest::timeout() { - Q_ASSERT(_state != UNSENT); - - // TIMEOUT!! - if (_state == IN_PROGRESS) { - qDebug() << "TImed out loading " << _url; - _state = FINISHED; - _result = TIMEOUT; - emit finished(); - } -} - ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const QUrl& url) { auto scheme = url.scheme(); if (scheme == URL_SCHEME_FILE) { diff --git a/libraries/networking/src/ResourceManager.h b/libraries/networking/src/ResourceManager.h index 599399fb15..1cb6b08a79 100644 --- a/libraries/networking/src/ResourceManager.h +++ b/libraries/networking/src/ResourceManager.h @@ -8,94 +8,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - #ifndef hifi_ResourceManager_h #define hifi_ResourceManager_h #include -#include -#include -#include -#include - -class ResourceRequest : public QObject { - Q_OBJECT -public: - ResourceRequest(QObject* parent, const QUrl& url); - - enum State { - UNSENT = 0, - IN_PROGRESS, - FINISHED - }; - - enum Result { - SUCCESS, - ERROR, - TIMEOUT, - NOT_FOUND - }; - - void send(); - QByteArray moveData() { return _data; } - State getState() const { return _state; } - Result getResult() const { return _result; } - QUrl getUrl() const { return _url; } - bool loadedFromCache() const { return _loadedFromCache; } - - void setCacheEnabled(bool value) { _cacheEnabled = value; } - -signals: - void progress(uint64_t bytesReceived, uint64_t bytesTotal); - void finished(); - -protected: - virtual void doSend() = 0; - - QUrl _url; - State _state { UNSENT }; - Result _result; - QTimer _sendTimer; - QByteArray _data; - bool _cacheEnabled { true }; - bool _loadedFromCache { false }; - -private slots: - void timeout(); -}; - -class HTTPResourceRequest : public ResourceRequest { - Q_OBJECT -public: - ~HTTPResourceRequest(); - - HTTPResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } - -protected: - virtual void doSend() override; - -private: - QNetworkReply* _reply { nullptr }; -}; - -class FileResourceRequest : public ResourceRequest { - Q_OBJECT -public: - FileResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } - -protected: - virtual void doSend() override; -}; - -class ATPResourceRequest : public ResourceRequest { - Q_OBJECT -public: - ATPResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } - -protected: - virtual void doSend() override; -}; +#include "ResourceRequest.h" class ResourceManager { public: diff --git a/libraries/networking/src/ResourceRequest.cpp b/libraries/networking/src/ResourceRequest.cpp new file mode 100644 index 0000000000..44bfaae254 --- /dev/null +++ b/libraries/networking/src/ResourceRequest.cpp @@ -0,0 +1,23 @@ +// +// ResourceRequest.cpp +// +// Created by Ryan Huffman on 2015/07/23 +// Copyright 2015 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 "ResourceRequest.h" + +ResourceRequest::ResourceRequest(QObject* parent, const QUrl& url) : + QObject(parent), + _url(url) { +} + +void ResourceRequest::send() { + Q_ASSERT(_state == UNSENT); + + _state = IN_PROGRESS; + doSend(); +} diff --git a/libraries/networking/src/ResourceRequest.h b/libraries/networking/src/ResourceRequest.h new file mode 100644 index 0000000000..3eb975d8d6 --- /dev/null +++ b/libraries/networking/src/ResourceRequest.h @@ -0,0 +1,59 @@ +// +// ResourceRequest.h +// +// Created by Ryan Huffman on 2015/07/23 +// Copyright 2015 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 +// + +#ifndef hifi_ResourceRequest_h +#define hifi_ResourceRequest_h + +#include +#include + +class ResourceRequest : public QObject { + Q_OBJECT +public: + ResourceRequest(QObject* parent, const QUrl& url); + + enum State { + UNSENT = 0, + IN_PROGRESS, + FINISHED + }; + + enum Result { + SUCCESS, + ERROR, + TIMEOUT, + NOT_FOUND + }; + + void send(); + QByteArray moveData() { return _data; } + State getState() const { return _state; } + Result getResult() const { return _result; } + QUrl getUrl() const { return _url; } + bool loadedFromCache() const { return _loadedFromCache; } + + void setCacheEnabled(bool value) { _cacheEnabled = value; } + +signals: + void progress(uint64_t bytesReceived, uint64_t bytesTotal); + void finished(); + +protected: + virtual void doSend() = 0; + + QUrl _url; + State _state { UNSENT }; + Result _result; + QByteArray _data; + bool _cacheEnabled { true }; + bool _loadedFromCache { false }; +}; + +#endif From e84595af4936327aae823b3984f4ffbdc8686616 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Aug 2015 16:50:54 -0700 Subject: [PATCH 350/549] add a wait condition for empty queue and loss list --- libraries/networking/src/udt/SendQueue.cpp | 61 +++++++++++++++++++--- libraries/networking/src/udt/SendQueue.h | 27 ++++++++-- 2 files changed, 76 insertions(+), 12 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index cfb969a186..fcede6fe03 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -56,8 +56,11 @@ SendQueue::SendQueue(Socket* socket, HifiSockAddr dest) : void SendQueue::queuePacket(std::unique_ptr packet) { { - QWriteLocker locker(&_packetsLock); + std::lock_guard locker(_packetsLock); _packets.push_back(std::move(packet)); + + // call notify_one on the condition_variable_any in case the send thread is sleeping waiting for packets + _emptyCondition.notify_one(); } if (!this->thread()->isRunning()) { this->thread()->start(); @@ -95,9 +98,12 @@ void SendQueue::queuePacketList(std::unique_ptr packetList) { } } - QWriteLocker locker(&_packetsLock); + std::lock_guard locker(_packetsLock); _packets.splice(_packets.end(), packetList->_packets); + + // call notify_one on the condition_variable_any in case the send thread is sleeping waiting for packets + _emptyCondition.notify_one(); } if (!this->thread()->isRunning()) { @@ -126,7 +132,7 @@ void SendQueue::ack(SequenceNumber ack) { } { // remove any sequence numbers equal to or lower than this ACK in the loss list - QWriteLocker nakLocker(&_naksLock); + std::lock_guard nakLocker(_naksLock); if (_naks.getLength() > 0 && _naks.getFirstSequenceNumber() <= ack) { _naks.remove(_naks.getFirstSequenceNumber(), ack); @@ -137,12 +143,15 @@ void SendQueue::ack(SequenceNumber ack) { } void SendQueue::nak(SequenceNumber start, SequenceNumber end) { - QWriteLocker locker(&_naksLock); + std::lock_guard nakLocker(_naksLock); _naks.insert(start, end); + + // call notify_one on the condition_variable_any in case the send thread is sleeping waiting for losses to re-send + _emptyCondition.notify_one(); } void SendQueue::overrideNAKListFromPacket(ControlPacket& packet) { - QWriteLocker locker(&_naksLock); + std::lock_guard nakLocker(_naksLock); _naks.clear(); SequenceNumber first, second; @@ -156,6 +165,9 @@ void SendQueue::overrideNAKListFromPacket(ControlPacket& packet) { _naks.append(first, second); } } + + // call notify_one on the condition_variable_any in case the send thread is sleeping waiting for losses to re-send + _emptyCondition.notify_one(); } SequenceNumber SendQueue::getNextSequenceNumber() { @@ -195,16 +207,20 @@ void SendQueue::run() { // Record timing _lastSendTimestamp = high_resolution_clock::now(); + bool naksEmpty = true; // used at the end of processing to see if we should wait for NAKs + bool resentPacket = false; // the following while makes sure that we find a packet to re-send, if there is one while (!resentPacket) { - QWriteLocker naksLocker(&_naksLock); + std::unique_lock nakLocker(_naksLock); if (_naks.getLength() > 0) { + naksEmpty = _naks.getLength() > 1; + // pull the sequence number we need to re-send SequenceNumber resendNumber = _naks.popFirstSequenceNumber(); - naksLocker.unlock(); + nakLocker.unlock(); // pull the packet to re-send from the sent packets list QReadLocker sentLocker(&_sentLock); @@ -233,21 +249,27 @@ void SendQueue::run() { // we'll fire the loop again to see if there is another to re-send continue; } + } else { + naksEmpty = true; } // break from the while, we didn't resend a packet break; } + bool packetsEmpty = false; // used after processing to check if we should wait for packets + bool sentPacket = false; + // if we didn't find a packet to re-send AND we think we can fit a new packet on the wire // (this is according to the current flow window size) then we send out a new packet if (!resentPacket && seqlen(SequenceNumber { (uint32_t) _lastACKSequenceNumber }, _currentSequenceNumber) <= _flowWindowSize) { // we didn't re-send a packet, so time to send a new one - QWriteLocker locker(&_packetsLock); + std::unique_lock locker(_packetsLock); if (_packets.size() > 0) { + SequenceNumber nextNumber = getNextSequenceNumber(); // grab the first packet we will send @@ -266,9 +288,13 @@ void SendQueue::run() { } } + packetsEmpty = _packets.size() == 0; + // unlock the packets, we're done pulling locker.unlock(); + sentPacket = true; + // definitely send the first packet sendNewPacketAndAddToSentList(move(firstPacket), nextNumber); @@ -279,6 +305,7 @@ void SendQueue::run() { } } else { + packetsEmpty = true; locker.unlock(); } } @@ -291,6 +318,24 @@ void SendQueue::run() { break; } + if (packetsEmpty && naksEmpty) { + // During our processing above the loss list and packet list were both empty. + + // If that is still the case we should use a condition_variable_any to sleep until we have data to handle. + // To confirm that the queue of packets and the NAKs list are still both empty we'll need to use the DoubleLock + DoubleLock doubleLock(_packetsLock, _naksLock); + + // The packets queue and loss list mutexes are now both locked - check if they're still both empty + if (_packets.empty() && _naks.getLength() == 0) { + // both are empty - let's use a condition_variable_any to wait + _emptyCondition.wait(doubleLock); + + // we have the double lock again - it'll be unlock once it goes out of scope + // skip to the next iteration + continue; + } + } + // sleep as long as we need until next packet send, if we can auto now = high_resolution_clock::now(); auto microsecondDuration = duration_cast((_lastSendTimestamp + microseconds(_packetSendPeriod)) - now); diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 901a9f7a87..af53ef79ec 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -13,7 +13,9 @@ #define hifi_SendQueue_h #include +#include #include +#include #include #include @@ -40,11 +42,26 @@ class SendQueue : public QObject { Q_OBJECT public: + + class DoubleLock { + public: + DoubleLock(std::mutex& mutex1, std::mutex& mutex2) : _mutex1(mutex1), _mutex2(mutex2) { lock(); } + ~DoubleLock() { unlock(); } + + DoubleLock(const DoubleLock&) = delete; + DoubleLock& operator=(const DoubleLock&) = delete; + + void lock() { std::lock(_mutex1, _mutex2); } + void unlock() { _mutex1.unlock(); _mutex2.unlock(); } + private: + std::mutex& _mutex1; + std::mutex& _mutex2; + }; + static std::unique_ptr create(Socket* socket, HifiSockAddr destination); void queuePacket(std::unique_ptr packet); void queuePacketList(std::unique_ptr packetList); - int getQueueSize() const { QReadLocker locker(&_packetsLock); return _packets.size(); } SequenceNumber getCurrentSequenceNumber() const { return SequenceNumber(_atomicCurrentSequenceNumber); } @@ -79,13 +96,13 @@ private: SequenceNumber getNextSequenceNumber(); MessageNumber getNextMessageNumber(); - mutable QReadWriteLock _packetsLock; // Protects the packets to be sent list. + mutable std::mutex _packetsLock; // Protects the packets to be sent list. std::list> _packets; // List of packets to be sent Socket* _socket { nullptr }; // Socket to send packet on HifiSockAddr _destination; // Destination addr - std::atomic _lastACKSequenceNumber; // Last ACKed sequence number + std::atomic _lastACKSequenceNumber { 0 }; // Last ACKed sequence number MessageNumber _currentMessageNumber { 0 }; SequenceNumber _currentSequenceNumber; // Last sequence number sent out @@ -97,11 +114,13 @@ private: std::atomic _flowWindowSize; // Flow control window size (number of packets that can be on wire) - set from CC - mutable QReadWriteLock _naksLock; // Protects the naks list. + mutable std::mutex _naksLock; // Protects the naks list. LossList _naks; // Sequence numbers of packets to resend mutable QReadWriteLock _sentLock; // Protects the sent packet list std::unordered_map> _sentPackets; // Packets waiting for ACK. + + std::condition_variable_any _emptyCondition; }; } From f7799bcf8fc8b45e3ec6cea14e889ea61d77fa55 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 24 Aug 2015 17:00:56 -0700 Subject: [PATCH 351/549] add TODO for settings fail, cleanup --- assignment-client/src/audio/AudioMixer.cpp | 2 ++ libraries/networking/src/DomainHandler.cpp | 37 ++-------------------- libraries/networking/src/DomainHandler.h | 1 - libraries/networking/src/udt/SendQueue.cpp | 2 +- libraries/networking/src/udt/SendQueue.h | 2 +- 5 files changed, 7 insertions(+), 37 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index c1d0cc2215..9fa0ac2faf 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -666,6 +666,8 @@ void AudioMixer::run() { connect(&domainHandler, &DomainHandler::settingsReceiveFail, &loop, &QEventLoop::quit); domainHandler.requestDomainSettings(); loop.exec(); + + domainHandler.requestDomainSettings(); if (domainHandler.getSettingsObject().isEmpty()) { qDebug() << "Failed to retreive settings object from domain-server. Bailing on assignment."; diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 62b00a8c98..df024b361d 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -227,6 +227,9 @@ void DomainHandler::setIsConnected(bool isConnected) { } void DomainHandler::requestDomainSettings() { + // TODO: the nodes basically lock if they don't get a response - add a timeout to this so that they at least restart + // if they can't get settings + NodeType_t owningNodeType = DependencyManager::get()->getOwnerType(); if (owningNodeType == NodeType::Agent) { // for now the agent nodes don't need any settings - this allows local assignment-clients @@ -248,40 +251,6 @@ void DomainHandler::requestDomainSettings() { } } -const int MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS = 5; - -void DomainHandler::settingsRequestFinished() { - QNetworkReply* settingsReply = reinterpret_cast(sender()); - - int replyCode = settingsReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - - if (settingsReply->error() == QNetworkReply::NoError && replyCode != 301 && replyCode != 302) { - // parse the JSON to a QJsonObject and save it - _settingsObject = QJsonDocument::fromJson(settingsReply->readAll()).object(); - - qCDebug(networking) << "Received domain settings."; - emit settingsReceived(_settingsObject); - - // reset failed settings requests to 0, we got them - _failedSettingsRequests = 0; - } else { - // error grabbing the settings - in some cases this means we are stuck - // so we should retry until we get it - qCDebug(networking) << "Error getting domain settings -" << settingsReply->errorString() << "- retrying"; - - if (++_failedSettingsRequests >= MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS) { - qCDebug(networking) << "Failed to retreive domain-server settings" << MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS - << "times. Re-setting connection to domain."; - clearSettings(); - clearConnectionInfo(); - emit settingsReceiveFail(); - } else { - requestDomainSettings(); - } - } - settingsReply->deleteLater(); -} - void DomainHandler::processSettingsPacketList(QSharedPointer packetList) { auto data = packetList->getMessage(); diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 349b3934eb..9dd4254c30 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -95,7 +95,6 @@ public slots: private slots: void completedHostnameLookup(const QHostInfo& hostInfo); void completedIceServerHostnameLookup(); - void settingsRequestFinished(); signals: void hostnameChanged(const QString& hostname); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index fcede6fe03..5e0e8312f2 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -330,7 +330,7 @@ void SendQueue::run() { // both are empty - let's use a condition_variable_any to wait _emptyCondition.wait(doubleLock); - // we have the double lock again - it'll be unlock once it goes out of scope + // we have the double lock again - it'll be unlocked once it goes out of scope // skip to the next iteration continue; } diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index af53ef79ec..1987dee9dc 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -106,7 +106,7 @@ private: MessageNumber _currentMessageNumber { 0 }; SequenceNumber _currentSequenceNumber; // Last sequence number sent out - std::atomic _atomicCurrentSequenceNumber;// Atomic for last sequence number sent out + std::atomic _atomicCurrentSequenceNumber { 0 };// Atomic for last sequence number sent out std::atomic _packetSendPeriod; // Interval between two packet send event in microseconds, set from CC std::chrono::high_resolution_clock::time_point _lastSendTimestamp; // Record last time of packet departure From 5e5bd77870a108b9b66aba6ad32d2a43a674016f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 25 Aug 2015 09:55:21 -0700 Subject: [PATCH 352/549] add initialization for all atomics in SendQueue --- libraries/networking/src/udt/SendQueue.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 1987dee9dc..618cf17009 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -108,11 +108,11 @@ private: SequenceNumber _currentSequenceNumber; // Last sequence number sent out std::atomic _atomicCurrentSequenceNumber { 0 };// Atomic for last sequence number sent out - std::atomic _packetSendPeriod; // Interval between two packet send event in microseconds, set from CC + std::atomic _packetSendPeriod { 0 }; // Interval between two packet send event in microseconds, set from CC std::chrono::high_resolution_clock::time_point _lastSendTimestamp; // Record last time of packet departure std::atomic _isRunning { false }; - std::atomic _flowWindowSize; // Flow control window size (number of packets that can be on wire) - set from CC + std::atomic _flowWindowSize { 0 }; // Flow control window size (number of packets that can be on wire) - set from CC mutable std::mutex _naksLock; // Protects the naks list. LossList _naks; // Sequence numbers of packets to resend From 92116dd6e7b66a903aa9a96dd7458dd480be6bc0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 25 Aug 2015 11:04:24 -0700 Subject: [PATCH 353/549] added stats for receive rate in Mbits --- tools/udt-test/src/UDTTest.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 234ae1e93e..d9cd9cc1b6 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -52,6 +52,9 @@ const QCommandLineOption MESSAGE_SIZE { const QCommandLineOption MESSAGE_SEED { "message-seed", "seed used for random number generation to match ordered messages (default is 742272)", "integer" }; +const QCommandLineOption STATS_INTERVAL { + "stats-interval", "stats output interval (default is 100ms)", "milliseconds" +}; const QStringList CLIENT_STATS_TABLE_HEADERS { "Send Rate (P/s)", "Bandwidth (P/s)", "RTT(ms)", "CW (P)", "Send Period (us)", @@ -60,7 +63,7 @@ const QStringList CLIENT_STATS_TABLE_HEADERS { }; const QStringList SERVER_STATS_TABLE_HEADERS { - "Receive Rate (P/s)", "Bandwidth (P/s)", "RTT(ms)", "CW (P)", + "Received Megabits", "Receive Rate (P/s)", "Bandwidth (P/s)", "RTT(ms)", "CW (P)", "Sent ACK", "Sent LACK", "Sent NAK", "Sent TNAK", "Recieved ACK2", "Duplicate Packets" }; @@ -180,9 +183,15 @@ UDTTest::UDTTest(int& argc, char** argv) : // the sender reports stats every 100 milliseconds static const int STATS_SAMPLE_INTERVAL = 100; + int statsInterval = STATS_SAMPLE_INTERVAL; + + if (_argumentParser.isSet(STATS_INTERVAL)) { + statsInterval = _argumentParser.value(STATS_INTERVAL).toInt(); + } + QTimer* statsTimer = new QTimer(this); connect(statsTimer, &QTimer::timeout, this, &UDTTest::sampleStats); - statsTimer->start(STATS_SAMPLE_INTERVAL); + statsTimer->start(statsInterval); } void UDTTest::parseArguments() { @@ -195,7 +204,7 @@ void UDTTest::parseArguments() { _argumentParser.addOptions({ PORT_OPTION, TARGET_OPTION, PACKET_SIZE, MIN_PACKET_SIZE, MAX_PACKET_SIZE, MAX_SEND_BYTES, MAX_SEND_PACKETS, UNRELIABLE_PACKETS, ORDERED_PACKETS, - MESSAGE_SIZE, MESSAGE_SEED + MESSAGE_SIZE, MESSAGE_SEED, STATS_INTERVAL }); if (!_argumentParser.parse(arguments())) { @@ -377,8 +386,11 @@ void UDTTest::sampleStats() { int headerIndex = -1; + static const double MEGABITS_PER_BYTE = 8.0 / 1000000.0; + // setup a list of left justified values QStringList values { + QString::number(stats.recievedBytes * MEGABITS_PER_BYTE).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.receiveRate).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.estimatedBandwith).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.rtt / USECS_PER_MSEC).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), From 9ff7bfd0b50d201293e32681346e63dfed1a9937 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 25 Aug 2015 11:21:04 -0700 Subject: [PATCH 354/549] some header cleanup in UDTTest output --- .../networking/src/udt/ConnectionStats.cpp | 22 ++++---- .../networking/src/udt/ConnectionStats.h | 12 ++-- tools/udt-test/src/UDTTest.cpp | 56 +++++++++---------- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/libraries/networking/src/udt/ConnectionStats.cpp b/libraries/networking/src/udt/ConnectionStats.cpp index 8c36750782..52188c29c3 100644 --- a/libraries/networking/src/udt/ConnectionStats.cpp +++ b/libraries/networking/src/udt/ConnectionStats.cpp @@ -48,14 +48,14 @@ void ConnectionStats::recordSentPackets(int payload, int total) { } void ConnectionStats::recordReceivedPackets(int payload, int total) { - ++_currentSample.recievedPackets; - ++_total.recievedPackets; + ++_currentSample.receivedPackets; + ++_total.receivedPackets; - _currentSample.recievedUtilBytes += payload; - _total.recievedUtilBytes += payload; + _currentSample.receivedUtilBytes += payload; + _total.receivedUtilBytes += payload; - _currentSample.recievedBytes += total; - _total.recievedBytes += total; + _currentSample.receivedBytes += total; + _total.receivedBytes += total; } void ConnectionStats::recordUnreliableSentPackets(int payload, int total) { @@ -70,14 +70,14 @@ void ConnectionStats::recordUnreliableSentPackets(int payload, int total) { } void ConnectionStats::recordUnreliableReceivedPackets(int payload, int total) { - ++_currentSample.recievedUnreliablePackets; - ++_total.recievedUnreliablePackets; + ++_currentSample.receivedUnreliablePackets; + ++_total.receivedUnreliablePackets; - _currentSample.recievedUnreliableUtilBytes += payload; - _total.recievedUnreliableUtilBytes += payload; + _currentSample.receivedUnreliableUtilBytes += payload; + _total.receivedUnreliableUtilBytes += payload; _currentSample.sentUnreliableBytes += total; - _total.recievedUnreliableBytes += total; + _total.receivedUnreliableBytes += total; } static const double EWMA_CURRENT_SAMPLE_WEIGHT = 0.125; diff --git a/libraries/networking/src/udt/ConnectionStats.h b/libraries/networking/src/udt/ConnectionStats.h index 2800db7720..494d433bca 100644 --- a/libraries/networking/src/udt/ConnectionStats.h +++ b/libraries/networking/src/udt/ConnectionStats.h @@ -44,18 +44,18 @@ public: // packet counts and sizes int sentPackets { 0 }; - int recievedPackets { 0 }; + int receivedPackets { 0 }; int sentUtilBytes { 0 }; - int recievedUtilBytes { 0 }; + int receivedUtilBytes { 0 }; int sentBytes { 0 }; - int recievedBytes { 0 }; + int receivedBytes { 0 }; int sentUnreliablePackets { 0 }; - int recievedUnreliablePackets { 0 }; + int receivedUnreliablePackets { 0 }; int sentUnreliableUtilBytes { 0 }; - int recievedUnreliableUtilBytes { 0 }; + int receivedUnreliableUtilBytes { 0 }; int sentUnreliableBytes { 0 }; - int recievedUnreliableBytes { 0 }; + int receivedUnreliableBytes { 0 }; // the following stats are trailing averages in the result, not totals int sendRate { 0 }; diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index d9cd9cc1b6..74d662287f 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -57,15 +57,15 @@ const QCommandLineOption STATS_INTERVAL { }; const QStringList CLIENT_STATS_TABLE_HEADERS { - "Send Rate (P/s)", "Bandwidth (P/s)", "RTT(ms)", "CW (P)", "Send Period (us)", - "Received ACK", "Processed ACK", "Received LACK", "Received NAK", "Received TNAK", + "Send (P/s)", "Est. Max (P/s)", "RTT (ms)", "CW (P)", "Period (us)", + "Recv ACK", "Procd ACK", "Recv LACK", "Recv NAK", "Recv TNAK", "Sent ACK2", "Sent Packets", "Re-sent Packets" }; const QStringList SERVER_STATS_TABLE_HEADERS { - "Received Megabits", "Receive Rate (P/s)", "Bandwidth (P/s)", "RTT(ms)", "CW (P)", + "Megabits", "Recv P/s", "Est. Max (P/s)", "RTT (ms)", "CW (P)", "Sent ACK", "Sent LACK", "Sent NAK", "Sent TNAK", - "Recieved ACK2", "Duplicate Packets" + "Recv ACK2", "Duplicates (P)" }; UDTTest::UDTTest(int& argc, char** argv) : @@ -356,19 +356,19 @@ void UDTTest::sampleStats() { // setup a list of left justified values QStringList values { - QString::number(stats.sendRate).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.estimatedBandwith).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.rtt / USECS_PER_MSEC).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.congestionWindowSize).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.packetSendPeriod).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedACK]).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::ProcessedACK]).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedLightACK]).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedNAK]).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedTimeoutNAK]).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::SentACK2]).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.sentPackets).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::Retransmission]).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()) + QString::number(stats.sendRate).rightJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.estimatedBandwith).rightJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.rtt / USECS_PER_MSEC, 'f', 2).rightJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.congestionWindowSize).rightJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.packetSendPeriod).rightJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedACK]).rightJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::ProcessedACK]).rightJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedLightACK]).rightJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedNAK]).rightJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedTimeoutNAK]).rightJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::SentACK2]).rightJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.sentPackets).rightJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::Retransmission]).rightJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()) }; // output this line of values @@ -390,17 +390,17 @@ void UDTTest::sampleStats() { // setup a list of left justified values QStringList values { - QString::number(stats.recievedBytes * MEGABITS_PER_BYTE).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.receiveRate).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.estimatedBandwith).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.rtt / USECS_PER_MSEC).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.congestionWindowSize).leftJustified(CLIENT_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::SentACK]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::SentLightACK]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::SentNAK]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::SentTimeoutNAK]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedACK2]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), - QString::number(stats.events[udt::ConnectionStats::Stats::Duplicate]).leftJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()) + QString::number(stats.receivedBytes * MEGABITS_PER_BYTE, 'f', 2).rightJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.receiveRate).rightJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.estimatedBandwith).rightJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.rtt / USECS_PER_MSEC, 'f', 2).rightJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.congestionWindowSize).rightJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::SentACK]).rightJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::SentLightACK]).rightJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::SentNAK]).rightJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::SentTimeoutNAK]).rightJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::ReceivedACK2]).rightJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(stats.events[udt::ConnectionStats::Stats::Duplicate]).rightJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()) }; // output this line of values From 61507bde09ac5767a21e26421b433270b5bf5b13 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 25 Aug 2015 11:24:26 -0700 Subject: [PATCH 355/549] fix order of member initialization in PacketList --- libraries/networking/src/udt/PacketList.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/PacketList.cpp b/libraries/networking/src/udt/PacketList.cpp index b135788985..6dad7e9133 100644 --- a/libraries/networking/src/udt/PacketList.cpp +++ b/libraries/networking/src/udt/PacketList.cpp @@ -26,9 +26,10 @@ PacketList::PacketList(PacketType packetType, QByteArray extendedHeader, bool is } PacketList::PacketList(PacketList&& other) : - _packetType(other._packetType), - _packets(std::move(other._packets)) + _packets(std::move(other._packets)), + _packetType(other._packetType) { + } void PacketList::startSegment() { From d76e8a7e48e5bc3a8e8b5c317bc3dba18a37d340 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 25 Aug 2015 11:27:31 -0700 Subject: [PATCH 356/549] remove double settings request for testing --- assignment-client/src/audio/AudioMixer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 9fa0ac2faf..1d8908845f 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -667,8 +667,6 @@ void AudioMixer::run() { domainHandler.requestDomainSettings(); loop.exec(); - domainHandler.requestDomainSettings(); - if (domainHandler.getSettingsObject().isEmpty()) { qDebug() << "Failed to retreive settings object from domain-server. Bailing on assignment."; setFinished(true); From b865a3f8fb548219f554e6a2ff5553b869011d2f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 25 Aug 2015 12:41:55 -0700 Subject: [PATCH 357/549] Add thread pool to AssetGet requests --- assignment-client/src/assets/AssetServer.cpp | 94 ++++++++++++++++++-- assignment-client/src/assets/AssetServer.h | 6 +- 2 files changed, 92 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 7dd31eba5f..f97769593d 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -11,23 +11,108 @@ #include "AssetServer.h" +#include #include #include #include #include #include #include +#include #include #include const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server"; -AssetServer::AssetServer(NLPacket& packet) : ThreadedAssignment(packet) { +void writeError(NLPacketList* packetList, AssetServerError error) { + packetList->writePrimitive(error); +} + +class SendAssetTask : public QRunnable { +public: + SendAssetTask(MessageID messageID, const QByteArray& assetHash, QString filePath, DataOffset start, DataOffset end, const SharedNodePointer& sendToNode) : + QRunnable(), + _messageID(messageID), + _assetHash(assetHash), + _filePath(filePath), + _start(start), + _end(end), + _sendToNode(sendToNode) + { + } + + void run(); + +signals: + void finished(); + +private: + MessageID _messageID; + QByteArray _assetHash; + QString _filePath; + DataOffset _start; + DataOffset _end; + SharedNodePointer _sendToNode; +}; + +void SendAssetTask::run() { + qDebug() << "Starting task to send asset: " << _assetHash << " for messageID " << _messageID; + auto replyPacketList = std::unique_ptr(new NLPacketList(PacketType::AssetGetReply, QByteArray(), true, true)); + + replyPacketList->write(_assetHash, HASH_HEX_LENGTH); + + replyPacketList->writePrimitive(_messageID); + + const int64_t MAX_LENGTH = 4294967296; + + if (_end <= _start) { + writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); + } else if (_end - _start > MAX_LENGTH) { + writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); + } else { + QFile file { _filePath }; + qDebug() << "Opening file: " << QString(QFileInfo(_assetHash).fileName()); + + if (file.open(QIODevice::ReadOnly)) { + if (file.size() < _end) { + writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); + } else { + auto size = _end - _start; + file.seek(_start); + replyPacketList->writePrimitive(AssetServerError::NO_ERROR); + replyPacketList->writePrimitive(size); + while (file.pos() < file.size()) { + static const int chunkSize = 20000; + QByteArray data = file.read(chunkSize); + replyPacketList->write(data, chunkSize); + } + qDebug() << "Done reading"; + } + file.close(); + } else { + qDebug() << "Asset not found"; + writeError(replyPacketList.get(), AssetServerError::ASSET_NOT_FOUND); + } + } + + qDebug() << "Sending asset"; + auto nodeList = DependencyManager::get(); + nodeList->sendPacketList(std::move(replyPacketList), *_sendToNode); +} + +AssetServer::AssetServer(NLPacket& packet) : + ThreadedAssignment(packet), + _taskPool(this) { + + // Most of the work will be I/O bound, reading from disk and constructing packet objects, + // so the ideal is greater than the number of cores on the system. + _taskPool.setMaxThreadCount(20); + auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(PacketType::AssetGet, this, "handleAssetGet"); packetReceiver.registerListener(PacketType::AssetGetInfo, this, "handleAssetGetInfo"); - packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload"); + packetReceiver.registerMessageListener(PacketType::AssetUpload, this, "handleAssetUpload"); } AssetServer::~AssetServer() { @@ -75,13 +160,10 @@ void AssetServer::run() { while (!_isFinished) { // since we're a while loop we need to help Qt's event processing QCoreApplication::processEvents(); + // QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents); } } -void AssetServer::writeError(NLPacket* packet, AssetServerError error) { - packet->writePrimitive(error); -} - void AssetServer::handleAssetGetInfo(QSharedPointer packet, SharedNodePointer senderNode) { if (packet->getPayloadSize() < HASH_HEX_LENGTH) { qDebug() << "ERROR bad file request"; diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 585ecaa259..94116b191e 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -14,6 +14,7 @@ #include #include +#include #include "AssetUtils.h" @@ -31,11 +32,12 @@ public slots: private slots: void handleAssetGetInfo(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode); - void handleAssetUpload(QSharedPointer packet, SharedNodePointer senderNode); + void handleAssetUpload(QSharedPointer packetList, SharedNodePointer senderNode); private: - static void writeError(NLPacket* packet, AssetServerError error); + static void writeError(NLPacketList* packetList, AssetServerError error); QDir _resourcesDirectory; + QThreadPool _taskPool; }; #endif From 0352782e4675a9c3a9eb3ca77f9717a4350a0c46 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 25 Aug 2015 12:46:44 -0700 Subject: [PATCH 358/549] Add SendAssetTask --- assignment-client/src/assets/AssetServer.cpp | 40 ++------------------ 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index f97769593d..1617307659 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -215,42 +215,10 @@ void AssetServer::handleAssetGet(QSharedPointer packet, SharedNodePoin qDebug() << "Received a request for the file: " << assetHash << " from " << start << " to " << end; - // We need to reply... - auto replyPacket = NLPacket::create(PacketType::AssetGetReply); - - replyPacket->write(assetHash, HASH_HEX_LENGTH); - - replyPacket->writePrimitive(messageID); - - const int64_t MAX_LENGTH = 1024; - - if (end <= start) { - writeError(replyPacket.get(), AssetServerError::INVALID_BYTE_RANGE); - } else if (end - start > MAX_LENGTH) { - writeError(replyPacket.get(), AssetServerError::INVALID_BYTE_RANGE); - } else { - QFile file { _resourcesDirectory.filePath(QString(assetHash)) }; - qDebug() << "Opening file: " << QString(QFileInfo(assetHash).fileName()); - - if (file.open(QIODevice::ReadOnly)) { - if (file.size() < end) { - writeError(replyPacket.get(), AssetServerError::INVALID_BYTE_RANGE); - } else { - auto size = end - start; - file.seek(start); - QByteArray data = file.read(size); - replyPacket->writePrimitive(AssetServerError::NO_ERROR); - replyPacket->writePrimitive(size); - replyPacket->write(data, size); - } - } else { - qDebug() << "Asset not found"; - writeError(replyPacket.get(), AssetServerError::ASSET_NOT_FOUND); - } - } - - auto nodeList = DependencyManager::get(); - nodeList->sendPacket(std::move(replyPacket), *senderNode); + // Queue task + QString filePath = _resourcesDirectory.filePath(QString(assetHash)); + auto task = new SendAssetTask(messageID, assetHash, filePath, start, end, senderNode); + _taskPool.start(task); } void AssetServer::handleAssetUpload(QSharedPointer packet, SharedNodePointer senderNode) { From c1b9613a309c53b973cc5ddb05da31f5ab00152c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 25 Aug 2015 14:58:56 -0700 Subject: [PATCH 359/549] Update PacketList::writeData() to be non-recursive --- libraries/networking/src/udt/PacketList.cpp | 148 +++++++++++--------- 1 file changed, 78 insertions(+), 70 deletions(-) diff --git a/libraries/networking/src/udt/PacketList.cpp b/libraries/networking/src/udt/PacketList.cpp index 2e9bef09e1..648736f6f9 100644 --- a/libraries/networking/src/udt/PacketList.cpp +++ b/libraries/networking/src/udt/PacketList.cpp @@ -68,7 +68,7 @@ std::unique_ptr PacketList::createPacket() { std::unique_ptr PacketList::createPacketWithExtendedHeader() { // use the static create method to create a new packet auto packet = createPacket(); - + if (!_extendedHeader.isEmpty()) { // add the extended header to the front of the packet if (packet->write(_extendedHeader) == -1) { @@ -76,7 +76,7 @@ std::unique_ptr PacketList::createPacketWithExtendedHeader() { << "- make sure that _extendedHeader is not larger than the payload capacity."; } } - + return packet; } @@ -98,83 +98,91 @@ QByteArray PacketList::getMessage() { } qint64 PacketList::writeData(const char* data, qint64 maxSize) { - if (!_currentPacket) { - // we don't have a current packet, time to set one up - _currentPacket = createPacketWithExtendedHeader(); - } - - // check if this block of data can fit into the currentPacket - if (maxSize <= _currentPacket->bytesAvailableForWrite()) { - // it fits, just write it to the current packet - _currentPacket->write(data, maxSize); - - // return the number of bytes written - return maxSize; - } else { - // it does not fit - this may need to be in the next packet - - if (!_isOrdered) { - auto newPacket = createPacketWithExtendedHeader(); - - if (_segmentStartIndex >= 0) { - // We in the process of writing a segment for an unordered PacketList. - // We need to try and pull the first part of the segment out to our new packet - - // check now to see if this is an unsupported write - int numBytesToEnd = _currentPacket->bytesAvailableForWrite(); - - if ((newPacket->size() - numBytesToEnd) < maxSize) { - // this is an unsupported case - the segment is bigger than the size of an individual packet - // but the PacketList is not going to be sent ordered - qDebug() << "Error in PacketList::writeData - attempted to write a segment to an unordered packet that is" - << "larger than the payload size."; - Q_ASSERT(false); - } - - int segmentSize = _currentPacket->pos() - _segmentStartIndex; - - // copy from currentPacket where the segment started to the beginning of the newPacket - newPacket->write(_currentPacket->getPayload() + _segmentStartIndex, segmentSize); - - // the current segment now starts at the beginning of the new packet - _segmentStartIndex = _extendedHeader.size(); - - // shrink the current payload to the actual size of the packet - _currentPacket->setPayloadSize(_segmentStartIndex); - } - - // move the current packet to our list of packets - _packets.push_back(std::move(_currentPacket)); - - // write the data to the newPacket - newPacket->write(data, maxSize); - - // swap our current packet with the new packet - _currentPacket.swap(newPacket); - - // return the number of bytes written to the new packet - return maxSize; + auto sizeRemaining = maxSize; + + while (sizeRemaining > 0) { + if (!_currentPacket) { + // we don't have a current packet, time to set one up + _currentPacket = createPacketWithExtendedHeader(); + } + + // check if this block of data can fit into the currentPacket + if (sizeRemaining <= _currentPacket->bytesAvailableForWrite()) { + // it fits, just write it to the current packet + _currentPacket->write(data, sizeRemaining); + + sizeRemaining = 0; } else { - // we're an ordered PacketList - let's fit what we can into the current packet and then put the leftover - // into a new packet - - int numBytesToEnd = _currentPacket->bytesAvailableForWrite(); - _currentPacket->write(data, numBytesToEnd); - - // move the current packet to our list of packets - _packets.push_back(std::move(_currentPacket)); - - // recursively call our writeData method for the remaining data to write to a new packet - return numBytesToEnd + writeData(data + numBytesToEnd, maxSize - numBytesToEnd); + // it does not fit - this may need to be in the next packet + + if (!_isOrdered) { + auto newPacket = createPacketWithExtendedHeader(); + + if (_segmentStartIndex >= 0) { + // We in the process of writing a segment for an unordered PacketList. + // We need to try and pull the first part of the segment out to our new packet + + // check now to see if this is an unsupported write + int numBytesToEnd = _currentPacket->bytesAvailableForWrite(); + + if ((newPacket->size() - numBytesToEnd) < sizeRemaining) { + // this is an unsupported case - the segment is bigger than the size of an individual packet + // but the PacketList is not going to be sent ordered + qDebug() << "Error in PacketList::writeData - attempted to write a segment to an unordered packet that is" + << "larger than the payload size."; + Q_ASSERT(false); + } + + int segmentSize = _currentPacket->pos() - _segmentStartIndex; + + // copy from currentPacket where the segment started to the beginning of the newPacket + newPacket->write(_currentPacket->getPayload() + _segmentStartIndex, segmentSize); + + // the current segment now starts at the beginning of the new packet + _segmentStartIndex = _extendedHeader.size(); + + // shrink the current payload to the actual size of the packet + _currentPacket->setPayloadSize(_segmentStartIndex); + } + + // move the current packet to our list of packets + _packets.push_back(std::move(_currentPacket)); + + // write the data to the newPacket + newPacket->write(data, sizeRemaining); + + // swap our current packet with the new packet + _currentPacket.swap(newPacket); + + // We've written all of the data, so set sizeRemaining to 0 + sizeRemaining = 0; + } else { + // we're an ordered PacketList - let's fit what we can into the current packet and then put the leftover + // into a new packet + + int numBytesToEnd = _currentPacket->bytesAvailableForWrite(); + _currentPacket->write(data, numBytesToEnd); + + // Remove number of bytes written from sizeRemaining + sizeRemaining -= numBytesToEnd; + + // Move the data pointer forward + data += numBytesToEnd; + + // move the current packet to our list of packets + _packets.push_back(std::move(_currentPacket)); + } } } + + return maxSize; } void PacketList::closeCurrentPacket(bool shouldSendEmpty) { if (shouldSendEmpty && !_currentPacket) { _currentPacket = createPacketWithExtendedHeader(); } - + if (_currentPacket) { // move the current packet to our list of packets _packets.push_back(std::move(_currentPacket)); From 85f80ff6f9af62e6b4edc75201692c580415b325 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 25 Aug 2015 15:05:35 -0700 Subject: [PATCH 360/549] Update AssetServer to use PacketList --- assignment-client/src/assets/AssetServer.cpp | 37 ++++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 1617307659..43387e7e66 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -221,38 +221,45 @@ void AssetServer::handleAssetGet(QSharedPointer packet, SharedNodePoin _taskPool.start(task); } -void AssetServer::handleAssetUpload(QSharedPointer packet, SharedNodePointer senderNode) { +void AssetServer::handleAssetUpload(QSharedPointer packetList, SharedNodePointer senderNode) { + auto data = packetList->getMessage(); + QBuffer buffer { &data }; + buffer.open(QIODevice::ReadOnly); + MessageID messageID; - packet->readPrimitive(&messageID); + buffer.read(reinterpret_cast(&messageID), sizeof(messageID)); + // buffer.readPrimitive(&messageID); - char extensionLength; - packet->readPrimitive(&extensionLength); + uint8_t extensionLength; + buffer.read(reinterpret_cast(&extensionLength), sizeof(extensionLength)); + // buffer.readPrimitive(&extensionLength); - char extension[extensionLength]; - packet->read(extension, extensionLength); + QByteArray extension = buffer.read(extensionLength); qDebug() << "Got extension: " << extension; - int fileSize; - packet->readPrimitive(&fileSize); + uint64_t fileSize; + buffer.read(reinterpret_cast(&fileSize), sizeof(fileSize)); + // buffer.readPrimitive(&fileSize); - const int MAX_LENGTH = 1024; - fileSize = std::min(MAX_LENGTH, fileSize); + // const uint64_t MAX_LENGTH = 1024; + // fileSize = std::min(MAX_LENGTH, fileSize); qDebug() << "Receiving a file of size " << fileSize; - QByteArray data = packet->read(fileSize); + QByteArray fileData = buffer.read(fileSize); - QString hash = hashData(data); + QString hash = hashData(fileData); - qDebug() << "Got data: (" << hash << ") " << data; + qDebug() << "Got data: (" << hash << ") "; - QFile file { _resourcesDirectory.filePath(QString(hash)) }; + QFile file { _resourcesDirectory.filePath(QString(hash)) }; //+ "." + QString(extension) }; if (file.exists()) { qDebug() << "[WARNING] This file already exists"; } else { file.open(QIODevice::WriteOnly); - file.write(data); + file.write(fileData); + file.close(); } auto replyPacket = NLPacket::create(PacketType::AssetUploadReply); From dc5d5cbb63ca70b0957b65c0cb6091c79486760a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 25 Aug 2015 15:06:40 -0700 Subject: [PATCH 361/549] Add asset server ping to stats --- interface/resources/qml/Stats.qml | 149 +++++++++++++++--------------- interface/src/ui/Stats.cpp | 2 + interface/src/ui/Stats.h | 2 + 3 files changed, 81 insertions(+), 72 deletions(-) diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index b7081afadf..878d784bdf 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -28,39 +28,39 @@ Item { anchors.fill: parent onClicked: { root.expanded = !root.expanded; } } - + Column { id: generalCol spacing: 4; x: 4; y: 4; - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize text: "Servers: " + root.serverCount } - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize - text: "Avatars: " + root.avatarCount + text: "Avatars: " + root.avatarCount } - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize - text: "Framerate: " + root.framerate + text: "Framerate: " + root.framerate } Text { color: root.fontColor; font.pixelSize: root.fontSize text: "Simrate: " + root.simrate } - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize - text: "Packets In/Out: " + root.packetInCount + "/" + root.packetOutCount + text: "Packets In/Out: " + root.packetInCount + "/" + root.packetOutCount } - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize - text: "Mbps In/Out: " + root.mbpsIn.toFixed(2) + "/" + root.mbpsOut.toFixed(2) + text: "Mbps In/Out: " + root.mbpsIn.toFixed(2) + "/" + root.mbpsOut.toFixed(2) } } } @@ -77,30 +77,35 @@ Item { Column { id: pingCol spacing: 4; x: 4; y: 4; - Text { + Text { color: root.fontColor font.pixelSize: root.fontSize - text: "Audio ping: " + root.audioPing + text: "Audio ping: " + root.audioPing } - Text { + Text { color: root.fontColor font.pixelSize: root.fontSize - text: "Avatar ping: " + root.avatarPing + text: "Avatar ping: " + root.avatarPing } - Text { + Text { color: root.fontColor font.pixelSize: root.fontSize - text: "Entities avg ping: " + root.entitiesPing + text: "Entities avg ping: " + root.entitiesPing } - Text { + Text { color: root.fontColor font.pixelSize: root.fontSize - visible: root.expanded; + text: "Asset ping: " + root.assetPing + } + Text { + color: root.fontColor + font.pixelSize: root.fontSize + visible: root.expanded; text: "Voxel max ping: " + 0 } } } - + Rectangle { width: geoCol.width + 8 height: geoCol.height + 8 @@ -112,34 +117,34 @@ Item { Column { id: geoCol spacing: 4; x: 4; y: 4; - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize - text: "Position: " + root.position.x.toFixed(1) + ", " + - root.position.y.toFixed(1) + ", " + root.position.z.toFixed(1) + text: "Position: " + root.position.x.toFixed(1) + ", " + + root.position.y.toFixed(1) + ", " + root.position.z.toFixed(1) } - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize - text: "Velocity: " + root.velocity.toFixed(1) + text: "Velocity: " + root.velocity.toFixed(1) } - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize - text: "Yaw: " + root.yaw.toFixed(1) + text: "Yaw: " + root.yaw.toFixed(1) } - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize - visible: root.expanded; - text: "Avatar Mixer: " + root.avatarMixerKbps + " kbps, " + - root.avatarMixerPps + "pps"; + visible: root.expanded; + text: "Avatar Mixer: " + root.avatarMixerKbps + " kbps, " + + root.avatarMixerPps + "pps"; } - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize - visible: root.expanded; - text: "Downloads: "; + visible: root.expanded; + text: "Downloads: "; } } } @@ -154,72 +159,72 @@ Item { Column { id: octreeCol spacing: 4; x: 4; y: 4; - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize - text: "Triangles: " + root.triangles + - " / Quads: " + root.quads + " / Material Switches: " + root.materialSwitches + text: "Triangles: " + root.triangles + + " / Quads: " + root.quads + " / Material Switches: " + root.materialSwitches } - Text { - color: root.fontColor; - font.pixelSize: root.fontSize - visible: root.expanded; - text: "\tMesh Parts Rendered Opaque: " + root.meshOpaque + - " / Translucent: " + root.meshTranslucent; - } - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize visible: root.expanded; - text: "\tOpaque considered: " + root.opaqueConsidered + - " / Out of view: " + root.opaqueOutOfView + " / Too small: " + root.opaqueTooSmall; + text: "\tMesh Parts Rendered Opaque: " + root.meshOpaque + + " / Translucent: " + root.meshTranslucent; } - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize - visible: !root.expanded - text: "Octree Elements Server: " + root.serverElements + - " Local: " + root.localElements; + visible: root.expanded; + text: "\tOpaque considered: " + root.opaqueConsidered + + " / Out of view: " + root.opaqueOutOfView + " / Too small: " + root.opaqueTooSmall; } - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize - visible: root.expanded - text: "Octree Sending Mode: " + root.sendingMode; + visible: !root.expanded + text: "Octree Elements Server: " + root.serverElements + + " Local: " + root.localElements; } - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize - visible: root.expanded - text: "Octree Packets to Process: " + root.packetStats; + visible: root.expanded + text: "Octree Sending Mode: " + root.sendingMode; } - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize - visible: root.expanded - text: "Octree Elements - "; + visible: root.expanded + text: "Octree Packets to Process: " + root.packetStats; } - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize - visible: root.expanded - text: "\tServer: " + root.serverElements + - " Internal: " + root.serverInternal + - " Leaves: " + root.serverLeaves; + visible: root.expanded + text: "Octree Elements - "; } - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize - visible: root.expanded - text: "\tLocal: " + root.localElements + - " Internal: " + root.localInternal + - " Leaves: " + root.localLeaves; + visible: root.expanded + text: "\tServer: " + root.serverElements + + " Internal: " + root.serverInternal + + " Leaves: " + root.serverLeaves; } - Text { + Text { color: root.fontColor; font.pixelSize: root.fontSize - visible: root.expanded - text: "LOD: " + root.lodStatus; + visible: root.expanded + text: "\tLocal: " + root.localElements + + " Internal: " + root.localInternal + + " Leaves: " + root.localLeaves; + } + Text { + color: root.fontColor; + font.pixelSize: root.fontSize + visible: root.expanded + text: "LOD: " + root.lodStatus; } } } diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 74e3a8f44f..74e6452d7f 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -126,8 +126,10 @@ void Stats::updateStats() { if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer); SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NodeType::AvatarMixer); + SharedNodePointer assetServerNode = nodeList->soloNodeOfType(NodeType::AssetServer); STAT_UPDATE(audioPing, audioMixerNode ? audioMixerNode->getPingMs() : -1); STAT_UPDATE(avatarPing, avatarMixerNode ? avatarMixerNode->getPingMs() : -1); + STAT_UPDATE(assetPing, assetServerNode ? assetServerNode->getPingMs() : -1); //// Now handle voxel servers, since there could be more than one, we average their ping times unsigned long totalPingOctree = 0; diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index 4f0619d9c8..096469a84d 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -39,6 +39,7 @@ class Stats : public QQuickItem { STATS_PROPERTY(int, audioPing, 0) STATS_PROPERTY(int, avatarPing, 0) STATS_PROPERTY(int, entitiesPing, 0) + STATS_PROPERTY(int, assetPing, 0) STATS_PROPERTY(QVector3D, position, QVector3D(0, 0, 0) ) STATS_PROPERTY(float, velocity, 0) STATS_PROPERTY(float, yaw, 0) @@ -105,6 +106,7 @@ signals: void audioPingChanged(); void avatarPingChanged(); void entitiesPingChanged(); + void assetPingChanged(); void positionChanged(); void velocityChanged(); void yawChanged(); From 4e3d0758e5c342615a5bd231937588b40578f2c3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 25 Aug 2015 15:07:07 -0700 Subject: [PATCH 362/549] Remove UNUSED_2 --- domain-server/src/DomainServer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 410b58d17f..f2f1f3dee9 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -571,7 +571,6 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet Date: Tue, 25 Aug 2015 15:18:40 -0700 Subject: [PATCH 363/549] Update Packet to properly copy packet position and message number --- libraries/networking/src/udt/Packet.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 2cc0624f7b..56c65e0657 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -93,6 +93,8 @@ Packet::Packet(Packet&& other) : _isReliable = other._isReliable; _isPartOfMessage = other._isPartOfMessage; _sequenceNumber = other._sequenceNumber; + _packetPosition = other._packetPosition; + _messageNumber = other._messageNumber; } Packet& Packet::operator=(Packet&& other) { @@ -101,6 +103,8 @@ Packet& Packet::operator=(Packet&& other) { _isReliable = other._isReliable; _isPartOfMessage = other._isPartOfMessage; _sequenceNumber = other._sequenceNumber; + _packetPosition = other._packetPosition; + _messageNumber = other._messageNumber; return *this; } From 2efba00e3e076f35bc68a788f7a2733ee8e63252 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 25 Aug 2015 15:19:07 -0700 Subject: [PATCH 364/549] Update BasePacket::read to do a copy --- libraries/networking/src/udt/BasePacket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/BasePacket.cpp b/libraries/networking/src/udt/BasePacket.cpp index 2bfa2b6805..aad547faa7 100644 --- a/libraries/networking/src/udt/BasePacket.cpp +++ b/libraries/networking/src/udt/BasePacket.cpp @@ -142,7 +142,7 @@ void BasePacket::setPayloadSize(qint64 payloadSize) { QByteArray BasePacket::read(qint64 maxSize) { qint64 sizeToRead = std::min(size() - pos(), maxSize); - QByteArray data { QByteArray::fromRawData(getPayload() + pos(), sizeToRead) }; + QByteArray data { QByteArray(getPayload() + pos(), sizeToRead) }; seek(pos() + sizeToRead); return data; } From 3959928bbb7e15003fffa32fd4e2cf37a3a79314 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 25 Aug 2015 15:20:00 -0700 Subject: [PATCH 365/549] Update ResourceRequest::moveData to getData --- libraries/networking/src/ResourceCache.cpp | 2 +- libraries/networking/src/ResourceRequest.h | 2 +- libraries/script-engine/src/BatchLoader.cpp | 2 +- libraries/script-engine/src/ScriptCache.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 018f9b1c36..bb4e4aeeb9 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -464,7 +464,7 @@ void Resource::handleReplyFinished() { auto result = _request->getResult(); if (result == ResourceRequest::SUCCESS) { - _data = _request->moveData(); + _data = _request->getData(); qDebug() << "Reqeust finsihed for " << _url << ", " << _activeUrl; _request->disconnect(this); diff --git a/libraries/networking/src/ResourceRequest.h b/libraries/networking/src/ResourceRequest.h index 3eb975d8d6..458a859d16 100644 --- a/libraries/networking/src/ResourceRequest.h +++ b/libraries/networking/src/ResourceRequest.h @@ -33,7 +33,7 @@ public: }; void send(); - QByteArray moveData() { return _data; } + QByteArray getData() { return _data; } State getState() const { return _state; } Result getResult() const { return _result; } QUrl getUrl() const { return _url; } diff --git a/libraries/script-engine/src/BatchLoader.cpp b/libraries/script-engine/src/BatchLoader.cpp index 99916310f4..58145c2ef3 100644 --- a/libraries/script-engine/src/BatchLoader.cpp +++ b/libraries/script-engine/src/BatchLoader.cpp @@ -42,7 +42,7 @@ void BatchLoader::start() { } connect(request, &ResourceRequest::finished, [=]() { if (request->getResult() == ResourceRequest::SUCCESS) { - _data.insert(url, request->moveData()); + _data.insert(url, request->getData()); } else { _data.insert(url, QString()); } diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index 94fff89c35..9409c10652 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -66,7 +66,7 @@ void ScriptCache::scriptDownloaded() { _scriptUsers.remove(url); if (req->getResult() == ResourceRequest::SUCCESS) { - _scriptCache[url] = req->moveData(); + _scriptCache[url] = req->getData(); qCDebug(scriptengine) << "Done downloading script at:" << url.toString(); foreach(ScriptUser* user, scriptUsers) { From 67816c033ae837d0767f269b311ccf0c2ab7ae19 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 25 Aug 2015 15:43:21 -0700 Subject: [PATCH 366/549] output megabits per second not per interval --- tools/udt-test/src/UDTTest.cpp | 16 ++++++++-------- tools/udt-test/src/UDTTest.h | 2 ++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 74d662287f..f11ff0d489 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -63,7 +63,7 @@ const QStringList CLIENT_STATS_TABLE_HEADERS { }; const QStringList SERVER_STATS_TABLE_HEADERS { - "Megabits", "Recv P/s", "Est. Max (P/s)", "RTT (ms)", "CW (P)", + " Mb/s ", "Recv P/s", "Est. Max (P/s)", "RTT (ms)", "CW (P)", "Sent ACK", "Sent LACK", "Sent NAK", "Sent TNAK", "Recv ACK2", "Duplicates (P)" }; @@ -180,18 +180,15 @@ UDTTest::UDTTest(int& argc, char** argv) : _socket.setPacketListHandler(std::bind(&UDTTest::handlePacketList, this, _1)); } - // the sender reports stats every 100 milliseconds - static const int STATS_SAMPLE_INTERVAL = 100; - - int statsInterval = STATS_SAMPLE_INTERVAL; + // the sender reports stats every 100 milliseconds, unless passed a custom value if (_argumentParser.isSet(STATS_INTERVAL)) { - statsInterval = _argumentParser.value(STATS_INTERVAL).toInt(); + _statsInterval = _argumentParser.value(STATS_INTERVAL).toInt(); } QTimer* statsTimer = new QTimer(this); connect(statsTimer, &QTimer::timeout, this, &UDTTest::sampleStats); - statsTimer->start(statsInterval); + statsTimer->start(_statsInterval); } void UDTTest::parseArguments() { @@ -387,10 +384,13 @@ void UDTTest::sampleStats() { int headerIndex = -1; static const double MEGABITS_PER_BYTE = 8.0 / 1000000.0; + static const double MS_PER_SECOND = 1000.0; + + double megabitsPerSecond = (stats.receivedBytes * MEGABITS_PER_BYTE * MS_PER_SECOND) / _statsInterval; // setup a list of left justified values QStringList values { - QString::number(stats.receivedBytes * MEGABITS_PER_BYTE, 'f', 2).rightJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), + QString::number(megabitsPerSecond, 'f', 2).rightJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.receiveRate).rightJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.estimatedBandwith).rightJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), QString::number(stats.rtt / USECS_PER_MSEC, 'f', 2).rightJustified(SERVER_STATS_TABLE_HEADERS[++headerIndex].size()), diff --git a/tools/udt-test/src/UDTTest.h b/tools/udt-test/src/UDTTest.h index 376dc98bf6..fda57cc183 100644 --- a/tools/udt-test/src/UDTTest.h +++ b/tools/udt-test/src/UDTTest.h @@ -60,6 +60,8 @@ private: int _totalQueuedPackets { 0 }; // keeps track of the number of packets we have already queued int _totalQueuedBytes { 0 }; // keeps track of the number of bytes we have already queued + + int _statsInterval { 100 }; // recording interval for stats in milliseconds }; #endif // hifi_UDTTest_h From 3eff605d72660ddf1c5e63fe400d695954a88f91 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 25 Aug 2015 15:44:37 -0700 Subject: [PATCH 367/549] Update asset server number --- libraries/networking/src/Assignment.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/Assignment.h b/libraries/networking/src/Assignment.h index fe0cd72fb6..0d7738d22b 100644 --- a/libraries/networking/src/Assignment.h +++ b/libraries/networking/src/Assignment.h @@ -29,12 +29,11 @@ public: AudioMixerType = 0, AvatarMixerType = 1, AgentType = 2, - UNUSED_0 = 3, - UNUSED_1 = 4, - UNUSED_2 = 5, + AssetServerType = 3, + UNUSED_0 = 4, + UNUSED_1 = 5, EntityServerType = 6, - AssetServerType = 7, - AllTypes = 8 + AllTypes = 7 }; enum Command { From 12b2dfb2f96a2a3060ebd27a81594c601edd5aa0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 25 Aug 2015 15:45:00 -0700 Subject: [PATCH 368/549] Clean up HTTPResourceRequest --- libraries/networking/src/HTTPResourceRequest.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/HTTPResourceRequest.cpp b/libraries/networking/src/HTTPResourceRequest.cpp index f684718bf1..cf074eb98b 100644 --- a/libraries/networking/src/HTTPResourceRequest.cpp +++ b/libraries/networking/src/HTTPResourceRequest.cpp @@ -54,12 +54,10 @@ void HTTPResourceRequest::onRequestFinished() { Q_ASSERT(_reply); _state = FINISHED; + auto error = _reply->error(); - qDebug() << "Loaded " << _url; - QString u = _url.path(); if (error == QNetworkReply::NoError) { _data = _reply->readAll(); - qDebug() << "!!!! " << _data.size() << " " << _url.path(); _loadedFromCache = _reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(); _result = ResourceRequest::SUCCESS; emit finished(); @@ -70,27 +68,28 @@ void HTTPResourceRequest::onRequestFinished() { _result = ResourceRequest::ERROR; emit finished(); } + _reply->deleteLater(); _reply = nullptr; } void HTTPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { if (_state == IN_PROGRESS) { - // Restart timer + // We've received data, so reset the timer _sendTimer.start(); } + + emit progress(bytesReceived, bytesTotal); } void HTTPResourceRequest::onTimeout() { Q_ASSERT(_state != UNSENT); - // TODO Cancel request if timed out, handle properly in - // receive callback if (_state == IN_PROGRESS) { qCDebug(networking) << "Timed out loading " << _url; + _reply->abort(); _state = FINISHED; _result = TIMEOUT; - _reply->abort(); emit finished(); } } From 0e98b179ddb8b7aaa7e66b1beb80266cb2a7f839 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 25 Aug 2015 16:34:44 -0700 Subject: [PATCH 369/549] Update Asset gettings and uploading in AssetClient --- libraries/networking/src/AssetClient.cpp | 38 +++++++++++++----------- libraries/networking/src/AssetClient.h | 2 +- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index cf8231abeb..3877f05fe9 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -10,6 +10,7 @@ #include "AssetClient.h" +#include #include #include "AssetRequest.h" @@ -22,7 +23,7 @@ MessageID AssetClient::_currentID = 0; AssetClient::AssetClient() { auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply"); - packetReceiver.registerListener(PacketType::AssetGetReply, this, "handleAssetGetReply"); + packetReceiver.registerMessageListener(PacketType::AssetGetReply, this, "handleAssetGetReply"); packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); } @@ -123,22 +124,25 @@ void AssetClient::handleAssetGetInfoReply(QSharedPointer packet, Share } } -void AssetClient::handleAssetGetReply(QSharedPointer packet, SharedNodePointer senderNode) { - auto assetHash = packet->read(HASH_HEX_LENGTH); +void AssetClient::handleAssetGetReply(QSharedPointer packetList, SharedNodePointer senderNode) { + QByteArray data = packetList->getMessage(); + QBuffer packet { &data }; + packet.open(QIODevice::ReadOnly); + + auto assetHash = packet.read(HASH_HEX_LENGTH); qDebug() << "Got reply for asset: " << assetHash; MessageID messageID; - packet->readPrimitive(&messageID); + packet.read(reinterpret_cast(&messageID), sizeof(messageID)); AssetServerError error; - packet->readPrimitive(&error); - QByteArray data; + packet.read(reinterpret_cast(&error), sizeof(AssetServerError)); + QByteArray assetData; if (!error) { DataOffset length; - packet->readPrimitive(&length); - data = packet->read(length); - qDebug() << "Got data: " << length << ", " << data.toHex(); + packet.read(reinterpret_cast(&length), sizeof(DataOffset)); + data = packet.read(length); } else { qDebug() << "Failure getting asset: " << error; } @@ -153,22 +157,22 @@ bool AssetClient::uploadAsset(QByteArray data, QString extension, UploadResultCa auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); if (assetServer) { - auto packet = NLPacket::create(PacketType::AssetUpload); + auto packetList = std::unique_ptr(new NLPacketList(PacketType::AssetUpload, QByteArray(), true, true)); auto messageID = _currentID++; - packet->writePrimitive(messageID); + packetList->writePrimitive(messageID); - packet->writePrimitive(static_cast(extension.length())); - packet->write(extension.toLatin1().constData(), extension.length()); + packetList->writePrimitive(static_cast(extension.length())); + packetList->write(extension.toLatin1().constData(), extension.length()); qDebug() << "Extension length: " << extension.length(); qDebug() << "Extension: " << extension; - int size = data.length(); - packet->writePrimitive(size); - packet->write(data.constData(), size); + uint64_t size = data.length(); + packetList->writePrimitive(size); + packetList->write(data.constData(), size); - nodeList->sendPacket(std::move(packet), *assetServer); + nodeList->sendPacketList(std::move(packetList), *assetServer); _pendingUploads[messageID] = callback; diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 7ad9c1a638..5e26ff18b6 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -44,7 +44,7 @@ public: private slots: void handleAssetGetInfoReply(QSharedPointer packet, SharedNodePointer senderNode); - void handleAssetGetReply(QSharedPointer packet, SharedNodePointer senderNode); + void handleAssetGetReply(QSharedPointer packetList, SharedNodePointer senderNode); void handleAssetUploadReply(QSharedPointer packet, SharedNodePointer senderNode); private: From 0bfa0c4942238925a849ddbae08ba7e34b043b1d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 25 Aug 2015 16:35:41 -0700 Subject: [PATCH 370/549] Add progress to AssetResourceRequest --- libraries/networking/src/AssetResourceRequest.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index f7727336a9..c29a54a787 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -24,6 +24,7 @@ void ATPResourceRequest::doSend() { return; } + connect(request, &AssetRequest::progress, this, &ATPResourceRequest::progress); QObject::connect(request, &AssetRequest::finished, [this](AssetRequest* req) mutable { if (_state != IN_PROGRESS) return; _state = FINISHED; @@ -41,4 +42,6 @@ void ATPResourceRequest::doSend() { } void ATPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { + qDebug() << "Got asset data: " << bytesReceived << " / " << bytesTotal; + emit progress(bytesReceived, bytesTotal); } From cabdee8391a6aa89ae4cd12dcc3058ca211ecfac Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 25 Aug 2015 17:12:03 -0700 Subject: [PATCH 371/549] send a handshake before first packet send --- libraries/networking/src/udt/Connection.cpp | 19 ++++++++++++++ libraries/networking/src/udt/Connection.h | 3 +++ .../networking/src/udt/ControlPacket.cpp | 2 +- libraries/networking/src/udt/ControlPacket.h | 4 ++- libraries/networking/src/udt/LossList.cpp | 3 ++- libraries/networking/src/udt/SendQueue.cpp | 25 +++++++++++++++++++ libraries/networking/src/udt/SendQueue.h | 3 +++ 7 files changed, 56 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 9f8b1eb3ee..d5b84ce070 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -400,6 +400,12 @@ void Connection::processControl(std::unique_ptr controlPacket) { case ControlPacket::TimeoutNAK: processTimeoutNAK(move(controlPacket)); break; + case ControlPacket::Handshake: + processHandshake(move(controlPacket)); + break; + case ControlPacket::HandshakeACK: + processHandshakeACK(move(controlPacket)); + break; } } @@ -589,6 +595,19 @@ void Connection::processNAK(std::unique_ptr controlPacket) { _stats.record(ConnectionStats::Stats::ReceivedNAK); } +void Connection::processHandshake(std::unique_ptr controlPacket) { + // immediately respond with a handshake ACK + static auto handshakeACK = ControlPacket::create(ControlPacket::HandshakeACK, 0); + _parentSocket->writeBasePacket(*handshakeACK, _destination); + + _hasReceivedHandshake = true; +} + +void Connection::processHandshakeACK(std::unique_ptr controlPacket) { + // hand off this handshake ACK to the send queue so it knows it can start sending + getSendQueue().handshakeACK(); +} + void Connection::processTimeoutNAK(std::unique_ptr controlPacket) { // Override SendQueue's LossList with the timeout NAK list getSendQueue().overrideNAKListFromPacket(*controlPacket); diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 307c90eda5..8b52b1cf5e 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -90,6 +90,8 @@ private: void processACK2(std::unique_ptr controlPacket); void processNAK(std::unique_ptr controlPacket); void processTimeoutNAK(std::unique_ptr controlPacket); + void processHandshake(std::unique_ptr controlPacket); + void processHandshakeACK(std::unique_ptr controlPacket); SendQueue& getSendQueue(); SequenceNumber nextACK() const; @@ -106,6 +108,7 @@ private: std::chrono::high_resolution_clock::time_point _lastNAKTime; bool _hasReceivedFirstPacket { false }; + bool _hasReceivedHandshake { false }; // flag for receipt of handshake from server LossList _lossList; // List of all missing packets SequenceNumber _lastReceivedSequenceNumber; // The largest sequence number received from the peer diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index b8407d42a4..8c799f97a6 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -100,7 +100,7 @@ void ControlPacket::readType() { Q_ASSERT_X(bitAndType & CONTROL_BIT_MASK, "ControlPacket::readHeader()", "This should be a control packet"); uint16_t packetType = (bitAndType & ~CONTROL_BIT_MASK) >> (8 * sizeof(Type)); - Q_ASSERT_X(packetType <= ControlPacket::Type::TimeoutNAK, "ControlPacket::readType()", "Received a control packet with wrong type"); + Q_ASSERT_X(packetType <= ControlPacket::Type::HandshakeACK, "ControlPacket::readType()", "Received a control packet with wrong type"); // read the type _type = (Type) packetType; diff --git a/libraries/networking/src/udt/ControlPacket.h b/libraries/networking/src/udt/ControlPacket.h index 83fab5bb12..bcc559f4f6 100644 --- a/libraries/networking/src/udt/ControlPacket.h +++ b/libraries/networking/src/udt/ControlPacket.h @@ -30,7 +30,9 @@ public: ACK, ACK2, NAK, - TimeoutNAK + TimeoutNAK, + Handshake, + HandshakeACK }; static std::unique_ptr create(Type type, qint64 size = -1); diff --git a/libraries/networking/src/udt/LossList.cpp b/libraries/networking/src/udt/LossList.cpp index c02d12c34a..846347142e 100644 --- a/libraries/networking/src/udt/LossList.cpp +++ b/libraries/networking/src/udt/LossList.cpp @@ -169,7 +169,8 @@ SequenceNumber LossList::popFirstSequenceNumber() { void LossList::write(ControlPacket& packet, int maxPairs) { int writtenPairs = 0; - for(const auto& pair : _lossList) { + + for (const auto& pair : _lossList) { packet.writePrimitive(pair.first); packet.writePrimitive(pair.second); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index cfb969a186..27f25442ea 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -195,6 +195,31 @@ void SendQueue::run() { // Record timing _lastSendTimestamp = high_resolution_clock::now(); + if (!_hasReceivedHandshakeACK) { + // we haven't received a handshake ACK from the client + // if it has been at least 100ms since we last sent a handshake, send another now + + // hold the time of last send in a static + static auto lastSendHandshake = high_resolution_clock::time_point(); + + static const int HANDSHAKE_RESEND_INTERVAL_MS = 100; + + // calculation the duration since the last handshake send + auto sinceLastHandshake = duration_cast(high_resolution_clock::now() - lastSendHandshake); + + if (sinceLastHandshake.count() >= HANDSHAKE_RESEND_INTERVAL_MS) { + + // it has been long enough since last handshake, send another + static auto handshakePacket = ControlPacket::create(ControlPacket::Handshake, 0); + _socket->writeBasePacket(*handshakePacket, _destination); + + lastSendHandshake = high_resolution_clock::now(); + } + + // skip over this iteration since we haven't completed the handshake + continue; + } + bool resentPacket = false; // the following while makes sure that we find a packet to re-send, if there is one diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 901a9f7a87..08d0f697ae 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -59,6 +59,7 @@ public slots: void ack(SequenceNumber ack); void nak(SequenceNumber start, SequenceNumber end); void overrideNAKListFromPacket(ControlPacket& packet); + void handshakeACK() { _hasReceivedHandshakeACK = true; } signals: void packetSent(int dataSize, int payloadSize); @@ -85,6 +86,8 @@ private: Socket* _socket { nullptr }; // Socket to send packet on HifiSockAddr _destination; // Destination addr + std::atomic _hasReceivedHandshakeACK { false }; // flag for receipt of handshake ACK from client + std::atomic _lastACKSequenceNumber; // Last ACKed sequence number MessageNumber _currentMessageNumber { 0 }; From 83d76084f1f4c3e97fc65c0367c0dd6598db5d56 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 25 Aug 2015 17:14:41 -0700 Subject: [PATCH 372/549] don't process packets in Connection without handshake --- libraries/networking/src/udt/Connection.cpp | 11 +++++++++++ libraries/networking/src/udt/Connection.h | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index d5b84ce070..044eb0780f 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -313,6 +313,11 @@ SequenceNumber Connection::nextACK() const { bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, int packetSize, int payloadSize) { + if (!_hasReceivedHandshake) { + // refuse to process any packets until we've received the handshake + return false; + } + _hasReceivedFirstPacket = true; // check if this is a packet pair we should estimate bandwidth from, or just a regular packet @@ -382,6 +387,12 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in } void Connection::processControl(std::unique_ptr controlPacket) { + + if (!_hasReceivedHandshake && controlPacket->getType() != ControlPacket::Handshake) { + // we refuse to process any packets until the handshake is received + return; + } + // Simple dispatch to control packets processing methods based on their type switch (controlPacket->getType()) { case ControlPacket::ACK: diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 8b52b1cf5e..e1933a0f02 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -63,7 +63,7 @@ public: void sync(); // rate control method, fired by Socket for all connections on SYN interval - // return indicates if this packet was a duplicate + // return indicates if this packet should be processed bool processReceivedSequenceNumber(SequenceNumber sequenceNumber, int packetSize, int payloadSize); void processControl(std::unique_ptr controlPacket); From 82f5e2e04ff53630ea0e9c68b82a8527b72c4e90 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 25 Aug 2015 17:26:25 -0700 Subject: [PATCH 373/549] skip processing of control packets before handshake --- libraries/networking/src/udt/Connection.cpp | 35 ++++++++++++++------- libraries/networking/src/udt/Connection.h | 1 + libraries/networking/src/udt/SendQueue.cpp | 7 +++-- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 044eb0780f..6f7ac8643d 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -388,28 +388,35 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in void Connection::processControl(std::unique_ptr controlPacket) { - if (!_hasReceivedHandshake && controlPacket->getType() != ControlPacket::Handshake) { - // we refuse to process any packets until the handshake is received - return; - } + // Simple dispatch to control packets processing methods based on their type. + + // Processing of control packets (other than Handshake / Handshake ACK) + // is not performed if the handshake has not been completed. - // Simple dispatch to control packets processing methods based on their type switch (controlPacket->getType()) { case ControlPacket::ACK: - if (controlPacket->getPayloadSize() == sizeof(SequenceNumber)) { - processLightACK(move(controlPacket)); - } else { - processACK(move(controlPacket)); + if (_hasReceivedHandshakeACK) { + if (controlPacket->getPayloadSize() == sizeof(SequenceNumber)) { + processLightACK(move(controlPacket)); + } else { + processACK(move(controlPacket)); + } } break; case ControlPacket::ACK2: - processACK2(move(controlPacket)); + if (_hasReceivedHandshake) { + processACK2(move(controlPacket)); + } break; case ControlPacket::NAK: - processNAK(move(controlPacket)); + if (_hasReceivedHandshakeACK) { + processNAK(move(controlPacket)); + } break; case ControlPacket::TimeoutNAK: - processTimeoutNAK(move(controlPacket)); + if (_hasReceivedHandshakeACK) { + processTimeoutNAK(move(controlPacket)); + } break; case ControlPacket::Handshake: processHandshake(move(controlPacket)); @@ -611,12 +618,16 @@ void Connection::processHandshake(std::unique_ptr controlPacket) static auto handshakeACK = ControlPacket::create(ControlPacket::HandshakeACK, 0); _parentSocket->writeBasePacket(*handshakeACK, _destination); + // indicate that handshake has been received _hasReceivedHandshake = true; } void Connection::processHandshakeACK(std::unique_ptr controlPacket) { // hand off this handshake ACK to the send queue so it knows it can start sending getSendQueue().handshakeACK(); + + // indicate that handshake ACK was received + _hasReceivedHandshakeACK = true; } void Connection::processTimeoutNAK(std::unique_ptr controlPacket) { diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index e1933a0f02..b37801a90f 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -109,6 +109,7 @@ private: bool _hasReceivedFirstPacket { false }; bool _hasReceivedHandshake { false }; // flag for receipt of handshake from server + bool _hasReceivedHandshakeACK { false }; // flag for receipt of handshake ACK from client LossList _lossList; // List of all missing packets SequenceNumber _lastReceivedSequenceNumber; // The largest sequence number received from the peer diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 27f25442ea..29036b026c 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -216,8 +216,8 @@ void SendQueue::run() { lastSendHandshake = high_resolution_clock::now(); } - // skip over this iteration since we haven't completed the handshake - continue; + // we allow processing in this while to continue so that processEvents is called + // but we skip over sending of packets until _hasReceivedHandshakeACK is true } bool resentPacket = false; @@ -266,7 +266,8 @@ void SendQueue::run() { // if we didn't find a packet to re-send AND we think we can fit a new packet on the wire // (this is according to the current flow window size) then we send out a new packet - if (!resentPacket + if (_hasReceivedHandshakeACK + && !resentPacket && seqlen(SequenceNumber { (uint32_t) _lastACKSequenceNumber }, _currentSequenceNumber) <= _flowWindowSize) { // we didn't re-send a packet, so time to send a new one From 0ce8e05f197e30264552c6969c98e588bce06f7b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 25 Aug 2015 18:01:37 -0700 Subject: [PATCH 374/549] reset the receiver's state on handshake --- libraries/networking/src/udt/Connection.cpp | 62 ++++++++++++++++--- libraries/networking/src/udt/Connection.h | 5 +- .../networking/src/udt/PacketTimeWindow.cpp | 5 ++ .../networking/src/udt/PacketTimeWindow.h | 2 + 4 files changed, 63 insertions(+), 11 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 6f7ac8643d..e0943a63f8 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -40,8 +40,7 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination, std::uniq // setup default SYN, RTT and RTT Variance based on the SYN interval in CongestionControl object _synInterval = _congestionControl->synInterval(); - _rtt = _synInterval * 10; - _rttVariance = _rtt / 2; + resetRTT(); // set the initial RTT and flow window size on congestion control object _congestionControl->setRTT(_rtt); @@ -64,6 +63,11 @@ Connection::~Connection() { } } +void Connection::resetRTT() { + _rtt = _synInterval * 10; + _rttVariance = _rtt / 2; +} + SendQueue& Connection::getSendQueue() { if (!_sendQueue) { // Lasily create send queue @@ -120,13 +124,15 @@ void Connection::sync() { // we send out a periodic ACK every rate control interval sendACK(); - // check if we need to re-transmit a loss list - // we do this if it has been longer than the current nakInterval since we last sent - auto now = high_resolution_clock::now(); - - if (duration_cast(now - _lastNAKTime).count() >= _nakInterval) { - // Send a timeout NAK packet - sendTimeoutNAK(); + if (_lossList.getLength() > 0) { + // check if we need to re-transmit a loss list + // we do this if it has been longer than the current nakInterval since we last sent + auto now = high_resolution_clock::now(); + + if (duration_cast(now - _lastNAKTime).count() >= _nakInterval) { + // Send a timeout NAK packet + sendTimeoutNAK(); + } } } } @@ -349,7 +355,7 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in _nakInterval += (int) (_lossList.getLength() * (USECS_PER_SECOND / receivedPacketsPerSecond)); } - // the NAK interval is at least the _minNAKInterval but might be the estimated timeout + // the NAK interval is at least the _minNAKInterval but might be the value calculated above, if that is larger _nakInterval = std::max(_nakInterval, _minNAKInterval); } @@ -614,6 +620,9 @@ void Connection::processNAK(std::unique_ptr controlPacket) { } void Connection::processHandshake(std::unique_ptr controlPacket) { + // server sent us a handshake - we need to assume this means state should be reset + resetReceiveState(); + // immediately respond with a handshake ACK static auto handshakeACK = ControlPacket::create(ControlPacket::HandshakeACK, 0); _parentSocket->writeBasePacket(*handshakeACK, _destination); @@ -640,6 +649,39 @@ void Connection::processTimeoutNAK(std::unique_ptr controlPacket) _stats.record(ConnectionStats::Stats::ReceivedTimeoutNAK); } +void Connection::resetReceiveState() { + // TODO: this should also reset any queued messages we might be processing + + // reset all SequenceNumber member variables back to default + SequenceNumber defaultSequenceNumber; + + _lastReceivedSequenceNumber = defaultSequenceNumber; + + _lastReceivedAcknowledgedACK = defaultSequenceNumber; + _currentACKSubSequenceNumber = defaultSequenceNumber; + + _lastSentACK = defaultSequenceNumber; + + // clear the loss list and _lastNAKTime + _lossList.clear(); + _lastNAKTime = high_resolution_clock::time_point(); + + // the _nakInterval need not be reset, that will happen on loss + + // clear sync variables + _hasReceivedFirstPacket = false; + + _acksDuringSYN = 1; + _lightACKsDuringSYN = 1; + _packetsSinceACK = 0; + + // reset RTT to initial value + resetRTT(); + + // clear the intervals in the receive window + _receiveWindow.reset(); +} + void Connection::updateRTT(int rtt) { // This updates the RTT using exponential weighted moving average // This is the Jacobson's forumla for RTT estimation diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index b37801a90f..0babfb76e1 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -93,6 +93,9 @@ private: void processHandshake(std::unique_ptr controlPacket); void processHandshakeACK(std::unique_ptr controlPacket); + void resetReceiveState(); + void resetRTT(); + SendQueue& getSendQueue(); SequenceNumber nextACK() const; void updateRTT(int rtt); @@ -103,7 +106,7 @@ private: int _synInterval; // Periodical Rate Control Interval, in microseconds - int _nakInterval; // NAK timeout interval, in microseconds + int _nakInterval { -1 }; // NAK timeout interval, in microseconds, set on loss int _minNAKInterval { 100000 }; // NAK timeout interval lower bound, default of 100ms std::chrono::high_resolution_clock::time_point _lastNAKTime; diff --git a/libraries/networking/src/udt/PacketTimeWindow.cpp b/libraries/networking/src/udt/PacketTimeWindow.cpp index 5c389f6d26..00eb43c7e6 100644 --- a/libraries/networking/src/udt/PacketTimeWindow.cpp +++ b/libraries/networking/src/udt/PacketTimeWindow.cpp @@ -31,6 +31,11 @@ PacketTimeWindow::PacketTimeWindow(int numPacketIntervals, int numProbeIntervals } +void PacketTimeWindow::reset() { + _packetIntervals.assign(_numPacketIntervals, DEFAULT_PACKET_INTERVAL_MICROSECONDS); + _probeIntervals.assign(_numProbeIntervals, DEFAULT_PROBE_INTERVAL_MICROSECONDS); +} + template int median(Iterator begin, Iterator end) { // use std::nth_element to grab the middle - for an even number of elements this is the upper middle diff --git a/libraries/networking/src/udt/PacketTimeWindow.h b/libraries/networking/src/udt/PacketTimeWindow.h index 25e3df8a43..a8a4e0c8b5 100644 --- a/libraries/networking/src/udt/PacketTimeWindow.h +++ b/libraries/networking/src/udt/PacketTimeWindow.h @@ -29,6 +29,8 @@ public: int32_t getPacketReceiveSpeed() const; int32_t getEstimatedBandwidth() const; + + void reset(); private: int _numPacketIntervals { 0 }; // the number of packet intervals to store int _numProbeIntervals { 0 }; // the number of probe intervals to store From 54f2dc54f6a912e9159716fd6a804e2897392769 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 25 Aug 2015 18:23:50 -0700 Subject: [PATCH 375/549] add a condition_variable wait_until to not lock for handshake --- libraries/networking/src/udt/SendQueue.cpp | 18 ++++++++++++++++-- libraries/networking/src/udt/SendQueue.h | 10 +++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 29036b026c..5ee2955ebd 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -158,6 +158,12 @@ void SendQueue::overrideNAKListFromPacket(ControlPacket& packet) { } } +void SendQueue::handshakeACK() { + std::unique_lock locker(_handshakeMutex); + _hasReceivedHandshakeACK = true; + _handshakeACKCondition.notify_one(); +} + SequenceNumber SendQueue::getNextSequenceNumber() { _atomicCurrentSequenceNumber = (SequenceNumber::Type)++_currentSequenceNumber; return _currentSequenceNumber; @@ -195,6 +201,8 @@ void SendQueue::run() { // Record timing _lastSendTimestamp = high_resolution_clock::now(); + std::unique_lock handshakeLock { _handshakeMutex }; + if (!_hasReceivedHandshakeACK) { // we haven't received a handshake ACK from the client // if it has been at least 100ms since we last sent a handshake, send another now @@ -216,10 +224,16 @@ void SendQueue::run() { lastSendHandshake = high_resolution_clock::now(); } - // we allow processing in this while to continue so that processEvents is called - // but we skip over sending of packets until _hasReceivedHandshakeACK is true + // we wait for the ACK or the re-send interval to expire + _handshakeACKCondition.wait_until(handshakeLock, + high_resolution_clock::now() + milliseconds(HANDSHAKE_RESEND_INTERVAL_MS)); + + // Once we're here we've either received the handshake ACK or it's going to be time to re-send a handshake. + // Either way let's continue processing - no packets will be sent if no handshake ACK has been received. } + handshakeLock.unlock(); + bool resentPacket = false; // the following while makes sure that we find a packet to re-send, if there is one diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 08d0f697ae..5590e1faa7 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -13,7 +13,9 @@ #define hifi_SendQueue_h #include +#include #include +#include #include #include @@ -59,7 +61,7 @@ public slots: void ack(SequenceNumber ack); void nak(SequenceNumber start, SequenceNumber end); void overrideNAKListFromPacket(ControlPacket& packet); - void handshakeACK() { _hasReceivedHandshakeACK = true; } + void handshakeACK(); signals: void packetSent(int dataSize, int payloadSize); @@ -86,8 +88,6 @@ private: Socket* _socket { nullptr }; // Socket to send packet on HifiSockAddr _destination; // Destination addr - std::atomic _hasReceivedHandshakeACK { false }; // flag for receipt of handshake ACK from client - std::atomic _lastACKSequenceNumber; // Last ACKed sequence number MessageNumber _currentMessageNumber { 0 }; @@ -105,6 +105,10 @@ private: mutable QReadWriteLock _sentLock; // Protects the sent packet list std::unordered_map> _sentPackets; // Packets waiting for ACK. + + std::mutex _handshakeMutex; // Protects the handshake ACK condition_variable + bool _hasReceivedHandshakeACK { false }; // flag for receipt of handshake ACK from client + std::condition_variable _handshakeACKCondition; }; } From d5e77ba907cbaceb3596216b13911617eff76ef8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 25 Aug 2015 18:26:30 -0700 Subject: [PATCH 376/549] clear the pending received messages on handshake receive --- libraries/networking/src/udt/Connection.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index e0943a63f8..f1b69e0039 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -650,8 +650,6 @@ void Connection::processTimeoutNAK(std::unique_ptr controlPacket) } void Connection::resetReceiveState() { - // TODO: this should also reset any queued messages we might be processing - // reset all SequenceNumber member variables back to default SequenceNumber defaultSequenceNumber; @@ -680,6 +678,9 @@ void Connection::resetReceiveState() { // clear the intervals in the receive window _receiveWindow.reset(); + + // clear any pending received messages + _pendingReceivedMessages.clear(); } void Connection::updateRTT(int rtt) { From 373d4b894482d9651917fb4fc5d8cb8fda05c9b1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 26 Aug 2015 15:53:49 +0200 Subject: [PATCH 377/549] Remove connection from socket when innactive If innactive for more than 5 seconds, remove it from hash --- libraries/networking/src/udt/Connection.cpp | 5 + libraries/networking/src/udt/Connection.h | 2 + libraries/networking/src/udt/SendQueue.cpp | 223 ++++++++++---------- libraries/networking/src/udt/SendQueue.h | 18 +- libraries/networking/src/udt/Socket.cpp | 10 +- libraries/networking/src/udt/Socket.h | 1 + 6 files changed, 143 insertions(+), 116 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 9f8b1eb3ee..c640392263 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -72,6 +72,7 @@ SendQueue& Connection::getSendQueue() { QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::packetSent); QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::recordSentPackets); QObject::connect(_sendQueue.get(), &SendQueue::packetRetransmitted, this, &Connection::recordRetransmission); + QObject::connect(_sendQueue.get(), &SendQueue::queueInnactive, this, &Connection::queueInnactive); // set defaults on the send queue from our congestion control object _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); @@ -81,6 +82,10 @@ SendQueue& Connection::getSendQueue() { return *_sendQueue; } +void Connection::queueInnactive() { + emit connectionInnactive(_destination); +} + void Connection::sendReliablePacket(std::unique_ptr packet) { Q_ASSERT_X(packet->isReliable(), "Connection::send", "Trying to send an unreliable packet reliably."); getSendQueue().queuePacket(std::move(packet)); diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 307c90eda5..fd7cd5ef88 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -73,10 +73,12 @@ public: signals: void packetSent(); + void connectionInnactive(HifiSockAddr sockAdrr); private slots: void recordSentPackets(int payload, int total); void recordRetransmission(); + void queueInnactive(); private: void sendACK(bool wasCausedBySyncTimeout = true); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 5e0e8312f2..65e5f9f7ba 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -12,6 +12,7 @@ #include "SendQueue.h" #include +#include #include #include @@ -194,8 +195,8 @@ void SendQueue::sendNewPacketAndAddToSentList(std::unique_ptr newPacket, // Insert the packet we have just sent in the sent list QWriteLocker locker(&_sentLock); _sentPackets[newPacket->getSequenceNumber()].swap(newPacket); - Q_ASSERT_X(!newPacket, "SendQueue::sendNewPacketAndAddToSentList()", "Overriden packet in sent list"); } + Q_ASSERT_X(!newPacket, "SendQueue::sendNewPacketAndAddToSentList()", "Overriden packet in sent list"); emit packetSent(packetSize, payloadSize); } @@ -204,110 +205,18 @@ void SendQueue::run() { _isRunning = true; while (_isRunning) { - // Record timing - _lastSendTimestamp = high_resolution_clock::now(); + // Record how long the loop takes to execute + auto loopStartTimestamp = high_resolution_clock::now(); - bool naksEmpty = true; // used at the end of processing to see if we should wait for NAKs + bool sentAPacket = maybeResendPacket(); + bool flowWindowFull = false; - bool resentPacket = false; - - // the following while makes sure that we find a packet to re-send, if there is one - while (!resentPacket) { - std::unique_lock nakLocker(_naksLock); - - if (_naks.getLength() > 0) { - naksEmpty = _naks.getLength() > 1; - - // pull the sequence number we need to re-send - SequenceNumber resendNumber = _naks.popFirstSequenceNumber(); - nakLocker.unlock(); - - // pull the packet to re-send from the sent packets list - QReadLocker sentLocker(&_sentLock); - - // see if we can find the packet to re-send - auto it = _sentPackets.find(resendNumber); - - if (it != _sentPackets.end()) { - // we found the packet - grab it - auto& resendPacket = *(it->second); - - // unlock the sent packets - sentLocker.unlock(); - - // send it off - sendPacket(resendPacket); - emit packetRetransmitted(); - - // mark that we did resend a packet - resentPacket = true; - - // break out of our while now that we have re-sent a packet - break; - } else { - // we didn't find this packet in the sentPackets queue - assume this means it was ACKed - // we'll fire the loop again to see if there is another to re-send - continue; - } - } else { - naksEmpty = true; - } - - // break from the while, we didn't resend a packet - break; - } - - bool packetsEmpty = false; // used after processing to check if we should wait for packets - bool sentPacket = false; - // if we didn't find a packet to re-send AND we think we can fit a new packet on the wire // (this is according to the current flow window size) then we send out a new packet - if (!resentPacket - && seqlen(SequenceNumber { (uint32_t) _lastACKSequenceNumber }, _currentSequenceNumber) <= _flowWindowSize) { - - // we didn't re-send a packet, so time to send a new one - std::unique_lock locker(_packetsLock); - - if (_packets.size() > 0) { - - SequenceNumber nextNumber = getNextSequenceNumber(); - - // grab the first packet we will send - std::unique_ptr firstPacket; - firstPacket.swap(_packets.front()); - _packets.pop_front(); - - std::unique_ptr secondPacket; - - if (((uint32_t) nextNumber & 0xF) == 0) { - // the first packet is the first in a probe pair - every 16 (rightmost 16 bits = 0) packets - // pull off a second packet if we can before we unlock - if (_packets.size() > 0) { - secondPacket.swap(_packets.front()); - _packets.pop_front(); - } - } - - packetsEmpty = _packets.size() == 0; - - // unlock the packets, we're done pulling - locker.unlock(); - - sentPacket = true; - - // definitely send the first packet - sendNewPacketAndAddToSentList(move(firstPacket), nextNumber); - - // do we have a second in a pair to send as well? - if (secondPacket) { - nextNumber = getNextSequenceNumber(); - sendNewPacketAndAddToSentList(move(secondPacket), nextNumber); - } - - } else { - packetsEmpty = true; - locker.unlock(); - } + if (!sentAPacket) { + flowWindowFull = (seqlen(SequenceNumber { (uint32_t) _lastACKSequenceNumber }, _currentSequenceNumber) > + _flowWindowSize); + sentAPacket = maybeSendNewPacket(); } // since we're a while loop, give the thread a chance to process events @@ -318,17 +227,24 @@ void SendQueue::run() { break; } - if (packetsEmpty && naksEmpty) { - // During our processing above the loss list and packet list were both empty. + if (!sentAPacket && !flowWindowFull) { + // During our processing above we didn't send any packets and the flow window is not full. // If that is still the case we should use a condition_variable_any to sleep until we have data to handle. // To confirm that the queue of packets and the NAKs list are still both empty we'll need to use the DoubleLock DoubleLock doubleLock(_packetsLock, _naksLock); // The packets queue and loss list mutexes are now both locked - check if they're still both empty - if (_packets.empty() && _naks.getLength() == 0) { + if (doubleLock.try_lock() && _packets.empty() && _naks.getLength() == 0) { // both are empty - let's use a condition_variable_any to wait - _emptyCondition.wait(doubleLock); + static const seconds CONSIDER_INNACTIVE_AFTER { 5 }; + auto cvStatus = _emptyCondition.wait_for(doubleLock, CONSIDER_INNACTIVE_AFTER); + + + // Check if we've been innactive for too long + if (cvStatus == std::cv_status::timeout) { + emit queueInnactive(); + } // we have the double lock again - it'll be unlocked once it goes out of scope // skip to the next iteration @@ -336,12 +252,99 @@ void SendQueue::run() { } } - // sleep as long as we need until next packet send, if we can - auto now = high_resolution_clock::now(); - auto microsecondDuration = duration_cast((_lastSendTimestamp + microseconds(_packetSendPeriod)) - now); + auto loopEndTimestamp = high_resolution_clock::now(); - if (microsecondDuration.count() > 0) { - usleep(microsecondDuration.count()); + // sleep as long as we need until next packet send, if we can + auto timeToSleep = (loopStartTimestamp + microseconds(_packetSendPeriod)) - loopEndTimestamp; + if (timeToSleep > timeToSleep.zero()) { + std::this_thread::sleep_for(timeToSleep); } } } + +bool SendQueue::maybeSendNewPacket() { + // we didn't re-send a packet, so time to send a new one + std::unique_lock locker(_packetsLock); + + if (_packets.size() > 0) { + SequenceNumber nextNumber = getNextSequenceNumber(); + + // grab the first packet we will send + std::unique_ptr firstPacket; + firstPacket.swap(_packets.front()); + _packets.pop_front(); + + std::unique_ptr secondPacket; + + if (((uint32_t) nextNumber & 0xF) == 0) { + // the first packet is the first in a probe pair - every 16 (rightmost 16 bits = 0) packets + // pull off a second packet if we can before we unlock + if (_packets.size() > 0) { + secondPacket.swap(_packets.front()); + _packets.pop_front(); + } + } + + // unlock the packets, we're done pulling + locker.unlock(); + + // definitely send the first packet + sendNewPacketAndAddToSentList(move(firstPacket), nextNumber); + + // do we have a second in a pair to send as well? + if (secondPacket) { + sendNewPacketAndAddToSentList(move(secondPacket), getNextSequenceNumber()); + } + + // We sent our packet(s), return here + return true; + } + + // No packets were sent + return false; +} + +bool SendQueue::maybeResendPacket() { + // the following while makes sure that we find a packet to re-send, if there is one + while (true) { + std::unique_lock naksLocker(_naksLock); + + if (_naks.getLength() > 0) { + // pull the sequence number we need to re-send + SequenceNumber resendNumber = _naks.popFirstSequenceNumber(); + naksLocker.unlock(); + + // pull the packet to re-send from the sent packets list + QReadLocker sentLocker(&_sentLock); + + // see if we can find the packet to re-send + auto it = _sentPackets.find(resendNumber); + + if (it != _sentPackets.end()) { + // we found the packet - grab it + auto& resendPacket = *(it->second); + + // unlock the sent packets + sentLocker.unlock(); + + // send it off + sendPacket(resendPacket); + emit packetRetransmitted(); + + // Signal that we did resend a packet + return true; + } else { + // we didn't find this packet in the sentPackets queue - assume this means it was ACKed + // we'll fire the loop again to see if there is another to re-send + continue; + } + } + + // break from the while, we didn't resend a packet + break; + } + + // No packet was resent + return false; +} + diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 618cf17009..1d3d0e4c51 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -43,17 +43,23 @@ class SendQueue : public QObject { public: + // This class is not thread-safe class DoubleLock { public: - DoubleLock(std::mutex& mutex1, std::mutex& mutex2) : _mutex1(mutex1), _mutex2(mutex2) { lock(); } + DoubleLock(std::mutex& mutex1, std::mutex& mutex2) : _mutex1(mutex1), _mutex2(mutex2) { }; ~DoubleLock() { unlock(); } DoubleLock(const DoubleLock&) = delete; DoubleLock& operator=(const DoubleLock&) = delete; - void lock() { std::lock(_mutex1, _mutex2); } - void unlock() { _mutex1.unlock(); _mutex2.unlock(); } + bool locked() { return _locked; } + + bool try_lock() { _locked = (std::try_lock(_mutex1, _mutex2) == -1); return _locked; } + void lock() { std::lock(_mutex1, _mutex2); _locked = true; } + void unlock() { if (locked()) { _mutex1.unlock(); _mutex2.unlock(); _locked = false; } } + private: + std::atomic _locked { false }; std::mutex& _mutex1; std::mutex& _mutex2; }; @@ -81,6 +87,8 @@ signals: void packetSent(int dataSize, int payloadSize); void packetRetransmitted(); + void queueInnactive(); + private slots: void run(); @@ -92,6 +100,9 @@ private: void sendPacket(const Packet& packet); void sendNewPacketAndAddToSentList(std::unique_ptr newPacket, SequenceNumber sequenceNumber); + bool maybeSendNewPacket(); // Figures out what packet to send next + bool maybeResendPacket(); // Determines whether to resend a packet and wich one + // Increments current sequence number and return it SequenceNumber getNextSequenceNumber(); MessageNumber getNextMessageNumber(); @@ -109,7 +120,6 @@ private: std::atomic _atomicCurrentSequenceNumber { 0 };// Atomic for last sequence number sent out std::atomic _packetSendPeriod { 0 }; // Interval between two packet send event in microseconds, set from CC - std::chrono::high_resolution_clock::time_point _lastSendTimestamp; // Record last time of packet departure std::atomic _isRunning { false }; std::atomic _flowWindowSize { 0 }; // Flow control window size (number of packets that can be on wire) - set from CC diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 0aac7f8f99..f423353836 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -147,12 +147,18 @@ Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { if (it == _connectionsHash.end()) { auto connection = std::unique_ptr(new Connection(this, sockAddr, _ccFactory->create())); + QObject::connect(connection.get(), &Connection::connectionInnactive, this, &Socket::cleanupConnection); it = _connectionsHash.insert(it, std::make_pair(sockAddr, std::move(connection))); } return *it->second; } +void Socket::cleanupConnection(HifiSockAddr sockAddr) { + qDebug() << "Cleaned up" << sockAddr; + _connectionsHash.erase(sockAddr); +} + void Socket::messageReceived(std::unique_ptr packetList) { if (_packetListHandler) { _packetListHandler(std::move(packetList)); @@ -205,8 +211,8 @@ void Socket::readPendingDatagrams() { // if this was a reliable packet then signal the matching connection with the sequence number auto& connection = findOrCreateConnection(senderSockAddr); connection.processReceivedSequenceNumber(packet->getSequenceNumber(), - packet->getDataSize(), - packet->getPayloadSize()); + packet->getDataSize(), + packet->getPayloadSize()); } if (packet->isPartOfMessage()) { diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 0c4276a767..266c0be6a5 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -76,6 +76,7 @@ public: private slots: void readPendingDatagrams(); void rateControlSync(); + void cleanupConnection(HifiSockAddr sockAddr); private: void setSystemBufferSizes(); From c96632d4b6a20f4c6deacf8bba806bcf8ddfb00b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 26 Aug 2015 16:07:47 +0200 Subject: [PATCH 378/549] Cleanup connection on node kills --- libraries/networking/src/LimitedNodeList.cpp | 4 ++++ libraries/networking/src/udt/Socket.h | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index e2bae6b5e8..b7a0cee44e 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -428,6 +428,10 @@ void LimitedNodeList::handleNodeKill(const SharedNodePointer& node) { qCDebug(networking) << "Killed" << *node; node->stopPingTimer(); emit nodeKilled(node); + + if (auto activeSocket = node->getActiveSocket()) { + _nodeSocket.cleanupConnection(*activeSocket); + } } SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType, diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 266c0be6a5..0014a97e2b 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -73,10 +73,12 @@ public: ConnectionStats::Stats sampleStatsForConnection(const HifiSockAddr& destination); std::vector getConnectionSockAddrs(); +public slots: + void cleanupConnection(HifiSockAddr sockAddr); + private slots: void readPendingDatagrams(); void rateControlSync(); - void cleanupConnection(HifiSockAddr sockAddr); private: void setSystemBufferSizes(); From 8049819beb14f3933278001157d5a7337af4efc2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 26 Aug 2015 17:11:32 +0200 Subject: [PATCH 379/549] Tweak DoubleLock --- libraries/networking/src/udt/SendQueue.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 1d3d0e4c51..936aa1a3f1 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -54,9 +54,9 @@ public: bool locked() { return _locked; } - bool try_lock() { _locked = (std::try_lock(_mutex1, _mutex2) == -1); return _locked; } + bool try_lock() { return _locked = (std::try_lock(_mutex1, _mutex2) == -1); } void lock() { std::lock(_mutex1, _mutex2); _locked = true; } - void unlock() { if (locked()) { _mutex1.unlock(); _mutex2.unlock(); _locked = false; } } + void unlock() { if (_locked) { _mutex1.unlock(); _mutex2.unlock(); _locked = false; } } private: std::atomic _locked { false }; From 3184dee10ad1ab87b9f08fcc4a9cc80498cb0b7a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 26 Aug 2015 17:49:17 +0200 Subject: [PATCH 380/549] Emit queueInnactive when flow window is full for too long --- libraries/networking/src/udt/SendQueue.cpp | 77 +++++++++++++++------- libraries/networking/src/udt/SendQueue.h | 27 ++------ 2 files changed, 61 insertions(+), 43 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 65e5f9f7ba..1ee8cce48a 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -25,7 +25,27 @@ #include "Socket.h" using namespace udt; -using namespace std::chrono; + +// This class is not thread-safe +class DoubleLock { +public: + DoubleLock(std::mutex& mutex1, std::mutex& mutex2) : _mutex1(mutex1), _mutex2(mutex2) { }; + ~DoubleLock() { unlock(); } + + DoubleLock(const DoubleLock&) = delete; + DoubleLock& operator=(const DoubleLock&) = delete; + + bool locked() { return _locked; } + + bool try_lock() { return _locked = (std::try_lock(_mutex1, _mutex2) == -1); } + void lock() { std::lock(_mutex1, _mutex2); _locked = true; } + void unlock() { if (_locked) { _mutex1.unlock(); _mutex2.unlock(); _locked = false; } } + +private: + std::atomic _locked { false }; + std::mutex& _mutex1; + std::mutex& _mutex2; +}; std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr destination) { auto queue = std::unique_ptr(new SendQueue(socket, destination)); @@ -206,7 +226,7 @@ void SendQueue::run() { while (_isRunning) { // Record how long the loop takes to execute - auto loopStartTimestamp = high_resolution_clock::now(); + auto loopStartTimestamp = clock::now(); bool sentAPacket = maybeResendPacket(); bool flowWindowFull = false; @@ -219,6 +239,12 @@ void SendQueue::run() { sentAPacket = maybeSendNewPacket(); } + // Keep track of how long the flow window has been full for + if (flowWindowFull && !_flowWindowWasFull) { + _flowWindowFullSince = loopStartTimestamp; + } + _flowWindowWasFull = flowWindowFull; + // since we're a while loop, give the thread a chance to process events QCoreApplication::processEvents(); @@ -227,35 +253,42 @@ void SendQueue::run() { break; } - if (!sentAPacket && !flowWindowFull) { - // During our processing above we didn't send any packets and the flow window is not full. + if (!sentAPacket) { + static const std::chrono::seconds CONSIDER_INNACTIVE_AFTER { 5 }; - // If that is still the case we should use a condition_variable_any to sleep until we have data to handle. - // To confirm that the queue of packets and the NAKs list are still both empty we'll need to use the DoubleLock - DoubleLock doubleLock(_packetsLock, _naksLock); - - // The packets queue and loss list mutexes are now both locked - check if they're still both empty - if (doubleLock.try_lock() && _packets.empty() && _naks.getLength() == 0) { - // both are empty - let's use a condition_variable_any to wait - static const seconds CONSIDER_INNACTIVE_AFTER { 5 }; - auto cvStatus = _emptyCondition.wait_for(doubleLock, CONSIDER_INNACTIVE_AFTER); + if (flowWindowFull && (clock::now() - _flowWindowFullSince) > CONSIDER_INNACTIVE_AFTER) { + // If the flow window has been full for over CONSIDER_INNACTIVE_AFTER, + // then signal the queue is innactive + emit queueInnactive(); + } else { + // During our processing above we didn't send any packets and the flow window is not full. + // If that is still the case we should use a condition_variable_any to sleep until we have data to handle. + // To confirm that the queue of packets and the NAKs list are still both empty we'll need to use the DoubleLock + DoubleLock doubleLock(_packetsLock, _naksLock); - // Check if we've been innactive for too long - if (cvStatus == std::cv_status::timeout) { - emit queueInnactive(); + // The packets queue and loss list mutexes are now both locked - check if they're still both empty + if (doubleLock.try_lock() && _packets.empty() && _naks.getLength() == 0) { + // both are empty - let's use a condition_variable_any to wait + auto cvStatus = _emptyCondition.wait_for(doubleLock, CONSIDER_INNACTIVE_AFTER); + + + // Check if we've been innactive for too long + if (cvStatus == std::cv_status::timeout) { + emit queueInnactive(); + } + + // we have the double lock again - it'll be unlocked once it goes out of scope + // skip to the next iteration + continue; } - - // we have the double lock again - it'll be unlocked once it goes out of scope - // skip to the next iteration - continue; } } - auto loopEndTimestamp = high_resolution_clock::now(); + auto loopEndTimestamp = clock::now(); // sleep as long as we need until next packet send, if we can - auto timeToSleep = (loopStartTimestamp + microseconds(_packetSendPeriod)) - loopEndTimestamp; + auto timeToSleep = (loopStartTimestamp + std::chrono::microseconds(_packetSendPeriod)) - loopEndTimestamp; if (timeToSleep > timeToSleep.zero()) { std::this_thread::sleep_for(timeToSleep); } diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 936aa1a3f1..cf20e03f20 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -42,27 +42,8 @@ class SendQueue : public QObject { Q_OBJECT public: - - // This class is not thread-safe - class DoubleLock { - public: - DoubleLock(std::mutex& mutex1, std::mutex& mutex2) : _mutex1(mutex1), _mutex2(mutex2) { }; - ~DoubleLock() { unlock(); } - - DoubleLock(const DoubleLock&) = delete; - DoubleLock& operator=(const DoubleLock&) = delete; - - bool locked() { return _locked; } - - bool try_lock() { return _locked = (std::try_lock(_mutex1, _mutex2) == -1); } - void lock() { std::lock(_mutex1, _mutex2); _locked = true; } - void unlock() { if (_locked) { _mutex1.unlock(); _mutex2.unlock(); _locked = false; } } - - private: - std::atomic _locked { false }; - std::mutex& _mutex1; - std::mutex& _mutex2; - }; + using clock = std::chrono::high_resolution_clock; + using time_point = clock::time_point; static std::unique_ptr create(Socket* socket, HifiSockAddr destination); @@ -124,6 +105,10 @@ private: std::atomic _flowWindowSize { 0 }; // Flow control window size (number of packets that can be on wire) - set from CC + // Used to detect when the connection becomes innactive for too long + bool _flowWindowWasFull = false; + time_point _flowWindowFullSince; + mutable std::mutex _naksLock; // Protects the naks list. LossList _naks; // Sequence numbers of packets to resend From d90ceb200a0fcc25624960b8381639e2aa307c77 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 26 Aug 2015 09:27:50 -0700 Subject: [PATCH 381/549] Add asset uploader to Menu --- interface/src/Menu.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 939d733a13..9f38999853 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -21,6 +21,7 @@ #include #include +#include #include "Application.h" #include "AccountManager.h" #include "audio/AudioScope.h" @@ -87,6 +88,36 @@ Menu::Menu() { addActionToQMenuAndActionHash(fileMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, qApp, SLOT(toggleRunningScriptsWidget())); + // Asset uploading + { + auto action = new QAction("Upload File", fileMenu); + fileMenu->addAction(action); + action->setMenuRole(QAction::NoRole); + _actionHash.insert("Upload File", action); + + connect(action, &QAction::triggered, [this](bool checked) { + qDebug() << "Clicked upload file"; + auto filename = QFileDialog::getOpenFileUrl(nullptr, "Select a file to upload"); + if (!filename.isEmpty()) { + qDebug() << "Selected: " << filename; + QFile file { filename.path() }; + if (file.open(QIODevice::ReadOnly)) { + auto fileInfo { filename.path() }; + auto extension = fileInfo.suffix(); + auto data = file.readAll(); + auto assetClient = DependencyManager::get(); + assetClient->uploadAsset(data, extension, [this](bool result, QString hash) mutable { + if (result) { + QMessageBox::information(this, "Upload Successful", "URL: apt:/" + hash + "." + extension); + } else { + QMessageBox::warning(this, "Upload Failed", "There was an error uploading the file."); + } + }); + } + } + }); + } + auto addressManager = DependencyManager::get(); addDisabledActionAndSeparator(fileMenu, "History"); From d503c5293aa667780d8af461073db080748cceea Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 26 Aug 2015 09:28:06 -0700 Subject: [PATCH 382/549] Remove commented out line --- assignment-client/src/assets/AssetServer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 43387e7e66..0ed5b12b61 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -160,7 +160,6 @@ void AssetServer::run() { while (!_isFinished) { // since we're a while loop we need to help Qt's event processing QCoreApplication::processEvents(); - // QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents); } } From 9b174bfbf443936177a29eeadbca5e130121da07 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 26 Aug 2015 09:28:19 -0700 Subject: [PATCH 383/549] Remove extension from filename --- assignment-client/src/assets/AssetServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 0ed5b12b61..ad5d2a1d63 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -251,7 +251,7 @@ void AssetServer::handleAssetUpload(QSharedPointer packetList, Sha qDebug() << "Got data: (" << hash << ") "; - QFile file { _resourcesDirectory.filePath(QString(hash)) }; //+ "." + QString(extension) }; + QFile file { _resourcesDirectory.filePath(QString(hash)) }; if (file.exists()) { qDebug() << "[WARNING] This file already exists"; From 24faab2089fb66b447b49d3781be292860d47ada Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 26 Aug 2015 09:29:15 -0700 Subject: [PATCH 384/549] Add sendPacketList that take Node --- libraries/networking/src/LimitedNodeList.cpp | 14 ++++++++++++++ libraries/networking/src/LimitedNodeList.h | 1 + 2 files changed, 15 insertions(+) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index b45a37d002..4dd1a2399d 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -32,6 +32,7 @@ #include "HifiSockAddr.h" #include "UUID.h" #include "NetworkLogging.h" +#include "udt/Packet.h" const char SOLO_NODE_TYPES[2] = { NodeType::AvatarMixer, @@ -344,6 +345,19 @@ qint64 LimitedNodeList::sendPacketList(std::unique_ptr packetList, return _nodeSocket.writePacketList(std::move(packetList), sockAddr); } +qint64 LimitedNodeList::sendPacketList(std::unique_ptr packetList, const Node& destinationNode) { + // close the last packet in the list + packetList->closeCurrentPacket(); + + for (std::unique_ptr& packet : packetList->_packets) { + NLPacket* nlPacket = static_cast(packet.get()); + collectPacketStats(*nlPacket); + fillPacketHeader(*nlPacket, destinationNode.getConnectionSecret()); + } + + return _nodeSocket.writePacketList(std::move(packetList), *destinationNode.getActiveSocket()); +} + qint64 LimitedNodeList::sendPacket(std::unique_ptr packet, const Node& destinationNode, const HifiSockAddr& overridenSockAddr) { // use the node's active socket as the destination socket if there is no overriden socket address diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 5f3e40fe11..1e94492e93 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -128,6 +128,7 @@ public: qint64 sendPacketList(NLPacketList& packetList, const HifiSockAddr& sockAddr, const QUuid& connectionSecret = QUuid()); qint64 sendPacketList(std::unique_ptr packetList, const HifiSockAddr& sockAddr); + qint64 sendPacketList(std::unique_ptr packetList, const Node& destinationNode); void (*linkedDataCreateCallback)(Node *); From 868558b4f0eb2aaa56d55a3bb7bdd953749a9dc9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 26 Aug 2015 09:29:46 -0700 Subject: [PATCH 385/549] Add registration of QSharedPointer meta type --- libraries/networking/src/PacketReceiver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index a086949ac8..002ecc2c6f 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -19,8 +19,10 @@ #include "NodeList.h" #include "SharedUtil.h" +Q_DECLARE_METATYPE(QSharedPointer); PacketReceiver::PacketReceiver(QObject* parent) : QObject(parent) { qRegisterMetaType>(); + qRegisterMetaType>(); } bool PacketReceiver::registerListenerForTypes(PacketTypeList types, QObject* listener, const char* slot) { From c878eb0cd99c0ed5ae005795c22f25247b8e9d62 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 26 Aug 2015 09:31:03 -0700 Subject: [PATCH 386/549] Fix atomics not being initialized in SendQueue --- libraries/networking/src/udt/SendQueue.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 901a9f7a87..2557d920c7 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -85,13 +85,13 @@ private: Socket* _socket { nullptr }; // Socket to send packet on HifiSockAddr _destination; // Destination addr - std::atomic _lastACKSequenceNumber; // Last ACKed sequence number + std::atomic _lastACKSequenceNumber { 0 }; // Last ACKed sequence number MessageNumber _currentMessageNumber { 0 }; SequenceNumber _currentSequenceNumber; // Last sequence number sent out - std::atomic _atomicCurrentSequenceNumber;// Atomic for last sequence number sent out + std::atomic _atomicCurrentSequenceNumber { 0 };// Atomic for last sequence number sent out - std::atomic _packetSendPeriod; // Interval between two packet send event in microseconds, set from CC + std::atomic _packetSendPeriod { 1 }; // Interval between two packet send event in microseconds, set from CC std::chrono::high_resolution_clock::time_point _lastSendTimestamp; // Record last time of packet departure std::atomic _isRunning { false }; From 7a5ed244850a389ea24f6128951d970b65d0d1b8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 26 Aug 2015 19:31:33 +0200 Subject: [PATCH 387/549] typo (I can't spell inactive correctly) --- libraries/networking/src/udt/Connection.cpp | 6 +++--- libraries/networking/src/udt/Connection.h | 4 ++-- libraries/networking/src/udt/SendQueue.cpp | 16 ++++++++-------- libraries/networking/src/udt/SendQueue.h | 4 ++-- libraries/networking/src/udt/Socket.cpp | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index c640392263..c44c0f4221 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -72,7 +72,7 @@ SendQueue& Connection::getSendQueue() { QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::packetSent); QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::recordSentPackets); QObject::connect(_sendQueue.get(), &SendQueue::packetRetransmitted, this, &Connection::recordRetransmission); - QObject::connect(_sendQueue.get(), &SendQueue::queueInnactive, this, &Connection::queueInnactive); + QObject::connect(_sendQueue.get(), &SendQueue::queueInactive, this, &Connection::queueInactive); // set defaults on the send queue from our congestion control object _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); @@ -82,8 +82,8 @@ SendQueue& Connection::getSendQueue() { return *_sendQueue; } -void Connection::queueInnactive() { - emit connectionInnactive(_destination); +void Connection::queueInactive() { + emit connectionInactive(_destination); } void Connection::sendReliablePacket(std::unique_ptr packet) { diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index fd7cd5ef88..ef713ea0c5 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -73,12 +73,12 @@ public: signals: void packetSent(); - void connectionInnactive(HifiSockAddr sockAdrr); + void connectionInactive(HifiSockAddr sockAdrr); private slots: void recordSentPackets(int payload, int total); void recordRetransmission(); - void queueInnactive(); + void queueInactive(); private: void sendACK(bool wasCausedBySyncTimeout = true); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 1ee8cce48a..93212770e5 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -254,12 +254,12 @@ void SendQueue::run() { } if (!sentAPacket) { - static const std::chrono::seconds CONSIDER_INNACTIVE_AFTER { 5 }; + static const std::chrono::seconds CONSIDER_INACTIVE_AFTER { 5 }; - if (flowWindowFull && (clock::now() - _flowWindowFullSince) > CONSIDER_INNACTIVE_AFTER) { - // If the flow window has been full for over CONSIDER_INNACTIVE_AFTER, - // then signal the queue is innactive - emit queueInnactive(); + if (flowWindowFull && (clock::now() - _flowWindowFullSince) > CONSIDER_INACTIVE_AFTER) { + // If the flow window has been full for over CONSIDER_INACTIVE_AFTER, + // then signal the queue is inactive + emit queueInactive(); } else { // During our processing above we didn't send any packets and the flow window is not full. @@ -270,12 +270,12 @@ void SendQueue::run() { // The packets queue and loss list mutexes are now both locked - check if they're still both empty if (doubleLock.try_lock() && _packets.empty() && _naks.getLength() == 0) { // both are empty - let's use a condition_variable_any to wait - auto cvStatus = _emptyCondition.wait_for(doubleLock, CONSIDER_INNACTIVE_AFTER); + auto cvStatus = _emptyCondition.wait_for(doubleLock, CONSIDER_INACTIVE_AFTER); - // Check if we've been innactive for too long + // Check if we've been inactive for too long if (cvStatus == std::cv_status::timeout) { - emit queueInnactive(); + emit queueInactive(); } // we have the double lock again - it'll be unlocked once it goes out of scope diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index cf20e03f20..8e8f3e4c89 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -68,7 +68,7 @@ signals: void packetSent(int dataSize, int payloadSize); void packetRetransmitted(); - void queueInnactive(); + void queueInactive(); private slots: void run(); @@ -105,7 +105,7 @@ private: std::atomic _flowWindowSize { 0 }; // Flow control window size (number of packets that can be on wire) - set from CC - // Used to detect when the connection becomes innactive for too long + // Used to detect when the connection becomes inactive for too long bool _flowWindowWasFull = false; time_point _flowWindowFullSince; diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index f423353836..7bdfc55398 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -147,7 +147,7 @@ Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { if (it == _connectionsHash.end()) { auto connection = std::unique_ptr(new Connection(this, sockAddr, _ccFactory->create())); - QObject::connect(connection.get(), &Connection::connectionInnactive, this, &Socket::cleanupConnection); + QObject::connect(connection.get(), &Connection::connectionInactive, this, &Socket::cleanupConnection); it = _connectionsHash.insert(it, std::make_pair(sockAddr, std::move(connection))); } From cd8d6df2877d1b8e60a931e81830ac7be9589cd5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 26 Aug 2015 19:36:18 +0200 Subject: [PATCH 388/549] Use high_resolution_clock instead of clock --- libraries/networking/src/udt/SendQueue.cpp | 6 +++--- libraries/networking/src/udt/SendQueue.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 93212770e5..691e65eea1 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -226,7 +226,7 @@ void SendQueue::run() { while (_isRunning) { // Record how long the loop takes to execute - auto loopStartTimestamp = clock::now(); + auto loopStartTimestamp = high_resolution_clock::now(); bool sentAPacket = maybeResendPacket(); bool flowWindowFull = false; @@ -256,7 +256,7 @@ void SendQueue::run() { if (!sentAPacket) { static const std::chrono::seconds CONSIDER_INACTIVE_AFTER { 5 }; - if (flowWindowFull && (clock::now() - _flowWindowFullSince) > CONSIDER_INACTIVE_AFTER) { + if (flowWindowFull && (high_resolution_clock::now() - _flowWindowFullSince) > CONSIDER_INACTIVE_AFTER) { // If the flow window has been full for over CONSIDER_INACTIVE_AFTER, // then signal the queue is inactive emit queueInactive(); @@ -285,7 +285,7 @@ void SendQueue::run() { } } - auto loopEndTimestamp = clock::now(); + auto loopEndTimestamp = high_resolution_clock::now(); // sleep as long as we need until next packet send, if we can auto timeToSleep = (loopStartTimestamp + std::chrono::microseconds(_packetSendPeriod)) - loopEndTimestamp; diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 8e8f3e4c89..ebc6702ac5 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -42,8 +42,8 @@ class SendQueue : public QObject { Q_OBJECT public: - using clock = std::chrono::high_resolution_clock; - using time_point = clock::time_point; + using high_resolution_clock = std::chrono::high_resolution_clock; + using time_point = high_resolution_clock::time_point; static std::unique_ptr create(Socket* socket, HifiSockAddr destination); From b1fa12cc431eea38df35c80dc01a9dea4ed118c0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 26 Aug 2015 19:38:24 +0200 Subject: [PATCH 389/549] Better debug message --- libraries/networking/src/udt/Socket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 7bdfc55398..d5e57df60b 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -155,7 +155,7 @@ Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { } void Socket::cleanupConnection(HifiSockAddr sockAddr) { - qDebug() << "Cleaned up" << sockAddr; + qCDebug(networking) << "Socket::cleanupConnection called for connection to" << sockAddr; _connectionsHash.erase(sockAddr); } From 5b5dc94335f67355d8c9ebe23481eb465a8f2bb6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 26 Aug 2015 20:03:04 +0200 Subject: [PATCH 390/549] Make DoubleLock thread-safe but not self-unlocked --- libraries/networking/src/udt/SendQueue.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 691e65eea1..9ba7b76a9c 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -26,23 +26,23 @@ using namespace udt; -// This class is not thread-safe class DoubleLock { public: - DoubleLock(std::mutex& mutex1, std::mutex& mutex2) : _mutex1(mutex1), _mutex2(mutex2) { }; - ~DoubleLock() { unlock(); } + DoubleLock(std::mutex& mutex1, std::mutex& mutex2) : _mutex1(mutex1), _mutex2(mutex2) { } DoubleLock(const DoubleLock&) = delete; DoubleLock& operator=(const DoubleLock&) = delete; - bool locked() { return _locked; } + // Either locks all the mutexes or none of them + bool try_lock() { return (std::try_lock(_mutex1, _mutex2) == -1); } - bool try_lock() { return _locked = (std::try_lock(_mutex1, _mutex2) == -1); } - void lock() { std::lock(_mutex1, _mutex2); _locked = true; } - void unlock() { if (_locked) { _mutex1.unlock(); _mutex2.unlock(); _locked = false; } } + // Locks all the mutexes + void lock() { std::lock(_mutex1, _mutex2); } + + // Undefined behavior if not locked + void unlock() { _mutex1.unlock(); _mutex2.unlock(); } private: - std::atomic _locked { false }; std::mutex& _mutex1; std::mutex& _mutex2; }; @@ -271,14 +271,15 @@ void SendQueue::run() { if (doubleLock.try_lock() && _packets.empty() && _naks.getLength() == 0) { // both are empty - let's use a condition_variable_any to wait auto cvStatus = _emptyCondition.wait_for(doubleLock, CONSIDER_INACTIVE_AFTER); - + + // we have the double lock again - Make sure to unlock it + doubleLock.unlock(); // Check if we've been inactive for too long if (cvStatus == std::cv_status::timeout) { emit queueInactive(); } - // we have the double lock again - it'll be unlocked once it goes out of scope // skip to the next iteration continue; } From aed1ba31c4a242d36c8cd73773f0bf028f16496d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 26 Aug 2015 12:26:24 -0700 Subject: [PATCH 391/549] Fix bugs in Menu.cpp --- interface/src/Menu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 3349171320..3305da5ba7 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -104,11 +104,11 @@ Menu::Menu() { qDebug() << "Selected: " << filename; QFile file { filename.path() }; if (file.open(QIODevice::ReadOnly)) { - auto fileInfo { filename.path() }; + QFileInfo fileInfo { filename.path() }; auto extension = fileInfo.suffix(); auto data = file.readAll(); auto assetClient = DependencyManager::get(); - assetClient->uploadAsset(data, extension, [this](bool result, QString hash) mutable { + assetClient->uploadAsset(data, extension, [this, extension](bool result, QString hash) mutable { if (result) { QMessageBox::information(this, "Upload Successful", "URL: apt:/" + hash + "." + extension); } else { From dc1f726283c1ad239baf4a64a3390108e7a890c2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 26 Aug 2015 12:36:48 -0700 Subject: [PATCH 392/549] don't assign the asset-server in domain by default --- domain-server/resources/describe-settings.json | 15 +++++++++++++++ domain-server/src/DomainServer.cpp | 14 ++++++++++++++ libraries/networking/src/Assignment.cpp | 2 ++ 3 files changed, 31 insertions(+) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index b04ea95a23..e3ab2c51b8 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -166,6 +166,21 @@ } ] }, + { + "name": "asset_server", + "label": "Asset Server", + "assignment-types": [3], + "settings": [ + { + "name": "enabled", + "type": "checkbox", + "label": "Enabled", + "help": "Assigns an asset-server in your domain to serve files to clients via the ATP protocol (over UDP)", + "default": false, + "advanced": true + } + ] + }, { "name": "audio_env", "label": "Audio Environment", diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 52b20d721f..5081ff55dc 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -574,6 +574,20 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet Date: Wed, 26 Aug 2015 12:37:47 -0700 Subject: [PATCH 393/549] remove an empty line --- domain-server/src/DomainServer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 5081ff55dc..da1d493e69 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -587,7 +587,6 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet Date: Wed, 26 Aug 2015 13:29:40 -0700 Subject: [PATCH 394/549] add a string for asset-server node type --- libraries/networking/src/Node.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 9f580c6d20..2b332d820d 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -31,6 +31,7 @@ void NodeType::init() { TypeNameHash.insert(NodeType::Agent, "Agent"); TypeNameHash.insert(NodeType::AudioMixer, "Audio Mixer"); TypeNameHash.insert(NodeType::AvatarMixer, "Avatar Mixer"); + TypeNameHash.insert(NodeType::AssetServer, "Asset Server"); TypeNameHash.insert(NodeType::Unassigned, "Unassigned"); } From 269d5bb6da810b9928aecbc812dd51f4712edc89 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 26 Aug 2015 14:04:55 -0700 Subject: [PATCH 395/549] Resolve bugs with *Cache changes --- libraries/networking/src/ResourceCache.cpp | 7 ++-- libraries/networking/src/ResourceCache.h | 4 +-- libraries/render-utils/src/GeometryCache.cpp | 36 +++++++++++--------- libraries/render-utils/src/GeometryCache.h | 10 +++--- 4 files changed, 31 insertions(+), 26 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 994a023a75..71e3de8254 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -207,8 +207,7 @@ Resource::Resource(const QUrl& url, bool delayLoad) : // start loading immediately unless instructed otherwise if (!(_startedLoading || delayLoad)) { - // QTimer::singleShot(1, this, &Resource::attemptRequest); - //attemptRequest(); + QTimer::singleShot(1, this, &Resource::attemptRequest); } } @@ -376,6 +375,8 @@ void Resource::handleReplyFinished() { ResourceCache::requestCompleted(this); + emit loaded(_data); + downloadFinished(_data); } else { _request->disconnect(this); @@ -408,6 +409,8 @@ void Resource::handleReplyFinished() { break; } + emit failed(QNetworkReply::UnknownNetworkError); + if (!retry) { ResourceCache::requestCompleted(this); } diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 3f40d32460..08d38db9a4 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -176,7 +176,7 @@ public: signals: /// Fired when the resource has been loaded. - void loaded(QNetworkReply& request); + void loaded(const QByteArray& request); /// Fired when resource failed to load. void failed(QNetworkReply::NetworkError error); @@ -219,8 +219,6 @@ private: void makeRequest(); void retry(); - void handleReplyErrorInternal(QNetworkReply::NetworkError error); - friend class ResourceCache; ResourceRequest* _request = nullptr; diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 2f81fe8b84..db7c25012c 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1678,15 +1678,15 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { } } -GeometryReader::GeometryReader(const QUrl& url, QNetworkReply* reply, const QVariantHash& mapping) : +GeometryReader::GeometryReader(const QUrl& url, const QByteArray& data, const QVariantHash& mapping) : _url(url), - _reply(reply), + _data(data), _mapping(mapping) { } void GeometryReader::run() { try { - if (!_reply) { + if (_data.isEmpty()) { throw QString("Reply is NULL ?!"); } QString urlname = _url.path().toLower(); @@ -1701,9 +1701,9 @@ void GeometryReader::run() { if (_url.path().toLower().endsWith(".fbx")) { const bool grabLightmaps = true; const float lightmapLevel = 1.0f; - fbxgeo = readFBX(_reply, _mapping, _url.path(), grabLightmaps, lightmapLevel); + fbxgeo = readFBX(_data, _mapping, _url.path(), grabLightmaps, lightmapLevel); } else if (_url.path().toLower().endsWith(".obj")) { - fbxgeo = OBJReader().readOBJ(_reply, _mapping, &_url); + fbxgeo = OBJReader().readOBJ(_data, _mapping); } else { QString errorStr("usupported format"); emit onError(NetworkGeometry::ModelParseError, errorStr); @@ -1717,7 +1717,6 @@ void GeometryReader::run() { qCDebug(renderutils) << "Error reading " << _url << ": " << error; emit onError(NetworkGeometry::ModelParseError, error); } - _reply->deleteLater(); } NetworkGeometry::NetworkGeometry(const QUrl& url, bool delayLoad, const QVariantHash& mapping, const QUrl& textureBaseUrl) : @@ -1746,8 +1745,10 @@ void NetworkGeometry::attemptRequest() { void NetworkGeometry::attemptRequestInternal() { if (_url.path().toLower().endsWith(".fst")) { + _mappingUrl = _url; requestMapping(_url); } else { + _modelUrl = _url; requestModel(_url); } } @@ -1838,8 +1839,8 @@ void NetworkGeometry::requestMapping(const QUrl& url) { _resource->deleteLater(); } _resource = new Resource(url, false); - connect(_resource, SIGNAL(loaded(QNetworkReply&)), SLOT(mappingRequestDone(QNetworkReply&))); - connect(_resource, SIGNAL(failed(QNetworkReply::NetworkError)), SLOT(mappingRequestError(QNetworkReply::NetworkError))); + connect(_resource, &Resource::loaded, this, &NetworkGeometry::mappingRequestDone); + connect(_resource, &Resource::failed, this, &NetworkGeometry::mappingRequestError); } void NetworkGeometry::requestModel(const QUrl& url) { @@ -1847,18 +1848,19 @@ void NetworkGeometry::requestModel(const QUrl& url) { if (_resource) { _resource->deleteLater(); } + _modelUrl = url; _resource = new Resource(url, false); - connect(_resource, SIGNAL(loaded(QNetworkReply&)), SLOT(modelRequestDone(QNetworkReply&))); - connect(_resource, SIGNAL(failed(QNetworkReply::NetworkError)), SLOT(modelRequestError(QNetworkReply::NetworkError))); + connect(_resource, &Resource::loaded, this, &NetworkGeometry::modelRequestDone); + connect(_resource, &Resource::failed, this, &NetworkGeometry::modelRequestError); } -void NetworkGeometry::mappingRequestDone(QNetworkReply& reply) { +void NetworkGeometry::mappingRequestDone(const QByteArray& data) { assert(_state == RequestMappingState); // parse the mapping file - _mapping = FSTReader::readMapping(reply.readAll()); + _mapping = FSTReader::readMapping(data); - QUrl replyUrl = reply.url(); + QUrl replyUrl = _mappingUrl; QString modelUrlStr = _mapping.value("filename").toString(); if (modelUrlStr.isNull()) { qCDebug(renderutils) << "Mapping file " << _url << "has no \"filename\" entry"; @@ -1873,8 +1875,8 @@ void NetworkGeometry::mappingRequestDone(QNetworkReply& reply) { _textureBaseUrl = replyUrl.resolved(texdir); } - QUrl modelUrl = replyUrl.resolved(modelUrlStr); - requestModel(modelUrl); + _modelUrl = replyUrl.resolved(modelUrlStr); + requestModel(_modelUrl); } } @@ -1884,13 +1886,13 @@ void NetworkGeometry::mappingRequestError(QNetworkReply::NetworkError error) { emit onFailure(*this, MappingRequestError); } -void NetworkGeometry::modelRequestDone(QNetworkReply& reply) { +void NetworkGeometry::modelRequestDone(const QByteArray& data) { assert(_state == RequestModelState); _state = ParsingModelState; // asynchronously parse the model file. - GeometryReader* geometryReader = new GeometryReader(reply.url(), &reply, _mapping); + GeometryReader* geometryReader = new GeometryReader(_modelUrl, data, _mapping); connect(geometryReader, SIGNAL(onSuccess(FBXGeometry*)), SLOT(modelParseSuccess(FBXGeometry*))); connect(geometryReader, SIGNAL(onError(int, QString)), SLOT(modelParseError(int, QString))); diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 71fa35c054..3820b58baf 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -348,10 +348,10 @@ signals: void onFailure(NetworkGeometry& networkGeometry, Error error); protected slots: - void mappingRequestDone(QNetworkReply& reply); + void mappingRequestDone(const QByteArray& data); void mappingRequestError(QNetworkReply::NetworkError error); - void modelRequestDone(QNetworkReply& reply); + void modelRequestDone(const QByteArray& data); void modelRequestError(QNetworkReply::NetworkError error); void modelParseSuccess(FBXGeometry* geometry); @@ -371,6 +371,8 @@ protected: State _state; QUrl _url; + QUrl _mappingUrl; + QUrl _modelUrl; QVariantHash _mapping; QUrl _textureBaseUrl; @@ -386,14 +388,14 @@ protected: class GeometryReader : public QObject, public QRunnable { Q_OBJECT public: - GeometryReader(const QUrl& url, QNetworkReply* reply, const QVariantHash& mapping); + GeometryReader(const QUrl& url, const QByteArray& data, const QVariantHash& mapping); virtual void run(); signals: void onSuccess(FBXGeometry* geometry); void onError(int error, QString str); private: QUrl _url; - QNetworkReply* _reply; + QByteArray _data; QVariantHash _mapping; }; From 2e585256ffc169b04b856e0b858ad5f3bac6a0c9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 26 Aug 2015 14:20:24 -0700 Subject: [PATCH 396/549] Update asset hash to Sha256 --- assignment-client/src/assets/AssetServer.cpp | 2 +- libraries/networking/src/AssetUtils.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index ad5d2a1d63..c7f61abdd3 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -273,6 +273,6 @@ void AssetServer::handleAssetUpload(QSharedPointer packetList, Sha } QString AssetServer::hashData(const QByteArray& data) { - return QString(QCryptographicHash::hash(data, QCryptographicHash::Md5).toHex()); + return QString(QCryptographicHash::hash(data, QCryptographicHash::Sha256).toHex()); } diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 61def81ea8..904fa71da2 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -14,7 +14,7 @@ using MessageID = uint32_t; using DataOffset = int64_t; -const int HASH_HEX_LENGTH = 32; +const int HASH_HEX_LENGTH = 64; enum AssetServerError : uint8_t { NO_ERROR = 0, From 4039c2e3e0fc5995b10a431c18f01a02eee307d5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 26 Aug 2015 14:27:12 -0700 Subject: [PATCH 397/549] fix for asset-server naming, deadlock in timeout/wait --- domain-server/src/DomainGatekeeper.cpp | 13 +++++++++++- libraries/networking/src/LimitedNodeList.cpp | 3 +++ libraries/networking/src/udt/SendQueue.cpp | 21 ++++++++++++++++++-- libraries/networking/src/udt/SendQueue.h | 2 +- libraries/networking/src/udt/Socket.cpp | 11 ++++++++++ libraries/networking/src/udt/Socket.h | 1 + 6 files changed, 47 insertions(+), 4 deletions(-) diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index 72b353f8a0..07afa007c5 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -48,7 +48,8 @@ QUuid DomainGatekeeper::assignmentUUIDForPendingAssignment(const QUuid& tempUUID } const NodeSet STATICALLY_ASSIGNED_NODES = NodeSet() << NodeType::AudioMixer - << NodeType::AvatarMixer << NodeType::EntityServer; + << NodeType::AvatarMixer << NodeType::EntityServer + << NodeType::AssetServer; void DomainGatekeeper::processConnectRequestPacket(QSharedPointer packet) { if (packet->getPayloadSize() == 0) { @@ -65,6 +66,16 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer pack return; } + static const NodeSet VALID_NODE_TYPES { + NodeType::AudioMixer, NodeType::AvatarMixer, NodeType::AssetServer, NodeType::EntityServer, NodeType::Agent + }; + + if (!VALID_NODE_TYPES.contains(nodeConnection.nodeType)) { + qDebug() << "Received an invalid node type with connect request. Will not allow connection from" + << nodeConnection.senderSockAddr; + return; + } + // check if this connect request matches an assignment in the queue auto pendingAssignment = _pendingAssignedNodes.find(nodeConnection.connectUUID); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index c342f660a3..e5923b059f 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -409,6 +409,9 @@ void LimitedNodeList::eraseAllNodes() { void LimitedNodeList::reset() { eraseAllNodes(); + + // we need to make sure any socket connections are gone so wait on that here + _nodeSocket.clearConnections(); } void LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) { diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index da702c7166..c0638a60f7 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -134,6 +134,12 @@ void SendQueue::queuePacketList(std::unique_ptr packetList) { void SendQueue::stop() { _isRunning = false; + + // in case we're waiting to send another handshake, release the condition_variable now so we cleanup sooner + _handshakeACKCondition.notify_one(); + + // in case the empty condition is waiting for packets/loss release it now so that the queue is cleaned up + _emptyCondition.notify_one(); } void SendQueue::sendPacket(const Packet& packet) { @@ -286,14 +292,22 @@ void SendQueue::run() { } _flowWindowWasFull = flowWindowFull; + // since we're a while loop, give the thread a chance to process events + QCoreApplication::processEvents(); + + // we just processed events so check now if we were just told to stop + if (!_isRunning) { + break; + } if (_hasReceivedHandshakeACK && !sentAPacket) { static const std::chrono::seconds CONSIDER_INACTIVE_AFTER { 5 }; if (flowWindowFull && (high_resolution_clock::now() - _flowWindowFullSince) > CONSIDER_INACTIVE_AFTER) { // If the flow window has been full for over CONSIDER_INACTIVE_AFTER, - // then signal the queue is inactive + // then signal the queue is inactive and return so it can be cleaned up emit queueInactive(); + return; } else { // During our processing above we didn't send any packets and the flow window is not full. @@ -303,15 +317,18 @@ void SendQueue::run() { // The packets queue and loss list mutexes are now both locked - check if they're still both empty if (doubleLock.try_lock() && _packets.empty() && _naks.getLength() == 0) { + // both are empty - let's use a condition_variable_any to wait auto cvStatus = _emptyCondition.wait_for(doubleLock, CONSIDER_INACTIVE_AFTER); // we have the double lock again - Make sure to unlock it doubleLock.unlock(); - // Check if we've been inactive for too long if (cvStatus == std::cv_status::timeout) { + // the wait_for released because we've been inactive for too long + // so emit our inactive signal and return so the send queue can be cleaned up emit queueInactive(); + return; } // skip to the next iteration diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 89dc2fae8f..70493f2054 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -83,7 +83,7 @@ private: void sendNewPacketAndAddToSentList(std::unique_ptr newPacket, SequenceNumber sequenceNumber); bool maybeSendNewPacket(); // Figures out what packet to send next - bool maybeResendPacket(); // Determines whether to resend a packet and wich one + bool maybeResendPacket(); // Determines whether to resend a packet and which one // Increments current sequence number and return it SequenceNumber getNextSequenceNumber(); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index d5e57df60b..db0377de05 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -154,6 +154,17 @@ Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { return *it->second; } +void Socket::clearConnections() { + if (thread() != QThread::currentThread()) { + QMetaObject::invokeMethod(this, "clearConnections", Qt::BlockingQueuedConnection); + return; + } + + // clear all of the current connections in the socket + qDebug() << "Clearing all remaining connections in Socket."; + _connectionsHash.clear(); +} + void Socket::cleanupConnection(HifiSockAddr sockAddr) { qCDebug(networking) << "Socket::cleanupConnection called for connection to" << sockAddr; _connectionsHash.erase(sockAddr); diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 0014a97e2b..f421b98288 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -75,6 +75,7 @@ public: public slots: void cleanupConnection(HifiSockAddr sockAddr); + void clearConnections(); private slots: void readPendingDatagrams(); From 34f7aa74f365516a4864638a00acf58a199be793 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 26 Aug 2015 14:26:09 -0700 Subject: [PATCH 398/549] Move SendAssetTask declaration to header --- assignment-client/src/assets/AssetServer.cpp | 37 ++++++-------------- assignment-client/src/assets/AssetServer.h | 19 ++++++++++ 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index c7f61abdd3..697b4b21ec 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -29,32 +29,17 @@ void writeError(NLPacketList* packetList, AssetServerError error) { packetList->writePrimitive(error); } -class SendAssetTask : public QRunnable { -public: - SendAssetTask(MessageID messageID, const QByteArray& assetHash, QString filePath, DataOffset start, DataOffset end, const SharedNodePointer& sendToNode) : - QRunnable(), - _messageID(messageID), - _assetHash(assetHash), - _filePath(filePath), - _start(start), - _end(end), - _sendToNode(sendToNode) - { - } - - void run(); - -signals: - void finished(); - -private: - MessageID _messageID; - QByteArray _assetHash; - QString _filePath; - DataOffset _start; - DataOffset _end; - SharedNodePointer _sendToNode; -}; +SendAssetTask::SendAssetTask(MessageID messageID, const QByteArray& assetHash, QString filePath, DataOffset start, DataOffset end, + const SharedNodePointer& sendToNode) : + QRunnable(), + _messageID(messageID), + _assetHash(assetHash), + _filePath(filePath), + _start(start), + _end(end), + _sendToNode(sendToNode) +{ +} void SendAssetTask::run() { qDebug() << "Starting task to send asset: " << _assetHash << " for messageID " << _messageID; diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 94116b191e..485614d984 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -40,4 +40,23 @@ private: QThreadPool _taskPool; }; +class SendAssetTask : public QRunnable { +public: + SendAssetTask(MessageID messageID, const QByteArray& assetHash, QString filePath, DataOffset start, DataOffset end, + const SharedNodePointer& sendToNode); + + void run(); + +signals: + void finished(); + +private: + MessageID _messageID; + QByteArray _assetHash; + QString _filePath; + DataOffset _start; + DataOffset _end; + SharedNodePointer _sendToNode; +}; + #endif From d3b19f36fd85bab43458bf76096a69505d8182a3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 26 Aug 2015 14:43:09 -0700 Subject: [PATCH 399/549] don't use remove_if since it can't be used on associative --- libraries/networking/src/PacketReceiver.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index c55461e8cf..556216bbd1 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -200,7 +200,7 @@ void PacketReceiver::registerVerifiedListener(PacketType type, QObject* object, qCWarning(networking) << "Registering a packet listener for packet type" << type << "that will remove a previously registered listener"; } - + // add the mapping _packetListenerMap[type] = ObjectMethodPair(QPointer(object), slot); } @@ -210,10 +210,17 @@ void PacketReceiver::unregisterListener(QObject* listener) { { QMutexLocker packetListenerLocker(&_packetListenerLock); - std::remove_if(std::begin(_packetListenerMap), std::end(_packetListenerMap), - [&listener](const ObjectMethodPair& pair) { - return pair.first == listener; - }); + + // clear any registrations for this listener + auto it = _packetListenerMap.begin(); + + while (it != _packetListenerMap.end()) { + if (it->first == listener) { + it = _packetListenerMap.erase(it); + } + + ++it; + } } QMutexLocker directConnectSetLocker(&_directConnectSetMutex); From c340c34b3889ca729120711218729da3cf7b24ab Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 26 Aug 2015 14:53:05 -0700 Subject: [PATCH 400/549] add comments for PacketReceiver TODOs --- libraries/networking/src/PacketReceiver.cpp | 15 ++++++++++++++- libraries/networking/src/PacketReceiver.h | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 556216bbd1..035432cf4b 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -211,7 +211,9 @@ void PacketReceiver::unregisterListener(QObject* listener) { { QMutexLocker packetListenerLocker(&_packetListenerLock); - // clear any registrations for this listener + // TODO: replace the two while loops below with a replace_if on the vector (once we move to Message everywhere) + + // clear any registrations for this listener in _packetListenerMap auto it = _packetListenerMap.begin(); while (it != _packetListenerMap.end()) { @@ -221,6 +223,17 @@ void PacketReceiver::unregisterListener(QObject* listener) { ++it; } + + // clear any registrations for this listener in _packetListListener + auto listIt = _packetListenerMap.end(); + + while (listIt != _packetListListenerMap.end()) { + if (listIt->first == listener) { + listIt = _packetListListenerMap.erase(listIt); + } + + ++listIt; + } } QMutexLocker directConnectSetLocker(&_directConnectSetMutex); diff --git a/libraries/networking/src/PacketReceiver.h b/libraries/networking/src/PacketReceiver.h index 9965eccdc2..1c6f9e73d2 100644 --- a/libraries/networking/src/PacketReceiver.h +++ b/libraries/networking/src/PacketReceiver.h @@ -69,6 +69,7 @@ private: using ObjectMethodPair = std::pair, QMetaMethod>; QMutex _packetListenerLock; + // TODO: replace the two following hashes with an std::vector once we switch Packet/PacketList to Message QHash _packetListenerMap; QHash _packetListListenerMap; int _inPacketCount = 0; From 9e286666b5dfa62d3cf0a6409a56a8ea171e74ed Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 26 Aug 2015 14:55:59 -0700 Subject: [PATCH 401/549] add UDT to comment for Connection cleanup --- libraries/networking/src/udt/Socket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index db0377de05..1a404eb6c1 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -166,7 +166,7 @@ void Socket::clearConnections() { } void Socket::cleanupConnection(HifiSockAddr sockAddr) { - qCDebug(networking) << "Socket::cleanupConnection called for connection to" << sockAddr; + qCDebug(networking) << "Socket::cleanupConnection called for UDT connection to" << sockAddr; _connectionsHash.erase(sockAddr); } From d66c5212009270b447fa925b94266f81d4307869 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 26 Aug 2015 15:37:23 -0700 Subject: [PATCH 402/549] Move SendAssetTask to separate file --- assignment-client/src/assets/AssetServer.cpp | 70 ++---------------- assignment-client/src/assets/AssetServer.h | 21 +----- .../src/assets/SendAssetTask.cpp | 73 +++++++++++++++++++ assignment-client/src/assets/SendAssetTask.h | 41 +++++++++++ libraries/networking/src/AssetUtils.h | 2 + 5 files changed, 125 insertions(+), 82 deletions(-) create mode 100644 assignment-client/src/assets/SendAssetTask.cpp create mode 100644 assignment-client/src/assets/SendAssetTask.h diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 697b4b21ec..f8f3aa8d4c 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -21,74 +21,16 @@ #include #include -#include +#include "NetworkLogging.h" +#include "NodeType.h" +#include "SendAssetTask.h" const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server"; -void writeError(NLPacketList* packetList, AssetServerError error) { - packetList->writePrimitive(error); -} - -SendAssetTask::SendAssetTask(MessageID messageID, const QByteArray& assetHash, QString filePath, DataOffset start, DataOffset end, - const SharedNodePointer& sendToNode) : - QRunnable(), - _messageID(messageID), - _assetHash(assetHash), - _filePath(filePath), - _start(start), - _end(end), - _sendToNode(sendToNode) -{ -} - -void SendAssetTask::run() { - qDebug() << "Starting task to send asset: " << _assetHash << " for messageID " << _messageID; - auto replyPacketList = std::unique_ptr(new NLPacketList(PacketType::AssetGetReply, QByteArray(), true, true)); - - replyPacketList->write(_assetHash, HASH_HEX_LENGTH); - - replyPacketList->writePrimitive(_messageID); - - const int64_t MAX_LENGTH = 4294967296; - - if (_end <= _start) { - writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); - } else if (_end - _start > MAX_LENGTH) { - writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); - } else { - QFile file { _filePath }; - qDebug() << "Opening file: " << QString(QFileInfo(_assetHash).fileName()); - - if (file.open(QIODevice::ReadOnly)) { - if (file.size() < _end) { - writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); - } else { - auto size = _end - _start; - file.seek(_start); - replyPacketList->writePrimitive(AssetServerError::NO_ERROR); - replyPacketList->writePrimitive(size); - while (file.pos() < file.size()) { - static const int chunkSize = 20000; - QByteArray data = file.read(chunkSize); - replyPacketList->write(data, chunkSize); - } - qDebug() << "Done reading"; - } - file.close(); - } else { - qDebug() << "Asset not found"; - writeError(replyPacketList.get(), AssetServerError::ASSET_NOT_FOUND); - } - } - - qDebug() << "Sending asset"; - auto nodeList = DependencyManager::get(); - nodeList->sendPacketList(std::move(replyPacketList), *_sendToNode); -} - AssetServer::AssetServer(NLPacket& packet) : - ThreadedAssignment(packet), - _taskPool(this) { + ThreadedAssignment(packet), + _taskPool(this) +{ // Most of the work will be I/O bound, reading from disk and constructing packet objects, // so the ideal is greater than the number of cores on the system. diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 485614d984..7a9cbd36ef 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -40,23 +40,8 @@ private: QThreadPool _taskPool; }; -class SendAssetTask : public QRunnable { -public: - SendAssetTask(MessageID messageID, const QByteArray& assetHash, QString filePath, DataOffset start, DataOffset end, - const SharedNodePointer& sendToNode); - - void run(); - -signals: - void finished(); - -private: - MessageID _messageID; - QByteArray _assetHash; - QString _filePath; - DataOffset _start; - DataOffset _end; - SharedNodePointer _sendToNode; -}; +inline void writeError(NLPacketList* packetList, AssetServerError error) { + packetList->writePrimitive(error); +} #endif diff --git a/assignment-client/src/assets/SendAssetTask.cpp b/assignment-client/src/assets/SendAssetTask.cpp new file mode 100644 index 0000000000..559331342f --- /dev/null +++ b/assignment-client/src/assets/SendAssetTask.cpp @@ -0,0 +1,73 @@ +// +// SendAssetTask.cpp +// +// Created by Ryan Huffman on 2015/08/26 +// Copyright 2015 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 "SendAssetTask.h" + +#include + +#include +#include +#include +#include +#include + +#include "AssetUtils.h" + +SendAssetTask::SendAssetTask(MessageID messageID, const QByteArray& assetHash, QString filePath, DataOffset start, DataOffset end, + const SharedNodePointer& sendToNode) : + QRunnable(), + _messageID(messageID), + _assetHash(assetHash), + _filePath(filePath), + _start(start), + _end(end), + _sendToNode(sendToNode) +{ +} + +void SendAssetTask::run() { + qDebug() << "Starting task to send asset: " << _assetHash << " for messageID " << _messageID; + auto replyPacketList = std::unique_ptr(new NLPacketList(PacketType::AssetGetReply, QByteArray(), true, true)); + + replyPacketList->write(_assetHash, HASH_HEX_LENGTH); + + replyPacketList->writePrimitive(_messageID); + + const int64_t MAX_LENGTH = 4294967296; + + if (_end <= _start) { + writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); + } else if (_end - _start > MAX_LENGTH) { + writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); + } else { + QFile file { _filePath }; + + if (file.open(QIODevice::ReadOnly)) { + if (file.size() < _end) { + writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); + qCDebug(networking) << "Bad byte range: " << _assetHash << " " << _start << ":" << _end; + } else { + auto size = _end - _start; + file.seek(_start); + replyPacketList->writePrimitive(AssetServerError::NO_ERROR); + replyPacketList->writePrimitive(size); + replyPacketList->write(file.read(size)); + } + file.close(); + qCDebug(networking) << "Sending asset: " << _assetHash; + } else { + qCDebug(networking) << "Asset not found: " << _assetHash; + writeError(replyPacketList.get(), AssetServerError::ASSET_NOT_FOUND); + } + } + + auto nodeList = DependencyManager::get(); + nodeList->sendPacketList(std::move(replyPacketList), *_sendToNode); +} diff --git a/assignment-client/src/assets/SendAssetTask.h b/assignment-client/src/assets/SendAssetTask.h new file mode 100644 index 0000000000..7dd3616f83 --- /dev/null +++ b/assignment-client/src/assets/SendAssetTask.h @@ -0,0 +1,41 @@ +// +// SendAssetTask.h +// +// Created by Ryan Huffman on 2015/08/26 +// Copyright 2015 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 +// + +#ifndef hifi_SendAssetTask_h +#define hifi_SendAssetTask_h + +#include +#include +#include + +#include "AssetUtils.h" +#include "AssetServer.h" +#include "Node.h" + +class SendAssetTask : public QRunnable { +public: + SendAssetTask(MessageID messageID, const QByteArray& assetHash, QString filePath, DataOffset start, DataOffset end, + const SharedNodePointer& sendToNode); + + void run(); + +signals: + void finished(); + +private: + MessageID _messageID; + QByteArray _assetHash; + QString _filePath; + DataOffset _start; + DataOffset _end; + SharedNodePointer _sendToNode; +}; + +#endif diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 904fa71da2..c23b54de5d 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -11,6 +11,8 @@ #ifndef hifi_AssetUtils_h #define hifi_AssetUtils_h +#include "NLPacketList.h" + using MessageID = uint32_t; using DataOffset = int64_t; From 287f2533eb32958ffd595f979dd99e35e5e01337 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 26 Aug 2015 15:37:38 -0700 Subject: [PATCH 403/549] Remove AssetServer dtor --- assignment-client/src/assets/AssetServer.cpp | 3 --- assignment-client/src/assets/AssetServer.h | 1 - 2 files changed, 4 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index f8f3aa8d4c..f89b288f9c 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -42,9 +42,6 @@ AssetServer::AssetServer(NLPacket& packet) : packetReceiver.registerMessageListener(PacketType::AssetUpload, this, "handleAssetUpload"); } -AssetServer::~AssetServer() { -} - void AssetServer::run() { ThreadedAssignment::commonInit(ASSET_SERVER_LOGGING_TARGET_NAME, NodeType::AssetServer); diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 7a9cbd36ef..07e0680c4f 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -22,7 +22,6 @@ class AssetServer : public ThreadedAssignment { Q_OBJECT public: AssetServer(NLPacket& packet); - ~AssetServer(); static QString hashData(const QByteArray& data); From 4ed5748afaaadc3fa419861461514e4466c78900 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 26 Aug 2015 15:37:58 -0700 Subject: [PATCH 404/549] Fix new asset loading in directory --- assignment-client/src/assets/AssetServer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index f89b288f9c..2c294e652c 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -58,8 +58,8 @@ void AssetServer::run() { // Scan for new files qDebug() << "Looking for new files in asset directory"; auto files = _resourcesDirectory.entryInfoList(QDir::Files); - QRegExp filenameRegex { "^[a-f0-9]{32}(\\..+)?$" }; - for (auto fileInfo : files) { + QRegExp filenameRegex { "^[a-f0-9]{" + QString::number(HASH_HEX_LENGTH) + "}(\\..+)?$" }; + for (const auto& fileInfo : files) { auto filename = fileInfo.fileName(); if (!filenameRegex.exactMatch(filename)) { qDebug() << "Found file: " << filename; From 59b32751f0efc2266335498d1886dcc398da4acd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 26 Aug 2015 15:54:02 -0700 Subject: [PATCH 405/549] Cleanup AssetScriptingInterface --- interface/src/AssetScriptingInterface.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/interface/src/AssetScriptingInterface.cpp b/interface/src/AssetScriptingInterface.cpp index 267f0cc25e..863d2ae3e7 100644 --- a/interface/src/AssetScriptingInterface.cpp +++ b/interface/src/AssetScriptingInterface.cpp @@ -27,7 +27,6 @@ AssetScriptingInterface::AssetScriptingInterface() { QScriptValue AssetScriptingInterface::getAsset(QString url, QScriptValue callback) { auto assetClient = DependencyManager::get(); - // auto request = assetClient->requestAsset(url); auto request = assetClient->create(url); if (!request) { @@ -42,11 +41,6 @@ QScriptValue AssetScriptingInterface::getAsset(QString url, QScriptValue callbac request->start(); - // bool success = AssetManager::getAsset(QUrl(url), [callback](AssetRequestUpdateType type, QByteArray data) mutable { - // auto result = callback.engine()->newVariant(data); - // QList arguments { type == AssetRequestUpdateType::COMPLETE, result }; - // callback.call(QScriptValue(), arguments); - // }); return true; } From 4105b7369cd4815e5c3ead6797edb373bb9732c5 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 26 Aug 2015 15:55:29 -0700 Subject: [PATCH 406/549] Remove AssetScriptingInterface --- interface/src/Application.cpp | 4 -- interface/src/AssetScriptingInterface.cpp | 53 ----------------------- interface/src/AssetScriptingInterface.h | 31 ------------- 3 files changed, 88 deletions(-) delete mode 100644 interface/src/AssetScriptingInterface.cpp delete mode 100644 interface/src/AssetScriptingInterface.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5974a33230..d94cff19f1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -53,7 +53,6 @@ #include #include #include -#include #include #include #include @@ -300,7 +299,6 @@ bool setupEssentials(int& argc, char** argv) { auto pathUtils = DependencyManager::set(); auto actionFactory = DependencyManager::set(); auto assetClient = DependencyManager::set(); - auto assetScriptingInterface = DependencyManager::set(); auto userInputMapper = DependencyManager::set(); return true; @@ -3987,8 +3985,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri qScriptRegisterMetaType(scriptEngine, RayToOverlayIntersectionResultToScriptValue, RayToOverlayIntersectionResultFromScriptValue); - scriptEngine->registerGlobalObject("Assets", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("Desktop", DependencyManager::get().data()); QScriptValue windowValue = scriptEngine->registerGlobalObject("Window", DependencyManager::get().data()); diff --git a/interface/src/AssetScriptingInterface.cpp b/interface/src/AssetScriptingInterface.cpp deleted file mode 100644 index 863d2ae3e7..0000000000 --- a/interface/src/AssetScriptingInterface.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// -// AssetScriptingInterface.cpp -// -// Created by Ryan Huffman on 2015/07/22 -// Copyright 2015 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 "AssetScriptingInterface.h" - -#include - -#include -#include -#include -#include -#include -#include - -#include - -AssetScriptingInterface::AssetScriptingInterface() { -} - -QScriptValue AssetScriptingInterface::getAsset(QString url, QScriptValue callback) { - - auto assetClient = DependencyManager::get(); - auto request = assetClient->create(url); - - if (!request) { - return false; - } - - connect(request, &AssetRequest::finished, [callback](AssetRequest* req) mutable { - auto result = callback.engine()->newVariant(req->getData()); - QList arguments { true, result }; - callback.call(QScriptValue(), arguments); - }); - - request->start(); - - return true; -} - -QScriptValue AssetScriptingInterface::uploadAsset(QString data, QString extension, QScriptValue callback) { - auto assetClient = DependencyManager::get(); - return assetClient->uploadAsset(data.toLatin1(), extension, [callback](bool success, QString hash) mutable { - QList arguments { success, hash }; - auto result = callback.call(QScriptValue(), arguments); - }); -} diff --git a/interface/src/AssetScriptingInterface.h b/interface/src/AssetScriptingInterface.h deleted file mode 100644 index 8c0f7a71a1..0000000000 --- a/interface/src/AssetScriptingInterface.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// AssetScriptingInterface.h -// -// Created by Ryan Huffman on 2015/07/22 -// Copyright 2015 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 -// - -#ifndef hifi_AssetScriptingInterface_h -#define hifi_AssetScriptingInterface_h - -#include -#include - -#include -#include -#include - -class AssetScriptingInterface : public QObject, public Dependency { - Q_OBJECT -public: - AssetScriptingInterface(); - -public slots: - QScriptValue getAsset(QString hash, QScriptValue callback); - QScriptValue uploadAsset(QString data, QString extension, QScriptValue callback); -}; - -#endif From c2fcf5865a5b7d1e7b5871e091d7dcf27063c3f3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 26 Aug 2015 16:02:47 -0700 Subject: [PATCH 407/549] Update log message for uploading assets --- libraries/networking/src/AssetClient.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 3877f05fe9..0c16b82774 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -182,7 +182,6 @@ bool AssetClient::uploadAsset(QByteArray data, QString extension, UploadResultCa } void AssetClient::handleAssetUploadReply(QSharedPointer packet, SharedNodePointer senderNode) { - qDebug() << "Got asset upload reply"; MessageID messageID; packet->readPrimitive(&messageID); @@ -196,9 +195,9 @@ void AssetClient::handleAssetUploadReply(QSharedPointer packet, Shared hashString = QString(hashData); - qDebug() << "Hash: " << hashString; + qDebug() << "Successfully uploaded asset to asset-server - SHA256 hash is " << hashString; } else { - qDebug() << "Error uploading file"; + qDebug() << "Error uploading file to asset server"; } if (_pendingUploads.contains(messageID)) { From 5b5941fea2e7101cbf9fac487dd74ed92d57d329 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 26 Aug 2015 16:30:09 -0700 Subject: [PATCH 408/549] move asset upload to AssetUploadDialogFactory --- interface/src/Menu.cpp | 53 ++++++------------ interface/src/Menu.h | 1 + interface/src/ui/AddressBarDialog.h | 3 +- interface/src/ui/AssetUploadDialogFactory.cpp | 55 +++++++++++++++++++ interface/src/ui/AssetUploadDialogFactory.h | 35 ++++++++++++ interface/src/ui/DialogsManager.cpp | 2 +- interface/src/ui/DialogsManager.h | 2 +- interface/src/ui/LoginDialog.h | 3 +- 8 files changed, 112 insertions(+), 42 deletions(-) create mode 100644 interface/src/ui/AssetUploadDialogFactory.cpp create mode 100644 interface/src/ui/AssetUploadDialogFactory.h diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 3305da5ba7..6c41a3d7da 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -22,8 +22,6 @@ #include #include -#include - #include "Application.h" #include "AccountManager.h" #include "audio/AudioScope.h" @@ -34,13 +32,15 @@ #include "devices/3DConnexionClient.h" #include "MainWindow.h" #include "scripting/MenuScriptingInterface.h" -#if defined(Q_OS_MAC) || defined(Q_OS_WIN) -#include "SpeechRecognizer.h" -#endif +#include "ui/AssetUploadDialogFactory.h" #include "ui/DialogsManager.h" #include "ui/StandAloneJSConsole.h" #include "InterfaceLogging.h" +#if defined(Q_OS_MAC) || defined(Q_OS_WIN) +#include "SpeechRecognizer.h" +#endif + #include "Menu.h" Menu* Menu::_instance = NULL; @@ -90,36 +90,6 @@ Menu::Menu() { addActionToQMenuAndActionHash(fileMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, qApp, SLOT(toggleRunningScriptsWidget())); - // Asset uploading - { - auto action = new QAction("Upload File", fileMenu); - fileMenu->addAction(action); - action->setMenuRole(QAction::NoRole); - _actionHash.insert("Upload File", action); - - connect(action, &QAction::triggered, [this](bool checked) { - qDebug() << "Clicked upload file"; - auto filename = QFileDialog::getOpenFileUrl(nullptr, "Select a file to upload"); - if (!filename.isEmpty()) { - qDebug() << "Selected: " << filename; - QFile file { filename.path() }; - if (file.open(QIODevice::ReadOnly)) { - QFileInfo fileInfo { filename.path() }; - auto extension = fileInfo.suffix(); - auto data = file.readAll(); - auto assetClient = DependencyManager::get(); - assetClient->uploadAsset(data, extension, [this, extension](bool result, QString hash) mutable { - if (result) { - QMessageBox::information(this, "Upload Successful", "URL: apt:/" + hash + "." + extension); - } else { - QMessageBox::warning(this, "Upload Failed", "There was an error uploading the file."); - } - }); - } - } - }); - } - auto addressManager = DependencyManager::get(); addDisabledActionAndSeparator(fileMenu, "History"); @@ -400,7 +370,18 @@ Menu::Menu() { addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, 0, // QML Qt::SHIFT | Qt::Key_L, dialogsManager.data(), SLOT(lodTools())); - + + MenuWrapper* assetDeveloperMenu = developerMenu->addMenu("Assets"); + + auto& assetDialogFactory = AssetUploadDialogFactory::getInstance(); + assetDialogFactory.setParent(this); + + addActionToQMenuAndActionHash(assetDeveloperMenu, + MenuOption::UploadAsset, + 0, + &AssetUploadDialogFactory::getInstance(), + SLOT(showDialog())); + MenuWrapper* avatarDebugMenu = developerMenu->addMenu("Avatar"); MenuWrapper* faceTrackingMenu = avatarDebugMenu->addMenu("Face Tracking"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 4bd1e7f664..948e159b04 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -288,6 +288,7 @@ namespace MenuOption { const QString ToolWindow = "Tool Window"; const QString TransmitterDrive = "Transmitter Drive"; const QString TurnWithHead = "Turn using Head"; + const QString UploadAsset = "Upload File to Local Asset Server"; const QString UseAudioForMouth = "Use Audio for Mouth"; const QString UseCamera = "Use Camera"; const QString VelocityFilter = "Velocity Filter"; diff --git a/interface/src/ui/AddressBarDialog.h b/interface/src/ui/AddressBarDialog.h index e0be8aa3fb..eec3acdbfc 100644 --- a/interface/src/ui/AddressBarDialog.h +++ b/interface/src/ui/AddressBarDialog.h @@ -14,8 +14,7 @@ #include -class AddressBarDialog : public OffscreenQmlDialog -{ +class AddressBarDialog : public OffscreenQmlDialog { Q_OBJECT HIFI_QML_DECL Q_PROPERTY(bool backEnabled READ backEnabled NOTIFY backEnabledChanged) diff --git a/interface/src/ui/AssetUploadDialogFactory.cpp b/interface/src/ui/AssetUploadDialogFactory.cpp new file mode 100644 index 0000000000..79e3cfa2db --- /dev/null +++ b/interface/src/ui/AssetUploadDialogFactory.cpp @@ -0,0 +1,55 @@ +// +// AssetUploadDialogFactory.cpp +// interface/src/ui +// +// Created by Stephen Birarda on 2015-08-26. +// Copyright 2015 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 "AssetUploadDialogFactory.h" + +#include + +#include +#include +#include + +AssetUploadDialogFactory& AssetUploadDialogFactory::getInstance() { + static AssetUploadDialogFactory staticInstance; + return staticInstance; +} + +AssetUploadDialogFactory::AssetUploadDialogFactory() { + +} + +void AssetUploadDialogFactory::showDialog() { + auto filename = QFileDialog::getOpenFileUrl(nullptr, "Select a file to upload"); + + if (!filename.isEmpty()) { + qDebug() << "Selected filename for upload to asset-server: " << filename; + + QFile file { filename.path() }; + + if (file.open(QIODevice::ReadOnly)) { + + QFileInfo fileInfo { filename.path() }; + auto extension = fileInfo.suffix(); + + auto data = file.readAll(); + + auto assetClient = DependencyManager::get(); + + assetClient->uploadAsset(data, extension, [this, extension](bool result, QString hash) mutable { + if (result) { + QMessageBox::information(_dialogParent, "Upload Successful", "URL: apt:/" + hash + "." + extension); + } else { + QMessageBox::warning(_dialogParent, "Upload Failed", "There was an error uploading the file."); + } + }); + } + } +} diff --git a/interface/src/ui/AssetUploadDialogFactory.h b/interface/src/ui/AssetUploadDialogFactory.h new file mode 100644 index 0000000000..3d830aa4bb --- /dev/null +++ b/interface/src/ui/AssetUploadDialogFactory.h @@ -0,0 +1,35 @@ +// +// AssetUploadDialogFactory.h +// interface/src/ui +// +// Created by Stephen Birarda on 2015-08-26. +// Copyright 2015 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 +// + +#pragma once + +#ifndef hifi_AssetUploadDialogFactory_h +#define hifi_AssetUploadDialogFactory_h + +#include + +class AssetUploadDialogFactory : public QObject { + Q_OBJECT +public: + AssetUploadDialogFactory(); + AssetUploadDialogFactory(const AssetUploadDialogFactory& other) = delete; + AssetUploadDialogFactory& operator=(const AssetUploadDialogFactory& rhs) = delete; + + static AssetUploadDialogFactory& getInstance(); + + void setDialogParent(QWidget* dialogParent) { _dialogParent = dialogParent; } +public slots: + void showDialog(); +private: + QWidget* _dialogParent { nullptr }; +}; + +#endif // hifi_AssetUploadDialogFactory_h diff --git a/interface/src/ui/DialogsManager.cpp b/interface/src/ui/DialogsManager.cpp index 58d2550752..308cfc9e8c 100644 --- a/interface/src/ui/DialogsManager.cpp +++ b/interface/src/ui/DialogsManager.cpp @@ -1,6 +1,6 @@ // // DialogsManager.cpp -// +// interface/src/ui // // Created by Clement on 1/18/15. // Copyright 2015 High Fidelity, Inc. diff --git a/interface/src/ui/DialogsManager.h b/interface/src/ui/DialogsManager.h index 2db700e72a..68d371021a 100644 --- a/interface/src/ui/DialogsManager.h +++ b/interface/src/ui/DialogsManager.h @@ -1,6 +1,6 @@ // // DialogsManager.h -// +// interface/src/ui // // Created by Clement on 1/18/15. // Copyright 2015 High Fidelity, Inc. diff --git a/interface/src/ui/LoginDialog.h b/interface/src/ui/LoginDialog.h index 50c820aa07..25ecf45898 100644 --- a/interface/src/ui/LoginDialog.h +++ b/interface/src/ui/LoginDialog.h @@ -16,8 +16,7 @@ #include -class LoginDialog : public OffscreenQmlDialog -{ +class LoginDialog : public OffscreenQmlDialog { Q_OBJECT HIFI_QML_DECL From f95957a2718988656ab4fdcae77ed713963f487d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 09:30:34 -0700 Subject: [PATCH 409/549] Cleanup AssetServer --- assignment-client/src/assets/AssetServer.cpp | 75 +++++++++----------- 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 2c294e652c..6b50edbf2f 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -80,28 +80,24 @@ void AssetServer::run() { file.rename(_resourcesDirectory.absoluteFilePath(hash)); } } - - while (!_isFinished) { - // since we're a while loop we need to help Qt's event processing - QCoreApplication::processEvents(); - } } void AssetServer::handleAssetGetInfo(QSharedPointer packet, SharedNodePointer senderNode) { - if (packet->getPayloadSize() < HASH_HEX_LENGTH) { + QByteArray assetHash; + MessageID messageID; + + if (packet->getPayloadSize() < qint64(HASH_HEX_LENGTH + sizeof(messageID))) { qDebug() << "ERROR bad file request"; return; } - QByteArray assetHash; - MessageID messageID; packet->readPrimitive(&messageID); - assetHash = packet->read(HASH_HEX_LENGTH); + assetHash = packet->readWithoutCopy(HASH_HEX_LENGTH); auto replyPacket = NLPacket::create(PacketType::AssetGetInfoReply); replyPacket->writePrimitive(messageID); - replyPacket->write(assetHash, HASH_HEX_LENGTH); + replyPacket->write(assetHash); QFileInfo fileInfo { _resourcesDirectory.filePath(QString(assetHash)) }; qDebug() << "Opening file: " << QString(QFileInfo(assetHash).fileName()); @@ -119,21 +115,19 @@ void AssetServer::handleAssetGetInfo(QSharedPointer packet, SharedNode } void AssetServer::handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode) { - if (packet->getPayloadSize() < HASH_HEX_LENGTH) { + MessageID messageID; + QByteArray assetHash; + DataOffset start; + DataOffset end; + + if (packet->getPayloadSize() < qint64(sizeof(messageID) + HASH_HEX_LENGTH + sizeof(start) + sizeof(end))) { qDebug() << "ERROR bad file request"; return; } - MessageID messageID; packet->readPrimitive(&messageID); - - QByteArray assetHash; assetHash = packet->read(HASH_HEX_LENGTH); - - DataOffset start; packet->readPrimitive(&start); - - DataOffset end; packet->readPrimitive(&end); qDebug() << "Received a request for the file: " << assetHash << " from " << start << " to " << end; @@ -151,11 +145,9 @@ void AssetServer::handleAssetUpload(QSharedPointer packetList, Sha MessageID messageID; buffer.read(reinterpret_cast(&messageID), sizeof(messageID)); - // buffer.readPrimitive(&messageID); uint8_t extensionLength; buffer.read(reinterpret_cast(&extensionLength), sizeof(extensionLength)); - // buffer.readPrimitive(&extensionLength); QByteArray extension = buffer.read(extensionLength); @@ -163,34 +155,33 @@ void AssetServer::handleAssetUpload(QSharedPointer packetList, Sha uint64_t fileSize; buffer.read(reinterpret_cast(&fileSize), sizeof(fileSize)); - // buffer.readPrimitive(&fileSize); - // const uint64_t MAX_LENGTH = 1024; - // fileSize = std::min(MAX_LENGTH, fileSize); qDebug() << "Receiving a file of size " << fileSize; - QByteArray fileData = buffer.read(fileSize); - - QString hash = hashData(fileData); - - qDebug() << "Got data: (" << hash << ") "; - - QFile file { _resourcesDirectory.filePath(QString(hash)) }; - - if (file.exists()) { - qDebug() << "[WARNING] This file already exists"; - } else { - file.open(QIODevice::WriteOnly); - file.write(fileData); - file.close(); - } - auto replyPacket = NLPacket::create(PacketType::AssetUploadReply); - replyPacket->writePrimitive(messageID); - replyPacket->writePrimitive(true); - replyPacket->write(hash.toLatin1().constData(), HASH_HEX_LENGTH); + if (fileSize > MAX_UPLOAD_SIZE) { + replyPacket->writePrimitive(false); + } else { + QByteArray fileData = buffer.read(fileSize); + + QString hash = hashData(fileData); + + qDebug() << "Got data: (" << hash << ") "; + + QFile file { _resourcesDirectory.filePath(QString(hash)) }; + + if (file.exists()) { + qDebug() << "[WARNING] This file already exists: " << hash; + } else { + file.open(QIODevice::WriteOnly); + file.write(fileData); + file.close(); + } + replyPacket->writePrimitive(true); + replyPacket->write(hash.toLatin1()); + } auto nodeList = DependencyManager::get(); nodeList->sendPacket(std::move(replyPacket), *senderNode); From 3731091d5e6b83f87fa88e83c24cd3d83867e27f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 09:30:47 -0700 Subject: [PATCH 410/549] Remove max chunk requesting from SendAssetTask --- assignment-client/src/assets/SendAssetTask.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/assignment-client/src/assets/SendAssetTask.cpp b/assignment-client/src/assets/SendAssetTask.cpp index 559331342f..84c3a33c9f 100644 --- a/assignment-client/src/assets/SendAssetTask.cpp +++ b/assignment-client/src/assets/SendAssetTask.cpp @@ -40,12 +40,8 @@ void SendAssetTask::run() { replyPacketList->writePrimitive(_messageID); - const int64_t MAX_LENGTH = 4294967296; - if (_end <= _start) { writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); - } else if (_end - _start > MAX_LENGTH) { - writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); } else { QFile file { _filePath }; From b72e7e356d18c1cb2c5271a748e1a277043acfa6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 09:31:17 -0700 Subject: [PATCH 411/549] Clean up AssertClient --- libraries/networking/src/AssetClient.cpp | 29 ++++++++++++------------ 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 0c16b82774..e72e05d5ff 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -16,6 +16,7 @@ #include "AssetRequest.h" #include "NodeList.h" #include "PacketReceiver.h" +#include "AssetUtils.h" MessageID AssetClient::_currentID = 0; @@ -37,7 +38,7 @@ AssetRequest* AssetClient::create(QString hash) { return req; } - if (hash.length() != 32) { + if (hash.length() != HASH_HEX_LENGTH) { qDebug() << "Invalid hash size"; return nullptr; } @@ -69,7 +70,7 @@ bool AssetClient::getAsset(QString hash, DataOffset start, DataOffset end, Recei auto messageID = ++_currentID; packet->writePrimitive(messageID); - packet->write(hash.toLatin1().constData(), 32); + packet->write(hash.toLatin1().constData(), HASH_HEX_LENGTH); packet->writePrimitive(start); packet->writePrimitive(end); @@ -92,7 +93,7 @@ bool AssetClient::getAssetInfo(QString hash, GetInfoCallback callback) { auto messageID = ++_currentID; packet->writePrimitive(messageID); - packet->write(hash.toLatin1().constData(), 32); + packet->write(hash.toLatin1().constData(), HASH_HEX_LENGTH); nodeList->sendPacket(std::move(packet), *assetServer); @@ -112,15 +113,15 @@ void AssetClient::handleAssetGetInfoReply(QSharedPointer packet, Share AssetServerError error; packet->readPrimitive(&error); - AssetInfo info; + AssetInfo info { assetHash, 0 }; - if (!error) { + if (error == NO_ERROR) { packet->readPrimitive(&info.size); } if (_pendingInfoRequests.contains(messageID)) { auto callback = _pendingInfoRequests.take(messageID); - callback(error != NO_ERROR, info); + callback(error == NO_ERROR, info); } } @@ -149,7 +150,7 @@ void AssetClient::handleAssetGetReply(QSharedPointer packetList, S if (_pendingRequests.contains(messageID)) { auto callback = _pendingRequests.take(messageID); - callback(!error, data); + callback(error == NO_ERROR, data); } } @@ -159,7 +160,7 @@ bool AssetClient::uploadAsset(QByteArray data, QString extension, UploadResultCa if (assetServer) { auto packetList = std::unique_ptr(new NLPacketList(PacketType::AssetUpload, QByteArray(), true, true)); - auto messageID = _currentID++; + auto messageID = ++_currentID; packetList->writePrimitive(messageID); packetList->writePrimitive(static_cast(extension.length())); @@ -185,23 +186,23 @@ void AssetClient::handleAssetUploadReply(QSharedPointer packet, Shared MessageID messageID; packet->readPrimitive(&messageID); - bool success; - packet->readPrimitive(&success); + AssetServerError error; + packet->readPrimitive(&error); QString hashString { "" }; - if (success) { + if (error) { + qDebug() << "Error uploading file to asset server"; + } else { auto hashData = packet->read(HASH_HEX_LENGTH); hashString = QString(hashData); qDebug() << "Successfully uploaded asset to asset-server - SHA256 hash is " << hashString; - } else { - qDebug() << "Error uploading file to asset server"; } if (_pendingUploads.contains(messageID)) { auto callback = _pendingUploads.take(messageID); - callback(success, hashString); + callback(error == NO_ERROR, hashString); } } From 15854c6715bb20f02f325aed98eba5f60d31a4d2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 09:31:34 -0700 Subject: [PATCH 412/549] Make AssetClient methods private --- libraries/networking/src/AssetClient.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 5e26ff18b6..ef10cc2ea8 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -37,10 +37,6 @@ public: AssetClient(); Q_INVOKABLE AssetRequest* create(QString hash); - bool getAssetInfo(QString hash, GetInfoCallback callback); - bool getAsset(QString hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback); - bool uploadAsset(QByteArray data, QString extension, UploadResultCallback callback); - bool abortDataRequest(MessageID messageID); private slots: void handleAssetGetInfoReply(QSharedPointer packet, SharedNodePointer senderNode); @@ -48,6 +44,13 @@ private slots: void handleAssetUploadReply(QSharedPointer packet, SharedNodePointer senderNode); private: + friend class AssetRequest; + friend class Menu; + + bool getAssetInfo(QString hash, GetInfoCallback callback); + bool getAsset(QString hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback); + bool uploadAsset(QByteArray data, QString extension, UploadResultCallback callback); + static MessageID _currentID; QHash _pendingRequests; QHash _pendingInfoRequests; From 92dbe9997c52a2aa44cd069927ed909dd5b37211 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 09:31:50 -0700 Subject: [PATCH 413/549] Clean up AssetRequest --- libraries/networking/src/AssetRequest.cpp | 7 +------ libraries/networking/src/AssetRequest.h | 23 +---------------------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index d3863a5882..9e77899961 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -27,7 +27,6 @@ AssetRequest::AssetRequest(QObject* parent, QString hash) : void AssetRequest::start() { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); - //(&AssetRequest::start) return; } @@ -38,7 +37,7 @@ void AssetRequest::start() { assetClient->getAssetInfo(_hash, [this](bool success, AssetInfo info) { _info = info; _data.resize(info.size); - const DataOffset CHUNK_SIZE = 1024; + const DataOffset CHUNK_SIZE = 1024000000; qDebug() << "Got size of " << _hash << " : " << info.size << " bytes"; @@ -72,7 +71,3 @@ void AssetRequest::start() { }); } } - -const QByteArray& AssetRequest::getData() { - return _data; -} diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index 402aacad09..1e3e3e2f27 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -19,18 +19,6 @@ #include "AssetUtils.h" -// You should be able to get an asset from any thread, and handle the responses in a safe way -// on your own thread. Everything should happen on AssetClient's thread, the caller should -// receive events by connecting to signals on an object that lives on AssetClient's threads. - -// Receives parts of an asset and puts them together -// Emits signals: -// Progress -// Completion, success or error -// On finished, the AssetClient is effectively immutable and can be read from -// any thread safely -// -// Will often make multiple requests to the AssetClient to get data class AssetRequest : public QObject { Q_OBJECT public: @@ -51,16 +39,8 @@ public: AssetRequest(QObject* parent, QString hash); Q_INVOKABLE void start(); - //AssetRequest* requestAsset(QString hash); - // Create AssetRequest - // Start request for hash - // Store messageID -> AssetRequest - // When complete: - // Update AssetRequest - // AssetRequest emits signal - void receiveData(DataOffset start, DataOffset end, QByteArray data); - const QByteArray& getData(); + const QByteArray& getData() { return _data; } signals: void finished(AssetRequest*); @@ -74,7 +54,6 @@ private: QString _hash; QByteArray _data; int _numPendingRequests { 0 }; - // Timeout }; #endif From 8765329a46a882ddf3e71a8dcf528321da2e2434 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 09:32:39 -0700 Subject: [PATCH 414/549] Add ASSET_TOO_LARGE to AssetUtils --- libraries/networking/src/AssetUtils.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index c23b54de5d..cc5b2a281f 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -16,12 +16,14 @@ using MessageID = uint32_t; using DataOffset = int64_t; -const int HASH_HEX_LENGTH = 64; +const size_t HASH_HEX_LENGTH = 64; +const uint64_t MAX_UPLOAD_SIZE = 1000 * 1000 * 1000; // 1GB enum AssetServerError : uint8_t { NO_ERROR = 0, ASSET_NOT_FOUND, INVALID_BYTE_RANGE, + ASSET_TOO_LARGE, }; #endif From 667db200c032456569cd090cc6155f3413cbb992 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 09:39:12 -0700 Subject: [PATCH 415/549] Cleanup BatchLoader --- libraries/networking/src/ResourceCache.cpp | 1 - libraries/script-engine/src/BatchLoader.cpp | 41 ++------------------- 2 files changed, 3 insertions(+), 39 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 71e3de8254..c24c2f5075 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -190,7 +190,6 @@ void ResourceCache::requestCompleted(Resource* resource) { i++; } if (highestIndex >= 0) { - qDebug() << "trying to attempt a pending request"; attemptRequest(sharedItems->_pendingRequests.takeAt(highestIndex)); } } diff --git a/libraries/script-engine/src/BatchLoader.cpp b/libraries/script-engine/src/BatchLoader.cpp index 58145c2ef3..109b715df6 100644 --- a/libraries/script-engine/src/BatchLoader.cpp +++ b/libraries/script-engine/src/BatchLoader.cpp @@ -50,47 +50,12 @@ void BatchLoader::start() { checkFinished(); }); + // If we end up being destroyed before the reply finishes, clean it up + connect(this, &QObject::destroyed, request, &QObject::deleteLater); + qCDebug(scriptengine) << "Loading script at " << url; request->send(); - -// if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") { -// QNetworkRequest request = QNetworkRequest(url); -// request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); -// QNetworkReply* reply = networkAccessManager.get(request); -// -// qCDebug(scriptengine) << "Downloading file at" << url; -// -// connect(reply, &QNetworkReply::finished, [=]() { -// if (reply->error()) { -// _data.insert(url, QString()); -// } else { -// _data.insert(url, reply->readAll()); -// } -// reply->deleteLater(); -// checkFinished(); -// }); -// -// // If we end up being destroyed before the reply finishes, clean it up -// connect(this, &QObject::destroyed, reply, &QObject::deleteLater); -// -// } else { -// #ifdef _WIN32 -// QString fileName = url.toString(); -// #else -// QString fileName = url.toLocalFile(); -// #endif -// -// qCDebug(scriptengine) << "Reading file at " << fileName; -// -// QFile scriptFile(fileName); -// if (scriptFile.open(QFile::ReadOnly | QFile::Text)) { -// QTextStream in(&scriptFile); -// _data.insert(url, in.readAll()); -// } else { -// _data.insert(url, QString()); -// } -// } } checkFinished(); } From 1d45293184e152e09e4be030a21e8093a19b67cb Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 09:56:26 -0700 Subject: [PATCH 416/549] Fix lambda callback affinity in BatchLoader --- libraries/script-engine/src/BatchLoader.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/script-engine/src/BatchLoader.cpp b/libraries/script-engine/src/BatchLoader.cpp index 109b715df6..01e4a5e869 100644 --- a/libraries/script-engine/src/BatchLoader.cpp +++ b/libraries/script-engine/src/BatchLoader.cpp @@ -34,13 +34,12 @@ void BatchLoader::start() { } _started = true; - // QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); for (QUrl url : _urls) { auto request = ResourceManager::createResourceRequest(this, url); if (!request) { continue; } - connect(request, &ResourceRequest::finished, [=]() { + connect(request, &ResourceRequest::finished, this, [=]() { if (request->getResult() == ResourceRequest::SUCCESS) { _data.insert(url, request->getData()); } else { From 628f275013a3ac226e413aaab91a3456d6bbd348 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 10:07:53 -0700 Subject: [PATCH 417/549] Fix asset server upload errors --- assignment-client/src/assets/AssetServer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 6b50edbf2f..d1bea55f36 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -162,7 +162,7 @@ void AssetServer::handleAssetUpload(QSharedPointer packetList, Sha replyPacket->writePrimitive(messageID); if (fileSize > MAX_UPLOAD_SIZE) { - replyPacket->writePrimitive(false); + replyPacket->writePrimitive(AssetServerError::ASSET_TOO_LARGE); } else { QByteArray fileData = buffer.read(fileSize); @@ -179,7 +179,7 @@ void AssetServer::handleAssetUpload(QSharedPointer packetList, Sha file.write(fileData); file.close(); } - replyPacket->writePrimitive(true); + replyPacket->writePrimitive(AssetServerError::NO_ERROR); replyPacket->write(hash.toLatin1()); } From 513cae0d401abb68e7eca391a987a3dc1138b039 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 10:23:02 -0700 Subject: [PATCH 418/549] thread the AssetUpload so it doesn't take over main --- assignment-client/src/assets/AssetServer.cpp | 5 -- .../src/octree/OctreePacketProcessor.cpp | 5 +- interface/src/ui/AssetUploadDialogFactory.cpp | 75 ++++++++++++++----- interface/src/ui/AssetUploadDialogFactory.h | 4 + libraries/networking/src/AssetClient.cpp | 29 +++++-- libraries/networking/src/AssetClient.h | 16 ++-- .../networking/src/AssetResourceRequest.cpp | 2 +- libraries/networking/src/AssetUpload.cpp | 53 +++++++++++++ libraries/networking/src/AssetUpload.h | 47 ++++++++++++ libraries/networking/src/AssetUtils.h | 2 + 10 files changed, 201 insertions(+), 37 deletions(-) create mode 100644 libraries/networking/src/AssetUpload.cpp create mode 100644 libraries/networking/src/AssetUpload.h diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 2c294e652c..281257e904 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -80,11 +80,6 @@ void AssetServer::run() { file.rename(_resourcesDirectory.absoluteFilePath(hash)); } } - - while (!_isFinished) { - // since we're a while loop we need to help Qt's event processing - QCoreApplication::processEvents(); - } } void AssetServer::handleAssetGetInfo(QSharedPointer packet, SharedNodePointer senderNode) { diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index 5b8ff78fad..4a92e7e8ac 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -18,9 +18,8 @@ OctreePacketProcessor::OctreePacketProcessor() { auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - - packetReceiver.registerDirectListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, - PacketType::EntityErase, PacketType::OctreeStats }, + + packetReceiver.registerDirectListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, this, "handleOctreePacket"); } diff --git a/interface/src/ui/AssetUploadDialogFactory.cpp b/interface/src/ui/AssetUploadDialogFactory.cpp index 79e3cfa2db..a948ba54ba 100644 --- a/interface/src/ui/AssetUploadDialogFactory.cpp +++ b/interface/src/ui/AssetUploadDialogFactory.cpp @@ -12,10 +12,15 @@ #include "AssetUploadDialogFactory.h" #include +#include +#include #include -#include +#include #include +#include +#include +#include AssetUploadDialogFactory& AssetUploadDialogFactory::getInstance() { static AssetUploadDialogFactory staticInstance; @@ -27,29 +32,63 @@ AssetUploadDialogFactory::AssetUploadDialogFactory() { } void AssetUploadDialogFactory::showDialog() { - auto filename = QFileDialog::getOpenFileUrl(nullptr, "Select a file to upload"); + auto filename = QFileDialog::getOpenFileUrl(_dialogParent, "Select a file to upload"); if (!filename.isEmpty()) { qDebug() << "Selected filename for upload to asset-server: " << filename; - QFile file { filename.path() }; + auto assetClient = DependencyManager::get(); + auto upload = assetClient->createUpload(filename.path()); - if (file.open(QIODevice::ReadOnly)) { + if (upload) { + // connect to the finished signal so we know when the AssetUpload is done + QObject::connect(upload, &AssetUpload::finished, this, &AssetUploadDialogFactory::handleUploadFinished); - QFileInfo fileInfo { filename.path() }; - auto extension = fileInfo.suffix(); - - auto data = file.readAll(); - - auto assetClient = DependencyManager::get(); - - assetClient->uploadAsset(data, extension, [this, extension](bool result, QString hash) mutable { - if (result) { - QMessageBox::information(_dialogParent, "Upload Successful", "URL: apt:/" + hash + "." + extension); - } else { - QMessageBox::warning(_dialogParent, "Upload Failed", "There was an error uploading the file."); - } - }); + // start the upload now + upload->start(); } } } + +void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const QString& hash) { + if (true) { + // show message box for successful upload, with copiable text for ATP hash + QDialog* hashCopyDialog = new QDialog(_dialogParent); + + // delete the dialog on close + hashCopyDialog->setAttribute(Qt::WA_DeleteOnClose); + + // set the window title + hashCopyDialog->setWindowTitle(tr("Successful Asset Upload")); + + // setup a layout for the contents of the dialog + QVBoxLayout* boxLayout = new QVBoxLayout; + + // set the label text (this shows above the text box) + QLabel* lineEditLabel = new QLabel; + lineEditLabel->setText(QString("ATP URL for %1").arg(upload->getFilename())); + + // setup the line edit to hold the copiable text + QLineEdit* lineEdit = new QLineEdit; + + // set the ATP URL as the text value so it's copiable + lineEdit->insert(QString("%1://%2").arg(ATP_SCHEME).arg(hash)); + + // add the label and line edit to the dialog + boxLayout->addWidget(lineEditLabel); + boxLayout->addWidget(lineEdit); + + // setup an OK button to close the dialog + QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); + connect(buttonBox, &QDialogButtonBox::accepted, hashCopyDialog, &QDialog::close); + boxLayout->addWidget(buttonBox); + + // set the new layout on the dialog + hashCopyDialog->setLayout(boxLayout); + + // show the new dialog + hashCopyDialog->show(); + } else { + // + } +} diff --git a/interface/src/ui/AssetUploadDialogFactory.h b/interface/src/ui/AssetUploadDialogFactory.h index 3d830aa4bb..0d3372cb03 100644 --- a/interface/src/ui/AssetUploadDialogFactory.h +++ b/interface/src/ui/AssetUploadDialogFactory.h @@ -16,6 +16,8 @@ #include +class AssetUpload; + class AssetUploadDialogFactory : public QObject { Q_OBJECT public: @@ -28,6 +30,8 @@ public: void setDialogParent(QWidget* dialogParent) { _dialogParent = dialogParent; } public slots: void showDialog(); +private slots: + void handleUploadFinished(AssetUpload* upload, const QString& hash); private: QWidget* _dialogParent { nullptr }; }; diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 3877f05fe9..78ddd5e6e0 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -14,6 +14,7 @@ #include #include "AssetRequest.h" +#include "AssetUpload.h" #include "NodeList.h" #include "PacketReceiver.h" @@ -27,7 +28,7 @@ AssetClient::AssetClient() { packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); } -AssetRequest* AssetClient::create(QString hash) { +AssetRequest* AssetClient::createRequest(QString hash) { if (QThread::currentThread() != thread()) { AssetRequest* req; QMetaObject::invokeMethod(this, "create", @@ -46,15 +47,32 @@ AssetRequest* AssetClient::create(QString hash) { SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); if (assetServer) { - auto assetClient = DependencyManager::get(); - auto request = new AssetRequest(assetClient.data(), hash); - - return request; + return new AssetRequest(this, hash); } return nullptr; } +AssetUpload* AssetClient::createUpload(QString filename) { + if (QThread::currentThread() != thread()) { + AssetUpload* upload; + QMetaObject::invokeMethod(this, "createUpload", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(AssetUpload*, upload), + Q_ARG(QString, filename)); + return upload; + } + + auto nodeList = DependencyManager::get(); + SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + + if (assetServer) { + return new AssetUpload(this, filename); + } + + return nullptr; +} + bool AssetClient::getAsset(QString hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback) { if (hash.length() != HASH_HEX_LENGTH) { qDebug() << "Invalid hash size"; @@ -156,6 +174,7 @@ void AssetClient::handleAssetGetReply(QSharedPointer packetList, S bool AssetClient::uploadAsset(QByteArray data, QString extension, UploadResultCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); + if (assetServer) { auto packetList = std::unique_ptr(new NLPacketList(PacketType::AssetUpload, QByteArray(), true, true)); diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 5e26ff18b6..9bd3b98be6 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -21,6 +21,7 @@ #include "NLPacket.h" class AssetRequest; +class AssetUpload; struct AssetInfo { QString hash; @@ -36,11 +37,8 @@ class AssetClient : public QObject, public Dependency { public: AssetClient(); - Q_INVOKABLE AssetRequest* create(QString hash); - bool getAssetInfo(QString hash, GetInfoCallback callback); - bool getAsset(QString hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback); - bool uploadAsset(QByteArray data, QString extension, UploadResultCallback callback); - bool abortDataRequest(MessageID messageID); + Q_INVOKABLE AssetRequest* createRequest(QString hash); + Q_INVOKABLE AssetUpload* createUpload(QString filename); private slots: void handleAssetGetInfoReply(QSharedPointer packet, SharedNodePointer senderNode); @@ -48,10 +46,18 @@ private slots: void handleAssetUploadReply(QSharedPointer packet, SharedNodePointer senderNode); private: + bool getAssetInfo(QString hash, GetInfoCallback callback); + bool getAsset(QString hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback); + bool uploadAsset(QByteArray data, QString extension, UploadResultCallback callback); + bool abortDataRequest(MessageID messageID); + static MessageID _currentID; QHash _pendingRequests; QHash _pendingInfoRequests; QHash _pendingUploads; + + friend class AssetRequest; + friend class AssetUpload; }; #endif diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index c29a54a787..7c58a5cb9b 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -18,7 +18,7 @@ void ATPResourceRequest::doSend() { auto assetClient = DependencyManager::get(); auto hash = _url.path(); - auto request = assetClient->create(hash); + auto request = assetClient->createRequest(hash); if (!request) { return; diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp new file mode 100644 index 0000000000..806709a6d6 --- /dev/null +++ b/libraries/networking/src/AssetUpload.cpp @@ -0,0 +1,53 @@ +// +// AssetUpload.cpp +// libraries/networking/src +// +// Created by Stephen Birarda on 2015-08-26. +// Copyright 2015 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 "AssetUpload.h" + +#include +#include + +#include "AssetClient.h" + +AssetUpload::AssetUpload(QObject* object, const QString& filename) : + _filename(filename) +{ + +} + +void AssetUpload::start() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "start", Qt::AutoConnection); + return; + } + + // try to open the file at the given filename + QFile file { _filename }; + + if (file.open(QIODevice::ReadOnly)) { + + // file opened, read the data and grab the extension + auto extension = QFileInfo(_filename).suffix(); + + auto data = file.readAll(); + + // ask the AssetClient to upload the asset and emit the proper signals from the passed callback + auto assetClient = DependencyManager::get(); + + assetClient->uploadAsset(data, extension, [this](bool result, QString hash){ + if (result) { + // successful upload - emit finished with a point to ourselves and the resulting hash + emit finished(this, hash); + } else { + + } + }); + } +} diff --git a/libraries/networking/src/AssetUpload.h b/libraries/networking/src/AssetUpload.h new file mode 100644 index 0000000000..c8921fcf84 --- /dev/null +++ b/libraries/networking/src/AssetUpload.h @@ -0,0 +1,47 @@ +// +// AssetUpload.h +// libraries/networking/src +// +// Created by Stephen Birarda on 2015-08-26. +// Copyright 2015 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 +// + +#pragma once + +#ifndef hifi_AssetUpload_h +#define hifi_AssetUpload_h + +#include + +// You should be able to upload an asset from any thread, and handle the responses in a safe way +// on your own thread. Everything should happen on AssetClient's thread, the caller should +// receive events by connecting to signals on an object that lives on AssetClient's threads. + +class AssetUpload : public QObject { + Q_OBJECT +public: + + enum Result { + Success = 0, + Timeout, + TooLarge, + }; + + AssetUpload(QObject* parent, const QString& filename); + + Q_INVOKABLE void start(); + + const QString& getFilename() const { return _filename; } + +signals: + void finished(AssetUpload* upload, const QString& hash); + void progress(uint64_t totalReceived, uint64_t total); + +private: + QString _filename; +}; + +#endif // hifi_AssetUpload_h diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index c23b54de5d..55091d7a7e 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -24,4 +24,6 @@ enum AssetServerError : uint8_t { INVALID_BYTE_RANGE, }; +const QString ATP_SCHEME = "atp"; + #endif From c6493b1720e9a3c26fa322a28396de62a2ae4bab Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 10:27:12 -0700 Subject: [PATCH 419/549] Remove extension from hash in AssetResourceRequest --- libraries/networking/src/AssetResourceRequest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index c29a54a787..5cf1faad88 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -16,7 +16,7 @@ void ATPResourceRequest::doSend() { // Make request to atp auto assetClient = DependencyManager::get(); - auto hash = _url.path(); + auto hash = _url.path().split(".", QString::SkipEmptyParts)[0]; auto request = assetClient->create(hash); From f92ee597e5a4038929c2a6c462c107d35da7b9a0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 11:32:03 -0700 Subject: [PATCH 420/549] fix width of asset upload dialog to fit ATP url --- interface/src/ui/AssetUploadDialogFactory.cpp | 20 +++++++++++++++++-- libraries/networking/src/AssetClient.cpp | 5 ++++- libraries/networking/src/AssetRequest.cpp | 1 + 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/AssetUploadDialogFactory.cpp b/interface/src/ui/AssetUploadDialogFactory.cpp index a948ba54ba..8a431ac55f 100644 --- a/interface/src/ui/AssetUploadDialogFactory.cpp +++ b/interface/src/ui/AssetUploadDialogFactory.cpp @@ -46,6 +46,8 @@ void AssetUploadDialogFactory::showDialog() { // start the upload now upload->start(); + } else { + // TODO: show a QMessageBox to say that there is no local asset server } } } @@ -66,13 +68,27 @@ void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const Q // set the label text (this shows above the text box) QLabel* lineEditLabel = new QLabel; - lineEditLabel->setText(QString("ATP URL for %1").arg(upload->getFilename())); + lineEditLabel->setText(QString("ATP URL for %1").arg(QFileInfo(upload->getFilename()).fileName())); // setup the line edit to hold the copiable text QLineEdit* lineEdit = new QLineEdit; + + QString atpURL = QString("%1://%2").arg(ATP_SCHEME).arg(hash); // set the ATP URL as the text value so it's copiable - lineEdit->insert(QString("%1://%2").arg(ATP_SCHEME).arg(hash)); + lineEdit->insert(atpURL); + + // figure out what size this line edit should be using font metrics + QFontMetrics textMetrics { lineEdit->font() }; + + // set the fixed width on the line edit + // pad it by 10 to cover the border and some extra space on the right side (for clicking) + static const int LINE_EDIT_RIGHT_PADDING { 10 }; + + lineEdit->setFixedWidth(textMetrics.width(atpURL) + LINE_EDIT_RIGHT_PADDING ); + + // left align the ATP URL line edit + lineEdit->home(true); // add the label and line edit to the dialog boxLayout->addWidget(lineEditLabel); diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 8e4ae48078..b06593da0a 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -32,7 +32,7 @@ AssetClient::AssetClient() { AssetRequest* AssetClient::createRequest(QString hash) { if (QThread::currentThread() != thread()) { AssetRequest* req; - QMetaObject::invokeMethod(this, "create", + QMetaObject::invokeMethod(this, "createRequest", Qt::BlockingQueuedConnection, Q_RETURN_ARG(AssetRequest*, req), Q_ARG(QString, hash)); @@ -87,6 +87,9 @@ bool AssetClient::getAsset(QString hash, DataOffset start, DataOffset end, Recei auto packet = NLPacket::create(PacketType::AssetGet); auto messageID = ++_currentID; + + qDebug() << "Requesting data from" << start << "to" << end << "of" << hash << "from asset-server."; + packet->writePrimitive(messageID); packet->write(hash.toLatin1().constData(), HASH_HEX_LENGTH); packet->writePrimitive(start); diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 9e77899961..1d9f21c329 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -48,6 +48,7 @@ void AssetRequest::start() { ++_numPendingRequests; auto start = i * CHUNK_SIZE; auto end = std::min((i + 1) * CHUNK_SIZE, info.size); + assetClient->getAsset(_hash, start, end, [this, start, end](bool success, QByteArray data) { Q_ASSERT(data.size() == (end - start)); From b3bd94c8db7aaf47ae8cba4e319fec9298c75e2a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 11:37:27 -0700 Subject: [PATCH 421/549] show a QMessageBox if not connected to asset-server --- interface/src/ui/AssetUploadDialogFactory.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/AssetUploadDialogFactory.cpp b/interface/src/ui/AssetUploadDialogFactory.cpp index 8a431ac55f..9e8d909a6e 100644 --- a/interface/src/ui/AssetUploadDialogFactory.cpp +++ b/interface/src/ui/AssetUploadDialogFactory.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -47,7 +48,11 @@ void AssetUploadDialogFactory::showDialog() { // start the upload now upload->start(); } else { - // TODO: show a QMessageBox to say that there is no local asset server + // show a QMessageBox to say that there is no local asset server + QString messageBoxText = QString("Could not upload \n\n%1\n\nbecause you are currently not connected" \ + " to a local asset-server.").arg(QFileInfo(filename.toString()).fileName()); + + QMessageBox::information(_dialogParent, "Failed to Upload", messageBoxText); } } } From a49a1eb0d6db9b061dfc2ba8290b6820f7c6d8e1 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 11:51:45 -0700 Subject: [PATCH 422/549] Add extension to atp requests --- assignment-client/src/assets/AssetServer.cpp | 24 ++++++++++++------- .../src/assets/SendAssetTask.cpp | 6 ++--- libraries/networking/src/AssetClient.cpp | 20 +++++++++++----- libraries/networking/src/AssetClient.h | 6 ++--- libraries/networking/src/AssetRequest.cpp | 9 +++---- libraries/networking/src/AssetRequest.h | 7 +++--- .../networking/src/AssetResourceRequest.cpp | 12 ++++++---- .../networking/src/AssetResourceRequest.h | 4 ++-- libraries/networking/src/ResourceManager.cpp | 2 +- 9 files changed, 55 insertions(+), 35 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index d1bea55f36..c6ad9f0f4d 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -77,7 +77,7 @@ void AssetServer::run() { qDebug() << "\tMoving " << filename << " to " << hash; - file.rename(_resourcesDirectory.absoluteFilePath(hash)); + file.rename(_resourcesDirectory.absoluteFilePath(hash) + "." + fileInfo.suffix()); } } } @@ -85,24 +85,28 @@ void AssetServer::run() { void AssetServer::handleAssetGetInfo(QSharedPointer packet, SharedNodePointer senderNode) { QByteArray assetHash; MessageID messageID; + uint8_t extensionLength; - if (packet->getPayloadSize() < qint64(HASH_HEX_LENGTH + sizeof(messageID))) { + if (packet->getPayloadSize() < qint64(HASH_HEX_LENGTH + sizeof(messageID) + sizeof(extensionLength))) { qDebug() << "ERROR bad file request"; return; } packet->readPrimitive(&messageID); assetHash = packet->readWithoutCopy(HASH_HEX_LENGTH); + packet->readPrimitive(&extensionLength); + QByteArray extension = packet->read(extensionLength); auto replyPacket = NLPacket::create(PacketType::AssetGetInfoReply); replyPacket->writePrimitive(messageID); replyPacket->write(assetHash); - QFileInfo fileInfo { _resourcesDirectory.filePath(QString(assetHash)) }; - qDebug() << "Opening file: " << QString(QFileInfo(assetHash).fileName()); + QString fileName = QString(assetHash) + "." + extension; + QFileInfo fileInfo { _resourcesDirectory.filePath(fileName) }; if (fileInfo.exists() && fileInfo.isReadable()) { + qDebug() << "Opening file: " << fileInfo.filePath(); replyPacket->writePrimitive(AssetServerError::NO_ERROR); replyPacket->writePrimitive(fileInfo.size()); } else { @@ -117,23 +121,27 @@ void AssetServer::handleAssetGetInfo(QSharedPointer packet, SharedNode void AssetServer::handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode) { MessageID messageID; QByteArray assetHash; + uint8_t extensionLength; DataOffset start; DataOffset end; - if (packet->getPayloadSize() < qint64(sizeof(messageID) + HASH_HEX_LENGTH + sizeof(start) + sizeof(end))) { + auto minSize = qint64(sizeof(messageID) + HASH_HEX_LENGTH + sizeof(extensionLength) + sizeof(start) + sizeof(end)); + if (packet->getPayloadSize() < minSize) { qDebug() << "ERROR bad file request"; return; } packet->readPrimitive(&messageID); assetHash = packet->read(HASH_HEX_LENGTH); + packet->readPrimitive(&extensionLength); + QByteArray extension = packet->read(extensionLength); packet->readPrimitive(&start); packet->readPrimitive(&end); - qDebug() << "Received a request for the file: " << assetHash << " from " << start << " to " << end; + qDebug() << "Received a request for the file (" << messageID << "): " << assetHash << " from " << start << " to " << end; // Queue task - QString filePath = _resourcesDirectory.filePath(QString(assetHash)); + QString filePath = _resourcesDirectory.filePath(QString(assetHash) + "." + QString(extension)); auto task = new SendAssetTask(messageID, assetHash, filePath, start, end, senderNode); _taskPool.start(task); } @@ -170,7 +178,7 @@ void AssetServer::handleAssetUpload(QSharedPointer packetList, Sha qDebug() << "Got data: (" << hash << ") "; - QFile file { _resourcesDirectory.filePath(QString(hash)) }; + QFile file { _resourcesDirectory.filePath(QString(hash)) + "." + QString(extension) }; if (file.exists()) { qDebug() << "[WARNING] This file already exists: " << hash; diff --git a/assignment-client/src/assets/SendAssetTask.cpp b/assignment-client/src/assets/SendAssetTask.cpp index 84c3a33c9f..f30689b042 100644 --- a/assignment-client/src/assets/SendAssetTask.cpp +++ b/assignment-client/src/assets/SendAssetTask.cpp @@ -36,7 +36,7 @@ void SendAssetTask::run() { qDebug() << "Starting task to send asset: " << _assetHash << " for messageID " << _messageID; auto replyPacketList = std::unique_ptr(new NLPacketList(PacketType::AssetGetReply, QByteArray(), true, true)); - replyPacketList->write(_assetHash, HASH_HEX_LENGTH); + replyPacketList->write(_assetHash); replyPacketList->writePrimitive(_messageID); @@ -55,11 +55,11 @@ void SendAssetTask::run() { replyPacketList->writePrimitive(AssetServerError::NO_ERROR); replyPacketList->writePrimitive(size); replyPacketList->write(file.read(size)); + qCDebug(networking) << "Sending asset: " << _assetHash; } file.close(); - qCDebug(networking) << "Sending asset: " << _assetHash; } else { - qCDebug(networking) << "Asset not found: " << _assetHash; + qCDebug(networking) << "Asset not found: " << _filePath << "(" << _assetHash << ")"; writeError(replyPacketList.get(), AssetServerError::ASSET_NOT_FOUND); } } diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index e72e05d5ff..f424171766 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -28,13 +28,14 @@ AssetClient::AssetClient() { packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); } -AssetRequest* AssetClient::create(QString hash) { +AssetRequest* AssetClient::create(QString hash, QString extension) { if (QThread::currentThread() != thread()) { AssetRequest* req; QMetaObject::invokeMethod(this, "create", Qt::BlockingQueuedConnection, Q_RETURN_ARG(AssetRequest*, req), - Q_ARG(QString, hash)); + Q_ARG(QString, hash), + Q_ARG(QString, extension)); return req; } @@ -48,7 +49,7 @@ AssetRequest* AssetClient::create(QString hash) { if (assetServer) { auto assetClient = DependencyManager::get(); - auto request = new AssetRequest(assetClient.data(), hash); + auto request = new AssetRequest(assetClient.data(), hash, extension); return request; } @@ -56,7 +57,7 @@ AssetRequest* AssetClient::create(QString hash) { return nullptr; } -bool AssetClient::getAsset(QString hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback) { +bool AssetClient::getAsset(QString hash, QString extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback) { if (hash.length() != HASH_HEX_LENGTH) { qDebug() << "Invalid hash size"; return false; @@ -70,7 +71,12 @@ bool AssetClient::getAsset(QString hash, DataOffset start, DataOffset end, Recei auto messageID = ++_currentID; packet->writePrimitive(messageID); - packet->write(hash.toLatin1().constData(), HASH_HEX_LENGTH); + + packet->write(hash.toLatin1()); + + packet->writePrimitive(uint8_t(extension.length())); + packet->write(extension.toLatin1()); + packet->writePrimitive(start); packet->writePrimitive(end); @@ -84,7 +90,7 @@ bool AssetClient::getAsset(QString hash, DataOffset start, DataOffset end, Recei return false; } -bool AssetClient::getAssetInfo(QString hash, GetInfoCallback callback) { +bool AssetClient::getAssetInfo(QString hash, QString extension, GetInfoCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); @@ -94,6 +100,8 @@ bool AssetClient::getAssetInfo(QString hash, GetInfoCallback callback) { auto messageID = ++_currentID; packet->writePrimitive(messageID); packet->write(hash.toLatin1().constData(), HASH_HEX_LENGTH); + packet->writePrimitive(uint8_t(extension.length())); + packet->write(extension.toLatin1()); nodeList->sendPacket(std::move(packet), *assetServer); diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index ef10cc2ea8..0e81c6cfa2 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -36,7 +36,7 @@ class AssetClient : public QObject, public Dependency { public: AssetClient(); - Q_INVOKABLE AssetRequest* create(QString hash); + Q_INVOKABLE AssetRequest* create(QString hash, QString extension); private slots: void handleAssetGetInfoReply(QSharedPointer packet, SharedNodePointer senderNode); @@ -47,8 +47,8 @@ private: friend class AssetRequest; friend class Menu; - bool getAssetInfo(QString hash, GetInfoCallback callback); - bool getAsset(QString hash, DataOffset start, DataOffset end, ReceivedAssetCallback callback); + bool getAssetInfo(QString hash, QString extension, GetInfoCallback callback); + bool getAsset(QString hash, QString extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback); bool uploadAsset(QByteArray data, QString extension, UploadResultCallback callback); static MessageID _currentID; diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 9e77899961..87e39e1edd 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -18,9 +18,10 @@ #include "NodeList.h" -AssetRequest::AssetRequest(QObject* parent, QString hash) : +AssetRequest::AssetRequest(QObject* parent, QString hash, QString extension) : QObject(parent), - _hash(hash) + _hash(hash), + _extension(extension) { } @@ -34,7 +35,7 @@ void AssetRequest::start() { _state = WAITING_FOR_INFO; auto assetClient = DependencyManager::get(); - assetClient->getAssetInfo(_hash, [this](bool success, AssetInfo info) { + assetClient->getAssetInfo(_hash, _extension, [this](bool success, AssetInfo info) { _info = info; _data.resize(info.size); const DataOffset CHUNK_SIZE = 1024000000; @@ -48,7 +49,7 @@ void AssetRequest::start() { ++_numPendingRequests; auto start = i * CHUNK_SIZE; auto end = std::min((i + 1) * CHUNK_SIZE, info.size); - assetClient->getAsset(_hash, start, end, [this, start, end](bool success, QByteArray data) { + assetClient->getAsset(_hash, _extension, start, end, [this, start, end](bool success, QByteArray data) { Q_ASSERT(data.size() == (end - start)); if (success) { diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index 1e3e3e2f27..d1cc9c9b33 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -20,7 +20,7 @@ #include "AssetUtils.h" class AssetRequest : public QObject { - Q_OBJECT + Q_OBJECT public: enum State { NOT_STARTED = 0, @@ -36,7 +36,7 @@ public: Error, }; - AssetRequest(QObject* parent, QString hash); + AssetRequest(QObject* parent, QString hash, QString extension); Q_INVOKABLE void start(); @@ -44,7 +44,7 @@ public: signals: void finished(AssetRequest*); - void progress(uint64_t totalReceived, uint64_t total); + void progress(qint64 totalReceived, qint64 total); private: State _state = NOT_STARTED; @@ -52,6 +52,7 @@ private: AssetInfo _info; uint64_t _totalReceived { 0 }; QString _hash; + QString _extension; QByteArray _data; int _numPendingRequests { 0 }; }; diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 5cf1faad88..5a0af8ef1f 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -13,18 +13,20 @@ #include "AssetClient.h" #include "AssetRequest.h" -void ATPResourceRequest::doSend() { +void AssetResourceRequest::doSend() { // Make request to atp auto assetClient = DependencyManager::get(); - auto hash = _url.path().split(".", QString::SkipEmptyParts)[0]; + auto parts = _url.path().split(".", QString::SkipEmptyParts); + auto hash = parts[0]; + auto extension = parts.length() > 1 ? parts[1] : ""; - auto request = assetClient->create(hash); + auto request = assetClient->create(hash, extension); if (!request) { return; } - connect(request, &AssetRequest::progress, this, &ATPResourceRequest::progress); + connect(request, &AssetRequest::progress, this, &AssetResourceRequest::progress); QObject::connect(request, &AssetRequest::finished, [this](AssetRequest* req) mutable { if (_state != IN_PROGRESS) return; _state = FINISHED; @@ -41,7 +43,7 @@ void ATPResourceRequest::doSend() { request->start(); } -void ATPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { +void AssetResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { qDebug() << "Got asset data: " << bytesReceived << " / " << bytesTotal; emit progress(bytesReceived, bytesTotal); } diff --git a/libraries/networking/src/AssetResourceRequest.h b/libraries/networking/src/AssetResourceRequest.h index 34c1878b04..2cfd1d28b7 100644 --- a/libraries/networking/src/AssetResourceRequest.h +++ b/libraries/networking/src/AssetResourceRequest.h @@ -15,10 +15,10 @@ #include "ResourceRequest.h" -class ATPResourceRequest : public ResourceRequest { +class AssetResourceRequest : public ResourceRequest { Q_OBJECT public: - ATPResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } + AssetResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } protected: virtual void doSend() override; diff --git a/libraries/networking/src/ResourceManager.cpp b/libraries/networking/src/ResourceManager.cpp index cfa7513a1a..b8e3eeeae7 100644 --- a/libraries/networking/src/ResourceManager.cpp +++ b/libraries/networking/src/ResourceManager.cpp @@ -29,7 +29,7 @@ ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const Q } else if (scheme == URL_SCHEME_HTTP || scheme == URL_SCHEME_HTTPS || scheme == URL_SCHEME_FTP) { return new HTTPResourceRequest(parent, url); } else if (scheme == URL_SCHEME_ATP) { - return new ATPResourceRequest(parent, url); + return new AssetResourceRequest(parent, url); } qDebug() << "Failed to load: " << url.url(); From c212ef5734f3894eb949d67fe67d863b6e73fbac Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 12:01:24 -0700 Subject: [PATCH 423/549] fix PacketReceiver cleanup, return permission error for upload --- assignment-client/src/assets/AssetServer.cpp | 22 +++++++++++++++++++ interface/src/ui/AssetUploadDialogFactory.cpp | 20 +++++++++++++++-- libraries/networking/src/AssetUpload.cpp | 12 ++++++++-- libraries/networking/src/AssetUpload.h | 3 +++ libraries/networking/src/AssetUtils.h | 1 + libraries/networking/src/PacketReceiver.cpp | 14 ++++++------ 6 files changed, 61 insertions(+), 11 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index d1bea55f36..9085828d88 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -139,6 +139,28 @@ void AssetServer::handleAssetGet(QSharedPointer packet, SharedNodePoin } void AssetServer::handleAssetUpload(QSharedPointer packetList, SharedNodePointer senderNode) { + + if (!senderNode->getCanRez()) { + // this is a node the domain told us is not allowed to rez entities + // for now this also means it isn't allowed to add assets + // so return a packet with error that indicates that + + auto permissionErrorPacket = NLPacket::create(PacketType::AssetUploadReply, sizeof(MessageID) + sizeof(AssetServerError)); + + MessageID defaultMessageID; + + // write the default message ID and permission denied error + permissionErrorPacket->writePrimitive(defaultMessageID); + permissionErrorPacket->writePrimitive(AssetServerError::PERMISSION_DENIED); + + // send off the packet + auto nodeList = DependencyManager::get(); + nodeList->sendPacket(std::move(permissionErrorPacket), *senderNode); + + // return so we're not attempting to handle upload + return; + } + auto data = packetList->getMessage(); QBuffer buffer { &data }; buffer.open(QIODevice::ReadOnly); diff --git a/interface/src/ui/AssetUploadDialogFactory.cpp b/interface/src/ui/AssetUploadDialogFactory.cpp index 9e8d909a6e..6edf71e758 100644 --- a/interface/src/ui/AssetUploadDialogFactory.cpp +++ b/interface/src/ui/AssetUploadDialogFactory.cpp @@ -58,7 +58,7 @@ void AssetUploadDialogFactory::showDialog() { } void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const QString& hash) { - if (true) { + if (upload->getResult() == AssetUpload::Success) { // show message box for successful upload, with copiable text for ATP hash QDialog* hashCopyDialog = new QDialog(_dialogParent); @@ -110,6 +110,22 @@ void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const Q // show the new dialog hashCopyDialog->show(); } else { - // + // figure out the right error message for the message box + QString errorMessage = QString("Failed to upload %1.\n\n").arg(QFileInfo(upload->getFilename()).fileName()); + + switch (upload->getResult()) { + case AssetUpload::PermissionDenied: + errorMessage += "You do not have permission to upload content to this asset-server."; + break; + case AssetUpload::TooLarge: + errorMessage += "The uploaded content was too large and could not be stored in the asset-server."; + break; + default: + // not handled, do not show a message box + return; + } + + // display a message box with the error + QMessageBox::warning(_dialogParent, "Failed Upload", errorMessage); } } diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index 806709a6d6..b7c1fa1c34 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -41,12 +41,20 @@ void AssetUpload::start() { // ask the AssetClient to upload the asset and emit the proper signals from the passed callback auto assetClient = DependencyManager::get(); - assetClient->uploadAsset(data, extension, [this](bool result, QString hash){ - if (result) { + assetClient->uploadAsset(data, extension, [this](bool success, QString hash){ + if (success) { // successful upload - emit finished with a point to ourselves and the resulting hash + _result = Success; + emit finished(this, hash); } else { + // error during upload - emit finished with an empty hash + // callers can get the error from this object + // TODO: get the actual error from the callback + _result = PermissionDenied; + + emit finished(this, hash); } }); } diff --git a/libraries/networking/src/AssetUpload.h b/libraries/networking/src/AssetUpload.h index c8921fcf84..c969e4373e 100644 --- a/libraries/networking/src/AssetUpload.h +++ b/libraries/networking/src/AssetUpload.h @@ -28,6 +28,7 @@ public: Success = 0, Timeout, TooLarge, + PermissionDenied }; AssetUpload(QObject* parent, const QString& filename); @@ -35,6 +36,7 @@ public: Q_INVOKABLE void start(); const QString& getFilename() const { return _filename; } + const Result& getResult() const { return _result; } signals: void finished(AssetUpload* upload, const QString& hash); @@ -42,6 +44,7 @@ signals: private: QString _filename; + Result _result; }; #endif // hifi_AssetUpload_h diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index f484bcc49f..0cc71dab70 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -24,6 +24,7 @@ enum AssetServerError : uint8_t { ASSET_NOT_FOUND, INVALID_BYTE_RANGE, ASSET_TOO_LARGE, + PERMISSION_DENIED }; const QString ATP_SCHEME = "atp"; diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 035432cf4b..03827d19af 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -217,22 +217,22 @@ void PacketReceiver::unregisterListener(QObject* listener) { auto it = _packetListenerMap.begin(); while (it != _packetListenerMap.end()) { - if (it->first == listener) { + if (it.value().first == listener) { it = _packetListenerMap.erase(it); + } else { + ++it; } - - ++it; } // clear any registrations for this listener in _packetListListener - auto listIt = _packetListenerMap.end(); + auto listIt = _packetListListenerMap.begin(); while (listIt != _packetListListenerMap.end()) { - if (listIt->first == listener) { + if (listIt.value().first == listener) { listIt = _packetListListenerMap.erase(listIt); + } else { + ++listIt; } - - ++listIt; } } From 16eee10cabfeb82e898a023bc3c2052c09e9369a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 12:13:20 -0700 Subject: [PATCH 424/549] repairs to permission error for asset-server upload --- assignment-client/src/assets/AssetServer.cpp | 20 +++++++++----------- interface/src/Menu.h | 2 +- libraries/networking/src/udt/Connection.cpp | 4 ++++ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 9085828d88..347e79fd5c 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -140,6 +140,13 @@ void AssetServer::handleAssetGet(QSharedPointer packet, SharedNodePoin void AssetServer::handleAssetUpload(QSharedPointer packetList, SharedNodePointer senderNode) { + auto data = packetList->getMessage(); + QBuffer buffer { &data }; + buffer.open(QIODevice::ReadOnly); + + MessageID messageID; + buffer.read(reinterpret_cast(&messageID), sizeof(messageID)); + if (!senderNode->getCanRez()) { // this is a node the domain told us is not allowed to rez entities // for now this also means it isn't allowed to add assets @@ -147,10 +154,8 @@ void AssetServer::handleAssetUpload(QSharedPointer packetList, Sha auto permissionErrorPacket = NLPacket::create(PacketType::AssetUploadReply, sizeof(MessageID) + sizeof(AssetServerError)); - MessageID defaultMessageID; - - // write the default message ID and permission denied error - permissionErrorPacket->writePrimitive(defaultMessageID); + // write the message ID and a permission denied error + permissionErrorPacket->writePrimitive(messageID); permissionErrorPacket->writePrimitive(AssetServerError::PERMISSION_DENIED); // send off the packet @@ -160,13 +165,6 @@ void AssetServer::handleAssetUpload(QSharedPointer packetList, Sha // return so we're not attempting to handle upload return; } - - auto data = packetList->getMessage(); - QBuffer buffer { &data }; - buffer.open(QIODevice::ReadOnly); - - MessageID messageID; - buffer.read(reinterpret_cast(&messageID), sizeof(messageID)); uint8_t extensionLength; buffer.read(reinterpret_cast(&extensionLength), sizeof(extensionLength)); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 948e159b04..7dfd1bc8d8 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -288,7 +288,7 @@ namespace MenuOption { const QString ToolWindow = "Tool Window"; const QString TransmitterDrive = "Transmitter Drive"; const QString TurnWithHead = "Turn using Head"; - const QString UploadAsset = "Upload File to Local Asset Server"; + const QString UploadAsset = "Upload File to Asset Server"; const QString UseAudioForMouth = "Use Audio for Mouth"; const QString UseCamera = "Use Camera"; const QString VelocityFilter = "Velocity Filter"; diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 1fa4111f85..61e2ac2cdf 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -655,6 +655,7 @@ void Connection::processTimeoutNAK(std::unique_ptr controlPacket) } void Connection::resetReceiveState() { + // reset all SequenceNumber member variables back to default SequenceNumber defaultSequenceNumber; @@ -665,6 +666,9 @@ void Connection::resetReceiveState() { _lastSentACK = defaultSequenceNumber; + // clear the sent ACKs + _sentACKs.clear(); + // clear the loss list and _lastNAKTime _lossList.clear(); _lastNAKTime = high_resolution_clock::time_point(); From 229015a5dac56e531fb611c616e94bc6e2bcc658 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 12:21:38 -0700 Subject: [PATCH 425/549] don't allow asset-server upload if no server present --- interface/src/Application.cpp | 7 +++++++ interface/src/Menu.cpp | 12 +++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d94cff19f1..28cd315c4c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3782,6 +3782,9 @@ void Application::nodeAdded(SharedNodePointer node) { if (node->getType() == NodeType::AvatarMixer) { // new avatar mixer, send off our identity packet right away _myAvatar->sendIdentityPacket(); + } else if (node->getType() == NodeType::AssetServer) { + // the addition of an asset-server always re-enables the upload to asset server menu option + Menu::getInstance()->getActionForOption(MenuOption::UploadAsset)->setEnabled(true); } } @@ -3829,6 +3832,10 @@ void Application::nodeKilled(SharedNodePointer node) { } else if (node->getType() == NodeType::AvatarMixer) { // our avatar mixer has gone away - clear the hash of avatars DependencyManager::get()->clearOtherAvatars(); + } else if (node->getType() == NodeType::AssetServer + && !DependencyManager::get()->soloNodeOfType(NodeType::AssetServer)) { + // this was our last asset server - disable the menu option to upload an asset + Menu::getInstance()->getActionForOption(MenuOption::UploadAsset)->setEnabled(false); } } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 6c41a3d7da..6d5eff8fa0 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -376,11 +376,13 @@ Menu::Menu() { auto& assetDialogFactory = AssetUploadDialogFactory::getInstance(); assetDialogFactory.setParent(this); - addActionToQMenuAndActionHash(assetDeveloperMenu, - MenuOption::UploadAsset, - 0, - &AssetUploadDialogFactory::getInstance(), - SLOT(showDialog())); + QAction* assetUpload = addActionToQMenuAndActionHash(assetDeveloperMenu, + MenuOption::UploadAsset, + 0, + &AssetUploadDialogFactory::getInstance(), + SLOT(showDialog())); + // disable the asset upload action by default - it gets enabled only if asset server becomes present + assetUpload->setEnabled(false); MenuWrapper* avatarDebugMenu = developerMenu->addMenu("Avatar"); From b30a008162b08a0e7ad0bfdbe1bb57d1c496e384 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 12:48:55 -0700 Subject: [PATCH 426/549] Fix bug with NetworkTexture occasionally breaking on assert --- libraries/networking/src/ResourceCache.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index c24c2f5075..7ed5866707 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -206,7 +206,7 @@ Resource::Resource(const QUrl& url, bool delayLoad) : // start loading immediately unless instructed otherwise if (!(_startedLoading || delayLoad)) { - QTimer::singleShot(1, this, &Resource::attemptRequest); + QTimer::singleShot(0, this, &Resource::ensureLoading); } } @@ -333,8 +333,6 @@ void Resource::reinsert() { void Resource::makeRequest() { Q_ASSERT(!_request); - static const int REPLY_TIMEOUT_MS = 5000; - _request = ResourceManager::createResourceRequest(this, _activeUrl); if (!_request) { @@ -366,7 +364,7 @@ void Resource::handleReplyFinished() { auto result = _request->getResult(); if (result == ResourceRequest::SUCCESS) { _data = _request->getData(); - qDebug() << "Reqeust finsihed for " << _url << ", " << _activeUrl; + qDebug() << "Request finished for " << _url << ", " << _activeUrl; _request->disconnect(this); _request->deleteLater(); @@ -408,7 +406,8 @@ void Resource::handleReplyFinished() { break; } - emit failed(QNetworkReply::UnknownNetworkError); + auto error = result == ResourceRequest::TIMEOUT ? QNetworkReply::TimeoutError : QNetworkReply::UnknownNetworkError; + emit failed(error); if (!retry) { ResourceCache::requestCompleted(this); From 750080fe66582ddf6aee15b42e5df5b2f5a19624 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 12:52:01 -0700 Subject: [PATCH 427/549] Remove early return in Model::restoreJointPosition --- libraries/render-utils/src/Model.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b4f3949a93..9c6dcdfc9c 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1356,7 +1356,6 @@ void Model::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm: bool Model::restoreJointPosition(int jointIndex, float fraction, float priority) { QString url = _url.path(); const FBXGeometry& geometry = _geometry->getFBXGeometry(); - return true; const QVector& freeLineage = geometry.joints.at(jointIndex).freeLineage; return _rig->restoreJointPosition(jointIndex, fraction, priority, freeLineage); } From 33d6f561eb94238b31b5436990057eacae75a797 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 12:52:11 -0700 Subject: [PATCH 428/549] Reintroduce request limit in ResourceCache --- libraries/networking/src/ResourceCache.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 7ed5866707..e4ff88b9e3 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -154,12 +154,12 @@ void ResourceCache::clearUnusedResource() { void ResourceCache::attemptRequest(Resource* resource) { auto sharedItems = DependencyManager::get(); - // if (_requestLimit <= 0) { - // qDebug() << "REQUEST LIMIT REACHED (" << _requestLimit << "), queueing: " << resource->getURL(); - // // wait until a slot becomes available - // sharedItems->_pendingRequests.append(resource); - // return; - // } + if (_requestLimit <= 0) { + qDebug() << "REQUEST LIMIT REACHED (" << _requestLimit << "), queueing: " << resource->getURL(); + // wait until a slot becomes available + sharedItems->_pendingRequests.append(resource); + return; + } qDebug() << "-- Decreasing limit for : " << resource->getURL(); _requestLimit--; sharedItems->_loadingRequests.append(resource); From 12d3cf557abe62c2ce1923f9f7cab0606bd457de Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 12:58:57 -0700 Subject: [PATCH 429/549] Remove assert in ScriptCache --- libraries/script-engine/src/ScriptCache.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index 9409c10652..e3d12313dc 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -27,8 +27,6 @@ ScriptCache::ScriptCache(QObject* parent) { } QString ScriptCache::getScript(const QUrl& url, ScriptUser* scriptUser, bool& isPending, bool reload) { - //assert(!_scriptCache.contains(url) || !reload); - QString scriptContents; if (_scriptCache.contains(url) && !reload) { qCDebug(scriptengine) << "Found script in cache:" << url.toString(); From b401a62d7f006feb7a5d98f4df5e2d4ae89a8c11 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 13:57:00 -0700 Subject: [PATCH 430/549] Disable request limiting for ATP requests in ResourceCache --- libraries/networking/src/ResourceCache.cpp | 10 ++++++++-- libraries/networking/src/ResourceManager.cpp | 6 ------ libraries/networking/src/ResourceManager.h | 6 ++++++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index e4ff88b9e3..db506e5320 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -161,7 +161,11 @@ void ResourceCache::attemptRequest(Resource* resource) { return; } qDebug() << "-- Decreasing limit for : " << resource->getURL(); - _requestLimit--; + + // Disable request limiting for ATP + if (resource->getURL() != URL_SCHEME_ATP) { + _requestLimit--; + } sharedItems->_loadingRequests.append(resource); resource->makeRequest(); } @@ -171,7 +175,9 @@ void ResourceCache::requestCompleted(Resource* resource) { auto sharedItems = DependencyManager::get(); sharedItems->_loadingRequests.removeOne(resource); qDebug() << "++ Increasing limit after finished: " << resource->getURL(); - _requestLimit++; + if (resource->getURL() != URL_SCHEME_ATP) { + _requestLimit++; + } // look for the highest priority pending request int highestIndex = -1; diff --git a/libraries/networking/src/ResourceManager.cpp b/libraries/networking/src/ResourceManager.cpp index b8e3eeeae7..648ce8376e 100644 --- a/libraries/networking/src/ResourceManager.cpp +++ b/libraries/networking/src/ResourceManager.cpp @@ -16,12 +16,6 @@ #include -const QString URL_SCHEME_FILE = "file"; -const QString URL_SCHEME_HTTP = "http"; -const QString URL_SCHEME_HTTPS = "https"; -const QString URL_SCHEME_FTP = "ftp"; -const QString URL_SCHEME_ATP = "atp"; - ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const QUrl& url) { auto scheme = url.scheme(); if (scheme == URL_SCHEME_FILE) { diff --git a/libraries/networking/src/ResourceManager.h b/libraries/networking/src/ResourceManager.h index 1cb6b08a79..e31577423b 100644 --- a/libraries/networking/src/ResourceManager.h +++ b/libraries/networking/src/ResourceManager.h @@ -15,6 +15,12 @@ #include "ResourceRequest.h" +const QString URL_SCHEME_FILE = "file"; +const QString URL_SCHEME_HTTP = "http"; +const QString URL_SCHEME_HTTPS = "https"; +const QString URL_SCHEME_FTP = "ftp"; +const QString URL_SCHEME_ATP = "atp"; + class ResourceManager { public: static ResourceRequest* createResourceRequest(QObject* parent, const QUrl& url); From 4fcfd5b8f8379b3868e9f32282778cc3ceb004ac Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 13:58:28 -0700 Subject: [PATCH 431/549] Fix indentation --- libraries/networking/src/udt/PacketList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketList.cpp b/libraries/networking/src/udt/PacketList.cpp index 98316ee0ab..7b90276b62 100644 --- a/libraries/networking/src/udt/PacketList.cpp +++ b/libraries/networking/src/udt/PacketList.cpp @@ -143,7 +143,7 @@ qint64 PacketList::writeData(const char* data, qint64 maxSize) { // this is an unsupported case - the segment is bigger than the size of an individual packet // but the PacketList is not going to be sent ordered qDebug() << "Error in PacketList::writeData - attempted to write a segment to an unordered packet that is" - << "larger than the payload size."; + << "larger than the payload size."; Q_ASSERT(false); } From 24eef654e0e64f754956eda0d4bf4cc968695e2e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 14:11:29 -0700 Subject: [PATCH 432/549] Remove unnecessary debug --- libraries/render-utils/src/TextureCache.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index 1fba515cbe..4954629d86 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -294,7 +294,6 @@ public: void ImageReader::run() { QSharedPointer texture = _texture.toStrongRef(); if (texture.isNull()) { - qDebug() << "TEXTURE IS NULL"; return; } From 755c33e5516af0fb021fa0c35890a5f291e22ecc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 14:11:40 -0700 Subject: [PATCH 433/549] Remove unused variable --- libraries/render-utils/src/Model.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 9c6dcdfc9c..c2d723a323 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1354,7 +1354,6 @@ void Model::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm: } bool Model::restoreJointPosition(int jointIndex, float fraction, float priority) { - QString url = _url.path(); const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& freeLineage = geometry.joints.at(jointIndex).freeLineage; return _rig->restoreJointPosition(jointIndex, fraction, priority, freeLineage); From 86a7a42d24fb1512bf0deca0961e871110118538 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 14:22:21 -0700 Subject: [PATCH 434/549] use compact hash representation for asset-server --- assignment-client/src/assets/AssetServer.cpp | 36 ++++++++++--------- assignment-client/src/assets/AssetServer.h | 2 +- .../src/assets/SendAssetTask.cpp | 4 +-- libraries/networking/src/AssetClient.cpp | 23 ++++++------ libraries/networking/src/AssetUtils.h | 3 +- 5 files changed, 36 insertions(+), 32 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index b2a4eefabf..181b45d464 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -58,7 +58,7 @@ void AssetServer::run() { // Scan for new files qDebug() << "Looking for new files in asset directory"; auto files = _resourcesDirectory.entryInfoList(QDir::Files); - QRegExp filenameRegex { "^[a-f0-9]{" + QString::number(HASH_HEX_LENGTH) + "}(\\..+)?$" }; + QRegExp filenameRegex { "^[a-f0-9]{" + QString::number(SHA256_HASH_HEX_LENGTH) + "}(\\..+)?$" }; for (const auto& fileInfo : files) { auto filename = fileInfo.fileName(); if (!filenameRegex.exactMatch(filename)) { @@ -74,10 +74,11 @@ void AssetServer::run() { QByteArray data = file.readAll(); auto hash = hashData(data); + auto hexHash = hash.toHex(); - qDebug() << "\tMoving " << filename << " to " << hash; + qDebug() << "\tMoving " << filename << " to " << hexHash; - file.rename(_resourcesDirectory.absoluteFilePath(hash) + "." + fileInfo.suffix()); + file.rename(_resourcesDirectory.absoluteFilePath(hexHash) + "." + fileInfo.suffix()); } } } @@ -87,13 +88,13 @@ void AssetServer::handleAssetGetInfo(QSharedPointer packet, SharedNode MessageID messageID; uint8_t extensionLength; - if (packet->getPayloadSize() < qint64(HASH_HEX_LENGTH + sizeof(messageID) + sizeof(extensionLength))) { + if (packet->getPayloadSize() < qint64(SHA256_HASH_LENGTH + sizeof(messageID) + sizeof(extensionLength))) { qDebug() << "ERROR bad file request"; return; } packet->readPrimitive(&messageID); - assetHash = packet->readWithoutCopy(HASH_HEX_LENGTH); + assetHash = packet->readWithoutCopy(SHA256_HASH_LENGTH); packet->readPrimitive(&extensionLength); QByteArray extension = packet->read(extensionLength); @@ -125,23 +126,25 @@ void AssetServer::handleAssetGet(QSharedPointer packet, SharedNodePoin DataOffset start; DataOffset end; - auto minSize = qint64(sizeof(messageID) + HASH_HEX_LENGTH + sizeof(extensionLength) + sizeof(start) + sizeof(end)); + auto minSize = qint64(sizeof(messageID) + SHA256_HASH_LENGTH + sizeof(extensionLength) + sizeof(start) + sizeof(end)); if (packet->getPayloadSize() < minSize) { qDebug() << "ERROR bad file request"; return; } packet->readPrimitive(&messageID); - assetHash = packet->read(HASH_HEX_LENGTH); + assetHash = packet->read(SHA256_HASH_LENGTH); packet->readPrimitive(&extensionLength); QByteArray extension = packet->read(extensionLength); packet->readPrimitive(&start); packet->readPrimitive(&end); + + QByteArray hexHash = assetHash.toHex(); - qDebug() << "Received a request for the file (" << messageID << "): " << assetHash << " from " << start << " to " << end; + qDebug() << "Received a request for the file (" << messageID << "): " << hexHash << " from " << start << " to " << end; // Queue task - QString filePath = _resourcesDirectory.filePath(QString(assetHash) + "." + QString(extension)); + QString filePath = _resourcesDirectory.filePath(QString(hexHash) + "." + QString(extension)); auto task = new SendAssetTask(messageID, assetHash, filePath, start, end, senderNode); _taskPool.start(task); } @@ -194,28 +197,29 @@ void AssetServer::handleAssetUpload(QSharedPointer packetList, Sha } else { QByteArray fileData = buffer.read(fileSize); - QString hash = hashData(fileData); + auto hash = hashData(fileData); + auto hexHash = hash.toHex(); - qDebug() << "Got data: (" << hash << ") "; + qDebug() << "Got data: (" << hexHash << ") "; - QFile file { _resourcesDirectory.filePath(QString(hash)) + "." + QString(extension) }; + QFile file { _resourcesDirectory.filePath(QString(hexHash)) + "." + QString(extension) }; if (file.exists()) { - qDebug() << "[WARNING] This file already exists: " << hash; + qDebug() << "[WARNING] This file already exists: " << hexHash; } else { file.open(QIODevice::WriteOnly); file.write(fileData); file.close(); } replyPacket->writePrimitive(AssetServerError::NO_ERROR); - replyPacket->write(hash.toLatin1()); + replyPacket->write(hash); } auto nodeList = DependencyManager::get(); nodeList->sendPacket(std::move(replyPacket), *senderNode); } -QString AssetServer::hashData(const QByteArray& data) { - return QString(QCryptographicHash::hash(data, QCryptographicHash::Sha256).toHex()); +QByteArray AssetServer::hashData(const QByteArray& data) { + return QCryptographicHash::hash(data, QCryptographicHash::Sha256); } diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 07e0680c4f..204a4869bb 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -23,7 +23,7 @@ class AssetServer : public ThreadedAssignment { public: AssetServer(NLPacket& packet); - static QString hashData(const QByteArray& data); + static QByteArray hashData(const QByteArray& data); public slots: void run(); diff --git a/assignment-client/src/assets/SendAssetTask.cpp b/assignment-client/src/assets/SendAssetTask.cpp index f30689b042..0c3b4cd02d 100644 --- a/assignment-client/src/assets/SendAssetTask.cpp +++ b/assignment-client/src/assets/SendAssetTask.cpp @@ -48,14 +48,14 @@ void SendAssetTask::run() { if (file.open(QIODevice::ReadOnly)) { if (file.size() < _end) { writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); - qCDebug(networking) << "Bad byte range: " << _assetHash << " " << _start << ":" << _end; + qCDebug(networking) << "Bad byte range: " << _assetHash.toHex() << " " << _start << ":" << _end; } else { auto size = _end - _start; file.seek(_start); replyPacketList->writePrimitive(AssetServerError::NO_ERROR); replyPacketList->writePrimitive(size); replyPacketList->write(file.read(size)); - qCDebug(networking) << "Sending asset: " << _assetHash; + qCDebug(networking) << "Sending asset: " << _assetHash.toHex(); } file.close(); } else { diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index d179977d20..d8207ae364 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -40,7 +40,7 @@ AssetRequest* AssetClient::createRequest(QString hash, QString extension) { return req; } - if (hash.length() != HASH_HEX_LENGTH) { + if (hash.length() != SHA256_HASH_HEX_LENGTH) { qDebug() << "Invalid hash size"; return nullptr; } @@ -76,7 +76,7 @@ AssetUpload* AssetClient::createUpload(QString filename) { } bool AssetClient::getAsset(QString hash, QString extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback) { - if (hash.length() != HASH_HEX_LENGTH) { + if (hash.length() != SHA256_HASH_HEX_LENGTH) { qDebug() << "Invalid hash size"; return false; } @@ -93,7 +93,7 @@ bool AssetClient::getAsset(QString hash, QString extension, DataOffset start, Da packet->writePrimitive(messageID); - packet->write(hash.toLatin1()); + packet->write(QByteArray::fromHex(hash.toLatin1())); packet->writePrimitive(uint8_t(extension.length())); packet->write(extension.toLatin1()); @@ -120,7 +120,7 @@ bool AssetClient::getAssetInfo(QString hash, QString extension, GetInfoCallback auto messageID = ++_currentID; packet->writePrimitive(messageID); - packet->write(hash.toLatin1().constData(), HASH_HEX_LENGTH); + packet->write(QByteArray::fromHex(hash.toLatin1())); packet->writePrimitive(uint8_t(extension.length())); packet->write(extension.toLatin1()); @@ -137,12 +137,12 @@ bool AssetClient::getAssetInfo(QString hash, QString extension, GetInfoCallback void AssetClient::handleAssetGetInfoReply(QSharedPointer packet, SharedNodePointer senderNode) { MessageID messageID; packet->readPrimitive(&messageID); - auto assetHash = QString(packet->read(HASH_HEX_LENGTH)); + auto assetHash = packet->read(SHA256_HASH_LENGTH); AssetServerError error; packet->readPrimitive(&error); - AssetInfo info { assetHash, 0 }; + AssetInfo info { assetHash.toHex(), 0 }; if (error == NO_ERROR) { packet->readPrimitive(&info.size); @@ -159,8 +159,8 @@ void AssetClient::handleAssetGetReply(QSharedPointer packetList, S QBuffer packet { &data }; packet.open(QIODevice::ReadOnly); - auto assetHash = packet.read(HASH_HEX_LENGTH); - qDebug() << "Got reply for asset: " << assetHash; + auto assetHash = packet.read(SHA256_HASH_LENGTH); + qDebug() << "Got reply for asset: " << assetHash.toHex(); MessageID messageID; packet.read(reinterpret_cast(&messageID), sizeof(messageID)); @@ -224,10 +224,9 @@ void AssetClient::handleAssetUploadReply(QSharedPointer packet, Shared if (error) { qDebug() << "Error uploading file to asset server"; } else { - auto hashData = packet->read(HASH_HEX_LENGTH); - - hashString = QString(hashData); - + auto hash = packet->read(SHA256_HASH_LENGTH); + hashString = hash.toHex(); + qDebug() << "Successfully uploaded asset to asset-server - SHA256 hash is " << hashString; } diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 0cc71dab70..0447e8b303 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -16,7 +16,8 @@ using MessageID = uint32_t; using DataOffset = int64_t; -const size_t HASH_HEX_LENGTH = 64; +const size_t SHA256_HASH_LENGTH = 32; +const size_t SHA256_HASH_HEX_LENGTH = 64; const uint64_t MAX_UPLOAD_SIZE = 1000 * 1000 * 1000; // 1GB enum AssetServerError : uint8_t { From 1da9eeab1f5b22c3609fae802f6a03f80f1db248 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 14:27:29 -0700 Subject: [PATCH 435/549] handle double handshake in Connection --- libraries/networking/src/udt/Connection.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index f1b69e0039..61cf7d6e74 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -620,8 +620,12 @@ void Connection::processNAK(std::unique_ptr controlPacket) { } void Connection::processHandshake(std::unique_ptr controlPacket) { - // server sent us a handshake - we need to assume this means state should be reset - resetReceiveState(); + + if (!_hasReceivedHandshake || _hasReceivedFirstPacket) { + // server sent us a handshake - we need to assume this means state should be reset + // as long as we haven't received a handshake yet or we have and we've received some data + resetReceiveState(); + } // immediately respond with a handshake ACK static auto handshakeACK = ControlPacket::create(ControlPacket::HandshakeACK, 0); From f238c1b167cd03fafa87bc68fcca60e1b3744a5c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 14:29:42 -0700 Subject: [PATCH 436/549] include the extension in upload confirmation --- interface/src/ui/AssetUploadDialogFactory.cpp | 2 +- libraries/networking/src/AssetUpload.cpp | 4 ++-- libraries/networking/src/AssetUpload.h | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/AssetUploadDialogFactory.cpp b/interface/src/ui/AssetUploadDialogFactory.cpp index 6edf71e758..3073171563 100644 --- a/interface/src/ui/AssetUploadDialogFactory.cpp +++ b/interface/src/ui/AssetUploadDialogFactory.cpp @@ -78,7 +78,7 @@ void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const Q // setup the line edit to hold the copiable text QLineEdit* lineEdit = new QLineEdit; - QString atpURL = QString("%1://%2").arg(ATP_SCHEME).arg(hash); + QString atpURL = QString("%1://%2.%3").arg(ATP_SCHEME).arg(hash).arg(upload->getExtension); // set the ATP URL as the text value so it's copiable lineEdit->insert(atpURL); diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index b7c1fa1c34..c9f5b804d4 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -34,14 +34,14 @@ void AssetUpload::start() { if (file.open(QIODevice::ReadOnly)) { // file opened, read the data and grab the extension - auto extension = QFileInfo(_filename).suffix(); + _extension = QFileInfo(_filename).suffix(); auto data = file.readAll(); // ask the AssetClient to upload the asset and emit the proper signals from the passed callback auto assetClient = DependencyManager::get(); - assetClient->uploadAsset(data, extension, [this](bool success, QString hash){ + assetClient->uploadAsset(data, _extension, [this](bool success, QString hash){ if (success) { // successful upload - emit finished with a point to ourselves and the resulting hash _result = Success; diff --git a/libraries/networking/src/AssetUpload.h b/libraries/networking/src/AssetUpload.h index c969e4373e..f55f4f9b71 100644 --- a/libraries/networking/src/AssetUpload.h +++ b/libraries/networking/src/AssetUpload.h @@ -36,6 +36,7 @@ public: Q_INVOKABLE void start(); const QString& getFilename() const { return _filename; } + const QString& getExtension() const { return _extension; } const Result& getResult() const { return _result; } signals: @@ -44,6 +45,7 @@ signals: private: QString _filename; + QString _extension; Result _result; }; From 5aa5bca8f7d566b42d48faba7e365c6a947059bf Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 14:29:54 -0700 Subject: [PATCH 437/549] Add path to headers --- assignment-client/src/assets/AssetServer.cpp | 1 + assignment-client/src/assets/AssetServer.h | 1 + assignment-client/src/assets/SendAssetTask.cpp | 1 + assignment-client/src/assets/SendAssetTask.h | 1 + libraries/networking/src/AssetClient.cpp | 1 + libraries/networking/src/AssetClient.h | 1 + libraries/networking/src/AssetRequest.cpp | 1 + libraries/networking/src/AssetRequest.h | 1 + libraries/networking/src/AssetResourceRequest.cpp | 1 + libraries/networking/src/AssetResourceRequest.h | 1 + libraries/networking/src/AssetUtils.h | 1 + libraries/networking/src/FileResourceRequest.cpp | 1 + libraries/networking/src/FileResourceRequest.h | 1 + libraries/networking/src/HTTPResourceRequest.cpp | 1 + libraries/networking/src/HTTPResourceRequest.h | 1 + libraries/networking/src/ResourceManager.cpp | 1 + libraries/networking/src/ResourceManager.h | 1 + libraries/networking/src/ResourceRequest.cpp | 1 + libraries/networking/src/ResourceRequest.h | 1 + 19 files changed, 19 insertions(+) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index c6ad9f0f4d..a5ad2962f8 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -1,5 +1,6 @@ // // AssetServer.cpp +// assignment-client/src/assets // // Created by Ryan Huffman on 2015/07/21 // Copyright 2015 High Fidelity, Inc. diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 07e0680c4f..e214be1eda 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -1,5 +1,6 @@ // // AssetServer.h +// assignment-client/src/assets // // Created by Ryan Huffman on 2015/07/21 // Copyright 2015 High Fidelity, Inc. diff --git a/assignment-client/src/assets/SendAssetTask.cpp b/assignment-client/src/assets/SendAssetTask.cpp index f30689b042..8516218681 100644 --- a/assignment-client/src/assets/SendAssetTask.cpp +++ b/assignment-client/src/assets/SendAssetTask.cpp @@ -1,5 +1,6 @@ // // SendAssetTask.cpp +// assignment-client/src/assets // // Created by Ryan Huffman on 2015/08/26 // Copyright 2015 High Fidelity, Inc. diff --git a/assignment-client/src/assets/SendAssetTask.h b/assignment-client/src/assets/SendAssetTask.h index 7dd3616f83..6b6c555326 100644 --- a/assignment-client/src/assets/SendAssetTask.h +++ b/assignment-client/src/assets/SendAssetTask.h @@ -1,5 +1,6 @@ // // SendAssetTask.h +// assignment-client/src/assets // // Created by Ryan Huffman on 2015/08/26 // Copyright 2015 High Fidelity, Inc. diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index f424171766..fa277d72f4 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -1,5 +1,6 @@ // // AssetClient.cpp +// libraries/networking/src // // Created by Ryan Huffman on 2015/07/21 // Copyright 2015 High Fidelity, Inc. diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 0e81c6cfa2..a397c500e3 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -1,5 +1,6 @@ // // AssetClient.h +// libraries/networking/src // // Created by Ryan Huffman on 2015/07/21 // Copyright 2015 High Fidelity, Inc. diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 87e39e1edd..c49d178412 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -1,5 +1,6 @@ // // AssetRequest.cpp +// libraries/networking/src // // Created by Ryan Huffman on 2015/07/24 // Copyright 2015 High Fidelity, Inc. diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index d1cc9c9b33..6e0738c333 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -1,5 +1,6 @@ // // AssetRequest.h +// libraries/networking/src // // Created by Ryan Huffman on 2015/07/24 // Copyright 2015 High Fidelity, Inc. diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 5a0af8ef1f..bdb6b51378 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -1,5 +1,6 @@ // // AssetResourceRequest.cpp +// libraries/networking/src // // Created by Ryan Huffman on 2015/07/23 // Copyright 2015 High Fidelity, Inc. diff --git a/libraries/networking/src/AssetResourceRequest.h b/libraries/networking/src/AssetResourceRequest.h index 2cfd1d28b7..fb9c25e092 100644 --- a/libraries/networking/src/AssetResourceRequest.h +++ b/libraries/networking/src/AssetResourceRequest.h @@ -1,5 +1,6 @@ // // AssetResourceRequest.h +// libraries/networking/src // // Created by Ryan Huffman on 2015/07/23 // Copyright 2015 High Fidelity, Inc. diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index cc5b2a281f..4018b5c96b 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -1,5 +1,6 @@ // // AssetUtils.h +// libraries/networking/src // // Created by Ryan Huffman on 2015/07/30 // Copyright 2015 High Fidelity, Inc. diff --git a/libraries/networking/src/FileResourceRequest.cpp b/libraries/networking/src/FileResourceRequest.cpp index 8bd7ecf94e..d8b8d962f5 100644 --- a/libraries/networking/src/FileResourceRequest.cpp +++ b/libraries/networking/src/FileResourceRequest.cpp @@ -1,5 +1,6 @@ // // FileResourceRequest.cpp +// libraries/networking/src // // Created by Ryan Huffman on 2015/07/23 // Copyright 2015 High Fidelity, Inc. diff --git a/libraries/networking/src/FileResourceRequest.h b/libraries/networking/src/FileResourceRequest.h index 7618311626..4ff0d2ecf2 100644 --- a/libraries/networking/src/FileResourceRequest.h +++ b/libraries/networking/src/FileResourceRequest.h @@ -1,5 +1,6 @@ // // FileResourceRequest.h +// libraries/networking/src // // Created by Ryan Huffman on 2015/07/23 // Copyright 2015 High Fidelity, Inc. diff --git a/libraries/networking/src/HTTPResourceRequest.cpp b/libraries/networking/src/HTTPResourceRequest.cpp index cf074eb98b..22f55cd641 100644 --- a/libraries/networking/src/HTTPResourceRequest.cpp +++ b/libraries/networking/src/HTTPResourceRequest.cpp @@ -1,5 +1,6 @@ // // HTTPResourceRequest.cpp +// libraries/networking/src // // Created by Ryan Huffman on 2015/07/23 // Copyright 2015 High Fidelity, Inc. diff --git a/libraries/networking/src/HTTPResourceRequest.h b/libraries/networking/src/HTTPResourceRequest.h index c42204f3e9..09c94314d6 100644 --- a/libraries/networking/src/HTTPResourceRequest.h +++ b/libraries/networking/src/HTTPResourceRequest.h @@ -1,5 +1,6 @@ // // HTTPResourceRequest.h +// libraries/networking/src // // Created by Ryan Huffman on 2015/07/23 // Copyright 2015 High Fidelity, Inc. diff --git a/libraries/networking/src/ResourceManager.cpp b/libraries/networking/src/ResourceManager.cpp index 648ce8376e..ded3dfe222 100644 --- a/libraries/networking/src/ResourceManager.cpp +++ b/libraries/networking/src/ResourceManager.cpp @@ -1,5 +1,6 @@ // // ResourceManager.cpp +// libraries/networking/src // // Created by Ryan Huffman on 2015/07/23 // Copyright 2015 High Fidelity, Inc. diff --git a/libraries/networking/src/ResourceManager.h b/libraries/networking/src/ResourceManager.h index e31577423b..3748036c8e 100644 --- a/libraries/networking/src/ResourceManager.h +++ b/libraries/networking/src/ResourceManager.h @@ -1,5 +1,6 @@ // // ResourceManager.h +// libraries/networking/src // // Created by Ryan Huffman on 2015/07/23 // Copyright 2015 High Fidelity, Inc. diff --git a/libraries/networking/src/ResourceRequest.cpp b/libraries/networking/src/ResourceRequest.cpp index 44bfaae254..d56033670b 100644 --- a/libraries/networking/src/ResourceRequest.cpp +++ b/libraries/networking/src/ResourceRequest.cpp @@ -1,5 +1,6 @@ // // ResourceRequest.cpp +// libraries/networking/src // // Created by Ryan Huffman on 2015/07/23 // Copyright 2015 High Fidelity, Inc. diff --git a/libraries/networking/src/ResourceRequest.h b/libraries/networking/src/ResourceRequest.h index 458a859d16..ac13523e96 100644 --- a/libraries/networking/src/ResourceRequest.h +++ b/libraries/networking/src/ResourceRequest.h @@ -1,5 +1,6 @@ // // ResourceRequest.h +// libraries/networking/src // // Created by Ryan Huffman on 2015/07/23 // Copyright 2015 High Fidelity, Inc. From dabea21d669920b2d0d99ee3e71ddb7e9ba6027f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 14:30:48 -0700 Subject: [PATCH 438/549] Remove unused variable --- libraries/networking/src/ResourceCache.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index db506e5320..b07c3cc60e 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -364,7 +364,6 @@ void Resource::handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTota } void Resource::handleReplyFinished() { - QString u = _url.path(); Q_ASSERT(_request); auto result = _request->getResult(); @@ -387,8 +386,7 @@ void Resource::handleReplyFinished() { _request = nullptr; if (result == ResourceRequest::Result::TIMEOUT) { - qDebug() << "Timed out loading" << _url << - "received" << _bytesReceived << "total" << _bytesTotal; + qDebug() << "Timed out loading" << _url << "received" << _bytesReceived << "total" << _bytesTotal; } else { qDebug() << "Error loading " << _url; } From 26757eae7a4c28ce9fa713bec1faeaf1fa4dcd3b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 14:37:44 -0700 Subject: [PATCH 439/549] immediately show permission denied error if applicable --- interface/src/ui/AssetUploadDialogFactory.cpp | 63 ++++++++++++------- interface/src/ui/AssetUploadDialogFactory.h | 2 + 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/interface/src/ui/AssetUploadDialogFactory.cpp b/interface/src/ui/AssetUploadDialogFactory.cpp index 3073171563..89a6046d71 100644 --- a/interface/src/ui/AssetUploadDialogFactory.cpp +++ b/interface/src/ui/AssetUploadDialogFactory.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -32,29 +33,39 @@ AssetUploadDialogFactory::AssetUploadDialogFactory() { } +static const QString PERMISSION_DENIED_ERROR = "You do not have permission to upload content to this asset-server."; + void AssetUploadDialogFactory::showDialog() { - auto filename = QFileDialog::getOpenFileUrl(_dialogParent, "Select a file to upload"); + auto nodeList = DependencyManager::get(); - if (!filename.isEmpty()) { - qDebug() << "Selected filename for upload to asset-server: " << filename; + if (nodeList->getThisNodeCanRez()) { + auto filename = QFileDialog::getOpenFileUrl(_dialogParent, "Select a file to upload"); - auto assetClient = DependencyManager::get(); - auto upload = assetClient->createUpload(filename.path()); - - if (upload) { - // connect to the finished signal so we know when the AssetUpload is done - QObject::connect(upload, &AssetUpload::finished, this, &AssetUploadDialogFactory::handleUploadFinished); + if (!filename.isEmpty()) { + qDebug() << "Selected filename for upload to asset-server: " << filename; - // start the upload now - upload->start(); - } else { - // show a QMessageBox to say that there is no local asset server - QString messageBoxText = QString("Could not upload \n\n%1\n\nbecause you are currently not connected" \ - " to a local asset-server.").arg(QFileInfo(filename.toString()).fileName()); + auto assetClient = DependencyManager::get(); + auto upload = assetClient->createUpload(filename.path()); - QMessageBox::information(_dialogParent, "Failed to Upload", messageBoxText); + if (upload) { + // connect to the finished signal so we know when the AssetUpload is done + QObject::connect(upload, &AssetUpload::finished, this, &AssetUploadDialogFactory::handleUploadFinished); + + // start the upload now + upload->start(); + } else { + // show a QMessageBox to say that there is no local asset server + QString messageBoxText = QString("Could not upload \n\n%1\n\nbecause you are currently not connected" \ + " to a local asset-server.").arg(QFileInfo(filename.toString()).fileName()); + + QMessageBox::information(_dialogParent, "Failed to Upload", messageBoxText); + } } + } else { + // we don't have permission to upload to asset server in this domain - show the permission denied error + showErrorDialog(QString(), PERMISSION_DENIED_ERROR); } + } void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const QString& hash) { @@ -78,7 +89,7 @@ void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const Q // setup the line edit to hold the copiable text QLineEdit* lineEdit = new QLineEdit; - QString atpURL = QString("%1://%2.%3").arg(ATP_SCHEME).arg(hash).arg(upload->getExtension); + QString atpURL = QString("%1://%2.%3").arg(ATP_SCHEME).arg(hash).arg(upload->getExtension()); // set the ATP URL as the text value so it's copiable lineEdit->insert(atpURL); @@ -111,14 +122,14 @@ void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const Q hashCopyDialog->show(); } else { // figure out the right error message for the message box - QString errorMessage = QString("Failed to upload %1.\n\n").arg(QFileInfo(upload->getFilename()).fileName()); + QString additionalError; switch (upload->getResult()) { case AssetUpload::PermissionDenied: - errorMessage += "You do not have permission to upload content to this asset-server."; + additionalError = PERMISSION_DENIED_ERROR; break; case AssetUpload::TooLarge: - errorMessage += "The uploaded content was too large and could not be stored in the asset-server."; + additionalError = "The uploaded content was too large and could not be stored in the asset-server."; break; default: // not handled, do not show a message box @@ -126,6 +137,16 @@ void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const Q } // display a message box with the error - QMessageBox::warning(_dialogParent, "Failed Upload", errorMessage); + showErrorDialog(QFileInfo(upload->getFilename()).fileName(), additionalError); } } + +void AssetUploadDialogFactory::showErrorDialog(const QString& filename, const QString& additionalError) { + QString errorMessage; + + if (!filename.isEmpty()) { + errorMessage += QString("Failed to upload %1.\n\n").arg(filename); + } + + QMessageBox::warning(_dialogParent, "Failed Upload", errorMessage); +} diff --git a/interface/src/ui/AssetUploadDialogFactory.h b/interface/src/ui/AssetUploadDialogFactory.h index 0d3372cb03..ae7f103437 100644 --- a/interface/src/ui/AssetUploadDialogFactory.h +++ b/interface/src/ui/AssetUploadDialogFactory.h @@ -33,6 +33,8 @@ public slots: private slots: void handleUploadFinished(AssetUpload* upload, const QString& hash); private: + void showErrorDialog(const QString& filename, const QString& additionalError); + QWidget* _dialogParent { nullptr }; }; From 59775e5756f24752f0379e80f101d3f935b1ad91 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 14:40:12 -0700 Subject: [PATCH 440/549] actually add the additional error to the dialog --- interface/src/ui/AssetUploadDialogFactory.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/ui/AssetUploadDialogFactory.cpp b/interface/src/ui/AssetUploadDialogFactory.cpp index 89a6046d71..16d966fe66 100644 --- a/interface/src/ui/AssetUploadDialogFactory.cpp +++ b/interface/src/ui/AssetUploadDialogFactory.cpp @@ -148,5 +148,7 @@ void AssetUploadDialogFactory::showErrorDialog(const QString& filename, const QS errorMessage += QString("Failed to upload %1.\n\n").arg(filename); } + errorMessage += additionalError; + QMessageBox::warning(_dialogParent, "Failed Upload", errorMessage); } From 0f36385b86d2bae6372efba867205f36fd7b5ac9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 14:58:22 -0700 Subject: [PATCH 441/549] remove version conflict markers accidentally committed --- domain-server/src/DomainServer.cpp | 205 +---------------------------- 1 file changed, 1 insertion(+), 204 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 4999674c4f..d61b4766af 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -289,18 +289,13 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { packetReceiver.registerListener(PacketType::DomainListRequest, this, "processListRequestPacket"); packetReceiver.registerListener(PacketType::DomainServerPathQuery, this, "processPathQueryPacket"); packetReceiver.registerListener(PacketType::NodeJsonStats, this, "processNodeJSONStatsPacket"); -<<<<<<< HEAD - packetReceiver.registerListener(PacketType::ICEPing, this, "processICEPingPacket"); - packetReceiver.registerListener(PacketType::ICEPingReply, this, "processICEPingReplyPacket"); - packetReceiver.registerListener(PacketType::ICEServerPeerInformation, this, "processICEPeerInformationPacket"); // NodeList won't be available to the settings manager when it is created, so call registerListener here packetReceiver.registerListener(PacketType::DomainSettingsRequest, &_settingsManager, "processSettingsRequestPacket"); -======= + packetReceiver.registerListener(PacketType::ICEPing, &_gatekeeper, "processICEPingPacket"); packetReceiver.registerListener(PacketType::ICEPingReply, &_gatekeeper, "processICEPingReplyPacket"); packetReceiver.registerListener(PacketType::ICEServerPeerInformation, &_gatekeeper, "processICEPeerInformationPacket"); ->>>>>>> d0db56a4a6902e9d1ee706ec02152e94688f4e5c // add whatever static assignments that have been parsed to the queue addStaticAssignmentsToQueue(); @@ -584,204 +579,6 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet packet) { - NodeType_t nodeType; - HifiSockAddr publicSockAddr, localSockAddr; - - if (packet->getPayloadSize() == 0) { - return; - } - - QDataStream packetStream(packet.data()); - - QUuid connectUUID; - packetStream >> connectUUID; - - const HifiSockAddr& senderSockAddr = packet->getSenderSockAddr(); - - parseNodeData(packetStream, nodeType, publicSockAddr, localSockAddr, senderSockAddr); - - if (localSockAddr.isNull() || senderSockAddr.isNull()) { - qDebug() << "Unexpected data received for node local socket or public socket. Will not allow connection."; - return; - } - - // check if this connect request matches an assignment in the queue - bool isAssignment = _pendingAssignedNodes.contains(connectUUID); - SharedAssignmentPointer matchingQueuedAssignment = SharedAssignmentPointer(); - PendingAssignedNodeData* pendingAssigneeData = NULL; - - if (isAssignment) { - pendingAssigneeData = _pendingAssignedNodes.value(connectUUID); - - if (pendingAssigneeData) { - matchingQueuedAssignment = matchingQueuedAssignmentForCheckIn(pendingAssigneeData->getAssignmentUUID(), nodeType); - - if (matchingQueuedAssignment) { - qDebug() << "Assignment deployed with" << uuidStringWithoutCurlyBraces(connectUUID) - << "matches unfulfilled assignment" - << uuidStringWithoutCurlyBraces(matchingQueuedAssignment->getUUID()); - - // remove this unique assignment deployment from the hash of pending assigned nodes - // cleanup of the PendingAssignedNodeData happens below after the node has been added to the LimitedNodeList - _pendingAssignedNodes.remove(connectUUID); - } else { - // this is a node connecting to fulfill an assignment that doesn't exist - // don't reply back to them so they cycle back and re-request an assignment - qDebug() << "No match for assignment deployed with" << uuidStringWithoutCurlyBraces(connectUUID); - return; - } - } - } - - QList nodeInterestList; - QString username; - QByteArray usernameSignature; - - auto limitedNodeList = DependencyManager::get(); - - packetStream >> nodeInterestList; - - if (packet->bytesLeftToRead() > 0) { - // try to verify username - packetStream >> username; - } - - bool isRestrictingAccess = - _settingsManager.valueOrDefaultValueForKeyPath(RESTRICTED_ACCESS_SETTINGS_KEYPATH).toBool(); - - // we always let in a user who is sending a packet from our local socket or from the localhost address - bool isLocalUser = (senderSockAddr.getAddress() == DependencyManager::get()->getLocalSockAddr().getAddress() || senderSockAddr.getAddress() == QHostAddress::LocalHost); - - if (isRestrictingAccess && !isLocalUser) { - if (!username.isEmpty()) { - // if there's a username, try to unpack username signature - packetStream >> usernameSignature; - - if (usernameSignature.isEmpty()) { - // if user didn't include usernameSignature in connect request, send a connectionToken packet - QUuid& connectionToken = _connectionTokenHash[username.toLower()]; - - if (connectionToken.isNull()) { - connectionToken = QUuid::createUuid(); - } - - static auto connectionTokenPacket = NLPacket::create(PacketType::DomainServerConnectionToken, NUM_BYTES_RFC4122_UUID); - connectionTokenPacket->reset(); - connectionTokenPacket->write(connectionToken.toRfc4122()); - limitedNodeList->sendUnreliablePacket(*connectionTokenPacket, packet->getSenderSockAddr()); - return; - } - } - } - - QString reason; - if (!isAssignment && !shouldAllowConnectionFromNode(username, usernameSignature, senderSockAddr, reason)) { - // this is an agent and we've decided we won't let them connect - send them a packet to deny connection - QByteArray utfString = reason.toUtf8(); - quint16 payloadSize = utfString.size(); - - auto connectionDeniedPacket = NLPacket::create(PacketType::DomainConnectionDenied, payloadSize + sizeof(payloadSize)); - if (payloadSize > 0) { - connectionDeniedPacket->writePrimitive(payloadSize); - connectionDeniedPacket->write(utfString); - } - // tell client it has been refused. - limitedNodeList->sendPacket(std::move(connectionDeniedPacket), senderSockAddr); - return; - } - - if ((!isAssignment && !STATICALLY_ASSIGNED_NODES.contains(nodeType)) - || (isAssignment && matchingQueuedAssignment)) { - // this was either not a static assignment or it was and we had a matching one in the queue - - QUuid nodeUUID; - - HifiSockAddr discoveredSocket = senderSockAddr; - SharedNetworkPeer connectedPeer = _icePeers.value(connectUUID); - - if (connectedPeer) { - // this user negotiated a connection with us via ICE, so re-use their ICE client ID - nodeUUID = connectUUID; - - if (connectedPeer->getActiveSocket()) { - // set their discovered socket to whatever the activated socket on the network peer object was - discoveredSocket = *connectedPeer->getActiveSocket(); - } - } else { - // we got a connectUUID we didn't recognize, just add the node with a new UUID - nodeUUID = QUuid::createUuid(); - } - - // if this user is in the editors list (or if the editors list is empty) set the user's node's canAdjustLocks to true - const QVariant* allowedEditorsVariant = - valueForKeyPath(_settingsManager.getSettingsMap(), ALLOWED_EDITORS_SETTINGS_KEYPATH); - QStringList allowedEditors = allowedEditorsVariant ? allowedEditorsVariant->toStringList() : QStringList(); - bool canAdjustLocks = allowedEditors.isEmpty() || allowedEditors.contains(username); - - const QVariant* editorsAreRezzersVariant = - valueForKeyPath(_settingsManager.getSettingsMap(), EDITORS_ARE_REZZERS_KEYPATH); - - bool onlyEditorsAreRezzers = false; - if (editorsAreRezzersVariant) { - onlyEditorsAreRezzers = editorsAreRezzersVariant->toBool(); - } - - bool canRez = true; - if (onlyEditorsAreRezzers) { - canRez = canAdjustLocks; - } - - SharedNodePointer newNode = limitedNodeList->addOrUpdateNode(nodeUUID, nodeType, - publicSockAddr, localSockAddr, - canAdjustLocks, canRez); - - // So that we can send messages to this node at will - we need to activate the correct socket on this node now - newNode->activateMatchingOrNewSymmetricSocket(discoveredSocket); - - // when the newNode is created the linked data is also created - // if this was a static assignment set the UUID, set the sendingSockAddr - DomainServerNodeData* nodeData = reinterpret_cast(newNode->getLinkedData()); - - if (isAssignment) { - nodeData->setAssignmentUUID(matchingQueuedAssignment->getUUID()); - nodeData->setWalletUUID(pendingAssigneeData->getWalletUUID()); - nodeData->setNodeVersion(pendingAssigneeData->getNodeVersion()); - - // always allow assignment clients to create and destroy entities - newNode->setCanAdjustLocks(true); - newNode->setCanRez(true); - - // now that we've pulled the wallet UUID and added the node to our list, delete the pending assignee data - delete pendingAssigneeData; - } - - if (!username.isEmpty()) { - // if we have a username from the connect request, set it on the DomainServerNodeData - nodeData->setUsername(username); - - // also add an interpolation to JSONBreakableMarshal so that servers can get username in stats - JSONBreakableMarshal::addInterpolationForKey(USERNAME_UUID_REPLACEMENT_STATS_KEY, - uuidStringWithoutCurlyBraces(nodeUUID), username); - } - - nodeData->setSendingSockAddr(senderSockAddr); - - // reply back to the user with a PacketType::DomainList - sendDomainListToNode(newNode, senderSockAddr, nodeInterestList.toSet()); - - // send out this node to our other connected nodes - broadcastNewNode(newNode); - } -} - - -======= ->>>>>>> d0db56a4a6902e9d1ee706ec02152e94688f4e5c void DomainServer::processListRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode) { QDataStream packetStream(packet.data()); From 777e6c3c2d29165c771a948afd1f6d70c0a478fe Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 15:03:13 -0700 Subject: [PATCH 442/549] use existing AssetUploadDialogFactory ref --- interface/src/Menu.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 230cfacf7a..abe08f58b2 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -362,8 +362,9 @@ Menu::Menu() { QAction* assetUpload = addActionToQMenuAndActionHash(assetDeveloperMenu, MenuOption::UploadAsset, 0, - &AssetUploadDialogFactory::getInstance(), + &assetDialogFactory, SLOT(showDialog())); + // disable the asset upload action by default - it gets enabled only if asset server becomes present assetUpload->setEnabled(false); From 46990184d66e77691972fa7e31c4b0f9d0e6c4c4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 15:07:15 -0700 Subject: [PATCH 443/549] AssetUploadDialogFactory constructor should be private --- interface/src/ui/AssetUploadDialogFactory.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/AssetUploadDialogFactory.h b/interface/src/ui/AssetUploadDialogFactory.h index ae7f103437..50980862e6 100644 --- a/interface/src/ui/AssetUploadDialogFactory.h +++ b/interface/src/ui/AssetUploadDialogFactory.h @@ -21,7 +21,6 @@ class AssetUpload; class AssetUploadDialogFactory : public QObject { Q_OBJECT public: - AssetUploadDialogFactory(); AssetUploadDialogFactory(const AssetUploadDialogFactory& other) = delete; AssetUploadDialogFactory& operator=(const AssetUploadDialogFactory& rhs) = delete; @@ -33,6 +32,8 @@ public slots: private slots: void handleUploadFinished(AssetUpload* upload, const QString& hash); private: + AssetUploadDialogFactory(); + void showErrorDialog(const QString& filename, const QString& additionalError); QWidget* _dialogParent { nullptr }; From 549c514400a203270f25bdcb729c2dc1dfdf4b64 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 15:12:08 -0700 Subject: [PATCH 444/549] fix upload leak, return error for failed load --- interface/src/ui/AssetUploadDialogFactory.cpp | 5 +++++ libraries/networking/src/AssetUpload.cpp | 6 ++++++ libraries/networking/src/AssetUpload.h | 3 ++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/AssetUploadDialogFactory.cpp b/interface/src/ui/AssetUploadDialogFactory.cpp index 16d966fe66..e163947c7c 100644 --- a/interface/src/ui/AssetUploadDialogFactory.cpp +++ b/interface/src/ui/AssetUploadDialogFactory.cpp @@ -131,6 +131,9 @@ void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const Q case AssetUpload::TooLarge: additionalError = "The uploaded content was too large and could not be stored in the asset-server."; break; + case AssetUpload::ErrorLoadingFile: + additionalError = "The file could not be opened. Please check your permissions and try again."; + break; default: // not handled, do not show a message box return; @@ -139,6 +142,8 @@ void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const Q // display a message box with the error showErrorDialog(QFileInfo(upload->getFilename()).fileName(), additionalError); } + + upload->deleteLater(); } void AssetUploadDialogFactory::showErrorDialog(const QString& filename, const QString& additionalError) { diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index c9f5b804d4..780d062084 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -57,5 +57,11 @@ void AssetUpload::start() { emit finished(this, hash); } }); + } else { + // we couldn't open the file - set the error result + _result = ErrorLoadingFile; + + // emit that we are done + emit finished(this, QString()); } } diff --git a/libraries/networking/src/AssetUpload.h b/libraries/networking/src/AssetUpload.h index f55f4f9b71..a678c0dc7e 100644 --- a/libraries/networking/src/AssetUpload.h +++ b/libraries/networking/src/AssetUpload.h @@ -28,7 +28,8 @@ public: Success = 0, Timeout, TooLarge, - PermissionDenied + PermissionDenied, + ErrorLoadingFile }; AssetUpload(QObject* parent, const QString& filename); From 413ec718de5d595d20209565cd249de6fba46948 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 15:22:53 -0700 Subject: [PATCH 445/549] fix max pairs for timeout NAK --- libraries/networking/src/udt/Connection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index ae8af16334..37e5cfacb5 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -302,7 +302,7 @@ void Connection::sendTimeoutNAK() { auto lossListPacket = ControlPacket::create(ControlPacket::TimeoutNAK, timeoutPayloadSize); // Pack in the lost sequence numbers - _lossList.write(*lossListPacket, timeoutPayloadSize / 2); + _lossList.write(*lossListPacket, timeoutPayloadSize / (2 * sizeof(SequenceNumber))); // have our parent socket send off this control packet _parentSocket->writeBasePacket(*lossListPacket, _destination); From 8452289e00ad73f1727eefda90bd13af49bc2b0d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 15:56:07 -0700 Subject: [PATCH 446/549] Fix issue with raw hash not being converted to hex --- assignment-client/src/assets/AssetServer.cpp | 4 +++- assignment-client/src/assets/SendAssetTask.cpp | 9 +++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index c1457db55b..0308042391 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -101,10 +101,12 @@ void AssetServer::handleAssetGetInfo(QSharedPointer packet, SharedNode auto replyPacket = NLPacket::create(PacketType::AssetGetInfoReply); + QByteArray hexHash = assetHash.toHex(); + replyPacket->writePrimitive(messageID); replyPacket->write(assetHash); - QString fileName = QString(assetHash) + "." + extension; + QString fileName = QString(hexHash) + "." + extension; QFileInfo fileInfo { _resourcesDirectory.filePath(fileName) }; if (fileInfo.exists() && fileInfo.isReadable()) { diff --git a/assignment-client/src/assets/SendAssetTask.cpp b/assignment-client/src/assets/SendAssetTask.cpp index 7099d69988..e80195c1b6 100644 --- a/assignment-client/src/assets/SendAssetTask.cpp +++ b/assignment-client/src/assets/SendAssetTask.cpp @@ -34,7 +34,8 @@ SendAssetTask::SendAssetTask(MessageID messageID, const QByteArray& assetHash, Q } void SendAssetTask::run() { - qDebug() << "Starting task to send asset: " << _assetHash << " for messageID " << _messageID; + QString assetHashHex = _assetHash.toHex(); + qDebug() << "Starting task to send asset: " << assetHashHex << " for messageID " << _messageID; auto replyPacketList = std::unique_ptr(new NLPacketList(PacketType::AssetGetReply, QByteArray(), true, true)); replyPacketList->write(_assetHash); @@ -49,18 +50,18 @@ void SendAssetTask::run() { if (file.open(QIODevice::ReadOnly)) { if (file.size() < _end) { writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); - qCDebug(networking) << "Bad byte range: " << _assetHash.toHex() << " " << _start << ":" << _end; + qCDebug(networking) << "Bad byte range: " << assetHashHex << " " << _start << ":" << _end; } else { auto size = _end - _start; file.seek(_start); replyPacketList->writePrimitive(AssetServerError::NO_ERROR); replyPacketList->writePrimitive(size); replyPacketList->write(file.read(size)); - qCDebug(networking) << "Sending asset: " << _assetHash.toHex(); + qCDebug(networking) << "Sending asset: " << assetHashHex; } file.close(); } else { - qCDebug(networking) << "Asset not found: " << _filePath << "(" << _assetHash << ")"; + qCDebug(networking) << "Asset not found: " << _filePath << "(" << assetHashHex << ")"; writeError(replyPacketList.get(), AssetServerError::ASSET_NOT_FOUND); } } From efef60af046c081d1a1d44ca282c2b235a287434 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 15:57:35 -0700 Subject: [PATCH 447/549] Rename assetHashHex to hexHash --- assignment-client/src/assets/SendAssetTask.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/assets/SendAssetTask.cpp b/assignment-client/src/assets/SendAssetTask.cpp index e80195c1b6..91782b95ad 100644 --- a/assignment-client/src/assets/SendAssetTask.cpp +++ b/assignment-client/src/assets/SendAssetTask.cpp @@ -34,8 +34,8 @@ SendAssetTask::SendAssetTask(MessageID messageID, const QByteArray& assetHash, Q } void SendAssetTask::run() { - QString assetHashHex = _assetHash.toHex(); - qDebug() << "Starting task to send asset: " << assetHashHex << " for messageID " << _messageID; + QString hexHash = _assetHash.toHex(); + qDebug() << "Starting task to send asset: " << hexHash << " for messageID " << _messageID; auto replyPacketList = std::unique_ptr(new NLPacketList(PacketType::AssetGetReply, QByteArray(), true, true)); replyPacketList->write(_assetHash); @@ -50,18 +50,18 @@ void SendAssetTask::run() { if (file.open(QIODevice::ReadOnly)) { if (file.size() < _end) { writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); - qCDebug(networking) << "Bad byte range: " << assetHashHex << " " << _start << ":" << _end; + qCDebug(networking) << "Bad byte range: " << hexHash << " " << _start << ":" << _end; } else { auto size = _end - _start; file.seek(_start); replyPacketList->writePrimitive(AssetServerError::NO_ERROR); replyPacketList->writePrimitive(size); replyPacketList->write(file.read(size)); - qCDebug(networking) << "Sending asset: " << assetHashHex; + qCDebug(networking) << "Sending asset: " << hexHash; } file.close(); } else { - qCDebug(networking) << "Asset not found: " << _filePath << "(" << assetHashHex << ")"; + qCDebug(networking) << "Asset not found: " << _filePath << "(" << hexHash << ")"; writeError(replyPacketList.get(), AssetServerError::ASSET_NOT_FOUND); } } From 8ee27bca2b3e0c6b77dc97b156fb0f0f20457a00 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 16:00:21 -0700 Subject: [PATCH 448/549] remove urlAsString from Model --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 2 +- libraries/render-utils/src/Model.cpp | 3 --- libraries/render-utils/src/Model.h | 2 -- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index eed908e429..8a05591b4b 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -227,7 +227,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) { if (hasModel()) { if (_model) { - if (getModelURL() != _model->getURLAsString()) { + if (getModelURL() != _model->getURL().toString()) { qDebug() << "Updating model URL: " << getModelURL(); _model->setURL(getModelURL()); } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index c2d723a323..74831becb1 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -70,7 +70,6 @@ Model::Model(RigPointer rig, QObject* parent) : _cauterizeBones(false), _pupilDilation(0.0f), _url(HTTP_INVALID_COM), - _urlAsString(HTTP_INVALID_COM), _isVisible(true), _blendNumber(0), _appliedBlendNumber(0), @@ -1028,14 +1027,12 @@ int Model::getLastFreeJointIndex(int jointIndex) const { } void Model::setURL(const QUrl& url) { - // don't recreate the geometry if it's the same URL if (_url == url && _geometry && _geometry->getURL() == url) { return; } _url = url; - _urlAsString = _url.toString(); { render::PendingChanges pendingChanges; diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index e55bff6aca..71fa3d2c2c 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -70,7 +70,6 @@ public: /// Sets the URL of the model to render. Q_INVOKABLE void setURL(const QUrl& url); const QUrl& getURL() const { return _url; } - const QString& getURLAsString() const { return _urlAsString; } // new Scene/Engine rendering support void setVisibleInScene(bool newValue, std::shared_ptr scene); @@ -314,7 +313,6 @@ private: QVector _blendshapeCoefficients; QUrl _url; - QString _urlAsString; QUrl _collisionUrl; bool _isVisible; From 43d2c0653dd00e74533a36c7802c59a5c657f74a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 16:06:54 -0700 Subject: [PATCH 449/549] return correct ATP url from upload dialog --- interface/src/ui/AssetUploadDialogFactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/AssetUploadDialogFactory.cpp b/interface/src/ui/AssetUploadDialogFactory.cpp index e163947c7c..7d87c17b16 100644 --- a/interface/src/ui/AssetUploadDialogFactory.cpp +++ b/interface/src/ui/AssetUploadDialogFactory.cpp @@ -89,7 +89,7 @@ void AssetUploadDialogFactory::handleUploadFinished(AssetUpload* upload, const Q // setup the line edit to hold the copiable text QLineEdit* lineEdit = new QLineEdit; - QString atpURL = QString("%1://%2.%3").arg(ATP_SCHEME).arg(hash).arg(upload->getExtension()); + QString atpURL = QString("%1:%2.%3").arg(ATP_SCHEME).arg(hash).arg(upload->getExtension()); // set the ATP URL as the text value so it's copiable lineEdit->insert(atpURL); From 31bdeed396b98662fba43f0fb47a9afe643c7c57 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 16:43:40 -0700 Subject: [PATCH 450/549] Remove cache limit for atp urls --- libraries/networking/src/ResourceCache.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index b07c3cc60e..c24b83a57f 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -154,28 +154,29 @@ void ResourceCache::clearUnusedResource() { void ResourceCache::attemptRequest(Resource* resource) { auto sharedItems = DependencyManager::get(); - if (_requestLimit <= 0) { - qDebug() << "REQUEST LIMIT REACHED (" << _requestLimit << "), queueing: " << resource->getURL(); - // wait until a slot becomes available - sharedItems->_pendingRequests.append(resource); - return; - } - qDebug() << "-- Decreasing limit for : " << resource->getURL(); // Disable request limiting for ATP if (resource->getURL() != URL_SCHEME_ATP) { + if (_requestLimit <= 0) { + qDebug() << "REQUEST LIMIT REACHED (" << _requestLimit << "), queueing: " << resource->getURL(); + // wait until a slot becomes available + sharedItems->_pendingRequests.append(resource); + return; + } + + qDebug() << "-- Decreasing limit for : " << resource->getURL(); _requestLimit--; } + sharedItems->_loadingRequests.append(resource); resource->makeRequest(); } void ResourceCache::requestCompleted(Resource* resource) { - auto sharedItems = DependencyManager::get(); sharedItems->_loadingRequests.removeOne(resource); - qDebug() << "++ Increasing limit after finished: " << resource->getURL(); if (resource->getURL() != URL_SCHEME_ATP) { + qDebug() << "++ Increasing limit after finished: " << resource->getURL(); _requestLimit++; } From 4bbbd892bd0372cc8e24be2fea515635bfd8afc2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 16:46:33 -0700 Subject: [PATCH 451/549] Fix atp scheme checking in ResourceCache --- libraries/networking/src/ResourceCache.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index c24b83a57f..ec34e9c0b0 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -156,7 +156,7 @@ void ResourceCache::attemptRequest(Resource* resource) { auto sharedItems = DependencyManager::get(); // Disable request limiting for ATP - if (resource->getURL() != URL_SCHEME_ATP) { + if (resource->getURL().scheme() != URL_SCHEME_ATP) { if (_requestLimit <= 0) { qDebug() << "REQUEST LIMIT REACHED (" << _requestLimit << "), queueing: " << resource->getURL(); // wait until a slot becomes available @@ -175,7 +175,7 @@ void ResourceCache::attemptRequest(Resource* resource) { void ResourceCache::requestCompleted(Resource* resource) { auto sharedItems = DependencyManager::get(); sharedItems->_loadingRequests.removeOne(resource); - if (resource->getURL() != URL_SCHEME_ATP) { + if (resource->getURL().scheme() != URL_SCHEME_ATP) { qDebug() << "++ Increasing limit after finished: " << resource->getURL(); _requestLimit++; } From 8ebcb03b2bc27b46bf4d3907858183d9105d97aa Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 16:55:13 -0700 Subject: [PATCH 452/549] don't process duplicate or pre-handshake packets --- libraries/networking/src/udt/Socket.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 1a404eb6c1..72174bf3e7 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -221,9 +221,13 @@ void Socket::readPendingDatagrams() { if (packet->isReliable()) { // if this was a reliable packet then signal the matching connection with the sequence number auto& connection = findOrCreateConnection(senderSockAddr); - connection.processReceivedSequenceNumber(packet->getSequenceNumber(), - packet->getDataSize(), - packet->getPayloadSize()); + + if (!connection.processReceivedSequenceNumber(packet->getSequenceNumber(), + packet->getDataSize(), + packet->getPayloadSize())) { + // the connection indicated that we should not continue processing this packet + return; + } } if (packet->isPartOfMessage()) { From 33dc65a00a6a1201511c04417aea78e543f8107c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 17:09:47 -0700 Subject: [PATCH 453/549] fix for return of processable packets --- libraries/networking/src/udt/Connection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 37e5cfacb5..fe545d8263 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -394,7 +394,7 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in _stats.recordReceivedPackets(payloadSize, packetSize); } - return wasDuplicate; + return !wasDuplicate; } void Connection::processControl(std::unique_ptr controlPacket) { From 5fc09a68a8fd12dc7bf5bf583dac5beb2c92db88 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 17:24:57 -0700 Subject: [PATCH 454/549] add an assert that enqueued packet is part of message --- libraries/networking/src/udt/Connection.cpp | 4 ++++ libraries/networking/src/udt/Socket.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index fe545d8263..de4b76a972 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -737,6 +737,10 @@ void Connection::updateCongestionControlAndSendQueue(std::function cong } void PendingReceivedMessage::enqueuePacket(std::unique_ptr packet) { + Q_ASSERT_X(packet->isPartOfMessage(), + "PendingReceivedMessage::enqueuePacket", + "called with a packet that is not part of a message"); + if (_isComplete) { qCDebug(networking) << "UNEXPECTED: Received packet for a message that is already complete"; return; diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 72174bf3e7..4b1f5f8a83 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -215,7 +215,7 @@ void Socket::readPendingDatagrams() { } else { // setup a Packet from the data we just read auto packet = Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); - + // call our verification operator to see if this packet is verified if (!_packetFilterOperator || _packetFilterOperator(*packet)) { if (packet->isReliable()) { From 147fbd4b54208f46ea167710aed1f4ad8eba2011 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 21:11:12 -0700 Subject: [PATCH 455/549] Update ResourceCache to only emit failure when not retrying --- libraries/networking/src/ResourceCache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index ec34e9c0b0..884ddee00a 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -412,9 +412,9 @@ void Resource::handleReplyFinished() { } auto error = result == ResourceRequest::TIMEOUT ? QNetworkReply::TimeoutError : QNetworkReply::UnknownNetworkError; - emit failed(error); if (!retry) { + emit failed(error); ResourceCache::requestCompleted(this); } } From 98888a36a33d4f84e6119f331eb41082745d94fb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 21:33:37 -0700 Subject: [PATCH 456/549] use const ref where appropriate for asset classes --- libraries/networking/src/AssetClient.cpp | 11 ++++++----- libraries/networking/src/AssetClient.h | 14 +++++++------- libraries/networking/src/AssetRequest.cpp | 5 +++-- libraries/networking/src/AssetRequest.h | 2 +- libraries/networking/src/AssetUpload.cpp | 2 +- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 5333285db6..ea1c99f228 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -30,7 +30,7 @@ AssetClient::AssetClient() { packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); } -AssetRequest* AssetClient::createRequest(QString hash, QString extension) { +AssetRequest* AssetClient::createRequest(const QString& hash, const QString& extension) { if (QThread::currentThread() != thread()) { AssetRequest* req; QMetaObject::invokeMethod(this, "createRequest", @@ -56,7 +56,7 @@ AssetRequest* AssetClient::createRequest(QString hash, QString extension) { return nullptr; } -AssetUpload* AssetClient::createUpload(QString filename) { +AssetUpload* AssetClient::createUpload(const QString& filename) { if (QThread::currentThread() != thread()) { AssetUpload* upload; QMetaObject::invokeMethod(this, "createUpload", @@ -76,7 +76,8 @@ AssetUpload* AssetClient::createUpload(QString filename) { return nullptr; } -bool AssetClient::getAsset(QString hash, QString extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback) { +bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, + ReceivedAssetCallback callback) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { qDebug() << "Invalid hash size"; return false; @@ -112,7 +113,7 @@ bool AssetClient::getAsset(QString hash, QString extension, DataOffset start, Da return false; } -bool AssetClient::getAssetInfo(QString hash, QString extension, GetInfoCallback callback) { +bool AssetClient::getAssetInfo(const QString& hash, const QString& extension, GetInfoCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); @@ -184,7 +185,7 @@ void AssetClient::handleAssetGetReply(QSharedPointer packetList, S } } -bool AssetClient::uploadAsset(QByteArray data, QString extension, UploadResultCallback callback) { +bool AssetClient::uploadAsset(const QByteArray& data, const QString& extension, UploadResultCallback callback) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 79e2e60458..e44737df21 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -29,17 +29,17 @@ struct AssetInfo { int64_t size; }; -using ReceivedAssetCallback = std::function; +using ReceivedAssetCallback = std::function; using GetInfoCallback = std::function; -using UploadResultCallback = std::function; +using UploadResultCallback = std::function; class AssetClient : public QObject, public Dependency { Q_OBJECT public: AssetClient(); - Q_INVOKABLE AssetRequest* createRequest(QString hash, QString extension); - Q_INVOKABLE AssetUpload* createUpload(QString filename); + Q_INVOKABLE AssetRequest* createRequest(const QString& hash, const QString& extension); + Q_INVOKABLE AssetUpload* createUpload(const QString& filename); private slots: void handleAssetGetInfoReply(QSharedPointer packet, SharedNodePointer senderNode); @@ -47,9 +47,9 @@ private slots: void handleAssetUploadReply(QSharedPointer packet, SharedNodePointer senderNode); private: - bool getAssetInfo(QString hash, QString extension, GetInfoCallback callback); - bool getAsset(QString hash, QString extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback); - bool uploadAsset(QByteArray data, QString extension, UploadResultCallback callback); + bool getAssetInfo(const QString& hash, const QString& extension, GetInfoCallback callback); + bool getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback); + bool uploadAsset(const QByteArray& data, const QString& extension, UploadResultCallback callback); static MessageID _currentID; QHash _pendingRequests; diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index be5933e188..771b256287 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -19,11 +19,12 @@ #include "NodeList.h" -AssetRequest::AssetRequest(QObject* parent, QString hash, QString extension) : +AssetRequest::AssetRequest(QObject* parent, const QString& hash, const QString& extension) : QObject(parent), _hash(hash), _extension(extension) { + } void AssetRequest::start() { @@ -51,7 +52,7 @@ void AssetRequest::start() { auto start = i * CHUNK_SIZE; auto end = std::min((i + 1) * CHUNK_SIZE, info.size); - assetClient->getAsset(_hash, _extension, start, end, [this, start, end](bool success, QByteArray data) { + assetClient->getAsset(_hash, _extension, start, end, [this, start, end](bool success, const QByteArray& data) { Q_ASSERT(data.size() == (end - start)); if (success) { diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index 6e0738c333..c369db6a2b 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -37,7 +37,7 @@ public: Error, }; - AssetRequest(QObject* parent, QString hash, QString extension); + AssetRequest(QObject* parent, const QString& hash, const QString& extension); Q_INVOKABLE void start(); diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index 780d062084..7f69f83e97 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -41,7 +41,7 @@ void AssetUpload::start() { // ask the AssetClient to upload the asset and emit the proper signals from the passed callback auto assetClient = DependencyManager::get(); - assetClient->uploadAsset(data, _extension, [this](bool success, QString hash){ + assetClient->uploadAsset(data, _extension, [this](bool success, const QString& hash){ if (success) { // successful upload - emit finished with a point to ourselves and the resulting hash _result = Success; From 341e27fecc4e5c87ed5977f4bccc0c7a1dd23f0d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 27 Aug 2015 22:02:08 -0700 Subject: [PATCH 457/549] unlock mutexes before calling notify --- libraries/networking/src/udt/SendQueue.cpp | 27 ++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index c0638a60f7..36ebd2a6b0 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -77,9 +77,13 @@ SendQueue::SendQueue(Socket* socket, HifiSockAddr dest) : void SendQueue::queuePacket(std::unique_ptr packet) { { - std::lock_guard locker(_packetsLock); + std::unique_lock locker(_packetsLock); + _packets.push_back(std::move(packet)); + // unlock the mutex before we notify + locker.unlock(); + // call notify_one on the condition_variable_any in case the send thread is sleeping waiting for packets _emptyCondition.notify_one(); } @@ -119,10 +123,13 @@ void SendQueue::queuePacketList(std::unique_ptr packetList) { } } - std::lock_guard locker(_packetsLock); + std::unique_lock locker(_packetsLock); _packets.splice(_packets.end(), packetList->_packets); + // unlock the mutex so we can notify + locker.unlock(); + // call notify_one on the condition_variable_any in case the send thread is sleeping waiting for packets _emptyCondition.notify_one(); } @@ -170,15 +177,19 @@ void SendQueue::ack(SequenceNumber ack) { } void SendQueue::nak(SequenceNumber start, SequenceNumber end) { - std::lock_guard nakLocker(_naksLock); + std::unique_lock nakLocker(_naksLock); + _naks.insert(start, end); + // unlock the locked mutex before we notify + nakLocker.unlock(); + // call notify_one on the condition_variable_any in case the send thread is sleeping waiting for losses to re-send _emptyCondition.notify_one(); } void SendQueue::overrideNAKListFromPacket(ControlPacket& packet) { - std::lock_guard nakLocker(_naksLock); + std::unique_lock nakLocker(_naksLock); _naks.clear(); SequenceNumber first, second; @@ -193,13 +204,21 @@ void SendQueue::overrideNAKListFromPacket(ControlPacket& packet) { } } + // unlock the mutex before we notify + nakLocker.unlock(); + // call notify_one on the condition_variable_any in case the send thread is sleeping waiting for losses to re-send _emptyCondition.notify_one(); } void SendQueue::handshakeACK() { std::unique_lock locker(_handshakeMutex); + _hasReceivedHandshakeACK = true; + + // unlock the mutex and notify on the handshake ACK condition + locker.unlock(); + _handshakeACKCondition.notify_one(); } From 2a4b25dd76899ac3e77bbf7885915b62bd1eaad4 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 22:23:06 -0700 Subject: [PATCH 458/549] Update names of ResourceRequest enums --- .../networking/src/AssetResourceRequest.cpp | 8 +++---- .../networking/src/FileResourceRequest.cpp | 6 ++--- .../networking/src/HTTPResourceRequest.cpp | 22 +++++++++---------- libraries/networking/src/ResourceCache.cpp | 10 ++++----- libraries/networking/src/ResourceRequest.cpp | 4 ++-- libraries/networking/src/ResourceRequest.h | 16 +++++++------- libraries/script-engine/src/BatchLoader.cpp | 2 +- libraries/script-engine/src/ScriptCache.cpp | 2 +- 8 files changed, 35 insertions(+), 35 deletions(-) diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 80d4729466..2fa01d917e 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -29,14 +29,14 @@ void AssetResourceRequest::doSend() { connect(request, &AssetRequest::progress, this, &AssetResourceRequest::progress); QObject::connect(request, &AssetRequest::finished, [this](AssetRequest* req) mutable { - if (_state != IN_PROGRESS) return; - _state = FINISHED; + if (_state != InProgress) return; + _state = Finished; if (true) { _data = req->getData(); - _result = ResourceRequest::SUCCESS; + _result = ResourceRequest::Success; emit finished(); } else { - _result = ResourceRequest::ERROR; + _result = ResourceRequest::Error; emit finished(); } }); diff --git a/libraries/networking/src/FileResourceRequest.cpp b/libraries/networking/src/FileResourceRequest.cpp index d8b8d962f5..87e5b5f08f 100644 --- a/libraries/networking/src/FileResourceRequest.cpp +++ b/libraries/networking/src/FileResourceRequest.cpp @@ -16,13 +16,13 @@ void FileResourceRequest::doSend() { QString filename = _url.toLocalFile(); QFile file(filename); - _state = FINISHED; + _state = Finished; if (file.open(QFile::ReadOnly)) { _data = file.readAll(); - _result = ResourceRequest::SUCCESS; + _result = ResourceRequest::Success; emit finished(); } else { - _result = ResourceRequest::ERROR; + _result = ResourceRequest::Error; emit finished(); } } diff --git a/libraries/networking/src/HTTPResourceRequest.cpp b/libraries/networking/src/HTTPResourceRequest.cpp index 22f55cd641..c61fe50f23 100644 --- a/libraries/networking/src/HTTPResourceRequest.cpp +++ b/libraries/networking/src/HTTPResourceRequest.cpp @@ -37,7 +37,7 @@ void HTTPResourceRequest::doSend() { networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); } else { networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); - } + } _reply = networkAccessManager.get(networkRequest); @@ -51,22 +51,22 @@ void HTTPResourceRequest::doSend() { } void HTTPResourceRequest::onRequestFinished() { - Q_ASSERT(_state == IN_PROGRESS); + Q_ASSERT(_state == InProgress); Q_ASSERT(_reply); - _state = FINISHED; + _state = Finished; auto error = _reply->error(); if (error == QNetworkReply::NoError) { _data = _reply->readAll(); _loadedFromCache = _reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(); - _result = ResourceRequest::SUCCESS; + _result = ResourceRequest::Success; emit finished(); } else if (error == QNetworkReply::TimeoutError) { - _result = ResourceRequest::TIMEOUT; + _result = ResourceRequest::Timeout; emit finished(); } else { - _result = ResourceRequest::ERROR; + _result = ResourceRequest::Error; emit finished(); } @@ -75,7 +75,7 @@ void HTTPResourceRequest::onRequestFinished() { } void HTTPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { - if (_state == IN_PROGRESS) { + if (_state == InProgress) { // We've received data, so reset the timer _sendTimer.start(); } @@ -84,13 +84,13 @@ void HTTPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesT } void HTTPResourceRequest::onTimeout() { - Q_ASSERT(_state != UNSENT); + Q_ASSERT(_state != Unsent); - if (_state == IN_PROGRESS) { + if (_state == InProgress) { qCDebug(networking) << "Timed out loading " << _url; _reply->abort(); - _state = FINISHED; - _result = TIMEOUT; + _state = Finished; + _result = Timeout; emit finished(); } } diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 884ddee00a..5598fda24a 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -368,7 +368,7 @@ void Resource::handleReplyFinished() { Q_ASSERT(_request); auto result = _request->getResult(); - if (result == ResourceRequest::SUCCESS) { + if (result == ResourceRequest::Success) { _data = _request->getData(); qDebug() << "Request finished for " << _url << ", " << _activeUrl; @@ -386,7 +386,7 @@ void Resource::handleReplyFinished() { _request->deleteLater(); _request = nullptr; - if (result == ResourceRequest::Result::TIMEOUT) { + if (result == ResourceRequest::Result::Timeout) { qDebug() << "Timed out loading" << _url << "received" << _bytesReceived << "total" << _bytesTotal; } else { qDebug() << "Error loading " << _url; @@ -394,8 +394,8 @@ void Resource::handleReplyFinished() { bool retry = false; switch (result) { - case ResourceRequest::Result::TIMEOUT: - case ResourceRequest::Result::ERROR: { + case ResourceRequest::Result::Timeout: + case ResourceRequest::Result::Error: { // retry with increasing delays const int MAX_ATTEMPTS = 8; const int BASE_DELAY_MS = 1000; @@ -411,7 +411,7 @@ void Resource::handleReplyFinished() { break; } - auto error = result == ResourceRequest::TIMEOUT ? QNetworkReply::TimeoutError : QNetworkReply::UnknownNetworkError; + auto error = result == ResourceRequest::Timeout ? QNetworkReply::TimeoutError : QNetworkReply::UnknownNetworkError; if (!retry) { emit failed(error); diff --git a/libraries/networking/src/ResourceRequest.cpp b/libraries/networking/src/ResourceRequest.cpp index d56033670b..d10f50264f 100644 --- a/libraries/networking/src/ResourceRequest.cpp +++ b/libraries/networking/src/ResourceRequest.cpp @@ -17,8 +17,8 @@ ResourceRequest::ResourceRequest(QObject* parent, const QUrl& url) : } void ResourceRequest::send() { - Q_ASSERT(_state == UNSENT); + Q_ASSERT(_state == Unsent); - _state = IN_PROGRESS; + _state = InProgress; doSend(); } diff --git a/libraries/networking/src/ResourceRequest.h b/libraries/networking/src/ResourceRequest.h index ac13523e96..d734c8caf1 100644 --- a/libraries/networking/src/ResourceRequest.h +++ b/libraries/networking/src/ResourceRequest.h @@ -21,16 +21,16 @@ public: ResourceRequest(QObject* parent, const QUrl& url); enum State { - UNSENT = 0, - IN_PROGRESS, - FINISHED + Unsent = 0, + InProgress, + Finished }; enum Result { - SUCCESS, - ERROR, - TIMEOUT, - NOT_FOUND + Success, + Error, + Timeout, + NotFound }; void send(); @@ -50,7 +50,7 @@ protected: virtual void doSend() = 0; QUrl _url; - State _state { UNSENT }; + State _state { Unsent }; Result _result; QByteArray _data; bool _cacheEnabled { true }; diff --git a/libraries/script-engine/src/BatchLoader.cpp b/libraries/script-engine/src/BatchLoader.cpp index 01e4a5e869..dae8c8e739 100644 --- a/libraries/script-engine/src/BatchLoader.cpp +++ b/libraries/script-engine/src/BatchLoader.cpp @@ -40,7 +40,7 @@ void BatchLoader::start() { continue; } connect(request, &ResourceRequest::finished, this, [=]() { - if (request->getResult() == ResourceRequest::SUCCESS) { + if (request->getResult() == ResourceRequest::Success) { _data.insert(url, request->getData()); } else { _data.insert(url, QString()); diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index e3d12313dc..9e04cd4ec3 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -63,7 +63,7 @@ void ScriptCache::scriptDownloaded() { QList scriptUsers = _scriptUsers.values(url); _scriptUsers.remove(url); - if (req->getResult() == ResourceRequest::SUCCESS) { + if (req->getResult() == ResourceRequest::Success) { _scriptCache[url] = req->getData(); qCDebug(scriptengine) << "Done downloading script at:" << url.toString(); From a7294eb0e5336fd26ed4a67ee2b2480ccb199f55 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 27 Aug 2015 22:48:15 -0700 Subject: [PATCH 459/549] Add AccessDenied error for failure to open File in FileResourceRequest --- libraries/networking/src/FileResourceRequest.cpp | 2 +- libraries/networking/src/ResourceRequest.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/FileResourceRequest.cpp b/libraries/networking/src/FileResourceRequest.cpp index 87e5b5f08f..261b1028f3 100644 --- a/libraries/networking/src/FileResourceRequest.cpp +++ b/libraries/networking/src/FileResourceRequest.cpp @@ -22,7 +22,7 @@ void FileResourceRequest::doSend() { _result = ResourceRequest::Success; emit finished(); } else { - _result = ResourceRequest::Error; + _result = ResourceRequest::AccessDenied; emit finished(); } } diff --git a/libraries/networking/src/ResourceRequest.h b/libraries/networking/src/ResourceRequest.h index d734c8caf1..055d32c1a5 100644 --- a/libraries/networking/src/ResourceRequest.h +++ b/libraries/networking/src/ResourceRequest.h @@ -23,14 +23,15 @@ public: enum State { Unsent = 0, InProgress, - Finished + Finished }; enum Result { Success, Error, Timeout, - NotFound + AccessDenied, + NotFound }; void send(); From d908cd4a530b9298307a279e0d88e471b0f22f10 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 06:35:02 -0700 Subject: [PATCH 460/549] use NotStarted instead of Unsent, return NotFound for Files --- .../networking/src/FileResourceRequest.cpp | 17 ++++++++++++----- .../networking/src/HTTPResourceRequest.cpp | 2 +- libraries/networking/src/ResourceRequest.cpp | 2 +- libraries/networking/src/ResourceRequest.h | 4 ++-- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/libraries/networking/src/FileResourceRequest.cpp b/libraries/networking/src/FileResourceRequest.cpp index 261b1028f3..1c5e0a1977 100644 --- a/libraries/networking/src/FileResourceRequest.cpp +++ b/libraries/networking/src/FileResourceRequest.cpp @@ -15,14 +15,21 @@ void FileResourceRequest::doSend() { QString filename = _url.toLocalFile(); + QFile file(filename); + _state = Finished; - if (file.open(QFile::ReadOnly)) { - _data = file.readAll(); - _result = ResourceRequest::Success; - emit finished(); + if (file.exists()) { + if (file.open(QFile::ReadOnly)) { + _data = file.readAll(); + _result = ResourceRequest::Success; + emit finished(); + } else { + _result = ResourceRequest::AccessDenied; + emit finished(); + } } else { - _result = ResourceRequest::AccessDenied; + _result = ResourceRequest::NotFound; emit finished(); } } diff --git a/libraries/networking/src/HTTPResourceRequest.cpp b/libraries/networking/src/HTTPResourceRequest.cpp index c61fe50f23..b122369c30 100644 --- a/libraries/networking/src/HTTPResourceRequest.cpp +++ b/libraries/networking/src/HTTPResourceRequest.cpp @@ -84,7 +84,7 @@ void HTTPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesT } void HTTPResourceRequest::onTimeout() { - Q_ASSERT(_state != Unsent); + Q_ASSERT(_state != NotStarted); if (_state == InProgress) { qCDebug(networking) << "Timed out loading " << _url; diff --git a/libraries/networking/src/ResourceRequest.cpp b/libraries/networking/src/ResourceRequest.cpp index d10f50264f..c6880636ea 100644 --- a/libraries/networking/src/ResourceRequest.cpp +++ b/libraries/networking/src/ResourceRequest.cpp @@ -17,7 +17,7 @@ ResourceRequest::ResourceRequest(QObject* parent, const QUrl& url) : } void ResourceRequest::send() { - Q_ASSERT(_state == Unsent); + Q_ASSERT(_state == NotStarted); _state = InProgress; doSend(); diff --git a/libraries/networking/src/ResourceRequest.h b/libraries/networking/src/ResourceRequest.h index 055d32c1a5..c5e56e4a85 100644 --- a/libraries/networking/src/ResourceRequest.h +++ b/libraries/networking/src/ResourceRequest.h @@ -21,7 +21,7 @@ public: ResourceRequest(QObject* parent, const QUrl& url); enum State { - Unsent = 0, + NotStarted = 0, InProgress, Finished }; @@ -51,7 +51,7 @@ protected: virtual void doSend() = 0; QUrl _url; - State _state { Unsent }; + State _state { NotStarted }; Result _result; QByteArray _data; bool _cacheEnabled { true }; From ea05fcea0c24d3dd663d41355b84dcecf9954da3 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 28 Aug 2015 15:55:00 +0200 Subject: [PATCH 461/549] Forward AssetResourceRequest loading errors --- assignment-client/src/assets/AssetServer.cpp | 2 +- libraries/networking/src/AssetClient.cpp | 13 +-- libraries/networking/src/AssetClient.h | 6 +- libraries/networking/src/AssetRequest.cpp | 86 ++++++++++--------- libraries/networking/src/AssetRequest.h | 15 ++-- .../networking/src/AssetResourceRequest.cpp | 27 ++++-- libraries/networking/src/ResourceCache.cpp | 3 +- 7 files changed, 81 insertions(+), 71 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 0308042391..1332ddf7f4 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -114,7 +114,7 @@ void AssetServer::handleAssetGetInfo(QSharedPointer packet, SharedNode replyPacket->writePrimitive(AssetServerError::NO_ERROR); replyPacket->writePrimitive(fileInfo.size()); } else { - qDebug() << "Asset not found: " << assetHash; + qDebug() << "Asset not found: " << assetHash.toHex(); replyPacket->writePrimitive(AssetServerError::ASSET_NOT_FOUND); } diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index ea1c99f228..4d228fc6bd 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -49,11 +49,12 @@ AssetRequest* AssetClient::createRequest(const QString& hash, const QString& ext auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); - if (assetServer) { - return new AssetRequest(this, hash, extension); + if (!assetServer) { + qDebug() << "No Asset Server"; + return nullptr; } - return nullptr; + return new AssetRequest(this, hash, extension); } AssetUpload* AssetClient::createUpload(const QString& filename) { @@ -152,7 +153,7 @@ void AssetClient::handleAssetGetInfoReply(QSharedPointer packet, Share if (_pendingInfoRequests.contains(messageID)) { auto callback = _pendingInfoRequests.take(messageID); - callback(error == NO_ERROR, info); + callback(error, info); } } @@ -181,7 +182,7 @@ void AssetClient::handleAssetGetReply(QSharedPointer packetList, S if (_pendingRequests.contains(messageID)) { auto callback = _pendingRequests.take(messageID); - callback(error == NO_ERROR, data); + callback(error, data); } } @@ -234,6 +235,6 @@ void AssetClient::handleAssetUploadReply(QSharedPointer packet, Shared if (_pendingUploads.contains(messageID)) { auto callback = _pendingUploads.take(messageID); - callback(error == NO_ERROR, hashString); + callback(error, hashString); } } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index e44737df21..7fa1771873 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -29,9 +29,9 @@ struct AssetInfo { int64_t size; }; -using ReceivedAssetCallback = std::function; -using GetInfoCallback = std::function; -using UploadResultCallback = std::function; +using ReceivedAssetCallback = std::function; +using GetInfoCallback = std::function; +using UploadResultCallback = std::function; class AssetClient : public QObject, public Dependency { Q_OBJECT diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 771b256287..2d2a15bd60 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -16,9 +16,9 @@ #include #include "AssetClient.h" +#include "NetworkLogging.h" #include "NodeList.h" - AssetRequest::AssetRequest(QObject* parent, const QString& hash, const QString& extension) : QObject(parent), _hash(hash), @@ -33,45 +33,49 @@ void AssetRequest::start() { return; } - if (_state == NOT_STARTED) { - _state = WAITING_FOR_INFO; - - auto assetClient = DependencyManager::get(); - assetClient->getAssetInfo(_hash, _extension, [this](bool success, AssetInfo info) { - _info = info; - _data.resize(info.size); - const DataOffset CHUNK_SIZE = 1024000000; - - qDebug() << "Got size of " << _hash << " : " << info.size << " bytes"; - - // Round up - int numChunks = (info.size + CHUNK_SIZE - 1) / CHUNK_SIZE; - auto assetClient = DependencyManager::get(); - for (int i = 0; i < numChunks; ++i) { - ++_numPendingRequests; - auto start = i * CHUNK_SIZE; - auto end = std::min((i + 1) * CHUNK_SIZE, info.size); - - assetClient->getAsset(_hash, _extension, start, end, [this, start, end](bool success, const QByteArray& data) { - Q_ASSERT(data.size() == (end - start)); - - if (success) { - _result = Success; - memcpy((_data.data() + start), data.constData(), end - start); - _totalReceived += data.size(); - emit progress(_totalReceived, _info.size); - } else { - _result = Error; - qDebug() << "Got error retrieving asset"; - } - - --_numPendingRequests; - if (_numPendingRequests == 0) { - _state = FINISHED; - emit finished(this); - } - }); - } - }); + if (_state != NOT_STARTED) { + qCWarning(networking) << "AssetRequest already started."; + return; } + + _state = WAITING_FOR_INFO; + + auto assetClient = DependencyManager::get(); + assetClient->getAssetInfo(_hash, _extension, [this](AssetServerError error, AssetInfo info) { + _info = info; + _error = error; + + if (_error != NO_ERROR) { + qCDebug(networking) << "Got error retrieving asset info for" << _hash; + _state = FINISHED; + emit finished(this); + return; + } + + _state = WAITING_FOR_DATA; + _data.resize(info.size); + + qCDebug(networking) << "Got size of " << _hash << " : " << info.size << " bytes"; + + // Round up + int start = 0, end = _info.size; + + auto assetClient = DependencyManager::get(); + assetClient->getAsset(_hash, _extension, start, end, [this, start, end](AssetServerError error, + const QByteArray& data) { + Q_ASSERT(data.size() == (end - start)); + + _error = error; + if (_error == NO_ERROR) { + memcpy(_data.data() + start, data.constData(), data.size()); + _totalReceived += data.size(); + emit progress(_totalReceived, _info.size); + } else { + qCDebug(networking) << "Got error retrieving asset" << _hash; + } + + _state = FINISHED; + emit finished(this); + }); + }); } diff --git a/libraries/networking/src/AssetRequest.h b/libraries/networking/src/AssetRequest.h index c369db6a2b..b33954d34e 100644 --- a/libraries/networking/src/AssetRequest.h +++ b/libraries/networking/src/AssetRequest.h @@ -30,26 +30,21 @@ public: FINISHED }; - enum Result { - Success = 0, - Timeout, - NotFound, - Error, - }; - AssetRequest(QObject* parent, const QString& hash, const QString& extension); Q_INVOKABLE void start(); - const QByteArray& getData() { return _data; } + const QByteArray& getData() const { return _data; } + State getState() const { return _state; } + AssetServerError getError() const { return _error; } signals: - void finished(AssetRequest*); + void finished(AssetRequest* thisRequest); void progress(qint64 totalReceived, qint64 total); private: State _state = NOT_STARTED; - Result _result; + AssetServerError _error; AssetInfo _info; uint64_t _totalReceived { 0 }; QString _hash; diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 2fa01d917e..4172990d86 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -29,16 +29,25 @@ void AssetResourceRequest::doSend() { connect(request, &AssetRequest::progress, this, &AssetResourceRequest::progress); QObject::connect(request, &AssetRequest::finished, [this](AssetRequest* req) mutable { - if (_state != InProgress) return; - _state = Finished; - if (true) { - _data = req->getData(); - _result = ResourceRequest::Success; - emit finished(); - } else { - _result = ResourceRequest::Error; - emit finished(); + + Q_ASSERT(_state == InProgress); + Q_ASSERT(req->getState() == AssetRequest::FINISHED); + + switch (req->getError()) { + case NO_ERROR: + _data = req->getData(); + _result = Success; + break; + case ASSET_NOT_FOUND: + _result = NotFound; + break; + default: + _result = Error; + break; } + + _state = Finished; + emit finished(); }); request->start(); diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 5598fda24a..f3b534af15 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -323,10 +323,11 @@ void Resource::attemptRequest() { } void Resource::finishedLoading(bool success) { - qDebug() << "Finished loading: " << _url; if (success) { + qDebug() << "Finished loading:" << _url; _loaded = true; } else { + qDebug() << "Failed to load:" << _url; _failedToLoad = true; } _loadPriorities.clear(); From 12fdec232b468d40260717e09ef747b8ca90121a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 28 Aug 2015 16:31:02 +0200 Subject: [PATCH 462/549] CR --- assignment-client/src/assets/AssetServer.cpp | 2 +- libraries/networking/src/AssetRequest.cpp | 1 - libraries/networking/src/AssetResourceRequest.cpp | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 1332ddf7f4..8c4807f412 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -114,7 +114,7 @@ void AssetServer::handleAssetGetInfo(QSharedPointer packet, SharedNode replyPacket->writePrimitive(AssetServerError::NO_ERROR); replyPacket->writePrimitive(fileInfo.size()); } else { - qDebug() << "Asset not found: " << assetHash.toHex(); + qDebug() << "Asset not found: " << QString(hexHash); replyPacket->writePrimitive(AssetServerError::ASSET_NOT_FOUND); } diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 2d2a15bd60..69bf86302c 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -57,7 +57,6 @@ void AssetRequest::start() { qCDebug(networking) << "Got size of " << _hash << " : " << info.size << " bytes"; - // Round up int start = 0, end = _info.size; auto assetClient = DependencyManager::get(); diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 4172990d86..93c1b49329 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -29,7 +29,6 @@ void AssetResourceRequest::doSend() { connect(request, &AssetRequest::progress, this, &AssetResourceRequest::progress); QObject::connect(request, &AssetRequest::finished, [this](AssetRequest* req) mutable { - Q_ASSERT(_state == InProgress); Q_ASSERT(req->getState() == AssetRequest::FINISHED); From 28d9610bd494c07edb23a18bf9284d94e5695e83 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 07:31:17 -0700 Subject: [PATCH 463/549] add a listen port option to ACs --- assignment-client/src/AssignmentClient.cpp | 6 +++--- assignment-client/src/AssignmentClient.h | 1 + assignment-client/src/AssignmentClientApp.cpp | 16 +++++++++++++--- assignment-client/src/AssignmentClientApp.h | 6 +++--- .../src/AssignmentClientMonitor.cpp | 4 ++-- assignment-client/src/AssignmentClientMonitor.h | 2 +- 6 files changed, 23 insertions(+), 12 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 3780655536..708589c32f 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -42,8 +42,8 @@ const long long ASSIGNMENT_REQUEST_INTERVAL_MSECS = 1 * 1000; int hifiSockAddrMeta = qRegisterMetaType("HifiSockAddr"); AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool, - QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort, - quint16 assignmentMonitorPort) : + quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, + quint16 assignmentServerPort, quint16 assignmentMonitorPort) : _assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME) { LogUtils::init(); @@ -53,7 +53,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri auto addressManager = DependencyManager::set(); // create a NodeList as an unassigned client, must be after addressManager - auto nodeList = DependencyManager::set(NodeType::Unassigned); + auto nodeList = DependencyManager::set(NodeType::Unassigned, listenPort); auto animationCache = DependencyManager::set(); auto entityScriptingInterface = DependencyManager::set(); diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index 73eaa3dc9f..9d2c816861 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -23,6 +23,7 @@ class AssignmentClient : public QObject { Q_OBJECT public: AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool, + quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort, quint16 assignmentMonitorPort); ~AssignmentClient(); diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 2edae340c3..3b9f8af868 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -59,6 +59,10 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : const QCommandLineOption poolOption(ASSIGNMENT_POOL_OPTION, "set assignment pool", "pool-name"); parser.addOption(poolOption); + + const QCommandLineOption portOption(ASSIGNMENT_CLIENT_LISTEN_PORT_OPTION, + "UDP port for this assignment client (or monitor)", "port"); + parser.addOption(portOption); const QCommandLineOption walletDestinationOption(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION, "set wallet destination", "wallet-uuid"); @@ -158,12 +162,18 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : // check for an overriden assignment server port quint16 assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT; if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) { - assignmentServerPort = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toString().toUInt(); + assignmentServerPort = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toUInt(); } if (parser.isSet(assignmentServerPortOption)) { assignmentServerPort = parser.value(assignmentServerPortOption).toInt(); } + + // check for an overidden listen port + quint16 listenPort = 0; + if (argumentVariantMap.contains(ASSIGNMENT_CLIENT_LISTEN_PORT_OPTION)) { + listenPort = argumentVariantMap.value(ASSIGNMENT_CLIENT_LISTEN_PORT_OPTION).toUInt(); + } if (parser.isSet(numChildsOption)) { if (minForks && minForks > numForks) { @@ -185,12 +195,12 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : if (numForks || minForks || maxForks) { AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks, requestAssignmentType, assignmentPool, - walletUUID, assignmentServerHostname, + listenPort, walletUUID, assignmentServerHostname, assignmentServerPort); monitor->setParent(this); connect(this, &QCoreApplication::aboutToQuit, monitor, &AssignmentClientMonitor::aboutToQuit); } else { - AssignmentClient* client = new AssignmentClient(requestAssignmentType, assignmentPool, + AssignmentClient* client = new AssignmentClient(requestAssignmentType, assignmentPool, listenPort, walletUUID, assignmentServerHostname, assignmentServerPort, monitorPort); client->setParent(this); diff --git a/assignment-client/src/AssignmentClientApp.h b/assignment-client/src/AssignmentClientApp.h index bbc60256a7..ab7e8ed304 100644 --- a/assignment-client/src/AssignmentClientApp.h +++ b/assignment-client/src/AssignmentClientApp.h @@ -17,15 +17,15 @@ const QString ASSIGNMENT_TYPE_OVERRIDE_OPTION = "t"; const QString ASSIGNMENT_POOL_OPTION = "pool"; +const QString ASSIGNMENT_CLIENT_LISTEN_PORT_OPTION = "p"; const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet"; -const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a"; -const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "p"; +const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "i"; +const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "server-port"; const QString ASSIGNMENT_NUM_FORKS_OPTION = "n"; const QString ASSIGNMENT_MIN_FORKS_OPTION = "min"; const QString ASSIGNMENT_MAX_FORKS_OPTION = "max"; const QString ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION = "monitor-port"; - class AssignmentClientApp : public QCoreApplication { Q_OBJECT public: diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index ddea6cc702..5bb31c8c6f 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -28,7 +28,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen const unsigned int minAssignmentClientForks, const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType, QString assignmentPool, - QUuid walletUUID, QString assignmentServerHostname, + quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort) : _numAssignmentClientForks(numAssignmentClientForks), _minAssignmentClientForks(minAssignmentClientForks), @@ -50,7 +50,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen // create a NodeList so we can receive stats from children DependencyManager::registerInheritance(); auto addressManager = DependencyManager::set(); - auto nodeList = DependencyManager::set(); + auto nodeList = DependencyManager::set(listenPort); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(PacketType::AssignmentClientStatus, this, "handleChildStatusPacket"); diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 8463498d7d..93fc9361ad 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -28,7 +28,7 @@ class AssignmentClientMonitor : public QObject { public: AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks, const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType, - QString assignmentPool, QUuid walletUUID, QString assignmentServerHostname, + QString assignmentPool, quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort); ~AssignmentClientMonitor(); From cf98d4a8f74616ca08f55eceb80e1e01d9decb00 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 07:31:44 -0700 Subject: [PATCH 464/549] add a control packet type for LightACK --- libraries/networking/src/udt/Connection.cpp | 12 ++++++------ libraries/networking/src/udt/ControlPacket.h | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index de4b76a972..a502c714e3 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -237,7 +237,7 @@ void Connection::sendLightACK() { // create the light ACK packet, make it static so we can re-use it static const int LIGHT_ACK_PACKET_PAYLOAD_BYTES = sizeof(SequenceNumber); - static auto lightACKPacket = ControlPacket::create(ControlPacket::ACK, LIGHT_ACK_PACKET_PAYLOAD_BYTES); + static auto lightACKPacket = ControlPacket::create(ControlPacket::LightACK, LIGHT_ACK_PACKET_PAYLOAD_BYTES); // reset the lightACKPacket before we go to write the ACK to it lightACKPacket->reset(); @@ -407,13 +407,13 @@ void Connection::processControl(std::unique_ptr controlPacket) { switch (controlPacket->getType()) { case ControlPacket::ACK: if (_hasReceivedHandshakeACK) { - if (controlPacket->getPayloadSize() == sizeof(SequenceNumber)) { - processLightACK(move(controlPacket)); - } else { - processACK(move(controlPacket)); - } + processACK(move(controlPacket)); } break; + case ControlPacket::LightACK: + if (_hasReceivedHandshakeACK) { + processLightACK(move(controlPacket)); + } case ControlPacket::ACK2: if (_hasReceivedHandshake) { processACK2(move(controlPacket)); diff --git a/libraries/networking/src/udt/ControlPacket.h b/libraries/networking/src/udt/ControlPacket.h index bcc559f4f6..1976899c14 100644 --- a/libraries/networking/src/udt/ControlPacket.h +++ b/libraries/networking/src/udt/ControlPacket.h @@ -29,6 +29,7 @@ public: enum Type : uint16_t { ACK, ACK2, + LightACK, NAK, TimeoutNAK, Handshake, From 77aeae7dc03a5dd2d83c24dc3750e714de4086c6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 09:10:06 -0700 Subject: [PATCH 465/549] change to timeout behaviour to re-send unACKed packets --- libraries/networking/src/udt/Connection.cpp | 7 +- libraries/networking/src/udt/SendQueue.cpp | 87 +++++++++++++++------ libraries/networking/src/udt/SendQueue.h | 7 +- 3 files changed, 73 insertions(+), 28 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index a502c714e3..74ad707b11 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -727,9 +727,12 @@ void Connection::updateCongestionControlAndSendQueue(std::function cong // fire congestion control callback congestionCallback(); + auto& sendQueue = getSendQueue(); + // now that we've updated the congestion control, update the packet send period and flow window size - getSendQueue().setPacketSendPeriod(_congestionControl->_packetSendPeriod); - getSendQueue().setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); + sendQueue.setPacketSendPeriod(_congestionControl->_packetSendPeriod); + sendQueue.setEstimatedTimeout(estimatedTimeout()); + sendQueue.setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); // record connection stats _stats.recordPacketSendPeriod(_congestionControl->_packetSendPeriod); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 36ebd2a6b0..7db24a63a3 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -154,6 +154,9 @@ void SendQueue::sendPacket(const Packet& packet) { } void SendQueue::ack(SequenceNumber ack) { + // this is a response from the client, re-set our timeout expiry + _timeoutExpiryCount = 0; + if (_lastACKSequenceNumber == (uint32_t) ack) { return; } @@ -177,6 +180,9 @@ void SendQueue::ack(SequenceNumber ack) { } void SendQueue::nak(SequenceNumber start, SequenceNumber end) { + // this is a response from the client, re-set our timeout expiry + _timeoutExpiryCount = 0; + std::unique_lock nakLocker(_naksLock); _naks.insert(start, end); @@ -189,6 +195,9 @@ void SendQueue::nak(SequenceNumber start, SequenceNumber end) { } void SendQueue::overrideNAKListFromPacket(ControlPacket& packet) { + // this is a response from the client, re-set our timeout expiry + _timeoutExpiryCount = 0; + std::unique_lock nakLocker(_naksLock); _naks.clear(); @@ -212,7 +221,7 @@ void SendQueue::overrideNAKListFromPacket(ControlPacket& packet) { } void SendQueue::handshakeACK() { - std::unique_lock locker(_handshakeMutex); + std::unique_lock locker { _handshakeMutex }; _hasReceivedHandshakeACK = true; @@ -258,7 +267,7 @@ void SendQueue::run() { while (_isRunning) { // Record how long the loop takes to execute auto loopStartTimestamp = high_resolution_clock::now(); - + std::unique_lock handshakeLock { _handshakeMutex }; if (!_hasReceivedHandshakeACK) { @@ -305,12 +314,6 @@ void SendQueue::run() { sentAPacket = maybeSendNewPacket(); } - // Keep track of how long the flow window has been full for - if (flowWindowFull && !_flowWindowWasFull) { - _flowWindowFullSince = loopStartTimestamp; - } - _flowWindowWasFull = flowWindowFull; - // since we're a while loop, give the thread a chance to process events QCoreApplication::processEvents(); @@ -320,15 +323,22 @@ void SendQueue::run() { } if (_hasReceivedHandshakeACK && !sentAPacket) { - static const std::chrono::seconds CONSIDER_INACTIVE_AFTER { 5 }; + // check if it is time to break this connection - if (flowWindowFull && (high_resolution_clock::now() - _flowWindowFullSince) > CONSIDER_INACTIVE_AFTER) { + // that will be the case if we have had 16 timeouts since hearing back from the client, and it has been + // at least 10 seconds + + static const int NUM_TIMEOUTS_BEFORE_INACTIVE = 16; + + if (_timeoutExpiryCount >= NUM_TIMEOUTS_BEFORE_INACTIVE) { // If the flow window has been full for over CONSIDER_INACTIVE_AFTER, // then signal the queue is inactive and return so it can be cleaned up + qDebug() << "SendQueue to" << _destination << "reached" << NUM_TIMEOUTS_BEFORE_INACTIVE << "timeouts and is" + << "considered inactive. It is now being stopped."; emit queueInactive(); return; } else { - // During our processing above we didn't send any packets and the flow window is not full. + // During our processing above we didn't send any packets // If that is still the case we should use a condition_variable_any to sleep until we have data to handle. // To confirm that the queue of packets and the NAKs list are still both empty we'll need to use the DoubleLock @@ -337,21 +347,49 @@ void SendQueue::run() { // The packets queue and loss list mutexes are now both locked - check if they're still both empty if (doubleLock.try_lock() && _packets.empty() && _naks.getLength() == 0) { - // both are empty - let's use a condition_variable_any to wait - auto cvStatus = _emptyCondition.wait_for(doubleLock, CONSIDER_INACTIVE_AFTER); - - // we have the double lock again - Make sure to unlock it - doubleLock.unlock(); + if (uint32_t(_lastACKSequenceNumber) == uint32_t(_currentSequenceNumber)) { + // we've sent the client as much data as we have (and they've ACKed it) + // either wait for new data to send or 5 seconds before cleaning up the queue + static const auto EMPTY_QUEUES_INACTIVE_TIMEOUT_US = std::chrono::microseconds(5 * 1000 * 1000); - if (cvStatus == std::cv_status::timeout) { - // the wait_for released because we've been inactive for too long - // so emit our inactive signal and return so the send queue can be cleaned up - emit queueInactive(); - return; + // use our condition_variable_any to wait + auto cvStatus = _emptyCondition.wait_for(doubleLock, EMPTY_QUEUES_INACTIVE_TIMEOUT_US); + + // we have the double lock again - Make sure to unlock it + doubleLock.unlock(); + + if (cvStatus == std::cv_status::timeout) { + qDebug() << "SendQueue to" << _destination << "has been empty for" + << std::chrono::duration_cast(EMPTY_QUEUES_INACTIVE_TIMEOUT_US).count() + << "and receiver has ACKed all packets. The queue is considered inactive and will be stopped"; + + // this queue is inactive - emit that signal and stop the while + emit queueInactive(); + return; + } + } else { + // We think the client is still waiting for data (based on the sequence number gap) + // Let's wait either for a response from the client or until the estimated timeout + auto waitDuration = std::chrono::microseconds(_estimatedTimeout); + + // use our condition_variable_any to wait + auto cvStatus = _emptyCondition.wait_for(doubleLock, waitDuration); + + if (cvStatus == std::cv_status::timeout) { + // increase the number of timeouts + ++_timeoutExpiryCount; + + // Add all of the packets above the last received ACKed sequence number to the loss list + // Note that thanks to the DoubleLock we have the _naksLock right now + _naks.append(SequenceNumber(_lastACKSequenceNumber) + 1, _currentSequenceNumber); + } + + // we have the double lock again - Make sure to unlock it + doubleLock.unlock(); + + // skip to the next iteration + continue; } - - // skip to the next iteration - continue; } } } @@ -452,4 +490,3 @@ bool SendQueue::maybeResendPacket() { // No packet was resent return false; } - diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 70493f2054..22d52d28f0 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -57,6 +57,8 @@ public: int getPacketSendPeriod() const { return _packetSendPeriod; } void setPacketSendPeriod(int newPeriod) { _packetSendPeriod = newPeriod; } + void setEstimatedTimeout(int estimatedTimeout) { _estimatedTimeout = estimatedTimeout; } + public slots: void stop(); @@ -104,6 +106,9 @@ private: std::atomic _packetSendPeriod { 0 }; // Interval between two packet send event in microseconds, set from CC std::atomic _isRunning { false }; + std::atomic _estimatedTimeout { 0 }; // Estimated timeout, set from CC + std::atomic _timeoutExpiryCount { 0 }; // The number of times the timeout has expired without response from client + std::atomic _flowWindowSize { 0 }; // Flow control window size (number of packets that can be on wire) - set from CC // Used to detect when the connection becomes inactive for too long @@ -117,7 +122,7 @@ private: std::unordered_map> _sentPackets; // Packets waiting for ACK. std::mutex _handshakeMutex; // Protects the handshake ACK condition_variable - bool _hasReceivedHandshakeACK { false }; // flag for receipt of handshake ACK from client + std::atomic _hasReceivedHandshakeACK { false }; // flag for receipt of handshake ACK from client std::condition_variable _handshakeACKCondition; std::condition_variable_any _emptyCondition; From 539108dd454a13cfb8ed345b2a47683aca42cfac Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 09:26:32 -0700 Subject: [PATCH 466/549] repairs for new timeout code --- libraries/networking/src/udt/Connection.cpp | 3 ++- libraries/networking/src/udt/SendQueue.cpp | 13 +++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 74ad707b11..93c13874ea 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -78,8 +78,9 @@ SendQueue& Connection::getSendQueue() { QObject::connect(_sendQueue.get(), &SendQueue::packetRetransmitted, this, &Connection::recordRetransmission); QObject::connect(_sendQueue.get(), &SendQueue::queueInactive, this, &Connection::queueInactive); - // set defaults on the send queue from our congestion control object + // set defaults on the send queue from our congestion control object and estimatedTimeout() _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); + _sendQueue->setEstimatedTimeout(estimatedTimeout()); _sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); } diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 7db24a63a3..d627937761 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -361,7 +361,8 @@ void SendQueue::run() { if (cvStatus == std::cv_status::timeout) { qDebug() << "SendQueue to" << _destination << "has been empty for" << std::chrono::duration_cast(EMPTY_QUEUES_INACTIVE_TIMEOUT_US).count() - << "and receiver has ACKed all packets. The queue is considered inactive and will be stopped"; + << "seconds and receiver has ACKed all packets." + << "The queue is considered inactive and will be stopped."; // this queue is inactive - emit that signal and stop the while emit queueInactive(); @@ -379,9 +380,13 @@ void SendQueue::run() { // increase the number of timeouts ++_timeoutExpiryCount; - // Add all of the packets above the last received ACKed sequence number to the loss list - // Note that thanks to the DoubleLock we have the _naksLock right now - _naks.append(SequenceNumber(_lastACKSequenceNumber) + 1, _currentSequenceNumber); + if (SequenceNumber(_lastACKSequenceNumber) < _currentSequenceNumber) { + // after a timeout if we still have sent packets that the client hasn't ACKed we + // add them to the loss list + + // Note that thanks to the DoubleLock we have the _naksLock right now + _naks.append(SequenceNumber(_lastACKSequenceNumber) + 1, _currentSequenceNumber); + } } // we have the double lock again - Make sure to unlock it From 21c80e45c2ef9823ccc9ae5ed0813095f19ada96 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 09:42:52 -0700 Subject: [PATCH 467/549] guard connection addition by a mutex in Socket --- libraries/networking/src/udt/SendQueue.cpp | 7 +++++++ libraries/networking/src/udt/Socket.cpp | 6 ++++++ libraries/networking/src/udt/Socket.h | 2 ++ 3 files changed, 15 insertions(+) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index d627937761..3ee4d48d1d 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -335,7 +335,11 @@ void SendQueue::run() { // then signal the queue is inactive and return so it can be cleaned up qDebug() << "SendQueue to" << _destination << "reached" << NUM_TIMEOUTS_BEFORE_INACTIVE << "timeouts and is" << "considered inactive. It is now being stopped."; + emit queueInactive(); + + _isRunning = false; + return; } else { // During our processing above we didn't send any packets @@ -366,6 +370,9 @@ void SendQueue::run() { // this queue is inactive - emit that signal and stop the while emit queueInactive(); + + _isRunning = false; + return; } } else { diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 4b1f5f8a83..c9a681abfc 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -143,6 +143,8 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc } Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { + QWriteLocker locker(&_connectionsMutex); + auto it = _connectionsHash.find(sockAddr); if (it == _connectionsHash.end()) { @@ -160,12 +162,16 @@ void Socket::clearConnections() { return; } + QWriteLocker locker(&_connectionsMutex); + // clear all of the current connections in the socket qDebug() << "Clearing all remaining connections in Socket."; _connectionsHash.clear(); } void Socket::cleanupConnection(HifiSockAddr sockAddr) { + QWriteLocker locker(&_connectionsMutex); + qCDebug(networking) << "Socket::cleanupConnection called for UDT connection to" << sockAddr; _connectionsHash.erase(sockAddr); } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index f421b98288..fa6bf874a8 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -94,6 +94,8 @@ private: std::unordered_map _unreliableSequenceNumbers; std::unordered_map> _connectionsHash; + QReadWriteLock _connectionsMutex; // guards concurrent access to connections hashs + int _synInterval = 10; // 10ms QTimer _synTimer; From dcd5a4aec2e9efe9f0ae9301d40d260d61431217 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 09:47:25 -0700 Subject: [PATCH 468/549] address comments in code review --- libraries/networking/src/FileResourceRequest.cpp | 5 ++--- libraries/networking/src/udt/SendQueue.cpp | 13 ++++++------- libraries/networking/src/udt/SendQueue.h | 4 ---- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/libraries/networking/src/FileResourceRequest.cpp b/libraries/networking/src/FileResourceRequest.cpp index 1c5e0a1977..ffaaa0d193 100644 --- a/libraries/networking/src/FileResourceRequest.cpp +++ b/libraries/networking/src/FileResourceRequest.cpp @@ -23,13 +23,12 @@ void FileResourceRequest::doSend() { if (file.open(QFile::ReadOnly)) { _data = file.readAll(); _result = ResourceRequest::Success; - emit finished(); } else { _result = ResourceRequest::AccessDenied; - emit finished(); } } else { _result = ResourceRequest::NotFound; - emit finished(); } + + emit finished(); } diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 3ee4d48d1d..9a371749e2 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -304,14 +304,13 @@ void SendQueue::run() { handshakeLock.unlock(); bool sentAPacket = maybeResendPacket(); - bool flowWindowFull = false; // if we didn't find a packet to re-send AND we think we can fit a new packet on the wire // (this is according to the current flow window size) then we send out a new packet if (_hasReceivedHandshakeACK && !sentAPacket) { - flowWindowFull = (seqlen(SequenceNumber { (uint32_t) _lastACKSequenceNumber }, _currentSequenceNumber) > - _flowWindowSize); - sentAPacket = maybeSendNewPacket(); + if (seqlen(SequenceNumber { (uint32_t) _lastACKSequenceNumber }, _currentSequenceNumber) > _flowWindowSize) { + sentAPacket = maybeSendNewPacket(); + } } // since we're a while loop, give the thread a chance to process events @@ -354,17 +353,17 @@ void SendQueue::run() { if (uint32_t(_lastACKSequenceNumber) == uint32_t(_currentSequenceNumber)) { // we've sent the client as much data as we have (and they've ACKed it) // either wait for new data to send or 5 seconds before cleaning up the queue - static const auto EMPTY_QUEUES_INACTIVE_TIMEOUT_US = std::chrono::microseconds(5 * 1000 * 1000); + static const auto EMPTY_QUEUES_INACTIVE_TIMEOUT = std::chrono::seconds(5 * 1000 * 1000); // use our condition_variable_any to wait - auto cvStatus = _emptyCondition.wait_for(doubleLock, EMPTY_QUEUES_INACTIVE_TIMEOUT_US); + auto cvStatus = _emptyCondition.wait_for(doubleLock, EMPTY_QUEUES_INACTIVE_TIMEOUT); // we have the double lock again - Make sure to unlock it doubleLock.unlock(); if (cvStatus == std::cv_status::timeout) { qDebug() << "SendQueue to" << _destination << "has been empty for" - << std::chrono::duration_cast(EMPTY_QUEUES_INACTIVE_TIMEOUT_US).count() + << EMPTY_QUEUES_INACTIVE_TIMEOUT.count() << "seconds and receiver has ACKed all packets." << "The queue is considered inactive and will be stopped."; diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 22d52d28f0..c6668f1d09 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -111,10 +111,6 @@ private: std::atomic _flowWindowSize { 0 }; // Flow control window size (number of packets that can be on wire) - set from CC - // Used to detect when the connection becomes inactive for too long - bool _flowWindowWasFull = false; - time_point _flowWindowFullSince; - mutable std::mutex _naksLock; // Protects the naks list. LossList _naks; // Sequence numbers of packets to resend From e662209754f3f7f7463f75ce322a841306e245e9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 09:48:55 -0700 Subject: [PATCH 469/549] use a QMutex instead of QReadWriteMutex --- libraries/networking/src/udt/Socket.cpp | 6 +++--- libraries/networking/src/udt/Socket.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index c9a681abfc..f3ce095b50 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -143,7 +143,7 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc } Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { - QWriteLocker locker(&_connectionsMutex); + QMutexLocker locker(&_connectionsMutex); auto it = _connectionsHash.find(sockAddr); @@ -162,7 +162,7 @@ void Socket::clearConnections() { return; } - QWriteLocker locker(&_connectionsMutex); + QMutexLocker locker(&_connectionsMutex); // clear all of the current connections in the socket qDebug() << "Clearing all remaining connections in Socket."; @@ -170,7 +170,7 @@ void Socket::clearConnections() { } void Socket::cleanupConnection(HifiSockAddr sockAddr) { - QWriteLocker locker(&_connectionsMutex); + QMutexLocker locker(&_connectionsMutex); qCDebug(networking) << "Socket::cleanupConnection called for UDT connection to" << sockAddr; _connectionsHash.erase(sockAddr); diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index fa6bf874a8..23dd313462 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -94,7 +94,7 @@ private: std::unordered_map _unreliableSequenceNumbers; std::unordered_map> _connectionsHash; - QReadWriteLock _connectionsMutex; // guards concurrent access to connections hashs + QMutex _connectionsMutex; // guards concurrent access to connections hashs int _synInterval = 10; // 10ms QTimer _synTimer; From 577b6bf62f5b966f02fc7435c54a2747eb9e0941 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 09:52:33 -0700 Subject: [PATCH 470/549] correct the check for flow window size --- libraries/networking/src/udt/SendQueue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 9a371749e2..686701be9c 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -308,7 +308,7 @@ void SendQueue::run() { // if we didn't find a packet to re-send AND we think we can fit a new packet on the wire // (this is according to the current flow window size) then we send out a new packet if (_hasReceivedHandshakeACK && !sentAPacket) { - if (seqlen(SequenceNumber { (uint32_t) _lastACKSequenceNumber }, _currentSequenceNumber) > _flowWindowSize) { + if (seqlen(SequenceNumber { (uint32_t) _lastACKSequenceNumber }, _currentSequenceNumber) <= _flowWindowSize) { sentAPacket = maybeSendNewPacket(); } } From d66375bb0983ee28efff0a2c81852671d3acd7d6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 09:54:51 -0700 Subject: [PATCH 471/549] fix queue timeout for empty queue --- libraries/networking/src/udt/SendQueue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 686701be9c..7fcf5517b1 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -353,7 +353,7 @@ void SendQueue::run() { if (uint32_t(_lastACKSequenceNumber) == uint32_t(_currentSequenceNumber)) { // we've sent the client as much data as we have (and they've ACKed it) // either wait for new data to send or 5 seconds before cleaning up the queue - static const auto EMPTY_QUEUES_INACTIVE_TIMEOUT = std::chrono::seconds(5 * 1000 * 1000); + static const auto EMPTY_QUEUES_INACTIVE_TIMEOUT = std::chrono::seconds(5); // use our condition_variable_any to wait auto cvStatus = _emptyCondition.wait_for(doubleLock, EMPTY_QUEUES_INACTIVE_TIMEOUT); From ac3a1d54b1d5dc1e4ace971802b94aceb1176098 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 10:07:01 -0700 Subject: [PATCH 472/549] don't lock in while for maybeResendPacket --- libraries/networking/src/udt/SendQueue.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 7fcf5517b1..1de2b6febc 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -459,9 +459,10 @@ bool SendQueue::maybeSendNewPacket() { } bool SendQueue::maybeResendPacket() { + std::unique_lock naksLocker(_naksLock); + // the following while makes sure that we find a packet to re-send, if there is one while (true) { - std::unique_lock naksLocker(_naksLock); if (_naks.getLength() > 0) { // pull the sequence number we need to re-send From 54cd430be99d3c51e05da7d77f1ee49b8fd63c40 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 10:35:29 -0700 Subject: [PATCH 473/549] unlock if double lock succeeds but queues not empty --- libraries/networking/src/udt/SendQueue.cpp | 97 ++++++++++++---------- 1 file changed, 51 insertions(+), 46 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 1de2b6febc..1bfefa12e1 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -347,60 +347,65 @@ void SendQueue::run() { // To confirm that the queue of packets and the NAKs list are still both empty we'll need to use the DoubleLock DoubleLock doubleLock(_packetsLock, _naksLock); - // The packets queue and loss list mutexes are now both locked - check if they're still both empty - if (doubleLock.try_lock() && _packets.empty() && _naks.getLength() == 0) { + if (doubleLock.try_lock()) { + // The packets queue and loss list mutexes are now both locked - check if they're still both empty - if (uint32_t(_lastACKSequenceNumber) == uint32_t(_currentSequenceNumber)) { - // we've sent the client as much data as we have (and they've ACKed it) - // either wait for new data to send or 5 seconds before cleaning up the queue - static const auto EMPTY_QUEUES_INACTIVE_TIMEOUT = std::chrono::seconds(5); - - // use our condition_variable_any to wait - auto cvStatus = _emptyCondition.wait_for(doubleLock, EMPTY_QUEUES_INACTIVE_TIMEOUT); - - // we have the double lock again - Make sure to unlock it - doubleLock.unlock(); - - if (cvStatus == std::cv_status::timeout) { - qDebug() << "SendQueue to" << _destination << "has been empty for" + if (_packets.empty() && _naks.getLength() == 0) { + if (uint32_t(_lastACKSequenceNumber) == uint32_t(_currentSequenceNumber)) { + // we've sent the client as much data as we have (and they've ACKed it) + // either wait for new data to send or 5 seconds before cleaning up the queue + static const auto EMPTY_QUEUES_INACTIVE_TIMEOUT = std::chrono::seconds(5); + + // use our condition_variable_any to wait + auto cvStatus = _emptyCondition.wait_for(doubleLock, EMPTY_QUEUES_INACTIVE_TIMEOUT); + + // we have the double lock again - Make sure to unlock it + doubleLock.unlock(); + + if (cvStatus == std::cv_status::timeout) { + qDebug() << "SendQueue to" << _destination << "has been empty for" << EMPTY_QUEUES_INACTIVE_TIMEOUT.count() << "seconds and receiver has ACKed all packets." << "The queue is considered inactive and will be stopped."; - - // this queue is inactive - emit that signal and stop the while - emit queueInactive(); - - _isRunning = false; - - return; - } - } else { - // We think the client is still waiting for data (based on the sequence number gap) - // Let's wait either for a response from the client or until the estimated timeout - auto waitDuration = std::chrono::microseconds(_estimatedTimeout); - - // use our condition_variable_any to wait - auto cvStatus = _emptyCondition.wait_for(doubleLock, waitDuration); - - if (cvStatus == std::cv_status::timeout) { - // increase the number of timeouts - ++_timeoutExpiryCount; - - if (SequenceNumber(_lastACKSequenceNumber) < _currentSequenceNumber) { - // after a timeout if we still have sent packets that the client hasn't ACKed we - // add them to the loss list - // Note that thanks to the DoubleLock we have the _naksLock right now - _naks.append(SequenceNumber(_lastACKSequenceNumber) + 1, _currentSequenceNumber); + // this queue is inactive - emit that signal and stop the while + emit queueInactive(); + + _isRunning = false; + + return; } + } else { + // We think the client is still waiting for data (based on the sequence number gap) + // Let's wait either for a response from the client or until the estimated timeout + auto waitDuration = std::chrono::microseconds(_estimatedTimeout); + + // use our condition_variable_any to wait + auto cvStatus = _emptyCondition.wait_for(doubleLock, waitDuration); + + if (cvStatus == std::cv_status::timeout) { + // increase the number of timeouts + ++_timeoutExpiryCount; + + if (SequenceNumber(_lastACKSequenceNumber) < _currentSequenceNumber) { + // after a timeout if we still have sent packets that the client hasn't ACKed we + // add them to the loss list + + // Note that thanks to the DoubleLock we have the _naksLock right now + _naks.append(SequenceNumber(_lastACKSequenceNumber) + 1, _currentSequenceNumber); + } + } + + // we have the double lock again - Make sure to unlock it + doubleLock.unlock(); + + // skip to the next iteration + continue; } - - // we have the double lock again - Make sure to unlock it - doubleLock.unlock(); - - // skip to the next iteration - continue; } + + // we got the try_lock but failed the other conditionals so we need to unlock + doubleLock.unlock(); } } } From 9575b47e4e7f8a6e7ca7e2d94e02bd8d53b1ae2d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 10:38:15 -0700 Subject: [PATCH 474/549] don't unlock double lock outside conditional --- libraries/networking/src/udt/SendQueue.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 1bfefa12e1..e088cb8d8b 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -402,10 +402,10 @@ void SendQueue::run() { // skip to the next iteration continue; } - } - - // we got the try_lock but failed the other conditionals so we need to unlock - doubleLock.unlock(); + } else { + // we got the try_lock but failed the other conditionals so we need to unlock + doubleLock.unlock(); + } } } } From c6d98f3c678ec0d196b8915f89d3057f5a1f462a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 28 Aug 2015 10:59:38 -0700 Subject: [PATCH 475/549] Update ResourceCache to retry an asset request when the node is unavailable --- libraries/networking/src/AssetResourceRequest.cpp | 15 +++++++++++++++ libraries/networking/src/ResourceCache.cpp | 1 + libraries/networking/src/ResourceRequest.h | 2 ++ 3 files changed, 18 insertions(+) diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 93c1b49329..b98560152a 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -13,6 +13,7 @@ #include "AssetClient.h" #include "AssetRequest.h" +#include "AssetUtils.h" void AssetResourceRequest::doSend() { // Make request to atp @@ -21,9 +22,23 @@ void AssetResourceRequest::doSend() { auto hash = parts[0]; auto extension = parts.length() > 1 ? parts[1] : ""; + if (hash.length() != SHA256_HASH_HEX_LENGTH) { + _result = InvalidURL; + _state = Finished; + + emit finished(); + + return; + } + auto request = assetClient->createRequest(hash, extension); if (!request) { + _result = ServerUnavailable; + _state = Finished; + + emit finished(); + return; } diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index f3b534af15..ea8c6c74c2 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -396,6 +396,7 @@ void Resource::handleReplyFinished() { bool retry = false; switch (result) { case ResourceRequest::Result::Timeout: + case ResourceRequest::Result::ServerUnavailable: case ResourceRequest::Result::Error: { // retry with increasing delays const int MAX_ATTEMPTS = 8; diff --git a/libraries/networking/src/ResourceRequest.h b/libraries/networking/src/ResourceRequest.h index c5e56e4a85..0aae013b62 100644 --- a/libraries/networking/src/ResourceRequest.h +++ b/libraries/networking/src/ResourceRequest.h @@ -30,7 +30,9 @@ public: Success, Error, Timeout, + ServerUnavailable, AccessDenied, + InvalidURL, NotFound }; From 3f85e8a2fed5b3c4ec5e211e1c0048cace4f9f36 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 11:12:52 -0700 Subject: [PATCH 476/549] add an UploadAssetTask so uploading is on diff thread --- assignment-client/src/assets/AssetServer.cpp | 77 ++------------- assignment-client/src/assets/AssetServer.h | 2 - assignment-client/src/assets/SendAssetTask.h | 3 - .../src/assets/UploadAssetTask.cpp | 99 +++++++++++++++++++ .../src/assets/UploadAssetTask.h | 37 +++++++ libraries/networking/src/AssetUtils.h | 4 +- libraries/networking/src/udt/SendQueue.h | 2 + 7 files changed, 147 insertions(+), 77 deletions(-) create mode 100644 assignment-client/src/assets/UploadAssetTask.cpp create mode 100644 assignment-client/src/assets/UploadAssetTask.h diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 8c4807f412..c046b39f66 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -25,6 +25,7 @@ #include "NetworkLogging.h" #include "NodeType.h" #include "SendAssetTask.h" +#include "UploadAssetTask.h" const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server"; @@ -35,7 +36,8 @@ AssetServer::AssetServer(NLPacket& packet) : // Most of the work will be I/O bound, reading from disk and constructing packet objects, // so the ideal is greater than the number of cores on the system. - _taskPool.setMaxThreadCount(20); + static const int TASK_POOL_THREAD_COUNT = 50; + _taskPool.setMaxThreadCount(TASK_POOL_THREAD_COUNT); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(PacketType::AssetGet, this, "handleAssetGet"); @@ -153,76 +155,9 @@ void AssetServer::handleAssetGet(QSharedPointer packet, SharedNodePoin } void AssetServer::handleAssetUpload(QSharedPointer packetList, SharedNodePointer senderNode) { + qDebug() << "Starting an UploadAssetTask for upload from" << uuidStringWithoutCurlyBraces(senderNode->getUUID()); - auto data = packetList->getMessage(); - QBuffer buffer { &data }; - buffer.open(QIODevice::ReadOnly); - - MessageID messageID; - buffer.read(reinterpret_cast(&messageID), sizeof(messageID)); - - if (!senderNode->getCanRez()) { - // this is a node the domain told us is not allowed to rez entities - // for now this also means it isn't allowed to add assets - // so return a packet with error that indicates that - - auto permissionErrorPacket = NLPacket::create(PacketType::AssetUploadReply, sizeof(MessageID) + sizeof(AssetServerError)); - - // write the message ID and a permission denied error - permissionErrorPacket->writePrimitive(messageID); - permissionErrorPacket->writePrimitive(AssetServerError::PERMISSION_DENIED); - - // send off the packet - auto nodeList = DependencyManager::get(); - nodeList->sendPacket(std::move(permissionErrorPacket), *senderNode); - - // return so we're not attempting to handle upload - return; - } - - uint8_t extensionLength; - buffer.read(reinterpret_cast(&extensionLength), sizeof(extensionLength)); - - QByteArray extension = buffer.read(extensionLength); - - qDebug() << "Got extension: " << extension; - - uint64_t fileSize; - buffer.read(reinterpret_cast(&fileSize), sizeof(fileSize)); - - qDebug() << "Receiving a file of size " << fileSize; - - auto replyPacket = NLPacket::create(PacketType::AssetUploadReply); - replyPacket->writePrimitive(messageID); - - if (fileSize > MAX_UPLOAD_SIZE) { - replyPacket->writePrimitive(AssetServerError::ASSET_TOO_LARGE); - } else { - QByteArray fileData = buffer.read(fileSize); - - auto hash = hashData(fileData); - auto hexHash = hash.toHex(); - - qDebug() << "Got data: (" << hexHash << ") "; - - QFile file { _resourcesDirectory.filePath(QString(hexHash)) + "." + QString(extension) }; - - if (file.exists()) { - qDebug() << "[WARNING] This file already exists: " << hexHash; - } else { - file.open(QIODevice::WriteOnly); - file.write(fileData); - file.close(); - } - replyPacket->writePrimitive(AssetServerError::NO_ERROR); - replyPacket->write(hash); - } - - auto nodeList = DependencyManager::get(); - nodeList->sendPacket(std::move(replyPacket), *senderNode); -} - -QByteArray AssetServer::hashData(const QByteArray& data) { - return QCryptographicHash::hash(data, QCryptographicHash::Sha256); + auto task = new UploadAssetTask(packetList, senderNode, _resourcesDirectory); + _taskPool.start(task); } diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 99a31b3768..1975f746a9 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -24,8 +24,6 @@ class AssetServer : public ThreadedAssignment { public: AssetServer(NLPacket& packet); - static QByteArray hashData(const QByteArray& data); - public slots: void run(); diff --git a/assignment-client/src/assets/SendAssetTask.h b/assignment-client/src/assets/SendAssetTask.h index 6b6c555326..477f42c1a3 100644 --- a/assignment-client/src/assets/SendAssetTask.h +++ b/assignment-client/src/assets/SendAssetTask.h @@ -27,9 +27,6 @@ public: void run(); -signals: - void finished(); - private: MessageID _messageID; QByteArray _assetHash; diff --git a/assignment-client/src/assets/UploadAssetTask.cpp b/assignment-client/src/assets/UploadAssetTask.cpp new file mode 100644 index 0000000000..66fdc80e90 --- /dev/null +++ b/assignment-client/src/assets/UploadAssetTask.cpp @@ -0,0 +1,99 @@ +// +// UploadAssetTask.cpp +// assignment-client/src/assets +// +// Created by Stephen Birarda on 2015-08-28. +// Copyright 2015 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 "UploadAssetTask.h" + +#include +#include + +#include +#include +#include + + +UploadAssetTask::UploadAssetTask(QSharedPointer packetList, SharedNodePointer senderNode, + const QDir& resourcesDir) : + _packetList(packetList), + _senderNode(senderNode), + _resourcesDir(resourcesDir) +{ + +} + +void UploadAssetTask::run() { + auto data = _packetList->getMessage(); + + QBuffer buffer { &data }; + buffer.open(QIODevice::ReadOnly); + + MessageID messageID; + buffer.read(reinterpret_cast(&messageID), sizeof(messageID)); + + if (!_senderNode->getCanRez()) { + // this is a node the domain told us is not allowed to rez entities + // for now this also means it isn't allowed to add assets + // so return a packet with error that indicates that + + auto permissionErrorPacket = NLPacket::create(PacketType::AssetUploadReply, sizeof(MessageID) + sizeof(AssetServerError)); + + // write the message ID and a permission denied error + permissionErrorPacket->writePrimitive(messageID); + permissionErrorPacket->writePrimitive(AssetServerError::PERMISSION_DENIED); + + // send off the packet + auto nodeList = DependencyManager::get(); + nodeList->sendPacket(std::move(permissionErrorPacket), *_senderNode); + + // return so we're not attempting to handle upload + return; + } + + uint8_t extensionLength; + buffer.read(reinterpret_cast(&extensionLength), sizeof(extensionLength)); + + QByteArray extension = buffer.read(extensionLength); + + uint64_t fileSize; + buffer.read(reinterpret_cast(&fileSize), sizeof(fileSize)); + + qDebug() << "UploadAssetTask reading a file of " << fileSize << "bytes and extension" << extension << "from" + << uuidStringWithoutCurlyBraces(_senderNode->getUUID()); + + auto replyPacket = NLPacket::create(PacketType::AssetUploadReply); + replyPacket->writePrimitive(messageID); + + if (fileSize > MAX_UPLOAD_SIZE) { + replyPacket->writePrimitive(AssetServerError::ASSET_TOO_LARGE); + } else { + QByteArray fileData = buffer.read(fileSize); + + auto hash = hashData(fileData); + auto hexHash = hash.toHex(); + + qDebug() << "Hash for uploaded file from" << uuidStringWithoutCurlyBraces(_senderNode->getUUID()) + << "is: (" << hexHash << ") "; + + QFile file { _resourcesDir.filePath(QString(hexHash)) + "." + QString(extension) }; + + if (file.exists()) { + qDebug() << "[WARNING] This file already exists: " << hexHash; + } else { + file.open(QIODevice::WriteOnly); + file.write(fileData); + file.close(); + } + replyPacket->writePrimitive(AssetServerError::NO_ERROR); + replyPacket->write(hash); + } + + auto nodeList = DependencyManager::get(); + nodeList->sendPacket(std::move(replyPacket), *_senderNode); +} diff --git a/assignment-client/src/assets/UploadAssetTask.h b/assignment-client/src/assets/UploadAssetTask.h new file mode 100644 index 0000000000..c310bfc948 --- /dev/null +++ b/assignment-client/src/assets/UploadAssetTask.h @@ -0,0 +1,37 @@ +// +// UploadAssetTask.h +// assignment-client/src/assets +// +// Created by Stephen Birarda on 2015-08-28. +// Copyright 2015 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 +// + +#pragma once + +#ifndef hifi_UploadAssetTask_h +#define hifi_UploadAssetTask_h + +#include +#include +#include +#include + +class NLPacketList; +class Node; + +class UploadAssetTask : public QRunnable { +public: + UploadAssetTask(QSharedPointer packetList, QSharedPointer senderNode, const QDir& resourcesDir); + + void run(); + +private: + QSharedPointer _packetList; + QSharedPointer _senderNode; + QDir _resourcesDir; +}; + +#endif // hifi_UploadAssetTask_h diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index ce9f3f4354..ae6f51df64 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -12,7 +12,7 @@ #ifndef hifi_AssetUtils_h #define hifi_AssetUtils_h -#include "NLPacketList.h" +#include using MessageID = uint32_t; using DataOffset = int64_t; @@ -31,4 +31,6 @@ enum AssetServerError : uint8_t { const QString ATP_SCHEME = "atp"; +inline QByteArray hashData(const QByteArray& data) { return QCryptographicHash::hash(data, QCryptographicHash::Sha256); } + #endif diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index c6668f1d09..fe07495e55 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -111,6 +111,8 @@ private: std::atomic _flowWindowSize { 0 }; // Flow control window size (number of packets that can be on wire) - set from CC + time_point _flowWindowFullSince; + mutable std::mutex _naksLock; // Protects the naks list. LossList _naks; // Sequence numbers of packets to resend From f2cb85ab09bcd3e005d5b62e305fca1dffe5c276 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 11:16:05 -0700 Subject: [PATCH 477/549] add missing break to switch for LightACK --- libraries/networking/src/udt/Connection.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 93c13874ea..a416991c7a 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -415,6 +415,7 @@ void Connection::processControl(std::unique_ptr controlPacket) { if (_hasReceivedHandshakeACK) { processLightACK(move(controlPacket)); } + break; case ControlPacket::ACK2: if (_hasReceivedHandshake) { processACK2(move(controlPacket)); From 058a3c422b547494441fef01f3e977fc3a0d7a8d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 11:32:17 -0700 Subject: [PATCH 478/549] re-remove the flow window full variable --- libraries/networking/src/udt/SendQueue.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index fe07495e55..c6668f1d09 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -111,8 +111,6 @@ private: std::atomic _flowWindowSize { 0 }; // Flow control window size (number of packets that can be on wire) - set from CC - time_point _flowWindowFullSince; - mutable std::mutex _naksLock; // Protects the naks list. LossList _naks; // Sequence numbers of packets to resend From 993217491fccb0465175d8baedbb369d8f2dfce1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 28 Aug 2015 19:43:37 +0200 Subject: [PATCH 479/549] Retry to load only on timeout --- libraries/networking/src/AssetClient.cpp | 7 ++- .../networking/src/FileResourceRequest.cpp | 16 +++-- .../networking/src/HTTPResourceRequest.cpp | 58 +++++++++---------- .../networking/src/HTTPResourceRequest.h | 3 +- libraries/networking/src/ResourceCache.cpp | 1 - libraries/script-engine/src/BatchLoader.cpp | 5 +- 6 files changed, 44 insertions(+), 46 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 4d228fc6bd..4bbc9f740a 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -70,11 +70,12 @@ AssetUpload* AssetClient::createUpload(const QString& filename) { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); - if (assetServer) { - return new AssetUpload(this, filename); + if (!assetServer) { + qDebug() << "No Asset Server"; + return nullptr; } - return nullptr; + return new AssetUpload(this, filename); } bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, diff --git a/libraries/networking/src/FileResourceRequest.cpp b/libraries/networking/src/FileResourceRequest.cpp index ffaaa0d193..dd2f6c8478 100644 --- a/libraries/networking/src/FileResourceRequest.cpp +++ b/libraries/networking/src/FileResourceRequest.cpp @@ -18,17 +18,15 @@ void FileResourceRequest::doSend() { QFile file(filename); - _state = Finished; - if (file.exists()) { - if (file.open(QFile::ReadOnly)) { - _data = file.readAll(); - _result = ResourceRequest::Success; - } else { - _result = ResourceRequest::AccessDenied; - } + if (!file.exists()) { + _result = NotFound; + } else if (file.open(QFile::ReadOnly)) { + _data = file.readAll(); + _result = Success; } else { - _result = ResourceRequest::NotFound; + _result = AccessDenied; } + _state = Finished; emit finished(); } diff --git a/libraries/networking/src/HTTPResourceRequest.cpp b/libraries/networking/src/HTTPResourceRequest.cpp index b122369c30..fbfcabb53d 100644 --- a/libraries/networking/src/HTTPResourceRequest.cpp +++ b/libraries/networking/src/HTTPResourceRequest.cpp @@ -54,43 +54,41 @@ void HTTPResourceRequest::onRequestFinished() { Q_ASSERT(_state == InProgress); Q_ASSERT(_reply); - _state = Finished; - - auto error = _reply->error(); - if (error == QNetworkReply::NoError) { - _data = _reply->readAll(); - _loadedFromCache = _reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(); - _result = ResourceRequest::Success; - emit finished(); - } else if (error == QNetworkReply::TimeoutError) { - _result = ResourceRequest::Timeout; - emit finished(); - } else { - _result = ResourceRequest::Error; - emit finished(); + _sendTimer.stop(); + + switch(_reply->error()) { + case QNetworkReply::NoError: + _data = _reply->readAll(); + _loadedFromCache = _reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(); + _result = Success; + break; + case QNetworkReply::TimeoutError: + _result = Timeout; + break; + default: + _result = Error; + break; } - - _reply->deleteLater(); - _reply = nullptr; + + _state = Finished; + emit finished(); } void HTTPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { - if (_state == InProgress) { - // We've received data, so reset the timer - _sendTimer.start(); - } + Q_ASSERT(_state == InProgress); + + // We've received data, so reset the timer + _sendTimer.start(); emit progress(bytesReceived, bytesTotal); } void HTTPResourceRequest::onTimeout() { - Q_ASSERT(_state != NotStarted); - - if (_state == InProgress) { - qCDebug(networking) << "Timed out loading " << _url; - _reply->abort(); - _state = Finished; - _result = Timeout; - emit finished(); - } + Q_ASSERT(_state == InProgress); + + qCDebug(networking) << "Timed out loading " << _url; + _reply->abort(); + _result = Timeout; + _state = Finished; + emit finished(); } diff --git a/libraries/networking/src/HTTPResourceRequest.h b/libraries/networking/src/HTTPResourceRequest.h index 09c94314d6..f0d3bb82d9 100644 --- a/libraries/networking/src/HTTPResourceRequest.h +++ b/libraries/networking/src/HTTPResourceRequest.h @@ -21,9 +21,8 @@ class HTTPResourceRequest : public ResourceRequest { Q_OBJECT public: - ~HTTPResourceRequest(); - HTTPResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } + ~HTTPResourceRequest(); protected: virtual void doSend() override; diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index ea8c6c74c2..01d9d804d2 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -423,7 +423,6 @@ void Resource::handleReplyFinished() { } void Resource::downloadFinished(const QByteArray& data) { - ; } uint qHash(const QPointer& value, uint seed) { diff --git a/libraries/script-engine/src/BatchLoader.cpp b/libraries/script-engine/src/BatchLoader.cpp index dae8c8e739..46ef05e65a 100644 --- a/libraries/script-engine/src/BatchLoader.cpp +++ b/libraries/script-engine/src/BatchLoader.cpp @@ -34,9 +34,11 @@ void BatchLoader::start() { } _started = true; - for (QUrl url : _urls) { + for (const auto& url : _urls) { auto request = ResourceManager::createResourceRequest(this, url); if (!request) { + _data.insert(url, QString()); + qCDebug(scriptengine) << "Could not load" << url; continue; } connect(request, &ResourceRequest::finished, this, [=]() { @@ -44,6 +46,7 @@ void BatchLoader::start() { _data.insert(url, request->getData()); } else { _data.insert(url, QString()); + qCDebug(scriptengine) << "Could not load" << url; } request->deleteLater(); checkFinished(); From a448eb9109c9762ecb8770b9314bc8d3264cd279 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 28 Aug 2015 20:26:51 +0200 Subject: [PATCH 480/549] Fix Asset Upload popup --- libraries/networking/src/AssetUpload.cpp | 29 ++++++++++---------- libraries/networking/src/ResourceManager.cpp | 2 +- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index 7f69f83e97..33d1dcc33a 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -41,21 +41,22 @@ void AssetUpload::start() { // ask the AssetClient to upload the asset and emit the proper signals from the passed callback auto assetClient = DependencyManager::get(); - assetClient->uploadAsset(data, _extension, [this](bool success, const QString& hash){ - if (success) { - // successful upload - emit finished with a point to ourselves and the resulting hash - _result = Success; - - emit finished(this, hash); - } else { - // error during upload - emit finished with an empty hash - // callers can get the error from this object - - // TODO: get the actual error from the callback - _result = PermissionDenied; - - emit finished(this, hash); + assetClient->uploadAsset(data, _extension, [this](AssetServerError error, const QString& hash){ + switch (error) { + case NO_ERROR: + _result = Success; + break; + case ASSET_TOO_LARGE: + _result = TooLarge; + break; + case PERMISSION_DENIED: + _result = PermissionDenied; + break; + default: + _result = ErrorLoadingFile; + break; } + emit finished(this, hash); }); } else { // we couldn't open the file - set the error result diff --git a/libraries/networking/src/ResourceManager.cpp b/libraries/networking/src/ResourceManager.cpp index ded3dfe222..74891487a4 100644 --- a/libraries/networking/src/ResourceManager.cpp +++ b/libraries/networking/src/ResourceManager.cpp @@ -27,7 +27,7 @@ ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const Q return new AssetResourceRequest(parent, url); } - qDebug() << "Failed to load: " << url.url(); + qDebug() << "Unknow scheme (" << scheme << ") for URL: " << url.url(); return nullptr; } From b9d1f39c652b0078b87b03ee74eb453828b12ee6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 12:36:44 -0700 Subject: [PATCH 481/549] remove include in SendQueue that is unneeded --- libraries/networking/src/udt/SendQueue.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index c6668f1d09..c9a40a4a75 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -20,7 +20,6 @@ #include #include -#include #include "../HifiSockAddr.h" From 729fd965390f844715d0e96096e8734c2be601d4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 28 Aug 2015 22:08:30 +0200 Subject: [PATCH 482/549] Fix bug where _requestLimit is stuck at 0 --- libraries/networking/src/ResourceCache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 01d9d804d2..18024000b3 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -402,7 +402,7 @@ void Resource::handleReplyFinished() { const int MAX_ATTEMPTS = 8; const int BASE_DELAY_MS = 1000; if (++_attempts < MAX_ATTEMPTS) { - QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(attemptRequest())); + QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, &Resource::makeRequest); retry = true; break; } From bcf3fceadcad3d1c55efc5018c00706fbbc4eda3 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 28 Aug 2015 22:10:54 +0200 Subject: [PATCH 483/549] Typo --- libraries/networking/src/ResourceManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/ResourceManager.cpp b/libraries/networking/src/ResourceManager.cpp index 74891487a4..c721419c7e 100644 --- a/libraries/networking/src/ResourceManager.cpp +++ b/libraries/networking/src/ResourceManager.cpp @@ -27,7 +27,7 @@ ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const Q return new AssetResourceRequest(parent, url); } - qDebug() << "Unknow scheme (" << scheme << ") for URL: " << url.url(); + qDebug() << "Unknown scheme (" << scheme << ") for URL: " << url.url(); return nullptr; } From b7d0aa062ac946c2e2dc926fd45ef51479795a1e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 14:19:20 -0700 Subject: [PATCH 484/549] repairs to cleanup of send queue --- libraries/networking/src/udt/Connection.cpp | 10 +++++++- libraries/networking/src/udt/Connection.h | 2 ++ libraries/networking/src/udt/SendQueue.cpp | 28 ++++++++++++--------- libraries/networking/src/udt/SendQueue.h | 2 ++ 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 93c13874ea..3260fcedc2 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -48,6 +48,10 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination, std::uniq } Connection::~Connection() { + stopSendQueue(); +} + +void Connection::stopSendQueue() { if (_sendQueue) { // grab the send queue thread so we can wait on it QThread* sendQueueThread = _sendQueue->thread(); @@ -73,6 +77,8 @@ SendQueue& Connection::getSendQueue() { // Lasily create send queue _sendQueue = SendQueue::create(_parentSocket, _destination); + qDebug() << "Created SendQueue for connection to" << _destination; + QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::packetSent); QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::recordSentPackets); QObject::connect(_sendQueue.get(), &SendQueue::packetRetransmitted, this, &Connection::recordRetransmission); @@ -88,7 +94,9 @@ SendQueue& Connection::getSendQueue() { } void Connection::queueInactive() { - emit connectionInactive(_destination); + // tell our current send queue to go down and reset our ptr to it to null + stopSendQueue(); + qDebug() << "Connection to" << _destination << "has stopped its SendQueue."; } void Connection::sendReliablePacket(std::unique_ptr packet) { diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 20306b5515..7914fa0676 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -106,6 +106,8 @@ private: void updateCongestionControlAndSendQueue(std::function congestionCallback); + void stopSendQueue(); + int _synInterval; // Periodical Rate Control Interval, in microseconds int _nakInterval { -1 }; // NAK timeout interval, in microseconds, set on loss diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index e088cb8d8b..6d123c7b58 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -161,7 +161,8 @@ void SendQueue::ack(SequenceNumber ack) { return; } - { // remove any ACKed packets from the map of sent packets + { + // remove any ACKed packets from the map of sent packets QWriteLocker locker(&_sentLock); for (auto seq = SequenceNumber { (uint32_t) _lastACKSequenceNumber }; seq <= ack; ++seq) { _sentPackets.erase(seq); @@ -335,9 +336,7 @@ void SendQueue::run() { qDebug() << "SendQueue to" << _destination << "reached" << NUM_TIMEOUTS_BEFORE_INACTIVE << "timeouts and is" << "considered inactive. It is now being stopped."; - emit queueInactive(); - - _isRunning = false; + deactivate(); return; } else { @@ -364,14 +363,11 @@ void SendQueue::run() { if (cvStatus == std::cv_status::timeout) { qDebug() << "SendQueue to" << _destination << "has been empty for" - << EMPTY_QUEUES_INACTIVE_TIMEOUT.count() - << "seconds and receiver has ACKed all packets." - << "The queue is considered inactive and will be stopped."; + << EMPTY_QUEUES_INACTIVE_TIMEOUT.count() + << "seconds and receiver has ACKed all packets." + << "The queue is considered inactive and will be stopped."; - // this queue is inactive - emit that signal and stop the while - emit queueInactive(); - - _isRunning = false; + deactivate(); return; } @@ -464,11 +460,12 @@ bool SendQueue::maybeSendNewPacket() { } bool SendQueue::maybeResendPacket() { - std::unique_lock naksLocker(_naksLock); // the following while makes sure that we find a packet to re-send, if there is one while (true) { + std::unique_lock naksLocker(_naksLock); + if (_naks.getLength() > 0) { // pull the sequence number we need to re-send SequenceNumber resendNumber = _naks.popFirstSequenceNumber(); @@ -507,3 +504,10 @@ bool SendQueue::maybeResendPacket() { // No packet was resent return false; } + +void SendQueue::deactivate() { + // this queue is inactive - emit that signal and stop the while + emit queueInactive(); + + _isRunning = false; +} diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index c6668f1d09..e59957aa3c 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -87,6 +87,8 @@ private: bool maybeSendNewPacket(); // Figures out what packet to send next bool maybeResendPacket(); // Determines whether to resend a packet and which one + void deactivate(); // makes the queue inactive and cleans it up + // Increments current sequence number and return it SequenceNumber getNextSequenceNumber(); MessageNumber getNextMessageNumber(); From 1e09321b1a8607ca31ca7d378c72076b36d461e6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 14:49:27 -0700 Subject: [PATCH 485/549] avoid creating multiple send queues from connection --- libraries/networking/src/udt/Connection.cpp | 30 +++++++++++---------- libraries/networking/src/udt/Connection.h | 5 ++-- libraries/networking/src/udt/Socket.cpp | 24 +++++++++-------- libraries/networking/src/udt/Socket.h | 2 +- 4 files changed, 33 insertions(+), 28 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 9517332dcb..179014e838 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -74,20 +74,22 @@ void Connection::resetRTT() { SendQueue& Connection::getSendQueue() { if (!_sendQueue) { - // Lasily create send queue - _sendQueue = SendQueue::create(_parentSocket, _destination); - - qDebug() << "Created SendQueue for connection to" << _destination; - - QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::packetSent); - QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::recordSentPackets); - QObject::connect(_sendQueue.get(), &SendQueue::packetRetransmitted, this, &Connection::recordRetransmission); - QObject::connect(_sendQueue.get(), &SendQueue::queueInactive, this, &Connection::queueInactive); - - // set defaults on the send queue from our congestion control object and estimatedTimeout() - _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); - _sendQueue->setEstimatedTimeout(estimatedTimeout()); - _sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); + std::call_once(_sendQueueCreateFlag, [this](){ + // Lasily create send queue + _sendQueue = SendQueue::create(_parentSocket, _destination); + + qDebug() << "Created SendQueue for connection to" << _destination; + + QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::packetSent); + QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::recordSentPackets); + QObject::connect(_sendQueue.get(), &SendQueue::packetRetransmitted, this, &Connection::recordRetransmission); + QObject::connect(_sendQueue.get(), &SendQueue::queueInactive, this, &Connection::queueInactive); + + // set defaults on the send queue from our congestion control object and estimatedTimeout() + _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); + _sendQueue->setEstimatedTimeout(estimatedTimeout()); + _sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); + }); } return *_sendQueue; diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 7914fa0676..97e7d36025 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -145,9 +145,10 @@ private: PacketTimeWindow _receiveWindow { 16, 64 }; // Window of interval between packets (16) and probes (64) for bandwidth and receive speed std::unique_ptr _congestionControl; - + std::unique_ptr _sendQueue; - + std::once_flag _sendQueueCreateFlag; // Guards the creation of SendQueue so it only happens once + std::map _pendingReceivedMessages; int _packetsSinceACK { 0 }; // The number of packets that have been received during the current ACK interval diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index f3ce095b50..94b6100dee 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -143,7 +143,7 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc } Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { - QMutexLocker locker(&_connectionsMutex); + QWriteLocker locker(&_connectionsMutex); auto it = _connectionsHash.find(sockAddr); @@ -157,12 +157,7 @@ Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { } void Socket::clearConnections() { - if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, "clearConnections", Qt::BlockingQueuedConnection); - return; - } - - QMutexLocker locker(&_connectionsMutex); + QWriteLocker locker(&_connectionsMutex); // clear all of the current connections in the socket qDebug() << "Clearing all remaining connections in Socket."; @@ -170,7 +165,7 @@ void Socket::clearConnections() { } void Socket::cleanupConnection(HifiSockAddr sockAddr) { - QMutexLocker locker(&_connectionsMutex); + QWriteLocker locker(&_connectionsMutex); qCDebug(networking) << "Socket::cleanupConnection called for UDT connection to" << sockAddr; _connectionsHash.erase(sockAddr); @@ -249,6 +244,8 @@ void Socket::readPendingDatagrams() { } void Socket::connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* receiver, const char* slot) { + QReadLocker readLocker(&_connectionsMutex); + auto it = _connectionsHash.find(destinationAddr); if (it != _connectionsHash.end()) { connect(it->second.get(), SIGNAL(packetSent()), receiver, slot); @@ -257,11 +254,15 @@ void Socket::connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* r void Socket::rateControlSync() { + QReadLocker readLocker(&_connectionsMutex); + // enumerate our list of connections and ask each of them to send off periodic ACK packet for rate control for (auto& connection : _connectionsHash) { connection.second->sync(); } + readLocker.unlock(); + if (_synTimer.interval() != _synInterval) { // if the _synTimer interval doesn't match the current _synInterval (changes when the CC factory is changed) // then restart it now with the right interval @@ -278,9 +279,7 @@ void Socket::setCongestionControlFactory(std::unique_ptr Socket::getConnectionSockAddrs() { + QReadLocker readLocker(&_connectionsMutex); + std::vector addr; addr.reserve(_connectionsHash.size()); + for (const auto& connectionPair : _connectionsHash) { addr.push_back(connectionPair.first); } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 23dd313462..fa6bf874a8 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -94,7 +94,7 @@ private: std::unordered_map _unreliableSequenceNumbers; std::unordered_map> _connectionsHash; - QMutex _connectionsMutex; // guards concurrent access to connections hashs + QReadWriteLock _connectionsMutex; // guards concurrent access to connections hashs int _synInterval = 10; // 10ms QTimer _synTimer; From a30bc79dd51bd2f24c167271763b0cd574227faa Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 14:55:25 -0700 Subject: [PATCH 486/549] guard send queue creation with a mutex --- libraries/networking/src/udt/Connection.cpp | 6 ++++-- libraries/networking/src/udt/Connection.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 179014e838..fe1da6529c 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -74,7 +74,9 @@ void Connection::resetRTT() { SendQueue& Connection::getSendQueue() { if (!_sendQueue) { - std::call_once(_sendQueueCreateFlag, [this](){ + std::unique_lock locker { _sendQueueMutex }; + + if (_sendQueue) { // Lasily create send queue _sendQueue = SendQueue::create(_parentSocket, _destination); @@ -89,7 +91,7 @@ SendQueue& Connection::getSendQueue() { _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); _sendQueue->setEstimatedTimeout(estimatedTimeout()); _sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); - }); + } } return *_sendQueue; diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 97e7d36025..d777fa9e7b 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -147,7 +147,7 @@ private: std::unique_ptr _congestionControl; std::unique_ptr _sendQueue; - std::once_flag _sendQueueCreateFlag; // Guards the creation of SendQueue so it only happens once + std::mutex _sendQueueMutex; // Guards the creation of SendQueue so it only happens once std::map _pendingReceivedMessages; From ee203dbe45db4900f3b207c4d587244dd5743abb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 14:57:22 -0700 Subject: [PATCH 487/549] fix check after mutex creation --- libraries/networking/src/udt/Connection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index fe1da6529c..7cd52bdb49 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -76,7 +76,7 @@ SendQueue& Connection::getSendQueue() { if (!_sendQueue) { std::unique_lock locker { _sendQueueMutex }; - if (_sendQueue) { + if (!_sendQueue) { // Lasily create send queue _sendQueue = SendQueue::create(_parentSocket, _destination); From d6310da8c813156ae60f2dba8cf5ce881e6db890 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 15:01:03 -0700 Subject: [PATCH 488/549] consider handshake ACK not received on send queue stop --- libraries/networking/src/udt/Connection.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 7cd52bdb49..814243f052 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -56,6 +56,9 @@ void Connection::stopSendQueue() { // grab the send queue thread so we can wait on it QThread* sendQueueThread = _sendQueue->thread(); + // since we're stopping the send queue we should consider our handshake ACK not receieved + _hasReceivedHandshakeACK = false; + // tell the send queue to stop and be deleted _sendQueue->stop(); _sendQueue->deleteLater(); From abffc0317b57ac7078f460911b95b03c0d8f1ef0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 15:07:07 -0700 Subject: [PATCH 489/549] expire the connection if it is 16 timeouts since data --- libraries/networking/src/udt/Connection.cpp | 18 ++++++++++++++++++ libraries/networking/src/udt/Connection.h | 4 +++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 814243f052..86b09ff56b 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -138,6 +138,21 @@ void Connection::queueReceivedMessagePacket(std::unique_ptr packet) { void Connection::sync() { if (_hasReceivedFirstPacket) { + + // check if it's time for us to consider this connection inactive + // we are inactive if it has been 16 * the estimated timeout since our last receive + static const int NUM_TIMEOUTS_FOR_EXPIRY = 16; + + auto sinceLastReceive = duration_cast(high_resolution_clock::now() - _lastReceiveTime); + + if (sinceLastReceive.count() >= NUM_TIMEOUTS_FOR_EXPIRY * estimatedTimeout()) { + // connection inactive - emit a signal so we will be cleaned up + emit connectionInactive(_destination); + + // return to abort before regular processing + return; + } + // reset the number of light ACKs or non SYN ACKs during this sync interval _lightACKsDuringSYN = 1; _acksDuringSYN = 1; @@ -347,6 +362,9 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in _hasReceivedFirstPacket = true; + // mark our last receive time as now (to push the potential expiry farther) + _lastReceiveTime = high_resolution_clock::now(); + // check if this is a packet pair we should estimate bandwidth from, or just a regular packet if (((uint32_t) sequenceNumber & 0xF) == 0) { _receiveWindow.onProbePair1Arrival(); diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index d777fa9e7b..39474ccc8e 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -73,7 +73,7 @@ public: signals: void packetSent(); - void connectionInactive(HifiSockAddr sockAdrr); + void connectionInactive(const HifiSockAddr& sockAddr); private slots: void recordSentPackets(int payload, int total); @@ -118,6 +118,8 @@ private: bool _hasReceivedHandshake { false }; // flag for receipt of handshake from server bool _hasReceivedHandshakeACK { false }; // flag for receipt of handshake ACK from client + std::chrono::high_resolution_clock::time_point _lastReceiveTime; // holds the last time we received anything from sender + LossList _lossList; // List of all missing packets SequenceNumber _lastReceivedSequenceNumber; // The largest sequence number received from the peer SequenceNumber _lastReceivedACK; // The last ACK received From 20d1244db4360f1f3cd789e18e3160beabc574dc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 15:17:44 -0700 Subject: [PATCH 490/549] use a write lock for sync so it can be recursive --- libraries/networking/src/udt/Connection.cpp | 3 +++ libraries/networking/src/udt/Socket.cpp | 4 ++-- libraries/networking/src/udt/Socket.h | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 86b09ff56b..59c0618a83 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -146,6 +146,9 @@ void Connection::sync() { auto sinceLastReceive = duration_cast(high_resolution_clock::now() - _lastReceiveTime); if (sinceLastReceive.count() >= NUM_TIMEOUTS_FOR_EXPIRY * estimatedTimeout()) { + qDebug() << "Connection to" << _destination << "has not received any new data for" + << NUM_TIMEOUTS_FOR_EXPIRY << "timeouts. It is now considered inactive and will be cleaned up."; + // connection inactive - emit a signal so we will be cleaned up emit connectionInactive(_destination); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 94b6100dee..ee86560a9f 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -254,14 +254,14 @@ void Socket::connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* r void Socket::rateControlSync() { - QReadLocker readLocker(&_connectionsMutex); + QWriteLocker writeLocker(&_connectionsMutex); // enumerate our list of connections and ask each of them to send off periodic ACK packet for rate control for (auto& connection : _connectionsHash) { connection.second->sync(); } - readLocker.unlock(); + writeLocker.unlock(); if (_synTimer.interval() != _synInterval) { // if the _synTimer interval doesn't match the current _synInterval (changes when the CC factory is changed) diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index fa6bf874a8..6e639d842d 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -94,7 +94,7 @@ private: std::unordered_map _unreliableSequenceNumbers; std::unordered_map> _connectionsHash; - QReadWriteLock _connectionsMutex; // guards concurrent access to connections hashs + QReadWriteLock _connectionsMutex { QReadWriteLock::Recursive }; // guards concurrent access to connections hashs int _synInterval = 10; // 10ms QTimer _synTimer; From 42105dfc33b46e340c288d97e643be6b220fbeda Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 16:34:24 -0700 Subject: [PATCH 491/549] replace mutexes with invoked methods in Socket --- assignment-client/src/avatars/AvatarMixer.cpp | 1 + libraries/networking/src/udt/Connection.cpp | 30 ++++----- libraries/networking/src/udt/Connection.h | 1 - libraries/networking/src/udt/Socket.cpp | 63 +++++++++++++------ libraries/networking/src/udt/Socket.h | 18 +++--- 5 files changed, 68 insertions(+), 45 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 1b0d93e2c5..47e5a00b48 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -513,6 +513,7 @@ void AvatarMixer::run() { qDebug() << "Waiting for domain settings from domain-server."; // block until we get the settingsRequestComplete signal + QEventLoop loop; connect(&domainHandler, &DomainHandler::settingsReceived, &loop, &QEventLoop::quit); connect(&domainHandler, &DomainHandler::settingsReceiveFail, &loop, &QEventLoop::quit); diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 59c0618a83..1d053633a7 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -77,24 +77,20 @@ void Connection::resetRTT() { SendQueue& Connection::getSendQueue() { if (!_sendQueue) { - std::unique_lock locker { _sendQueueMutex }; + // Lasily create send queue + _sendQueue = SendQueue::create(_parentSocket, _destination); - if (!_sendQueue) { - // Lasily create send queue - _sendQueue = SendQueue::create(_parentSocket, _destination); - - qDebug() << "Created SendQueue for connection to" << _destination; - - QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::packetSent); - QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::recordSentPackets); - QObject::connect(_sendQueue.get(), &SendQueue::packetRetransmitted, this, &Connection::recordRetransmission); - QObject::connect(_sendQueue.get(), &SendQueue::queueInactive, this, &Connection::queueInactive); - - // set defaults on the send queue from our congestion control object and estimatedTimeout() - _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); - _sendQueue->setEstimatedTimeout(estimatedTimeout()); - _sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); - } + qDebug() << "Created SendQueue for connection to" << _destination; + + QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::packetSent); + QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::recordSentPackets); + QObject::connect(_sendQueue.get(), &SendQueue::packetRetransmitted, this, &Connection::recordRetransmission); + QObject::connect(_sendQueue.get(), &SendQueue::queueInactive, this, &Connection::queueInactive); + + // set defaults on the send queue from our congestion control object and estimatedTimeout() + _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); + _sendQueue->setEstimatedTimeout(estimatedTimeout()); + _sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); } return *_sendQueue; diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 39474ccc8e..5895aac167 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -149,7 +149,6 @@ private: std::unique_ptr _congestionControl; std::unique_ptr _sendQueue; - std::mutex _sendQueueMutex; // Guards the creation of SendQueue so it only happens once std::map _pendingReceivedMessages; diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index ee86560a9f..628804ed9f 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -24,9 +24,15 @@ using namespace udt; +Q_DECLARE_METATYPE(Packet*); +Q_DECLARE_METATYPE(PacketList*); + Socket::Socket(QObject* parent) : QObject(parent) { + qRegisterMetaType(); + qRegisterMetaType(); + connect(&_udpSocket, &QUdpSocket::readyRead, this, &Socket::readPendingDatagrams); // make sure our synchronization method is called every SYN interval @@ -97,8 +103,20 @@ qint64 Socket::writePacket(const Packet& packet, const HifiSockAddr& sockAddr) { } qint64 Socket::writePacket(std::unique_ptr packet, const HifiSockAddr& sockAddr) { + if (packet->isReliable()) { - findOrCreateConnection(sockAddr).sendReliablePacket(move(packet)); + // hand this packet off to writeReliablePacket + // because Qt can't invoke with the unique_ptr we have to release it here and re-construct in writeReliablePacket + + if (QThread::currentThread() != thread()) { + qDebug() << "About to invoke with" << packet.get(); + QMetaObject::invokeMethod(this, "writeReliablePacket", Qt::QueuedConnection, + Q_ARG(Packet*, packet.release()), + Q_ARG(HifiSockAddr, sockAddr)); + } else { + writeReliablePacket(packet.release(), sockAddr); + } + return 0; } @@ -107,9 +125,17 @@ qint64 Socket::writePacket(std::unique_ptr packet, const HifiSockAddr& s qint64 Socket::writePacketList(std::unique_ptr packetList, const HifiSockAddr& sockAddr) { if (packetList->isReliable()) { - // Reliable and Ordered - // Reliable and Unordered - findOrCreateConnection(sockAddr).sendReliablePacketList(move(packetList)); + // hand this packetList off to writeReliablePacketList + // because Qt can't invoke with the unique_ptr we have to release it here and re-construct in writeReliablePacketList + + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "writeReliablePacketList", Qt::QueuedConnection, + Q_ARG(PacketList*, packetList.release()), + Q_ARG(HifiSockAddr, sockAddr)); + } else { + writeReliablePacketList(packetList.release(), sockAddr); + } + return 0; } @@ -122,6 +148,14 @@ qint64 Socket::writePacketList(std::unique_ptr packetList, const Hif return totalBytesSent; } +void Socket::writeReliablePacket(Packet* packet, const HifiSockAddr& sockAddr) { + findOrCreateConnection(sockAddr).sendReliablePacket(std::unique_ptr(packet)); +} + +void Socket::writeReliablePacketList(PacketList* packetList, const HifiSockAddr& sockAddr) { + findOrCreateConnection(sockAddr).sendReliablePacketList(std::unique_ptr(packetList)); +} + qint64 Socket::writeDatagram(const char* data, qint64 size, const HifiSockAddr& sockAddr) { return writeDatagram(QByteArray::fromRawData(data, size), sockAddr); } @@ -143,8 +177,6 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc } Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { - QWriteLocker locker(&_connectionsMutex); - auto it = _connectionsHash.find(sockAddr); if (it == _connectionsHash.end()) { @@ -157,7 +189,10 @@ Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { } void Socket::clearConnections() { - QWriteLocker locker(&_connectionsMutex); + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "clearConnections", Qt::BlockingQueuedConnection); + return; + } // clear all of the current connections in the socket qDebug() << "Clearing all remaining connections in Socket."; @@ -165,8 +200,6 @@ void Socket::clearConnections() { } void Socket::cleanupConnection(HifiSockAddr sockAddr) { - QWriteLocker locker(&_connectionsMutex); - qCDebug(networking) << "Socket::cleanupConnection called for UDT connection to" << sockAddr; _connectionsHash.erase(sockAddr); } @@ -244,8 +277,6 @@ void Socket::readPendingDatagrams() { } void Socket::connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* receiver, const char* slot) { - QReadLocker readLocker(&_connectionsMutex); - auto it = _connectionsHash.find(destinationAddr); if (it != _connectionsHash.end()) { connect(it->second.get(), SIGNAL(packetSent()), receiver, slot); @@ -254,15 +285,11 @@ void Socket::connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* r void Socket::rateControlSync() { - QWriteLocker writeLocker(&_connectionsMutex); - // enumerate our list of connections and ask each of them to send off periodic ACK packet for rate control for (auto& connection : _connectionsHash) { connection.second->sync(); } - writeLocker.unlock(); - if (_synTimer.interval() != _synInterval) { // if the _synTimer interval doesn't match the current _synInterval (changes when the CC factory is changed) // then restart it now with the right interval @@ -279,8 +306,6 @@ void Socket::setCongestionControlFactory(std::unique_ptrsecond->sampleStats(); @@ -289,9 +314,7 @@ ConnectionStats::Stats Socket::sampleStatsForConnection(const HifiSockAddr& dest } } -std::vector Socket::getConnectionSockAddrs() { - QReadLocker readLocker(&_connectionsMutex); - +std::vector Socket::getConnectionSockAddrs() { std::vector addr; addr.reserve(_connectionsHash.size()); diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 6e639d842d..4bcee9efbf 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -32,6 +32,7 @@ class ControlSender; class Packet; class PacketList; class SequenceNumber; +class UDTTest; using PacketFilterOperator = std::function; @@ -65,13 +66,8 @@ public: { _unfilteredHandlers[senderSockAddr] = handler; } void setCongestionControlFactory(std::unique_ptr ccFactory); - - void connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* receiver, const char* slot); void messageReceived(std::unique_ptr packetList); - - ConnectionStats::Stats sampleStatsForConnection(const HifiSockAddr& destination); - std::vector getConnectionSockAddrs(); public slots: void cleanupConnection(HifiSockAddr sockAddr); @@ -84,6 +80,14 @@ private slots: private: void setSystemBufferSizes(); Connection& findOrCreateConnection(const HifiSockAddr& sockAddr); + + // privatized methods used by UDTTest - they are private since they must be called on the Socket thread + ConnectionStats::Stats sampleStatsForConnection(const HifiSockAddr& destination); + std::vector getConnectionSockAddrs(); + void connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* receiver, const char* slot); + + Q_INVOKABLE void writeReliablePacket(Packet* packet, const HifiSockAddr& sockAddr); + Q_INVOKABLE void writeReliablePacketList(PacketList* packetList, const HifiSockAddr& sockAddr); QUdpSocket _udpSocket { this }; PacketFilterOperator _packetFilterOperator; @@ -94,12 +98,12 @@ private: std::unordered_map _unreliableSequenceNumbers; std::unordered_map> _connectionsHash; - QReadWriteLock _connectionsMutex { QReadWriteLock::Recursive }; // guards concurrent access to connections hashs - int _synInterval = 10; // 10ms QTimer _synTimer; std::unique_ptr _ccFactory { new CongestionControlFactory() }; + + friend class UDTTest; }; } // namespace udt From 441a5d34bf568a175a0106ed848425aac7d73a66 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 28 Aug 2015 16:36:07 -0700 Subject: [PATCH 492/549] don't go inactive in sync --- libraries/networking/src/udt/Connection.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 1d053633a7..a4dcb09612 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -135,23 +135,6 @@ void Connection::queueReceivedMessagePacket(std::unique_ptr packet) { void Connection::sync() { if (_hasReceivedFirstPacket) { - // check if it's time for us to consider this connection inactive - // we are inactive if it has been 16 * the estimated timeout since our last receive - static const int NUM_TIMEOUTS_FOR_EXPIRY = 16; - - auto sinceLastReceive = duration_cast(high_resolution_clock::now() - _lastReceiveTime); - - if (sinceLastReceive.count() >= NUM_TIMEOUTS_FOR_EXPIRY * estimatedTimeout()) { - qDebug() << "Connection to" << _destination << "has not received any new data for" - << NUM_TIMEOUTS_FOR_EXPIRY << "timeouts. It is now considered inactive and will be cleaned up."; - - // connection inactive - emit a signal so we will be cleaned up - emit connectionInactive(_destination); - - // return to abort before regular processing - return; - } - // reset the number of light ACKs or non SYN ACKs during this sync interval _lightACKsDuringSYN = 1; _acksDuringSYN = 1; From 71ff855d866097af74a9112918275782c2eff19f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Sat, 29 Aug 2015 14:28:24 -0700 Subject: [PATCH 493/549] add connection cleanup that respects send/receive --- libraries/networking/src/udt/Connection.cpp | 52 +++++++++++++++++++-- libraries/networking/src/udt/Connection.h | 5 +- libraries/networking/src/udt/SendQueue.cpp | 20 +++++--- libraries/networking/src/udt/SendQueue.h | 1 + libraries/networking/src/udt/Socket.cpp | 8 +++- 5 files changed, 72 insertions(+), 14 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index a4dcb09612..01e4735254 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -30,7 +30,8 @@ using namespace std::chrono; Connection::Connection(Socket* parentSocket, HifiSockAddr destination, std::unique_ptr congestionControl) : _parentSocket(parentSocket), _destination(destination), - _congestionControl(move(congestionControl)) + _congestionControl(move(congestionControl)), + _connectionStart(high_resolution_clock::now()) { Q_ASSERT_X(socket, "Connection::Connection", "Must be called with a valid Socket*"); @@ -100,6 +101,11 @@ void Connection::queueInactive() { // tell our current send queue to go down and reset our ptr to it to null stopSendQueue(); qDebug() << "Connection to" << _destination << "has stopped its SendQueue."; + + if (!_hasReceivedHandshake || !_isReceivingData) { + qDebug() << "Connection SendQueue to" << _destination << "stopped and no data is being received - stopping connection."; + emit connectionInactive(_destination); + } } void Connection::sendReliablePacket(std::unique_ptr packet) { @@ -133,7 +139,29 @@ void Connection::queueReceivedMessagePacket(std::unique_ptr packet) { } void Connection::sync() { - if (_hasReceivedFirstPacket) { + if (_isReceivingData) { + + // check if we should expire the receive portion of this connection + // this occurs if it has been 16 timeouts since the last data received and at least 5 seconds + static const int NUM_TIMEOUTS_BEFORE_EXPIRY = 16; + static const int MIN_SECONDS_BEFORE_EXPIRY = 5; + + auto now = high_resolution_clock::now(); + + auto sincePacketReceive = now - _lastReceiveTime; + + if (duration_cast(sincePacketReceive).count() >= NUM_TIMEOUTS_BEFORE_EXPIRY * estimatedTimeout() + && duration_cast(sincePacketReceive).count() >= MIN_SECONDS_BEFORE_EXPIRY ) { + // the receive side of this connection is expired + _isReceivingData = false; + + // if we don't have a send queue that means the whole connection has expired and we can emit our signal + // otherwise we'll wait for it to also timeout before cleaning up + if (!_sendQueue) { + qDebug() << "Connection to" << _destination << "no longer receiving any data and there is currently no send queue - stopping connection."; + emit connectionInactive(_destination); + } + } // reset the number of light ACKs or non SYN ACKs during this sync interval _lightACKsDuringSYN = 1; @@ -152,6 +180,20 @@ void Connection::sync() { sendTimeoutNAK(); } } + } else if (!_sendQueue) { + // we haven't received a packet and we're not sending + // this most likely means we were started erroneously + // check the start time for this connection and auto expire it after 5 seconds of not receiving or sending any data + static const int CONNECTION_NOT_USED_EXPIRY_SECONDS = 5; + auto secondsSinceStart = duration_cast(high_resolution_clock::now() - _connectionStart).count(); + + if (secondsSinceStart >= CONNECTION_NOT_USED_EXPIRY_SECONDS) { + // it's been CONNECTION_NOT_USED_EXPIRY_SECONDS and nothing has actually happened with this connection + // consider it inactive and emit our inactivity signal + qDebug() << "Connection to" << _destination << "did not receive or send any data in last" + << CONNECTION_NOT_USED_EXPIRY_SECONDS << "seconds - stopping connection."; + emit connectionInactive(_destination); + } } } @@ -342,7 +384,7 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in return false; } - _hasReceivedFirstPacket = true; + _isReceivingData = true; // mark our last receive time as now (to push the potential expiry farther) _lastReceiveTime = high_resolution_clock::now(); @@ -643,7 +685,7 @@ void Connection::processNAK(std::unique_ptr controlPacket) { void Connection::processHandshake(std::unique_ptr controlPacket) { - if (!_hasReceivedHandshake || _hasReceivedFirstPacket) { + if (!_hasReceivedHandshake || _isReceivingData) { // server sent us a handshake - we need to assume this means state should be reset // as long as we haven't received a handshake yet or we have and we've received some data resetReceiveState(); @@ -697,7 +739,7 @@ void Connection::resetReceiveState() { // the _nakInterval need not be reset, that will happen on loss // clear sync variables - _hasReceivedFirstPacket = false; + _isReceivingData = false; _acksDuringSYN = 1; _lightACKsDuringSYN = 1; diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 5895aac167..eb5961695c 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -114,11 +114,12 @@ private: int _minNAKInterval { 100000 }; // NAK timeout interval lower bound, default of 100ms std::chrono::high_resolution_clock::time_point _lastNAKTime; - bool _hasReceivedFirstPacket { false }; bool _hasReceivedHandshake { false }; // flag for receipt of handshake from server bool _hasReceivedHandshakeACK { false }; // flag for receipt of handshake ACK from client - + + std::chrono::high_resolution_clock::time_point _connectionStart; // holds the time_point for creation of this connection std::chrono::high_resolution_clock::time_point _lastReceiveTime; // holds the last time we received anything from sender + bool _isReceivingData { false }; // flag used for expiry of receipt portion of connection LossList _lossList; // List of all missing packets SequenceNumber _lastReceivedSequenceNumber; // The largest sequence number received from the peer diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 6d123c7b58..8ce5825892 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -154,8 +155,9 @@ void SendQueue::sendPacket(const Packet& packet) { } void SendQueue::ack(SequenceNumber ack) { - // this is a response from the client, re-set our timeout expiry + // this is a response from the client, re-set our timeout expiry and our last response time _timeoutExpiryCount = 0; + _lastReceiverResponse = uint64_t(QDateTime::currentMSecsSinceEpoch()); if (_lastACKSequenceNumber == (uint32_t) ack) { return; @@ -183,6 +185,7 @@ void SendQueue::ack(SequenceNumber ack) { void SendQueue::nak(SequenceNumber start, SequenceNumber end) { // this is a response from the client, re-set our timeout expiry _timeoutExpiryCount = 0; + _lastReceiverResponse = uint64_t(QDateTime::currentMSecsSinceEpoch()); std::unique_lock nakLocker(_naksLock); @@ -198,6 +201,7 @@ void SendQueue::nak(SequenceNumber start, SequenceNumber end) { void SendQueue::overrideNAKListFromPacket(ControlPacket& packet) { // this is a response from the client, re-set our timeout expiry _timeoutExpiryCount = 0; + _lastReceiverResponse = uint64_t(QDateTime::currentMSecsSinceEpoch()); std::unique_lock nakLocker(_naksLock); _naks.clear(); @@ -326,15 +330,19 @@ void SendQueue::run() { // check if it is time to break this connection // that will be the case if we have had 16 timeouts since hearing back from the client, and it has been - // at least 10 seconds + // at least 5 seconds static const int NUM_TIMEOUTS_BEFORE_INACTIVE = 16; + static const int MIN_SECONDS_BEFORE_INACTIVE_MS = 5 * 1000; - if (_timeoutExpiryCount >= NUM_TIMEOUTS_BEFORE_INACTIVE) { + auto sinceEpochNow = QDateTime::currentMSecsSinceEpoch(); + + if (_timeoutExpiryCount >= NUM_TIMEOUTS_BEFORE_INACTIVE + && (sinceEpochNow - _lastReceiverResponse) > MIN_SECONDS_BEFORE_INACTIVE_MS) { // If the flow window has been full for over CONSIDER_INACTIVE_AFTER, // then signal the queue is inactive and return so it can be cleaned up - qDebug() << "SendQueue to" << _destination << "reached" << NUM_TIMEOUTS_BEFORE_INACTIVE << "timeouts and is" - << "considered inactive. It is now being stopped."; + qDebug() << "SendQueue to" << _destination << "reached" << NUM_TIMEOUTS_BEFORE_INACTIVE << "timeouts" + << "and 10s before receiving any ACK/NAK and is now inactive. Stopping."; deactivate(); @@ -365,7 +373,7 @@ void SendQueue::run() { qDebug() << "SendQueue to" << _destination << "has been empty for" << EMPTY_QUEUES_INACTIVE_TIMEOUT.count() << "seconds and receiver has ACKed all packets." - << "The queue is considered inactive and will be stopped."; + << "The queue is now inactive and will be stopped."; deactivate(); diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index b0fce46d88..beb89a77d6 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -109,6 +109,7 @@ private: std::atomic _estimatedTimeout { 0 }; // Estimated timeout, set from CC std::atomic _timeoutExpiryCount { 0 }; // The number of times the timeout has expired without response from client + std::atomic _lastReceiverResponse { 0 }; // Timestamp for the last time we got new data from the receiver (ACK/NAK) std::atomic _flowWindowSize { 0 }; // Flow control window size (number of packets that can be on wire) - set from CC diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 628804ed9f..1be2485e5c 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -181,8 +181,14 @@ Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { if (it == _connectionsHash.end()) { auto connection = std::unique_ptr(new Connection(this, sockAddr, _ccFactory->create())); - QObject::connect(connection.get(), &Connection::connectionInactive, this, &Socket::cleanupConnection); + + // we queue the connection to cleanup connection in case it asks for it during its own rate control sync + QObject::connect(connection.get(), &Connection::connectionInactive, this, &Socket::cleanupConnection, + Qt::QueuedConnection); + it = _connectionsHash.insert(it, std::make_pair(sockAddr, std::move(connection))); + + qDebug() << "Creating new connection to" << sockAddr; } return *it->second; From 2b0b883db22b6c28d409b925971ec9aa153a470e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Sat, 29 Aug 2015 14:28:50 -0700 Subject: [PATCH 494/549] remove debug for writeReliablePacket invoke --- libraries/networking/src/udt/Socket.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 1be2485e5c..bf400f85d2 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -109,7 +109,6 @@ qint64 Socket::writePacket(std::unique_ptr packet, const HifiSockAddr& s // because Qt can't invoke with the unique_ptr we have to release it here and re-construct in writeReliablePacket if (QThread::currentThread() != thread()) { - qDebug() << "About to invoke with" << packet.get(); QMetaObject::invokeMethod(this, "writeReliablePacket", Qt::QueuedConnection, Q_ARG(Packet*, packet.release()), Q_ARG(HifiSockAddr, sockAddr)); From e67a3e85418161d1fcea484f518b63e26f914c99 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Sat, 29 Aug 2015 14:36:46 -0700 Subject: [PATCH 495/549] use define to hide verbose connection debugging --- libraries/networking/src/udt/Connection.cpp | 31 ++++++++++++++++----- libraries/networking/src/udt/SendQueue.cpp | 9 ++++-- libraries/networking/src/udt/Socket.cpp | 9 ++++-- libraries/networking/src/udt/Socket.h | 2 ++ 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 01e4735254..4d2ca8cda3 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -30,8 +30,8 @@ using namespace std::chrono; Connection::Connection(Socket* parentSocket, HifiSockAddr destination, std::unique_ptr congestionControl) : _parentSocket(parentSocket), _destination(destination), - _congestionControl(move(congestionControl)), _connectionStart(high_resolution_clock::now()) + _congestionControl(move(congestionControl)) { Q_ASSERT_X(socket, "Connection::Connection", "Must be called with a valid Socket*"); @@ -80,8 +80,10 @@ SendQueue& Connection::getSendQueue() { if (!_sendQueue) { // Lasily create send queue _sendQueue = SendQueue::create(_parentSocket, _destination); - - qDebug() << "Created SendQueue for connection to" << _destination; + + #ifdef UDT_CONNECTION_DEBUG + qCDebug(networking) << "Created SendQueue for connection to" << _destination; + #endif QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::packetSent); QObject::connect(_sendQueue.get(), &SendQueue::packetSent, this, &Connection::recordSentPackets); @@ -100,10 +102,16 @@ SendQueue& Connection::getSendQueue() { void Connection::queueInactive() { // tell our current send queue to go down and reset our ptr to it to null stopSendQueue(); - qDebug() << "Connection to" << _destination << "has stopped its SendQueue."; + + #ifdef UDT_CONNECTION_DEBUG + qCDebug(networking) << "Connection to" << _destination << "has stopped its SendQueue."; + #endif if (!_hasReceivedHandshake || !_isReceivingData) { - qDebug() << "Connection SendQueue to" << _destination << "stopped and no data is being received - stopping connection."; + #ifdef UDT_CONNECTION_DEBUG + qCDebug(networking) << "Connection SendQueue to" << _destination << "stopped and no data is being received - stopping connection."; + #endif + emit connectionInactive(_destination); } } @@ -158,7 +166,11 @@ void Connection::sync() { // if we don't have a send queue that means the whole connection has expired and we can emit our signal // otherwise we'll wait for it to also timeout before cleaning up if (!_sendQueue) { - qDebug() << "Connection to" << _destination << "no longer receiving any data and there is currently no send queue - stopping connection."; + + #ifdef UDT_CONNECTION_DEBUG + qCDebug(networking) << "Connection to" << _destination << "no longer receiving any data and there is currently no send queue - stopping connection."; + #endif + emit connectionInactive(_destination); } } @@ -190,8 +202,12 @@ void Connection::sync() { if (secondsSinceStart >= CONNECTION_NOT_USED_EXPIRY_SECONDS) { // it's been CONNECTION_NOT_USED_EXPIRY_SECONDS and nothing has actually happened with this connection // consider it inactive and emit our inactivity signal - qDebug() << "Connection to" << _destination << "did not receive or send any data in last" + + #ifdef UDT_CONNECTION_DEBUG + qCDebug(networking) << "Connection to" << _destination << "did not receive or send any data in last" << CONNECTION_NOT_USED_EXPIRY_SECONDS << "seconds - stopping connection."; + #endif + emit connectionInactive(_destination); } } @@ -740,6 +756,7 @@ void Connection::resetReceiveState() { // clear sync variables _isReceivingData = false; + _connectionStart = high_resolution_clock::now(); _acksDuringSYN = 1; _lightACKsDuringSYN = 1; diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 8ce5825892..52f1a48420 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -341,8 +341,11 @@ void SendQueue::run() { && (sinceEpochNow - _lastReceiverResponse) > MIN_SECONDS_BEFORE_INACTIVE_MS) { // If the flow window has been full for over CONSIDER_INACTIVE_AFTER, // then signal the queue is inactive and return so it can be cleaned up - qDebug() << "SendQueue to" << _destination << "reached" << NUM_TIMEOUTS_BEFORE_INACTIVE << "timeouts" + + #ifdef UDT_CONNECTION_DEBUG + qCDebug(networking) << "SendQueue to" << _destination << "reached" << NUM_TIMEOUTS_BEFORE_INACTIVE << "timeouts" << "and 10s before receiving any ACK/NAK and is now inactive. Stopping."; + #endif deactivate(); @@ -370,10 +373,12 @@ void SendQueue::run() { doubleLock.unlock(); if (cvStatus == std::cv_status::timeout) { - qDebug() << "SendQueue to" << _destination << "has been empty for" + #ifdef UDT_CONNECTION_DEBUG + qCDebug(networking) << "SendQueue to" << _destination << "has been empty for" << EMPTY_QUEUES_INACTIVE_TIMEOUT.count() << "seconds and receiver has ACKed all packets." << "The queue is now inactive and will be stopped."; + #endif deactivate(); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index bf400f85d2..805da8790e 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -185,9 +185,11 @@ Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { QObject::connect(connection.get(), &Connection::connectionInactive, this, &Socket::cleanupConnection, Qt::QueuedConnection); - it = _connectionsHash.insert(it, std::make_pair(sockAddr, std::move(connection))); + #ifdef UDT_CONNECTION_DEBUG + qCDebug(networking) << "Creating new connection to" << sockAddr; + #endif - qDebug() << "Creating new connection to" << sockAddr; + it = _connectionsHash.insert(it, std::make_pair(sockAddr, std::move(connection))); } return *it->second; @@ -205,7 +207,10 @@ void Socket::clearConnections() { } void Socket::cleanupConnection(HifiSockAddr sockAddr) { + #ifdef UDT_CONNECTION_DEBUG qCDebug(networking) << "Socket::cleanupConnection called for UDT connection to" << sockAddr; + #endif + _connectionsHash.erase(sockAddr); } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 4bcee9efbf..ad30031624 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -25,6 +25,8 @@ #include "CongestionControl.h" #include "Connection.h" +#define UDT_CONNECTION_DEBUG 0 + namespace udt { class BasePacket; From b81f99636674eecd7073674b403bc15aaa0d32e6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Sat, 29 Aug 2015 14:38:07 -0700 Subject: [PATCH 496/549] add network logging to SendQueue, fix ctor order --- libraries/networking/src/udt/Connection.cpp | 2 +- libraries/networking/src/udt/SendQueue.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 4d2ca8cda3..b8dbc7c62e 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -28,9 +28,9 @@ using namespace udt; using namespace std::chrono; Connection::Connection(Socket* parentSocket, HifiSockAddr destination, std::unique_ptr congestionControl) : + _connectionStart(high_resolution_clock::now()), _parentSocket(parentSocket), _destination(destination), - _connectionStart(high_resolution_clock::now()) _congestionControl(move(congestionControl)) { Q_ASSERT_X(socket, "Connection::Connection", "Must be called with a valid Socket*"); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 52f1a48420..171a79dccc 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -20,6 +20,7 @@ #include +#include "../NetworkLogging.h" #include "ControlPacket.h" #include "Packet.h" #include "PacketList.h" From 7937101a583615b18c27763c19b81489c2f4b168 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Sat, 29 Aug 2015 14:44:18 -0700 Subject: [PATCH 497/549] fix define for UDT_CONNECTION_DEBUG --- libraries/networking/src/udt/Socket.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index ad30031624..2809ec795a 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -25,7 +25,7 @@ #include "CongestionControl.h" #include "Connection.h" -#define UDT_CONNECTION_DEBUG 0 +#define UDT_CONNECTION_DEBUG namespace udt { From fc80745c08b7836e594ffbb994700f37722bc620 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Sun, 30 Aug 2015 20:03:15 -0700 Subject: [PATCH 498/549] Update message handling to use insertion sort --- libraries/networking/src/udt/Connection.cpp | 25 ++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index b8dbc7c62e..e2cdbb8651 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -825,30 +825,35 @@ void PendingReceivedMessage::enqueuePacket(std::unique_ptr packet) { return; } + auto sequenceNumber = packet->getSequenceNumber(); + if (packet->getPacketPosition() == Packet::PacketPosition::FIRST) { _hasFirstSequenceNumber = true; - _firstSequenceNumber = packet->getSequenceNumber(); + _firstSequenceNumber = sequenceNumber; } else if (packet->getPacketPosition() == Packet::PacketPosition::LAST) { _hasLastSequenceNumber = true; - _lastSequenceNumber = packet->getSequenceNumber(); + _lastSequenceNumber = sequenceNumber; } else if (packet->getPacketPosition() == Packet::PacketPosition::ONLY) { _hasFirstSequenceNumber = true; _hasLastSequenceNumber = true; - _firstSequenceNumber = packet->getSequenceNumber(); - _lastSequenceNumber = packet->getSequenceNumber(); + _firstSequenceNumber = sequenceNumber; + _lastSequenceNumber = sequenceNumber; } - _packets.push_back(std::move(packet)); + // Insert into the packets list in sorted order. Because we generally expect to receive packets in order, begin + // searching from the end of the list. + auto it = _packets.rbegin(); + for (auto rend = _packets.rend(); it != rend; ++it) { + if (sequenceNumber > (*it)->getSequenceNumber()) { + break; + } + } + _packets.insert(it.base(), std::move(packet)); if (_hasFirstSequenceNumber && _hasLastSequenceNumber) { auto numPackets = udt::seqlen(_firstSequenceNumber, _lastSequenceNumber); if (uint64_t(numPackets) == _packets.size()) { _isComplete = true; - - // Sort packets by sequence number - _packets.sort([](std::unique_ptr& a, std::unique_ptr& b) { - return a->getSequenceNumber() < b->getSequenceNumber(); - }); } } } From 181c8a8b65eba7dd63e3a2d15a2d26b2381c3b29 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 31 Aug 2015 10:48:45 -0700 Subject: [PATCH 499/549] handle packet probe when no data available --- libraries/networking/src/udt/Connection.cpp | 30 ++++++++++++++++++- libraries/networking/src/udt/Connection.h | 4 ++- .../networking/src/udt/ControlPacket.cpp | 2 +- libraries/networking/src/udt/ControlPacket.h | 3 +- libraries/networking/src/udt/SendQueue.cpp | 6 ++++ 5 files changed, 41 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index b8dbc7c62e..7f5ad0c1a0 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -409,7 +409,14 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in if (((uint32_t) sequenceNumber & 0xF) == 0) { _receiveWindow.onProbePair1Arrival(); } else if (((uint32_t) sequenceNumber & 0xF) == 1) { - _receiveWindow.onProbePair2Arrival(); + // only use this packet for bandwidth estimation if we didn't just receive a control packet in its place + if (!_receivedControlProbeTail) { + _receiveWindow.onProbePair2Arrival(); + } else { + // reset our control probe tail marker so the next probe that comes with data can be used + _receivedControlProbeTail = false; + } + } _receiveWindow.onPacketArrival(); @@ -510,6 +517,11 @@ void Connection::processControl(std::unique_ptr controlPacket) { case ControlPacket::HandshakeACK: processHandshakeACK(move(controlPacket)); break; + case ControlPacket::ProbeTail: + if (_isReceivingData) { + processProbeTail(move(controlPacket)); + } + break; } } @@ -733,6 +745,21 @@ void Connection::processTimeoutNAK(std::unique_ptr controlPacket) _stats.record(ConnectionStats::Stats::ReceivedTimeoutNAK); } +void Connection::processProbeTail(std::unique_ptr controlPacket) { + // this is the second packet in a probe set so we can estimate bandwidth + // the sender sent this to us in lieu of sending new data (because they didn't have any) + +#ifdef UDT_CONNECTION_DEBUG + qCDebug(networking) << "Processing second packet of probe from control packet instead of data packet"; +#endif + + _receiveWindow.onProbePair2Arrival(); + + // mark that we processed a control packet for the second in the pair and we should not mark + // the next data packet received + _receivedControlProbeTail = true; +} + void Connection::resetReceiveState() { // reset all SequenceNumber member variables back to default @@ -767,6 +794,7 @@ void Connection::resetReceiveState() { // clear the intervals in the receive window _receiveWindow.reset(); + _receivedControlProbeTail = false; // clear any pending received messages _pendingReceivedMessages.clear(); diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index eb5961695c..f10c9dd720 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -94,6 +94,7 @@ private: void processTimeoutNAK(std::unique_ptr controlPacket); void processHandshake(std::unique_ptr controlPacket); void processHandshakeACK(std::unique_ptr controlPacket); + void processProbeTail(std::unique_ptr controlPacket); void resetReceiveState(); void resetRTT(); @@ -145,7 +146,8 @@ private: Socket* _parentSocket { nullptr }; HifiSockAddr _destination; - PacketTimeWindow _receiveWindow { 16, 64 }; // Window of interval between packets (16) and probes (64) for bandwidth and receive speed + PacketTimeWindow _receiveWindow { 16, 64 }; // Window of interval between packets (16) and probes (64) for timing + bool _receivedControlProbeTail { false }; // Marker for receipt of control packet probe tail (in lieu of probe with data) std::unique_ptr _congestionControl; diff --git a/libraries/networking/src/udt/ControlPacket.cpp b/libraries/networking/src/udt/ControlPacket.cpp index 8c799f97a6..e672ab426b 100644 --- a/libraries/networking/src/udt/ControlPacket.cpp +++ b/libraries/networking/src/udt/ControlPacket.cpp @@ -100,7 +100,7 @@ void ControlPacket::readType() { Q_ASSERT_X(bitAndType & CONTROL_BIT_MASK, "ControlPacket::readHeader()", "This should be a control packet"); uint16_t packetType = (bitAndType & ~CONTROL_BIT_MASK) >> (8 * sizeof(Type)); - Q_ASSERT_X(packetType <= ControlPacket::Type::HandshakeACK, "ControlPacket::readType()", "Received a control packet with wrong type"); + Q_ASSERT_X(packetType <= ControlPacket::Type::ProbeTail, "ControlPacket::readType()", "Received a control packet with wrong type"); // read the type _type = (Type) packetType; diff --git a/libraries/networking/src/udt/ControlPacket.h b/libraries/networking/src/udt/ControlPacket.h index 1976899c14..fea8210ba0 100644 --- a/libraries/networking/src/udt/ControlPacket.h +++ b/libraries/networking/src/udt/ControlPacket.h @@ -33,7 +33,8 @@ public: NAK, TimeoutNAK, Handshake, - HandshakeACK + HandshakeACK, + ProbeTail }; static std::unique_ptr create(Type type, qint64 size = -1); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 171a79dccc..7abb195005 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -463,6 +463,12 @@ bool SendQueue::maybeSendNewPacket() { // do we have a second in a pair to send as well? if (secondPacket) { sendNewPacketAndAddToSentList(move(secondPacket), getNextSequenceNumber()); + } else { + // we didn't get a second packet to send in the probe pair + // send a control packet of type ProbePairTail so the receiver can still do + // proper bandwidth estimation + static auto pairTailPacket = ControlPacket::create(ControlPacket::ProbeTail); + _socket->writeBasePacket(*pairTailPacket, _destination); } // We sent our packet(s), return here From de2bfd0d0d04226954c705b1caba8edf61b03388 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 31 Aug 2015 11:30:31 -0700 Subject: [PATCH 500/549] some QThread cleanup and fix in Socket --- interface/src/Application.cpp | 12 ++++++++---- libraries/networking/src/AssetClient.cpp | 5 +++++ libraries/networking/src/LimitedNodeList.cpp | 2 +- libraries/networking/src/udt/SendQueue.cpp | 2 +- libraries/networking/src/udt/Socket.cpp | 8 ++++---- libraries/networking/src/udt/Socket.h | 3 ++- libraries/shared/src/GenericThread.cpp | 3 ++- 7 files changed, 23 insertions(+), 12 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1daba493d9..2474668fe9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -457,8 +457,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : audioThread->start(); - - QThread* assetThread = new QThread(); + QThread* assetThread = new QThread; assetThread->setObjectName("Asset Thread"); auto assetClient = DependencyManager::get(); @@ -467,7 +466,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : assetThread->start(); - const DomainHandler& domainHandler = nodeList->getDomainHandler(); connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&))); @@ -878,6 +876,12 @@ Application::~Application() { DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); + + // cleanup the AssetClient thread + QThread* assetThread = DependencyManager::get()->thread(); + DependencyManager::destroy(); + assetThread->quit(); + assetThread->wait(); QThread* nodeThread = DependencyManager::get()->thread(); @@ -887,7 +891,7 @@ Application::~Application() { // ask the node thread to quit and wait until it is done nodeThread->quit(); nodeThread->wait(); - + Leapmotion::destroy(); RealSense::destroy(); ConnexionClient::getInstance().destroy(); diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 4d228fc6bd..2d89a7259f 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -24,6 +24,11 @@ MessageID AssetClient::_currentID = 0; AssetClient::AssetClient() { + + setCustomDeleter([](Dependency* dependency){ + static_cast(dependency)->deleteLater(); + }); + auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply"); packetReceiver.registerMessageListener(PacketType::AssetGetReply, this, "handleAssetGetReply"); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index e5923b059f..2d1c98287c 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -66,7 +66,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short firstCall = false; } - + qRegisterMetaType("ConnectionStep"); _nodeSocket.bind(QHostAddress::AnyIPv4, socketListenPort); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index e088cb8d8b..8210848fec 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -53,7 +53,7 @@ std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr destin Q_ASSERT_X(socket, "SendQueue::create", "Must be called with a valid Socket*"); // Setup queue private thread - QThread* thread = new QThread(); + QThread* thread = new QThread; thread->setObjectName("Networking: SendQueue " + destination.objectName()); // Name thread for easier debug connect(thread, &QThread::started, queue.get(), &SendQueue::run); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index f3ce095b50..1c3d6ca557 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -30,10 +30,10 @@ Socket::Socket(QObject* parent) : connect(&_udpSocket, &QUdpSocket::readyRead, this, &Socket::readPendingDatagrams); // make sure our synchronization method is called every SYN interval - connect(&_synTimer, &QTimer::timeout, this, &Socket::rateControlSync); + connect(_synTimer, &QTimer::timeout, this, &Socket::rateControlSync); // start our timer for the synchronization time interval - _synTimer.start(_synInterval); + _synTimer->start(_synInterval); } void Socket::rebind() { @@ -262,10 +262,10 @@ void Socket::rateControlSync() { connection.second->sync(); } - if (_synTimer.interval() != _synInterval) { + if (_synTimer->interval() != _synInterval) { // if the _synTimer interval doesn't match the current _synInterval (changes when the CC factory is changed) // then restart it now with the right interval - _synTimer.start(_synInterval); + _synTimer->start(_synInterval); } } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 23dd313462..564fba6539 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -43,6 +43,7 @@ class Socket : public QObject { Q_OBJECT public: Socket(QObject* object = 0); + ~Socket(); quint16 localPort() const { return _udpSocket.localPort(); } @@ -97,7 +98,7 @@ private: QMutex _connectionsMutex; // guards concurrent access to connections hashs int _synInterval = 10; // 10ms - QTimer _synTimer; + QTimer* _synTimer; std::unique_ptr _ccFactory { new CongestionControlFactory() }; }; diff --git a/libraries/shared/src/GenericThread.cpp b/libraries/shared/src/GenericThread.cpp index be984d5899..18f5224229 100644 --- a/libraries/shared/src/GenericThread.cpp +++ b/libraries/shared/src/GenericThread.cpp @@ -19,6 +19,7 @@ GenericThread::GenericThread(QObject* parent) : _stopThread(false), _isThreaded(false) // assume non-threaded, must call initialize() { + } GenericThread::~GenericThread() { @@ -32,7 +33,7 @@ void GenericThread::initialize(bool isThreaded, QThread::Priority priority) { _isThreaded = isThreaded; if (_isThreaded) { _thread = new QThread(this); - + // match the thread name to our object name _thread->setObjectName(objectName()); From 46d90b4f3196d042747c1a362b6cb3b1fff381d2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 31 Aug 2015 11:40:06 -0700 Subject: [PATCH 501/549] =?UTF-8?q?make=20sure=20syn=20timer=20is=C2=A0mov?= =?UTF-8?q?ed=20to=20Socket=20thread?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libraries/networking/src/udt/Socket.cpp | 3 ++- libraries/networking/src/udt/Socket.h | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 1c3d6ca557..c9ae878cee 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -25,7 +25,8 @@ using namespace udt; Socket::Socket(QObject* parent) : - QObject(parent) + QObject(parent), + _synTimer(new QTimer(this)) { connect(&_udpSocket, &QUdpSocket::readyRead, this, &Socket::readPendingDatagrams); diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 564fba6539..faf8aeedf7 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -43,7 +43,6 @@ class Socket : public QObject { Q_OBJECT public: Socket(QObject* object = 0); - ~Socket(); quint16 localPort() const { return _udpSocket.localPort(); } From e8fba991fa97785639acd8b675105e894ee595e0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 31 Aug 2015 12:35:41 -0700 Subject: [PATCH 502/549] Update raw loop to use find_if for message packet sorting --- libraries/networking/src/udt/Connection.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index e2cdbb8651..368a6d459e 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -842,11 +842,8 @@ void PendingReceivedMessage::enqueuePacket(std::unique_ptr packet) { // Insert into the packets list in sorted order. Because we generally expect to receive packets in order, begin // searching from the end of the list. - auto it = _packets.rbegin(); - for (auto rend = _packets.rend(); it != rend; ++it) { - if (sequenceNumber > (*it)->getSequenceNumber()) { - break; - } + auto it = find_if(_packets.rbegin(), _packets.rend(), + [&](const std::unique_ptr& packet) { return sequenceNumber > packet->getSequenceNumber(); }); } _packets.insert(it.base(), std::move(packet)); From 15e97978275b9ba4eff141738128ed2dbc8ccab5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 31 Aug 2015 22:12:42 +0200 Subject: [PATCH 503/549] CR --- libraries/networking/src/AssetClient.cpp | 4 +- .../networking/src/FileResourceRequest.cpp | 15 +++--- .../networking/src/HTTPResourceRequest.cpp | 3 ++ libraries/networking/src/ResourceCache.cpp | 48 +++++++------------ 4 files changed, 30 insertions(+), 40 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 4bbc9f740a..68b7c5ad76 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -50,7 +50,7 @@ AssetRequest* AssetClient::createRequest(const QString& hash, const QString& ext SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); if (!assetServer) { - qDebug() << "No Asset Server"; + qDebug().nospace() << "Could not request " << hash << "." << extension << " since you are not currently connected to an asset-server."; return nullptr; } @@ -71,7 +71,7 @@ AssetUpload* AssetClient::createUpload(const QString& filename) { SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); if (!assetServer) { - qDebug() << "No Asset Server"; + qDebug() << "Could not upload" << filename << "since you are not currently connected to an asset-server."; return nullptr; } diff --git a/libraries/networking/src/FileResourceRequest.cpp b/libraries/networking/src/FileResourceRequest.cpp index dd2f6c8478..9e0320f6b7 100644 --- a/libraries/networking/src/FileResourceRequest.cpp +++ b/libraries/networking/src/FileResourceRequest.cpp @@ -17,14 +17,15 @@ void FileResourceRequest::doSend() { QString filename = _url.toLocalFile(); QFile file(filename); - - if (!file.exists()) { - _result = NotFound; - } else if (file.open(QFile::ReadOnly)) { - _data = file.readAll(); - _result = Success; + if (file.exists()) { + if (file.open(QFile::ReadOnly)) { + _data = file.readAll(); + _result = ResourceRequest::Success; + } else { + _result = ResourceRequest::AccessDenied; + } } else { - _result = AccessDenied; + _result = ResourceRequest::NotFound; } _state = Finished; diff --git a/libraries/networking/src/HTTPResourceRequest.cpp b/libraries/networking/src/HTTPResourceRequest.cpp index fbfcabb53d..f48c7d9132 100644 --- a/libraries/networking/src/HTTPResourceRequest.cpp +++ b/libraries/networking/src/HTTPResourceRequest.cpp @@ -69,6 +69,9 @@ void HTTPResourceRequest::onRequestFinished() { _result = Error; break; } + _reply->disconnect(this); + _reply->deleteLater(); + _reply = nullptr; _state = Finished; emit finished(); diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 18024000b3..1e0e5f745b 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -158,14 +158,12 @@ void ResourceCache::attemptRequest(Resource* resource) { // Disable request limiting for ATP if (resource->getURL().scheme() != URL_SCHEME_ATP) { if (_requestLimit <= 0) { - qDebug() << "REQUEST LIMIT REACHED (" << _requestLimit << "), queueing: " << resource->getURL(); // wait until a slot becomes available sharedItems->_pendingRequests.append(resource); return; } - qDebug() << "-- Decreasing limit for : " << resource->getURL(); - _requestLimit--; + --_requestLimit; } sharedItems->_loadingRequests.append(resource); @@ -176,8 +174,7 @@ void ResourceCache::requestCompleted(Resource* resource) { auto sharedItems = DependencyManager::get(); sharedItems->_loadingRequests.removeOne(resource); if (resource->getURL().scheme() != URL_SCHEME_ATP) { - qDebug() << "++ Increasing limit after finished: " << resource->getURL(); - _requestLimit++; + ++_requestLimit; } // look for the highest priority pending request @@ -367,33 +364,22 @@ void Resource::handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTota void Resource::handleReplyFinished() { Q_ASSERT(_request); - + + ResourceCache::requestCompleted(this); + auto result = _request->getResult(); if (result == ResourceRequest::Success) { _data = _request->getData(); qDebug() << "Request finished for " << _url << ", " << _activeUrl; - - _request->disconnect(this); - _request->deleteLater(); - _request = nullptr; - - ResourceCache::requestCompleted(this); - + + finishedLoading(false); emit loaded(_data); - downloadFinished(_data); } else { - _request->disconnect(this); - _request->deleteLater(); - _request = nullptr; - if (result == ResourceRequest::Result::Timeout) { qDebug() << "Timed out loading" << _url << "received" << _bytesReceived << "total" << _bytesTotal; - } else { - qDebug() << "Error loading " << _url; } - bool retry = false; switch (result) { case ResourceRequest::Result::Timeout: case ResourceRequest::Result::ServerUnavailable: @@ -402,24 +388,24 @@ void Resource::handleReplyFinished() { const int MAX_ATTEMPTS = 8; const int BASE_DELAY_MS = 1000; if (++_attempts < MAX_ATTEMPTS) { - QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, &Resource::makeRequest); - retry = true; + QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(attemptRequest())); break; } // fall through to final failure } - default: + default: { + qDebug() << "Error loading " << _url; + auto error = (result == ResourceRequest::Timeout) ? QNetworkReply::TimeoutError : QNetworkReply::UnknownNetworkError; + emit failed(error); finishedLoading(false); break; - } - - auto error = result == ResourceRequest::Timeout ? QNetworkReply::TimeoutError : QNetworkReply::UnknownNetworkError; - - if (!retry) { - emit failed(error); - ResourceCache::requestCompleted(this); + } } } + + _request->disconnect(this); + _request->deleteLater(); + _request = nullptr; } void Resource::downloadFinished(const QByteArray& data) { From 9a9c703a78f26e2beda1a6d330bf814fd5b644f0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 31 Aug 2015 22:31:24 +0200 Subject: [PATCH 504/549] Some code cleanup --- libraries/networking/src/ResourceCache.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 1e0e5f745b..47568c22a6 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -372,30 +372,29 @@ void Resource::handleReplyFinished() { _data = _request->getData(); qDebug() << "Request finished for " << _url << ", " << _activeUrl; - finishedLoading(false); + finishedLoading(true); emit loaded(_data); downloadFinished(_data); } else { - if (result == ResourceRequest::Result::Timeout) { - qDebug() << "Timed out loading" << _url << "received" << _bytesReceived << "total" << _bytesTotal; - } - switch (result) { case ResourceRequest::Result::Timeout: + qDebug() << "Timed out loading" << _url << "received" << _bytesReceived << "total" << _bytesTotal; + // Fall through to other cases case ResourceRequest::Result::ServerUnavailable: case ResourceRequest::Result::Error: { // retry with increasing delays const int MAX_ATTEMPTS = 8; const int BASE_DELAY_MS = 1000; if (++_attempts < MAX_ATTEMPTS) { - QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(attemptRequest())); + QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, &Resource::attemptRequest); break; } // fall through to final failure } default: { qDebug() << "Error loading " << _url; - auto error = (result == ResourceRequest::Timeout) ? QNetworkReply::TimeoutError : QNetworkReply::UnknownNetworkError; + auto error = (result == ResourceRequest::Timeout) ? QNetworkReply::TimeoutError + : QNetworkReply::UnknownNetworkError; emit failed(error); finishedLoading(false); break; From 8f74935e96d359945cef2a83ab3ec8dcb902453f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 31 Aug 2015 22:34:16 +0200 Subject: [PATCH 505/549] Don't reload on error --- libraries/networking/src/ResourceCache.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 47568c22a6..cea48e7419 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -380,13 +380,14 @@ void Resource::handleReplyFinished() { case ResourceRequest::Result::Timeout: qDebug() << "Timed out loading" << _url << "received" << _bytesReceived << "total" << _bytesTotal; // Fall through to other cases - case ResourceRequest::Result::ServerUnavailable: - case ResourceRequest::Result::Error: { + case ResourceRequest::Result::ServerUnavailable: { // retry with increasing delays const int MAX_ATTEMPTS = 8; const int BASE_DELAY_MS = 1000; if (++_attempts < MAX_ATTEMPTS) { - QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, &Resource::attemptRequest); + auto waitTime = BASE_DELAY_MS * (int)pow(2.0, _attempts); + qDebug() << "Retrying to load the asset in " << waitTime; + QTimer::singleShot(waitTime, this, &Resource::attemptRequest); break; } // fall through to final failure From dc7d7ef4442bc0a4ec1b14b56d5e10d88da577df Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 31 Aug 2015 15:17:40 -0600 Subject: [PATCH 506/549] make SendAssetTask be consistent with new UploadAssetTask --- assignment-client/src/assets/AssetServer.cpp | 48 ++++++++++--------- .../src/assets/SendAssetTask.cpp | 32 +++++++++---- assignment-client/src/assets/SendAssetTask.h | 18 ++++--- .../src/assets/UploadAssetTask.cpp | 19 -------- 4 files changed, 61 insertions(+), 56 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index c046b39f66..62f1b877b5 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -125,39 +125,43 @@ void AssetServer::handleAssetGetInfo(QSharedPointer packet, SharedNode } void AssetServer::handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode) { - MessageID messageID; - QByteArray assetHash; - uint8_t extensionLength; - DataOffset start; - DataOffset end; - auto minSize = qint64(sizeof(messageID) + SHA256_HASH_LENGTH + sizeof(extensionLength) + sizeof(start) + sizeof(end)); + auto minSize = qint64(sizeof(MessageID) + SHA256_HASH_LENGTH + sizeof(uint8_t) + sizeof(DataOffset) + sizeof(DataOffset)); + if (packet->getPayloadSize() < minSize) { qDebug() << "ERROR bad file request"; return; } - packet->readPrimitive(&messageID); - assetHash = packet->read(SHA256_HASH_LENGTH); - packet->readPrimitive(&extensionLength); - QByteArray extension = packet->read(extensionLength); - packet->readPrimitive(&start); - packet->readPrimitive(&end); - - QByteArray hexHash = assetHash.toHex(); - - qDebug() << "Received a request for the file (" << messageID << "): " << hexHash << " from " << start << " to " << end; - // Queue task - QString filePath = _resourcesDirectory.filePath(QString(hexHash) + "." + QString(extension)); - auto task = new SendAssetTask(messageID, assetHash, filePath, start, end, senderNode); + auto task = new SendAssetTask(packet, senderNode, _resourcesDirectory); _taskPool.start(task); } void AssetServer::handleAssetUpload(QSharedPointer packetList, SharedNodePointer senderNode) { - qDebug() << "Starting an UploadAssetTask for upload from" << uuidStringWithoutCurlyBraces(senderNode->getUUID()); - auto task = new UploadAssetTask(packetList, senderNode, _resourcesDirectory); - _taskPool.start(task); + if (senderNode->getCanRez()) { + qDebug() << "Starting an UploadAssetTask for upload from" << uuidStringWithoutCurlyBraces(senderNode->getUUID()); + + auto task = new UploadAssetTask(packetList, senderNode, _resourcesDirectory); + _taskPool.start(task); + } else { + // this is a node the domain told us is not allowed to rez entities + // for now this also means it isn't allowed to add assets + // so return a packet with error that indicates that + + auto permissionErrorPacket = NLPacket::create(PacketType::AssetUploadReply, sizeof(MessageID) + sizeof(AssetServerError)); + + MessageID messageID; + packetList->readPrimitive(&messageID); + + // write the message ID and a permission denied error + permissionErrorPacket->writePrimitive(messageID); + permissionErrorPacket->writePrimitive(AssetServerError::PERMISSION_DENIED); + + // send off the packet + auto nodeList = DependencyManager::get(); + nodeList->sendPacket(std::move(permissionErrorPacket), *senderNode); + } } diff --git a/assignment-client/src/assets/SendAssetTask.cpp b/assignment-client/src/assets/SendAssetTask.cpp index 91782b95ad..c4c7bf2503 100644 --- a/assignment-client/src/assets/SendAssetTask.cpp +++ b/assignment-client/src/assets/SendAssetTask.cpp @@ -18,23 +18,35 @@ #include #include #include +#include #include "AssetUtils.h" -SendAssetTask::SendAssetTask(MessageID messageID, const QByteArray& assetHash, QString filePath, DataOffset start, DataOffset end, - const SharedNodePointer& sendToNode) : +SendAssetTask::SendAssetTask(QSharedPointer packet, const SharedNodePointer& sendToNode, const QDir& resourcesDir) : QRunnable(), - _messageID(messageID), - _assetHash(assetHash), - _filePath(filePath), - _start(start), - _end(end), - _sendToNode(sendToNode) + _packet(packet), + _senderNode(sendToNode), + _resourcesDir(resourcesDir) { + } void SendAssetTask::run() { + MessageID messageID; + uint8_t extensionLength; + DataOffset start, end; + + _packet->readPrimitive(&messageID); + QByteArray assetHash = _packet->read(SHA256_HASH_LENGTH); + _packet->readPrimitive(&extensionLength); + QByteArray extension = _packet->read(extensionLength); + _packet->readPrimitive(&start); + _packet->readPrimitive(&end); + QString hexHash = _assetHash.toHex(); + + qDebug() << "Received a request for the file (" << messageID << "): " << hexHash << " from " << start << " to " << end; + qDebug() << "Starting task to send asset: " << hexHash << " for messageID " << _messageID; auto replyPacketList = std::unique_ptr(new NLPacketList(PacketType::AssetGetReply, QByteArray(), true, true)); @@ -45,6 +57,8 @@ void SendAssetTask::run() { if (_end <= _start) { writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); } else { + QString filePath = _resourcesDir.filePath(QString(hexHash) + "." + QString(extension)); + QFile file { _filePath }; if (file.open(QIODevice::ReadOnly)) { @@ -67,5 +81,5 @@ void SendAssetTask::run() { } auto nodeList = DependencyManager::get(); - nodeList->sendPacketList(std::move(replyPacketList), *_sendToNode); + nodeList->sendPacketList(std::move(replyPacketList), *_senderNode); } diff --git a/assignment-client/src/assets/SendAssetTask.h b/assignment-client/src/assets/SendAssetTask.h index 477f42c1a3..1dc6c8dca2 100644 --- a/assignment-client/src/assets/SendAssetTask.h +++ b/assignment-client/src/assets/SendAssetTask.h @@ -12,28 +12,34 @@ #ifndef hifi_SendAssetTask_h #define hifi_SendAssetTask_h -#include -#include -#include +#include +#include +#include +#include #include "AssetUtils.h" #include "AssetServer.h" #include "Node.h" +namespace udt { + class Packet; +} + class SendAssetTask : public QRunnable { public: - SendAssetTask(MessageID messageID, const QByteArray& assetHash, QString filePath, DataOffset start, DataOffset end, - const SharedNodePointer& sendToNode); + SendAssetTask(QSharedPointer packet, const SharedNodePointer& sendToNode, const QDir& resourcesDir); void run(); private: + QSharedPointer _packet; MessageID _messageID; QByteArray _assetHash; QString _filePath; DataOffset _start; DataOffset _end; - SharedNodePointer _sendToNode; + SharedNodePointer _senderNode; + QDir _resourcesDir; }; #endif diff --git a/assignment-client/src/assets/UploadAssetTask.cpp b/assignment-client/src/assets/UploadAssetTask.cpp index 66fdc80e90..d4991f9554 100644 --- a/assignment-client/src/assets/UploadAssetTask.cpp +++ b/assignment-client/src/assets/UploadAssetTask.cpp @@ -37,25 +37,6 @@ void UploadAssetTask::run() { MessageID messageID; buffer.read(reinterpret_cast(&messageID), sizeof(messageID)); - if (!_senderNode->getCanRez()) { - // this is a node the domain told us is not allowed to rez entities - // for now this also means it isn't allowed to add assets - // so return a packet with error that indicates that - - auto permissionErrorPacket = NLPacket::create(PacketType::AssetUploadReply, sizeof(MessageID) + sizeof(AssetServerError)); - - // write the message ID and a permission denied error - permissionErrorPacket->writePrimitive(messageID); - permissionErrorPacket->writePrimitive(AssetServerError::PERMISSION_DENIED); - - // send off the packet - auto nodeList = DependencyManager::get(); - nodeList->sendPacket(std::move(permissionErrorPacket), *_senderNode); - - // return so we're not attempting to handle upload - return; - } - uint8_t extensionLength; buffer.read(reinterpret_cast(&extensionLength), sizeof(extensionLength)); From 3f5394281b24d48e24c5116111039a98443a50d7 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 31 Aug 2015 23:20:07 +0200 Subject: [PATCH 507/549] Fix HTTPS timeout issue --- libraries/networking/src/AssetResourceRequest.cpp | 1 - libraries/networking/src/HTTPResourceRequest.cpp | 12 +++++++----- libraries/networking/src/ResourceCache.cpp | 8 +++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index b98560152a..d27151ac53 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -68,6 +68,5 @@ void AssetResourceRequest::doSend() { } void AssetResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { - qDebug() << "Got asset data: " << bytesReceived << " / " << bytesTotal; emit progress(bytesReceived, bytesTotal); } diff --git a/libraries/networking/src/HTTPResourceRequest.cpp b/libraries/networking/src/HTTPResourceRequest.cpp index f48c7d9132..fd650df348 100644 --- a/libraries/networking/src/HTTPResourceRequest.cpp +++ b/libraries/networking/src/HTTPResourceRequest.cpp @@ -40,12 +40,12 @@ void HTTPResourceRequest::doSend() { } _reply = networkAccessManager.get(networkRequest); - + connect(_reply, &QNetworkReply::finished, this, &HTTPResourceRequest::onRequestFinished); + connect(_reply, &QNetworkReply::downloadProgress, this, &HTTPResourceRequest::onDownloadProgress); + connect(&_sendTimer, &QTimer::timeout, this, &HTTPResourceRequest::onTimeout); static const int TIMEOUT_MS = 10000; - - connect(&_sendTimer, &QTimer::timeout, this, &HTTPResourceRequest::onTimeout); _sendTimer.setSingleShot(true); _sendTimer.start(TIMEOUT_MS); } @@ -88,9 +88,11 @@ void HTTPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesT void HTTPResourceRequest::onTimeout() { Q_ASSERT(_state == InProgress); - - qCDebug(networking) << "Timed out loading " << _url; + _reply->disconnect(this); _reply->abort(); + _reply->deleteLater(); + _reply = nullptr; + _result = Timeout; _state = Finished; emit finished(); diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index cea48e7419..1b1dae5beb 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -377,16 +377,18 @@ void Resource::handleReplyFinished() { downloadFinished(_data); } else { switch (result) { - case ResourceRequest::Result::Timeout: + case ResourceRequest::Result::Timeout: { qDebug() << "Timed out loading" << _url << "received" << _bytesReceived << "total" << _bytesTotal; // Fall through to other cases + } case ResourceRequest::Result::ServerUnavailable: { // retry with increasing delays const int MAX_ATTEMPTS = 8; const int BASE_DELAY_MS = 1000; - if (++_attempts < MAX_ATTEMPTS) { + if (_attempts++ < MAX_ATTEMPTS) { auto waitTime = BASE_DELAY_MS * (int)pow(2.0, _attempts); - qDebug() << "Retrying to load the asset in " << waitTime; + qDebug().nospace() << "Retrying to load the asset in " << waitTime + << ", attempt " << _attempts << " of " << MAX_ATTEMPTS; QTimer::singleShot(waitTime, this, &Resource::attemptRequest); break; } From 0de4c02e8d46bf02222181f2c084df0b2661657f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 31 Aug 2015 23:24:14 +0200 Subject: [PATCH 508/549] Add time unit in debug --- libraries/networking/src/ResourceCache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 1b1dae5beb..18135cf6df 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -388,7 +388,7 @@ void Resource::handleReplyFinished() { if (_attempts++ < MAX_ATTEMPTS) { auto waitTime = BASE_DELAY_MS * (int)pow(2.0, _attempts); qDebug().nospace() << "Retrying to load the asset in " << waitTime - << ", attempt " << _attempts << " of " << MAX_ATTEMPTS; + << "ms, attempt " << _attempts << " of " << MAX_ATTEMPTS; QTimer::singleShot(waitTime, this, &Resource::attemptRequest); break; } From cb903a8d06471c9744ec0ed4076da65de657d0ef Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 31 Aug 2015 15:30:18 -0600 Subject: [PATCH 509/549] fix the new send asset task --- .../src/assets/SendAssetTask.cpp | 24 +++++++++---------- assignment-client/src/assets/SendAssetTask.h | 13 +++------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/assignment-client/src/assets/SendAssetTask.cpp b/assignment-client/src/assets/SendAssetTask.cpp index c4c7bf2503..8131bafaf3 100644 --- a/assignment-client/src/assets/SendAssetTask.cpp +++ b/assignment-client/src/assets/SendAssetTask.cpp @@ -22,7 +22,7 @@ #include "AssetUtils.h" -SendAssetTask::SendAssetTask(QSharedPointer packet, const SharedNodePointer& sendToNode, const QDir& resourcesDir) : +SendAssetTask::SendAssetTask(QSharedPointer packet, const SharedNodePointer& sendToNode, const QDir& resourcesDir) : QRunnable(), _packet(packet), _senderNode(sendToNode), @@ -43,31 +43,31 @@ void SendAssetTask::run() { _packet->readPrimitive(&start); _packet->readPrimitive(&end); - QString hexHash = _assetHash.toHex(); + QString hexHash = assetHash.toHex(); qDebug() << "Received a request for the file (" << messageID << "): " << hexHash << " from " << start << " to " << end; - qDebug() << "Starting task to send asset: " << hexHash << " for messageID " << _messageID; + qDebug() << "Starting task to send asset: " << hexHash << " for messageID " << messageID; auto replyPacketList = std::unique_ptr(new NLPacketList(PacketType::AssetGetReply, QByteArray(), true, true)); - replyPacketList->write(_assetHash); + replyPacketList->write(assetHash); - replyPacketList->writePrimitive(_messageID); + replyPacketList->writePrimitive(messageID); - if (_end <= _start) { + if (end <= start) { writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); } else { QString filePath = _resourcesDir.filePath(QString(hexHash) + "." + QString(extension)); - QFile file { _filePath }; + QFile file { filePath }; if (file.open(QIODevice::ReadOnly)) { - if (file.size() < _end) { + if (file.size() < end) { writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); - qCDebug(networking) << "Bad byte range: " << hexHash << " " << _start << ":" << _end; + qCDebug(networking) << "Bad byte range: " << hexHash << " " << start << ":" << end; } else { - auto size = _end - _start; - file.seek(_start); + auto size = end - start; + file.seek(start); replyPacketList->writePrimitive(AssetServerError::NO_ERROR); replyPacketList->writePrimitive(size); replyPacketList->write(file.read(size)); @@ -75,7 +75,7 @@ void SendAssetTask::run() { } file.close(); } else { - qCDebug(networking) << "Asset not found: " << _filePath << "(" << hexHash << ")"; + qCDebug(networking) << "Asset not found: " << filePath << "(" << hexHash << ")"; writeError(replyPacketList.get(), AssetServerError::ASSET_NOT_FOUND); } } diff --git a/assignment-client/src/assets/SendAssetTask.h b/assignment-client/src/assets/SendAssetTask.h index 1dc6c8dca2..4e1a35b3fe 100644 --- a/assignment-client/src/assets/SendAssetTask.h +++ b/assignment-client/src/assets/SendAssetTask.h @@ -21,23 +21,16 @@ #include "AssetServer.h" #include "Node.h" -namespace udt { - class Packet; -} +class NLPacket; class SendAssetTask : public QRunnable { public: - SendAssetTask(QSharedPointer packet, const SharedNodePointer& sendToNode, const QDir& resourcesDir); + SendAssetTask(QSharedPointer packet, const SharedNodePointer& sendToNode, const QDir& resourcesDir); void run(); private: - QSharedPointer _packet; - MessageID _messageID; - QByteArray _assetHash; - QString _filePath; - DataOffset _start; - DataOffset _end; + QSharedPointer _packet; SharedNodePointer _senderNode; QDir _resourcesDir; }; From e36c2b85678c944f82d3d3b49fee7f84e53b466e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 31 Aug 2015 16:55:35 -0700 Subject: [PATCH 510/549] Remove extra curly brace --- libraries/networking/src/udt/Connection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 368a6d459e..9101356fb1 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -844,7 +844,7 @@ void PendingReceivedMessage::enqueuePacket(std::unique_ptr packet) { // searching from the end of the list. auto it = find_if(_packets.rbegin(), _packets.rend(), [&](const std::unique_ptr& packet) { return sequenceNumber > packet->getSequenceNumber(); }); - } + _packets.insert(it.base(), std::move(packet)); if (_hasFirstSequenceNumber && _hasLastSequenceNumber) { From 12a1085530bddf2dde28620229fcbb5dabb9685b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 31 Aug 2015 17:30:02 -0700 Subject: [PATCH 511/549] Fix friend declaration in Socket from udt::UDTTest to UDTTest --- libraries/networking/src/udt/Socket.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 414f923901..262f548d2e 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -27,6 +27,8 @@ #define UDT_CONNECTION_DEBUG +class UDTTest; + namespace udt { class BasePacket; @@ -34,7 +36,6 @@ class ControlSender; class Packet; class PacketList; class SequenceNumber; -class UDTTest; using PacketFilterOperator = std::function; From 791652557eb32b1986c4a9fe28ae813a35f70870 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 31 Aug 2015 17:30:02 -0700 Subject: [PATCH 512/549] Fix friend declaration in Socket from udt::UDTTest to UDTTest --- libraries/networking/src/udt/Socket.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 414f923901..923248caad 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -27,6 +27,8 @@ #define UDT_CONNECTION_DEBUG +class UDTTest; + namespace udt { class BasePacket; @@ -34,7 +36,6 @@ class ControlSender; class Packet; class PacketList; class SequenceNumber; -class UDTTest; using PacketFilterOperator = std::function; @@ -105,7 +106,7 @@ private: std::unique_ptr _ccFactory { new CongestionControlFactory() }; - friend class UDTTest; + friend UDTTest; }; } // namespace udt From 4824b38465b76364a304d7cb74b2b058fed2d096 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 1 Sep 2015 10:17:07 -0600 Subject: [PATCH 513/549] move UUID back to shared --- libraries/{networking => shared}/src/UUID.cpp | 0 libraries/{networking => shared}/src/UUID.h | 0 libraries/{networking => shared}/src/UUIDHasher.h | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename libraries/{networking => shared}/src/UUID.cpp (100%) rename libraries/{networking => shared}/src/UUID.h (100%) rename libraries/{networking => shared}/src/UUIDHasher.h (100%) diff --git a/libraries/networking/src/UUID.cpp b/libraries/shared/src/UUID.cpp similarity index 100% rename from libraries/networking/src/UUID.cpp rename to libraries/shared/src/UUID.cpp diff --git a/libraries/networking/src/UUID.h b/libraries/shared/src/UUID.h similarity index 100% rename from libraries/networking/src/UUID.h rename to libraries/shared/src/UUID.h diff --git a/libraries/networking/src/UUIDHasher.h b/libraries/shared/src/UUIDHasher.h similarity index 100% rename from libraries/networking/src/UUIDHasher.h rename to libraries/shared/src/UUIDHasher.h From be78d7f3aaa1e3234e7bcd1d9ad5db2da3703bc0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 1 Sep 2015 10:20:06 -0600 Subject: [PATCH 514/549] fix headers for move of UUID to shared --- libraries/networking/src/AddressManager.cpp | 3 ++- libraries/networking/src/DataServerAccountInfo.cpp | 3 ++- libraries/networking/src/LimitedNodeList.cpp | 2 +- libraries/networking/src/NLPacket.h | 3 ++- libraries/networking/src/NetworkPeer.cpp | 3 ++- libraries/networking/src/Node.cpp | 3 ++- libraries/networking/src/NodeList.cpp | 9 ++++++--- libraries/networking/src/WalletTransaction.cpp | 3 ++- 8 files changed, 19 insertions(+), 10 deletions(-) diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index ed4728ad78..f99e498ebf 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -18,11 +18,12 @@ #include #include +#include #include "AddressManager.h" #include "NodeList.h" #include "NetworkLogging.h" -#include "UUID.h" + const QString ADDRESS_MANAGER_SETTINGS_GROUP = "AddressManager"; const QString SETTINGS_CURRENT_ADDRESS_KEY = "address"; diff --git a/libraries/networking/src/DataServerAccountInfo.cpp b/libraries/networking/src/DataServerAccountInfo.cpp index 0628e21574..5d633a8df1 100644 --- a/libraries/networking/src/DataServerAccountInfo.cpp +++ b/libraries/networking/src/DataServerAccountInfo.cpp @@ -16,7 +16,8 @@ #include #include -#include "UUID.h" +#include + #include "NetworkLogging.h" #include "DataServerAccountInfo.h" diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 2d1c98287c..d874921ada 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -26,11 +26,11 @@ #include #include #include +#include #include "AccountManager.h" #include "Assignment.h" #include "HifiSockAddr.h" -#include "UUID.h" #include "NetworkLogging.h" #include "udt/Packet.h" diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index b5d5fc0766..57ada84607 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -14,7 +14,8 @@ #include -#include "UUID.h" +#include + #include "udt/Packet.h" class NLPacket : public udt::Packet { diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index 0ffb87fe6c..b17656aea0 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -16,10 +16,11 @@ #include #include +#include #include "BandwidthRecorder.h" #include "NetworkLogging.h" -#include "UUID.h" + NetworkPeer::NetworkPeer(QObject* parent) : QObject(parent), diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 2b332d820d..5fea670dd0 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -12,9 +12,10 @@ #include #include +#include + #include "Node.h" #include "SharedUtil.h" -#include "UUID.h" #include #include diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index c4053a871b..cf202fa83a 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "NodeList.h" + #include #include #include @@ -19,17 +21,18 @@ #include #include +#include #include "AccountManager.h" #include "AddressManager.h" #include "Assignment.h" #include "HifiSockAddr.h" #include "JSONBreakableMarshal.h" -#include "NodeList.h" + +#include "NetworkLogging.h" #include "udt/PacketHeaders.h" #include "SharedUtil.h" -#include "UUID.h" -#include "NetworkLogging.h" + NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned short dtlsListenPort) : LimitedNodeList(socketListenPort, dtlsListenPort), diff --git a/libraries/networking/src/WalletTransaction.cpp b/libraries/networking/src/WalletTransaction.cpp index 67fc73de07..0c823555fd 100644 --- a/libraries/networking/src/WalletTransaction.cpp +++ b/libraries/networking/src/WalletTransaction.cpp @@ -11,7 +11,8 @@ #include -#include "UUID.h" +#include + #include "WalletTransaction.h" From db92e3155cf3bbefd2c7e298933ca773244a32fc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Sep 2015 09:39:30 -0700 Subject: [PATCH 515/549] Update AssetServerError enum to be camelcase --- assignment-client/src/assets/AssetServer.cpp | 6 +++--- assignment-client/src/assets/SendAssetTask.cpp | 8 ++++---- assignment-client/src/assets/UploadAssetTask.cpp | 4 ++-- libraries/networking/src/AssetResourceRequest.cpp | 2 +- libraries/networking/src/AssetUpload.cpp | 6 +++--- libraries/networking/src/AssetUtils.h | 10 +++++----- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 62f1b877b5..9d60b74508 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -113,11 +113,11 @@ void AssetServer::handleAssetGetInfo(QSharedPointer packet, SharedNode if (fileInfo.exists() && fileInfo.isReadable()) { qDebug() << "Opening file: " << fileInfo.filePath(); - replyPacket->writePrimitive(AssetServerError::NO_ERROR); + replyPacket->writePrimitive(AssetServerError::NoError); replyPacket->writePrimitive(fileInfo.size()); } else { qDebug() << "Asset not found: " << QString(hexHash); - replyPacket->writePrimitive(AssetServerError::ASSET_NOT_FOUND); + replyPacket->writePrimitive(AssetServerError::AssetNotFound); } auto nodeList = DependencyManager::get(); @@ -157,7 +157,7 @@ void AssetServer::handleAssetUpload(QSharedPointer packetList, Sha // write the message ID and a permission denied error permissionErrorPacket->writePrimitive(messageID); - permissionErrorPacket->writePrimitive(AssetServerError::PERMISSION_DENIED); + permissionErrorPacket->writePrimitive(AssetServerError::PermissionDenied); // send off the packet auto nodeList = DependencyManager::get(); diff --git a/assignment-client/src/assets/SendAssetTask.cpp b/assignment-client/src/assets/SendAssetTask.cpp index 8131bafaf3..1495a7b52e 100644 --- a/assignment-client/src/assets/SendAssetTask.cpp +++ b/assignment-client/src/assets/SendAssetTask.cpp @@ -55,7 +55,7 @@ void SendAssetTask::run() { replyPacketList->writePrimitive(messageID); if (end <= start) { - writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); + writeError(replyPacketList.get(), AssetServerError::InvalidByteRange); } else { QString filePath = _resourcesDir.filePath(QString(hexHash) + "." + QString(extension)); @@ -63,12 +63,12 @@ void SendAssetTask::run() { if (file.open(QIODevice::ReadOnly)) { if (file.size() < end) { - writeError(replyPacketList.get(), AssetServerError::INVALID_BYTE_RANGE); + writeError(replyPacketList.get(), AssetServerError::InvalidByteRange); qCDebug(networking) << "Bad byte range: " << hexHash << " " << start << ":" << end; } else { auto size = end - start; file.seek(start); - replyPacketList->writePrimitive(AssetServerError::NO_ERROR); + replyPacketList->writePrimitive(AssetServerError::NoError); replyPacketList->writePrimitive(size); replyPacketList->write(file.read(size)); qCDebug(networking) << "Sending asset: " << hexHash; @@ -76,7 +76,7 @@ void SendAssetTask::run() { file.close(); } else { qCDebug(networking) << "Asset not found: " << filePath << "(" << hexHash << ")"; - writeError(replyPacketList.get(), AssetServerError::ASSET_NOT_FOUND); + writeError(replyPacketList.get(), AssetServerError::AssetNotFound); } } diff --git a/assignment-client/src/assets/UploadAssetTask.cpp b/assignment-client/src/assets/UploadAssetTask.cpp index d4991f9554..1acca295b4 100644 --- a/assignment-client/src/assets/UploadAssetTask.cpp +++ b/assignment-client/src/assets/UploadAssetTask.cpp @@ -52,7 +52,7 @@ void UploadAssetTask::run() { replyPacket->writePrimitive(messageID); if (fileSize > MAX_UPLOAD_SIZE) { - replyPacket->writePrimitive(AssetServerError::ASSET_TOO_LARGE); + replyPacket->writePrimitive(AssetServerError::AssetTooLarge); } else { QByteArray fileData = buffer.read(fileSize); @@ -71,7 +71,7 @@ void UploadAssetTask::run() { file.write(fileData); file.close(); } - replyPacket->writePrimitive(AssetServerError::NO_ERROR); + replyPacket->writePrimitive(AssetServerError::NoError); replyPacket->write(hash); } diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index d27151ac53..1ec52bede6 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -52,7 +52,7 @@ void AssetResourceRequest::doSend() { _data = req->getData(); _result = Success; break; - case ASSET_NOT_FOUND: + case AssetNotFound: _result = NotFound; break; default: diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index 33d1dcc33a..14e5354f0b 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -43,13 +43,13 @@ void AssetUpload::start() { assetClient->uploadAsset(data, _extension, [this](AssetServerError error, const QString& hash){ switch (error) { - case NO_ERROR: + case AssetServerError::NoError: _result = Success; break; - case ASSET_TOO_LARGE: + case AssetServerError::AssetTooLarge: _result = TooLarge; break; - case PERMISSION_DENIED: + case AssetServerError::PermissionDenied: _result = PermissionDenied; break; default: diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index ae6f51df64..de1083afa7 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -22,11 +22,11 @@ const size_t SHA256_HASH_HEX_LENGTH = 64; const uint64_t MAX_UPLOAD_SIZE = 1000 * 1000 * 1000; // 1GB enum AssetServerError : uint8_t { - NO_ERROR = 0, - ASSET_NOT_FOUND, - INVALID_BYTE_RANGE, - ASSET_TOO_LARGE, - PERMISSION_DENIED + NoError, + AssetNotFound, + InvalidByteRange, + AssetTooLarge, + PermissionDenied }; const QString ATP_SCHEME = "atp"; From 899b94eab3fcbe14d1c9164506229dc48222cb84 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Sep 2015 09:41:19 -0700 Subject: [PATCH 516/549] Add cstdint include to Asset* files --- libraries/networking/src/AssetClient.cpp | 2 ++ libraries/networking/src/AssetUpload.h | 2 ++ libraries/networking/src/AssetUtils.h | 2 ++ 3 files changed, 6 insertions(+) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 65806f3e96..dfa094ba78 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -14,6 +14,8 @@ #include #include +#include + #include "AssetRequest.h" #include "AssetUpload.h" #include "NodeList.h" diff --git a/libraries/networking/src/AssetUpload.h b/libraries/networking/src/AssetUpload.h index a678c0dc7e..0fef814a07 100644 --- a/libraries/networking/src/AssetUpload.h +++ b/libraries/networking/src/AssetUpload.h @@ -16,6 +16,8 @@ #include +#include + // You should be able to upload an asset from any thread, and handle the responses in a safe way // on your own thread. Everything should happen on AssetClient's thread, the caller should // receive events by connecting to signals on an object that lives on AssetClient's threads. diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index de1083afa7..7281678a10 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -14,6 +14,8 @@ #include +#include + using MessageID = uint32_t; using DataOffset = int64_t; From 6c9021c2886944039b11d2252fc41b49a4121230 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 1 Sep 2015 11:10:19 -0600 Subject: [PATCH 517/549] only send second packet of pair when required --- libraries/networking/src/udt/SendQueue.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index ff53bcfc54..28f71ec93f 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -443,10 +443,12 @@ bool SendQueue::maybeSendNewPacket() { _packets.pop_front(); std::unique_ptr secondPacket; + bool shouldSendPairTail = false; if (((uint32_t) nextNumber & 0xF) == 0) { // the first packet is the first in a probe pair - every 16 (rightmost 16 bits = 0) packets // pull off a second packet if we can before we unlock + shouldSendPairTail = true; if (_packets.size() > 0) { secondPacket.swap(_packets.front()); @@ -463,7 +465,7 @@ bool SendQueue::maybeSendNewPacket() { // do we have a second in a pair to send as well? if (secondPacket) { sendNewPacketAndAddToSentList(move(secondPacket), getNextSequenceNumber()); - } else { + } else if (shouldSendPairTail) { // we didn't get a second packet to send in the probe pair // send a control packet of type ProbePairTail so the receiver can still do // proper bandwidth estimation From 0733ba54c7153ad96486b31365dc923f469a27e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Brisset?= Date: Tue, 1 Sep 2015 18:23:44 +0100 Subject: [PATCH 518/549] Win build fixes --- libraries/networking/src/AssetClient.cpp | 2 +- libraries/networking/src/udt/BasePacket.h | 2 ++ libraries/networking/src/udt/CongestionControl.h | 1 + libraries/networking/src/udt/SendQueue.h | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index dfa094ba78..959c1562f2 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -155,7 +155,7 @@ void AssetClient::handleAssetGetInfoReply(QSharedPointer packet, Share AssetInfo info { assetHash.toHex(), 0 }; - if (error == NO_ERROR) { + if (error == AssetServerError::NoError) { packet->readPrimitive(&info.size); } diff --git a/libraries/networking/src/udt/BasePacket.h b/libraries/networking/src/udt/BasePacket.h index 33d4aab6ea..fd4b7ffa43 100644 --- a/libraries/networking/src/udt/BasePacket.h +++ b/libraries/networking/src/udt/BasePacket.h @@ -14,6 +14,8 @@ #ifndef hifi_BasePacket_h #define hifi_BasePacket_h +#include + #include #include "../HifiSockAddr.h" diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index 5208ff9d3b..f19ba4ab56 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -14,6 +14,7 @@ #include #include +#include #include "LossList.h" #include "SequenceNumber.h" diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index beb89a77d6..300b9c3e3d 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -12,6 +12,7 @@ #ifndef hifi_SendQueue_h #define hifi_SendQueue_h +#include #include #include #include From 56d6d95df9e9589b6e62b9c6bfca269228e01069 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 1 Sep 2015 12:09:58 -0600 Subject: [PATCH 519/549] only process cp tail if in the right spot --- libraries/networking/src/udt/Connection.cpp | 22 +++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 3625735c34..84928fa298 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -746,18 +746,20 @@ void Connection::processTimeoutNAK(std::unique_ptr controlPacket) } void Connection::processProbeTail(std::unique_ptr controlPacket) { - // this is the second packet in a probe set so we can estimate bandwidth - // the sender sent this to us in lieu of sending new data (because they didn't have any) - + if (((uint32_t) _lastReceivedSequenceNumber & 0xF) == 0) { + // this is the second packet in a probe set so we can estimate bandwidth + // the sender sent this to us in lieu of sending new data (because they didn't have any) + #ifdef UDT_CONNECTION_DEBUG - qCDebug(networking) << "Processing second packet of probe from control packet instead of data packet"; + qCDebug(networking) << "Processing second packet of probe from control packet instead of data packet"; #endif - - _receiveWindow.onProbePair2Arrival(); - - // mark that we processed a control packet for the second in the pair and we should not mark - // the next data packet received - _receivedControlProbeTail = true; + + _receiveWindow.onProbePair2Arrival(); + + // mark that we processed a control packet for the second in the pair and we should not mark + // the next data packet received + _receivedControlProbeTail = true; + } } void Connection::resetReceiveState() { From 019d234ffd3e99ceca4a1c5c728e14a80357a7a7 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Sep 2015 11:55:26 -0700 Subject: [PATCH 520/549] Replace std::bind for methods that use std::unique_ptr with a lambda --- ice-server/src/IceServer.cpp | 2 +- libraries/networking/src/LimitedNodeList.cpp | 6 +++--- tools/udt-test/src/UDTTest.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index a2603269d9..a44b6393de 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -36,7 +36,7 @@ IceServer::IceServer(int argc, char* argv[]) : // set processPacket as the verified packet callback for the udt::Socket using std::placeholders::_1; - _serverSocket.setPacketHandler(std::bind(&IceServer::processPacket, this, _1)); + _serverSocket.setPacketHandler([this](std::unique_ptr packet) { processPacket(std::move(packet)); }); // set packetVersionMatch as the verify packet operator for the udt::Socket _serverSocket.setPacketFilterOperator(std::bind(&IceServer::packetVersionMatch, this, _1)); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 2d1c98287c..74d922ce67 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -95,8 +95,8 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short // set &PacketReceiver::handleVerifiedPacket as the verified packet callback for the udt::Socket using std::placeholders::_1; - _nodeSocket.setPacketHandler(std::bind(&PacketReceiver::handleVerifiedPacket, _packetReceiver, _1)); - _nodeSocket.setPacketListHandler(std::bind(&PacketReceiver::handleVerifiedPacketList, _packetReceiver, _1)); + _nodeSocket.setPacketHandler([this](std::unique_ptr packet) { _packetReceiver->handleVerifiedPacket(std::move(packet)); }); + _nodeSocket.setPacketListHandler([this](std::unique_ptr packetList) { _packetReceiver->handleVerifiedPacketList(std::move(packetList)); }); // set our isPacketVerified method as the verify operator for the udt::Socket _nodeSocket.setPacketFilterOperator(std::bind(&LimitedNodeList::isPacketVerified, this, _1)); @@ -764,7 +764,7 @@ void LimitedNodeList::possiblyTimeoutSTUNAddressLookup() { void LimitedNodeList::addSTUNHandlerToUnfiltered() { // make ourselves the handler of STUN packets when they come in using std::placeholders::_1; - _nodeSocket.addUnfilteredHandler(_stunSockAddr, std::bind(&LimitedNodeList::processSTUNResponse, this, _1)); + _nodeSocket.addUnfilteredHandler(_stunSockAddr, [this](std::unique_ptr packet) { processSTUNResponse(std::move(packet)); }); } void LimitedNodeList::stopInitialSTUNUpdate(bool success) { diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index f11ff0d489..d8d20436b4 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -177,7 +177,7 @@ UDTTest::UDTTest(int& argc, char** argv) : // this is a receiver - in case there are ordered packets (messages) being sent to us make sure that we handle them // so that they can be verified using std::placeholders::_1; - _socket.setPacketListHandler(std::bind(&UDTTest::handlePacketList, this, _1)); + _socket.setPacketListHandler([this](std::unique_ptr packetList) { handlePacketList(std::move(packetList)); }); } // the sender reports stats every 100 milliseconds, unless passed a custom value From cb5a49e6e4561bea153ea2453e7feec7b02577c0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Sep 2015 11:59:45 -0700 Subject: [PATCH 521/549] Add missing headers needed to build on Windows --- libraries/networking/src/HifiSockAddr.h | 1 + libraries/networking/src/ResourceRequest.h | 2 ++ libraries/networking/src/udt/BasePacket.h | 4 ++++ libraries/networking/src/udt/CongestionControl.h | 1 + libraries/networking/src/udt/SendQueue.h | 3 +++ 5 files changed, 11 insertions(+) diff --git a/libraries/networking/src/HifiSockAddr.h b/libraries/networking/src/HifiSockAddr.h index c66579eca1..637b9e56ce 100644 --- a/libraries/networking/src/HifiSockAddr.h +++ b/libraries/networking/src/HifiSockAddr.h @@ -12,6 +12,7 @@ #ifndef hifi_HifiSockAddr_h #define hifi_HifiSockAddr_h +#include #include #ifdef WIN32 diff --git a/libraries/networking/src/ResourceRequest.h b/libraries/networking/src/ResourceRequest.h index 0aae013b62..b229951a49 100644 --- a/libraries/networking/src/ResourceRequest.h +++ b/libraries/networking/src/ResourceRequest.h @@ -15,6 +15,8 @@ #include #include +#include + class ResourceRequest : public QObject { Q_OBJECT public: diff --git a/libraries/networking/src/udt/BasePacket.h b/libraries/networking/src/udt/BasePacket.h index 33d4aab6ea..4e13d99013 100644 --- a/libraries/networking/src/udt/BasePacket.h +++ b/libraries/networking/src/udt/BasePacket.h @@ -14,6 +14,8 @@ #ifndef hifi_BasePacket_h #define hifi_BasePacket_h +#include + #include #include "../HifiSockAddr.h" @@ -29,6 +31,8 @@ public: static std::unique_ptr create(qint64 size = -1); static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); + + // Current level's header size static int localHeaderSize(); diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index 5208ff9d3b..63baee0e28 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -13,6 +13,7 @@ #define hifi_CongestionControl_h #include +#include #include #include "LossList.h" diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index beb89a77d6..564e74a3fb 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -12,9 +12,12 @@ #ifndef hifi_SendQueue_h #define hifi_SendQueue_h +#include #include #include +#include #include +#include #include #include From d166e6d8c39f1e859afc561293b8ea0389cc2239 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Sep 2015 12:00:43 -0700 Subject: [PATCH 522/549] Move UUID.cpp/h to libraries/shared --- libraries/networking/src/UUID.cpp | 17 ----------------- libraries/networking/src/UUID.h | 21 --------------------- 2 files changed, 38 deletions(-) delete mode 100644 libraries/networking/src/UUID.cpp delete mode 100644 libraries/networking/src/UUID.h diff --git a/libraries/networking/src/UUID.cpp b/libraries/networking/src/UUID.cpp deleted file mode 100644 index eafd7dd181..0000000000 --- a/libraries/networking/src/UUID.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// -// UUID.cpp -// libraries/shared/src -// -// Created by Stephen Birarda on 10/7/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 "UUID.h" - -QString uuidStringWithoutCurlyBraces(const QUuid& uuid) { - QString uuidStringNoBraces = uuid.toString().mid(1, uuid.toString().length() - 2); - return uuidStringNoBraces; -} diff --git a/libraries/networking/src/UUID.h b/libraries/networking/src/UUID.h deleted file mode 100644 index 7e7048486f..0000000000 --- a/libraries/networking/src/UUID.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// UUID.h -// libraries/shared/src -// -// Created by Stephen Birarda on 10/7/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 -// - -#ifndef hifi_UUID_h -#define hifi_UUID_h - -#include - -const int NUM_BYTES_RFC4122_UUID = 16; - -QString uuidStringWithoutCurlyBraces(const QUuid& uuid); - -#endif // hifi_UUID_h From fb8e822fa869780169658c311aba3f6cdeba63fd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Sep 2015 12:14:58 -0700 Subject: [PATCH 523/549] Fix lines longer than 120 columns --- libraries/networking/src/LimitedNodeList.cpp | 12 ++++++++++-- tools/udt-test/src/UDTTest.cpp | 3 ++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 74d922ce67..4e197a3ee4 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -95,8 +95,16 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short // set &PacketReceiver::handleVerifiedPacket as the verified packet callback for the udt::Socket using std::placeholders::_1; - _nodeSocket.setPacketHandler([this](std::unique_ptr packet) { _packetReceiver->handleVerifiedPacket(std::move(packet)); }); - _nodeSocket.setPacketListHandler([this](std::unique_ptr packetList) { _packetReceiver->handleVerifiedPacketList(std::move(packetList)); }); + _nodeSocket.setPacketHandler( + [this](std::unique_ptr packet) { + _packetReceiver->handleVerifiedPacket(std::move(packet)); + } + ); + _nodeSocket.setPacketListHandler( + [this](std::unique_ptr packetList) { + _packetReceiver->handleVerifiedPacketList(std::move(packetList)); + } + ); // set our isPacketVerified method as the verify operator for the udt::Socket _nodeSocket.setPacketFilterOperator(std::bind(&LimitedNodeList::isPacketVerified, this, _1)); diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index d8d20436b4..4b12c97f7c 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -177,7 +177,8 @@ UDTTest::UDTTest(int& argc, char** argv) : // this is a receiver - in case there are ordered packets (messages) being sent to us make sure that we handle them // so that they can be verified using std::placeholders::_1; - _socket.setPacketListHandler([this](std::unique_ptr packetList) { handlePacketList(std::move(packetList)); }); + _socket.setPacketListHandler( + [this](std::unique_ptr packetList) { handlePacketList(std::move(packetList)); }); } // the sender reports stats every 100 milliseconds, unless passed a custom value From b73d30721032d4cc166ec01c0b489d2e18d77e63 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Sep 2015 12:23:24 -0700 Subject: [PATCH 524/549] Move std::placeholders::_1 to where they are used --- ice-server/src/IceServer.cpp | 2 +- libraries/networking/src/LimitedNodeList.cpp | 3 +-- tools/udt-test/src/UDTTest.cpp | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index a44b6393de..a6a28caa23 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -35,10 +35,10 @@ IceServer::IceServer(int argc, char* argv[]) : _serverSocket.bind(QHostAddress::AnyIPv4, ICE_SERVER_DEFAULT_PORT); // set processPacket as the verified packet callback for the udt::Socket - using std::placeholders::_1; _serverSocket.setPacketHandler([this](std::unique_ptr packet) { processPacket(std::move(packet)); }); // set packetVersionMatch as the verify packet operator for the udt::Socket + using std::placeholders::_1; _serverSocket.setPacketFilterOperator(std::bind(&IceServer::packetVersionMatch, this, _1)); // setup our timer to clear inactive peers diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 4e197a3ee4..e0b35b5773 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -94,7 +94,6 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short updateLocalSockAddr(); // set &PacketReceiver::handleVerifiedPacket as the verified packet callback for the udt::Socket - using std::placeholders::_1; _nodeSocket.setPacketHandler( [this](std::unique_ptr packet) { _packetReceiver->handleVerifiedPacket(std::move(packet)); @@ -107,6 +106,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short ); // set our isPacketVerified method as the verify operator for the udt::Socket + using std::placeholders::_1; _nodeSocket.setPacketFilterOperator(std::bind(&LimitedNodeList::isPacketVerified, this, _1)); _packetStatTimer.start(); @@ -771,7 +771,6 @@ void LimitedNodeList::possiblyTimeoutSTUNAddressLookup() { void LimitedNodeList::addSTUNHandlerToUnfiltered() { // make ourselves the handler of STUN packets when they come in - using std::placeholders::_1; _nodeSocket.addUnfilteredHandler(_stunSockAddr, [this](std::unique_ptr packet) { processSTUNResponse(std::move(packet)); }); } diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 4b12c97f7c..9a828ebafb 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -176,7 +176,6 @@ UDTTest::UDTTest(int& argc, char** argv) : } else { // this is a receiver - in case there are ordered packets (messages) being sent to us make sure that we handle them // so that they can be verified - using std::placeholders::_1; _socket.setPacketListHandler( [this](std::unique_ptr packetList) { handlePacketList(std::move(packetList)); }); } From 70c937d37f59bdd11423e7a7b08b7bfff504b7bb Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Sep 2015 12:31:30 -0700 Subject: [PATCH 525/549] Replace NO_ERROR with NoError --- libraries/networking/src/AssetRequest.cpp | 4 ++-- libraries/networking/src/AssetResourceRequest.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 69bf86302c..f989f10ae8 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -45,7 +45,7 @@ void AssetRequest::start() { _info = info; _error = error; - if (_error != NO_ERROR) { + if (_error != NoError) { qCDebug(networking) << "Got error retrieving asset info for" << _hash; _state = FINISHED; emit finished(this); @@ -65,7 +65,7 @@ void AssetRequest::start() { Q_ASSERT(data.size() == (end - start)); _error = error; - if (_error == NO_ERROR) { + if (_error == NoError) { memcpy(_data.data() + start, data.constData(), data.size()); _totalReceived += data.size(); emit progress(_totalReceived, _info.size); diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 1ec52bede6..b9adba99b7 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -48,7 +48,7 @@ void AssetResourceRequest::doSend() { Q_ASSERT(req->getState() == AssetRequest::FINISHED); switch (req->getError()) { - case NO_ERROR: + case NoError: _data = req->getData(); _result = Success; break; From 639dbea25b98a2264fde74d1425c80a118d0d98a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Sep 2015 13:22:44 -0700 Subject: [PATCH 526/549] Move lastHeardMicroStamp to be updated when filtering packets --- libraries/networking/src/LimitedNodeList.cpp | 4 ++++ libraries/networking/src/PacketReceiver.cpp | 12 ------------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index d874921ada..e2d809a863 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -226,6 +226,10 @@ bool LimitedNodeList::packetSourceAndHashMatch(const udt::Packet& packet) { return false; } } + + // No matter if this packet is handled or not, we update the timestamp for the last time we heard + // from this sending node + matchingNode->setLastHeardMicrostamp(usecTimestampNow()); return true; diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 03827d19af..fb1e2d896f 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -258,12 +258,6 @@ void PacketReceiver::handleVerifiedPacketList(std::unique_ptr p if (!nlPacketList->getSourceID().isNull()) { matchingNode = nodeList->nodeWithUUID(nlPacketList->getSourceID()); - - if (matchingNode) { - // No matter if this packet is handled or not, we update the timestamp for the last time we heard - // from this sending node - matchingNode->setLastHeardMicrostamp(usecTimestampNow()); - } } QMutexLocker packetListenerLocker(&_packetListenerLock); @@ -384,12 +378,6 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { if (!nlPacket->getSourceID().isNull()) { matchingNode = nodeList->nodeWithUUID(nlPacket->getSourceID()); - - if (matchingNode) { - // No matter if this packet is handled or not, we update the timestamp for the last time we heard - // from this sending node - matchingNode->setLastHeardMicrostamp(usecTimestampNow()); - } } QMutexLocker packetListenerLocker(&_packetListenerLock); From f24a267d83779d7906650692fa66acf1b20d7a29 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 1 Sep 2015 15:16:02 -0600 Subject: [PATCH 527/549] fix hasher for HifiSockAddr on ubuntu --- libraries/networking/src/HifiSockAddr.h | 39 +++++++++++++------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/libraries/networking/src/HifiSockAddr.h b/libraries/networking/src/HifiSockAddr.h index 637b9e56ce..d678f93ac0 100644 --- a/libraries/networking/src/HifiSockAddr.h +++ b/libraries/networking/src/HifiSockAddr.h @@ -69,25 +69,28 @@ private: uint qHash(const HifiSockAddr& key, uint seed); -template <> -struct std::hash { - // NOTE: this hashing specifically ignores IPv6 addresses - if we begin to support those we will need - // to conditionally hash the bytes that represent an IPv6 address - std::size_t operator()(const HifiSockAddr& sockAddr) const { - // use XOR of implemented std::hash templates for new hash - // depending on the type of address we're looking at - - if (sockAddr.getAddress().protocol() == QAbstractSocket::IPv4Protocol) { - return std::hash()((uint32_t) sockAddr.getAddress().toIPv4Address()) - ^ std::hash()((uint16_t) sockAddr.getPort()); - } else { - // NOTE: if we start to use IPv6 addresses, it's possible their hashing - // can be faster by XORing the hash for each 64 bits in the address - return std::hash()(sockAddr.getAddress().toString().toStdString()) - ^ std::hash()((uint16_t) sockAddr.getPort()); +namespace std { + template <> + struct hash { + // NOTE: this hashing specifically ignores IPv6 addresses - if we begin to support those we will need + // to conditionally hash the bytes that represent an IPv6 address + size_t operator()(const HifiSockAddr& sockAddr) const { + // use XOR of implemented std::hash templates for new hash + // depending on the type of address we're looking at + + if (sockAddr.getAddress().protocol() == QAbstractSocket::IPv4Protocol) { + return hash()((uint32_t) sockAddr.getAddress().toIPv4Address()) + ^ hash()((uint16_t) sockAddr.getPort()); + } else { + // NOTE: if we start to use IPv6 addresses, it's possible their hashing + // can be faster by XORing the hash for each 64 bits in the address + return hash()(sockAddr.getAddress().toString().toStdString()) + ^ hash()((uint16_t) sockAddr.getPort()); + } } - } -}; + }; +} + QHostAddress getLocalAddress(); From 29285028c37c99df51132eee351e5a0a05975510 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 1 Sep 2015 15:18:59 -0600 Subject: [PATCH 528/549] fix for sixense not present on OS X --- libraries/input-plugins/src/input-plugins/SixenseManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp index c6cc8a404b..052a05b9a9 100644 --- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp +++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp @@ -50,8 +50,10 @@ const float CONTROLLER_THRESHOLD = 0.35f; #ifdef __APPLE__ typedef int (*SixenseBaseFunction)(); typedef int (*SixenseTakeIntFunction)(int); +#ifdef HAVE_SIXENSE typedef int (*SixenseTakeIntAndSixenseControllerData)(int, sixenseControllerData*); #endif +#endif const QString SixenseManager::NAME = "Sixense"; From d29449b43a45ca816ba235b0c7dbcaedd7d31e67 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 1 Sep 2015 15:19:50 -0600 Subject: [PATCH 529/549] no consts if HAVE_SIXENSE not set --- libraries/input-plugins/src/input-plugins/SixenseManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp index 052a05b9a9..579fddcd63 100644 --- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp +++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp @@ -34,6 +34,8 @@ Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") const unsigned int LEFT_MASK = 0; const unsigned int RIGHT_MASK = 1U << 1; +#ifdef HAVE_SIXENSE + const int CALIBRATION_STATE_IDLE = 0; const int CALIBRATION_STATE_X = 1; const int CALIBRATION_STATE_Y = 2; @@ -47,6 +49,8 @@ const float NECK_Z = 0.3f; // meters const float CONTROLLER_THRESHOLD = 0.35f; +#endif + #ifdef __APPLE__ typedef int (*SixenseBaseFunction)(); typedef int (*SixenseTakeIntFunction)(int); From 231ea3b240f2c212349ccd4f5457d9b1a2314482 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 1 Sep 2015 15:35:50 -0600 Subject: [PATCH 530/549] fix namespacing for sequence number hasher --- libraries/networking/src/udt/SequenceNumber.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/udt/SequenceNumber.h b/libraries/networking/src/udt/SequenceNumber.h index fae5a7bb01..23284c4d9a 100644 --- a/libraries/networking/src/udt/SequenceNumber.h +++ b/libraries/networking/src/udt/SequenceNumber.h @@ -140,10 +140,12 @@ int seqoff(const SequenceNumber& seq1, const SequenceNumber& seq2); } -template<> struct std::hash { - size_t operator()(const udt::SequenceNumber& SequenceNumber) const { - return std::hash()(SequenceNumber._value); - } -}; +namespace std { + template<> struct hash { + size_t operator()(const udt::SequenceNumber& SequenceNumber) const { + return hash()(SequenceNumber._value); + } + }; +} #endif // hifi_SequenceNumber_h From 3875a7d8811575dabab0270bd6843537a1aff143 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 4 Sep 2015 12:39:35 -0600 Subject: [PATCH 531/549] fix bad copy on merge to FileResourceRequest --- libraries/networking/src/FileResourceRequest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/FileResourceRequest.cpp b/libraries/networking/src/FileResourceRequest.cpp index 7fc7359330..6dd5e925a3 100644 --- a/libraries/networking/src/FileResourceRequest.cpp +++ b/libraries/networking/src/FileResourceRequest.cpp @@ -19,7 +19,7 @@ void FileResourceRequest::doSend() { // sometimes on windows, we see the toLocalFile() return null, // in this case we will attempt to simply use the url as a string if (fileName.isEmpty()) { - fileName = url.toString(); + fileName = _url.toString(); } QFile file(filename); From 875d10575f50575bf0f5eccd64b130afcb78e591 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 4 Sep 2015 12:43:43 -0600 Subject: [PATCH 532/549] add filename rename somehow missed in previous commit --- libraries/networking/src/FileResourceRequest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/FileResourceRequest.cpp b/libraries/networking/src/FileResourceRequest.cpp index 6dd5e925a3..58a2074103 100644 --- a/libraries/networking/src/FileResourceRequest.cpp +++ b/libraries/networking/src/FileResourceRequest.cpp @@ -18,8 +18,8 @@ void FileResourceRequest::doSend() { // sometimes on windows, we see the toLocalFile() return null, // in this case we will attempt to simply use the url as a string - if (fileName.isEmpty()) { - fileName = _url.toString(); + if (filename.isEmpty()) { + filename = _url.toString(); } QFile file(filename); From c49088846f45c9fb5bf36c0aaf6357bab7e47a58 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Sep 2015 08:26:14 -0700 Subject: [PATCH 533/549] add an alias for AvatarDataSequenceNumber --- assignment-client/src/avatars/AvatarMixer.cpp | 4 ++-- libraries/avatars/src/AvatarData.cpp | 2 +- libraries/avatars/src/AvatarData.h | 8 +++++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 6a0a955a6f..195bd53a97 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -259,8 +259,8 @@ void AvatarMixer::broadcastAvatarData() { return; } - uint16_t lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(otherNode->getUUID()); - uint16_t lastSeqFromSender = otherNodeData->getLastReceivedSequenceNumber(); + AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(otherNode->getUUID()); + AvatarDataSequenceNumber lastSeqFromSender = otherNodeData->getLastReceivedSequenceNumber(); if (lastSeqToReceiver > lastSeqFromSender) { // Did we somehow get out of order packets from the sender? diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 1091b299b9..9430c73091 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1098,7 +1098,7 @@ void AvatarData::sendAvatarDataPacket() { QByteArray avatarByteArray = toByteArray(true, sendFullUpdate); doneEncoding(true); - static uint16_t sequenceNumber = 0; + static AvatarDataSequenceNumber sequenceNumber = 0; auto avatarPacket = NLPacket::create(PacketType::AvatarData, avatarByteArray.size() + sizeof(sequenceNumber)); avatarPacket->writePrimitive(sequenceNumber++); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index af97180cbd..19f3081255 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -59,9 +59,11 @@ typedef unsigned long long quint64; #include "Recorder.h" #include "Referential.h" -typedef std::shared_ptr AvatarSharedPointer; -typedef std::weak_ptr AvatarWeakPointer; -typedef QHash AvatarHash; +using AvatarSharedPointer = std::shared_ptr; +using AvatarWeakPointer = std::weak_ptr; +using AvatarHash = QHash; + +using AvatarDataSequenceNumber = uint16_t; // avatar motion behaviors const quint32 AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED = 1U << 0; From b2778bff09542209094184a4e9fecdea5c7f97aa Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Sep 2015 08:30:16 -0700 Subject: [PATCH 534/549] fix a bad replacement for AC server hostname --- assignment-client/src/AssignmentClientApp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/AssignmentClientApp.h b/assignment-client/src/AssignmentClientApp.h index ab7e8ed304..c4705e30eb 100644 --- a/assignment-client/src/AssignmentClientApp.h +++ b/assignment-client/src/AssignmentClientApp.h @@ -19,7 +19,7 @@ const QString ASSIGNMENT_TYPE_OVERRIDE_OPTION = "t"; const QString ASSIGNMENT_POOL_OPTION = "pool"; const QString ASSIGNMENT_CLIENT_LISTEN_PORT_OPTION = "p"; const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet"; -const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "i"; +const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a"; const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "server-port"; const QString ASSIGNMENT_NUM_FORKS_OPTION = "n"; const QString ASSIGNMENT_MIN_FORKS_OPTION = "min"; From 987814366149d79e5e98c1315cb1d1d193218c02 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Sep 2015 08:58:35 -0700 Subject: [PATCH 535/549] repairs to ShaderCache for Resource changes --- .../src/RenderableProceduralItem.cpp | 2 +- libraries/networking/src/ResourceCache.h | 3 ++- libraries/render-utils/src/ShaderCache.cpp | 12 ++++++------ libraries/render-utils/src/ShaderCache.h | 4 ++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableProceduralItem.cpp b/libraries/entities-renderer/src/RenderableProceduralItem.cpp index bec2b57a71..d70f1c1424 100644 --- a/libraries/entities-renderer/src/RenderableProceduralItem.cpp +++ b/libraries/entities-renderer/src/RenderableProceduralItem.cpp @@ -93,7 +93,7 @@ bool RenderableProceduralItem::ProceduralInfo::ready() { void RenderableProceduralItem::ProceduralInfo::prepare(gpu::Batch& batch) { if (_shaderUrl.isLocalFile()) { - auto lastModified = QFileInfo(_shaderPath).lastModified().toMSecsSinceEpoch(); + auto lastModified = (quint64) QFileInfo(_shaderPath).lastModified().toMSecsSinceEpoch(); if (lastModified > _shaderModified) { QFile file(_shaderPath); file.open(QIODevice::ReadOnly); diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 08d38db9a4..a11ee30174 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -173,6 +173,7 @@ public: Q_INVOKABLE void allReferencesCleared(); const QUrl& getURL() const { return _url; } + const QByteArray& getData() const { return _data; } signals: /// Fired when the resource has been loaded. @@ -190,7 +191,7 @@ protected slots: protected: virtual void init(); - /// Called when the download has finished. The recipient should delete the reply when done with it. + /// Called when the download has finished virtual void downloadFinished(const QByteArray& data); /// Should be called by subclasses when all the loading that will be done has been done. diff --git a/libraries/render-utils/src/ShaderCache.cpp b/libraries/render-utils/src/ShaderCache.cpp index e4ef8250b9..d0c5d6631f 100644 --- a/libraries/render-utils/src/ShaderCache.cpp +++ b/libraries/render-utils/src/ShaderCache.cpp @@ -8,13 +8,13 @@ #include "ShaderCache.h" NetworkShader::NetworkShader(const QUrl& url, bool delayLoad) - : Resource(url, delayLoad) {}; + : Resource(url, delayLoad) +{ + +} -void NetworkShader::downloadFinished(QNetworkReply* reply) { - if (reply) { - _source = reply->readAll(); - reply->deleteLater(); - } +void NetworkShader::downloadFinished(const QByteArray& data) { + _source = QString::fromUtf8(data); } ShaderCache& ShaderCache::instance() { diff --git a/libraries/render-utils/src/ShaderCache.h b/libraries/render-utils/src/ShaderCache.h index 7698252924..ffe8d437ce 100644 --- a/libraries/render-utils/src/ShaderCache.h +++ b/libraries/render-utils/src/ShaderCache.h @@ -14,9 +14,9 @@ class NetworkShader : public Resource { public: NetworkShader(const QUrl& url, bool delayLoad); - virtual void downloadFinished(QNetworkReply* reply) override; + virtual void downloadFinished(const QByteArray& data) override; - QByteArray _source; + QString _source; }; using NetworkShaderPointer = QSharedPointer; From 8fffb77f13e1e36ab6854e1a33e71697d558d4b1 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Sep 2015 09:53:02 -0700 Subject: [PATCH 536/549] Add comment about byte range for ATP get asset request --- assignment-client/src/assets/SendAssetTask.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/assignment-client/src/assets/SendAssetTask.cpp b/assignment-client/src/assets/SendAssetTask.cpp index 1495a7b52e..f12603d6c7 100644 --- a/assignment-client/src/assets/SendAssetTask.cpp +++ b/assignment-client/src/assets/SendAssetTask.cpp @@ -40,6 +40,10 @@ void SendAssetTask::run() { QByteArray assetHash = _packet->read(SHA256_HASH_LENGTH); _packet->readPrimitive(&extensionLength); QByteArray extension = _packet->read(extensionLength); + + // `start` and `end` indicate the range of data to retrieve for the asset identified by `assetHash`. + // `start` is inclusive, `end` is exclusive. Requesting `start` = 1, `end` = 10 will retrieve 9 bytes of data, + // starting at index 1. _packet->readPrimitive(&start); _packet->readPrimitive(&end); From c728cd4c4c3fa026aa5af087ed5f105211816125 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 8 Sep 2015 11:57:35 -0700 Subject: [PATCH 537/549] Fix for RenderableParticleffectEntityItem assert. When a particle system had no living particles, PendingChanges::updateItem would assert, due to the access to _vertices[0]. In release this might be harmless as this memory is never accessed, but different implementations of std::vector might do different things here. So, let's be safe and early return when the number of particles is 0. --- .../src/RenderableParticleEffectEntityItem.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index f683083ed1..9c839bfaad 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -219,6 +219,14 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { // update vertex buffer auto vertexBuffer = payload.getVertexBuffer(); size_t numBytes = sizeof(Vertex) * _vertices.size(); + + if (numBytes == 0) { + vertexBuffer->resize(0); + auto indexBuffer = payload.getIndexBuffer(); + indexBuffer->resize(0); + return; + } + vertexBuffer->resize(numBytes); gpu::Byte* data = vertexBuffer->editData(); memcpy(data, &(_vertices[0]), numBytes); @@ -284,7 +292,7 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { payload.setPipeline(_untexturedPipeline); } }); - + _scene->enqueuePendingChanges(pendingChanges); } From 7133fc94f5dfc9df25d4def931407bbc2831bb97 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 8 Sep 2015 12:54:02 -0700 Subject: [PATCH 538/549] hydraGrab now grabs entities based on how they want to be grabbed (through setting of userData field with a key called spatialKey --- .../hydraGrab.js => handControllerGrab.js} | 41 +++++++++++-------- examples/entityScripts/sprayPaintCan.js | 36 ++++++++-------- 2 files changed, 43 insertions(+), 34 deletions(-) rename examples/controllers/{hydra/hydraGrab.js => handControllerGrab.js} (89%) diff --git a/examples/controllers/hydra/hydraGrab.js b/examples/controllers/handControllerGrab.js similarity index 89% rename from examples/controllers/hydra/hydraGrab.js rename to examples/controllers/handControllerGrab.js index bd060ecc14..87b21602c5 100644 --- a/examples/controllers/hydra/hydraGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -11,7 +11,8 @@ // -Script.include("../../libraries/utils.js"); +Script.include("../libraries/utils.js"); + var RIGHT_HAND_CLICK = Controller.findAction("RIGHT_HAND_CLICK"); var rightTriggerAction = RIGHT_HAND_CLICK; @@ -41,7 +42,7 @@ var INTERSECT_COLOR = { blue: 10 }; -var GRAB_RADIUS = 0.5; +var GRAB_RADIUS = 1.0; var GRAB_COLOR = { red: 250, @@ -135,7 +136,9 @@ controller.prototype.checkForIntersections = function(origin, direction) { var intersection = Entities.findRayIntersection(pickRay, true); if (intersection.intersects && intersection.properties.collisionsWillMove === 1) { - this.distanceToEntity = Vec3.distance(origin, intersection.properties.position); + var handPosition = Controller.getSpatialControlPosition(this.palm); + this.distanceToEntity = Vec3.distance(handPosition, intersection.properties.position); + print("distance to entity " + JSON.stringify(this.distanceToEntity)); Entities.editEntity(this.pointer, { linePoints: [ ZERO_VEC, @@ -188,6 +191,7 @@ controller.prototype.hidePointer = function() { controller.prototype.letGo = function() { if (this.grabbedEntity && this.actionID) { + print("DELETE ACTION") this.deactivateEntity(this.grabbedEntity); Entities.deleteAction(this.grabbedEntity, this.actionID); } @@ -236,19 +240,24 @@ controller.prototype.update = function() { controller.prototype.grabEntity = function() { var handRotation = this.getHandRotation(); var handPosition = this.getHandPosition(); - - var objectRotation = Entities.getEntityProperties(this.grabbedEntity).rotation; - var offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); - - var objectPosition = Entities.getEntityProperties(this.grabbedEntity).position; - var offset = Vec3.subtract(objectPosition, handPosition); - var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset); this.closeGrabbing = true; + //check if our entity has instructions on how to be grabbed, otherwise, just use default relative position and rotation + var userData = getEntityUserData(this.grabbedEntity); + var relativePosition = ZERO_VEC; + var relativeRotation = Quat.fromPitchYawRollDegrees(0, 0, 0); + if(userData.spatialKey) { + if(userData.spatialKey.relativePosition) { + relativePosition = userData.spatialKey.relativePosition; + } + if(userData.spatialKey.relativeRotation) { + relativeRotation = userData.spatialKey.relativeRotation; + } + } this.actionID = Entities.addAction("hold", this.grabbedEntity, { - relativePosition: offsetPosition, - relativeRotation: offsetRotation, hand: this.hand, - timeScale: 0.05 + timeScale: 0.05, + relativePosition: relativePosition, + relativeRotation: relativeRotation }); } @@ -305,10 +314,10 @@ controller.prototype.onActionEvent = function(action, state) { self.checkForEntityArrival = true; }, 500); var handPosition = Controller.getSpatialControlPosition(this.palm); - var direction = Controller.getSpatialControlNormal(this.tip); + var direction = Vec3.normalize(Controller.getSpatialControlNormal(this.tip)); //move final destination along line a bit, so it doesnt hit avatar hand Entities.updateAction(this.grabbedEntity, this.actionID, { - targetPosition: Vec3.sum(handPosition, Vec3.multiply(2, direction)) + targetPosition: Vec3.sum(handPosition, Vec3.multiply(3, direction)) }); } } @@ -339,8 +348,6 @@ function cleanup() { leftController.cleanup(); } - - Script.scriptEnding.connect(cleanup); Script.update.connect(update) Controller.actionEvent.connect(onActionEvent); \ No newline at end of file diff --git a/examples/entityScripts/sprayPaintCan.js b/examples/entityScripts/sprayPaintCan.js index 8ec107f779..914e855349 100644 --- a/examples/entityScripts/sprayPaintCan.js +++ b/examples/entityScripts/sprayPaintCan.js @@ -1,16 +1,6 @@ -// -// sprayPaintCan.js -// examples/entityScripts -// -// Created by Eric Levin on 9/3/15 -// Copyright 2015 High Fidelity, Inc. -// -// This is an example of an entity script for painting with a spraypaint can -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - (function() { + Script.include("../libraries/utils.js"); + SPATIAL_USER_DATA_KEY = "spatialKey"; this.userData = {}; var TIP_OFFSET_Z = 0.14; @@ -36,6 +26,8 @@ }); this.getUserData = function() { + + if (this.properties.userData) { this.userData = JSON.parse(this.properties.userData); } @@ -50,8 +42,7 @@ this.update = function(deltaTime) { self.properties = Entities.getEntityProperties(self.entityId); self.getUserData(); - //Only run the logic if this is the client whose avatar is grabbing - if (self.userData.grabKey && self.userData.grabKey.activated === true && self.userData.grabKey.avatarId === MyAvatar.sessionUUID) { + if (self.userData.grabKey && self.userData.grabKey.activated === true) { if (self.activated !== true) { Entities.editEntity(self.paintStream, { animationSettings: startSetting @@ -70,6 +61,8 @@ this.sprayStream = function() { var forwardVec = Quat.getFront(self.properties.rotation); + forwardVec = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, 90, 0), forwardVec); + var upVec = Quat.getUp(self.properties.rotation); var position = Vec3.sum(self.properties.position, Vec3.multiply(forwardVec, TIP_OFFSET_Z)); position = Vec3.sum(position, Vec3.multiply(upVec, TIP_OFFSET_Y)) @@ -92,11 +85,12 @@ var normal = Vec3.multiply(-1, Quat.getFront(intersection.properties.rotation)); this.paint(intersection.intersection, normal); } + + } this.paint = function(position, normal) { if (!this.painting) { - print("position " + JSON.stringify(position)) this.newStroke(position); this.painting = true; @@ -125,6 +119,7 @@ strokeWidths: this.strokeWidths }); + } this.newStroke = function(position) { @@ -157,10 +152,16 @@ this.entityId = entityId; this.properties = Entities.getEntityProperties(self.entityId); this.getUserData(); - print("USER DATA " + JSON.stringify(this.userData)) - if (this.userData.activated) { + if (this.userData.grabKey && this.userData.grabKey.activated) { this.activated = true; } + if(!this.userData.spatialKey) { + var data = { + relativePosition: {x: 0, y: 0, z: 0}, + relativeRotation: Quat.fromPitchYawRollDegrees(0, 0,0) + } + setEntityCustomData(SPATIAL_USER_DATA_KEY, this.entityId, data); + } this.initialize(); } @@ -173,6 +174,7 @@ running: false }); + this.paintStream = Entities.addEntity({ type: "ParticleEffect", animationSettings: animationSettings, From e0a8469354cfa290ed0b68a04ece3dffbea5df1f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Sep 2015 13:42:52 -0700 Subject: [PATCH 539/549] fix for sequence point warning --- libraries/networking/src/udt/SequenceNumber.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/SequenceNumber.h b/libraries/networking/src/udt/SequenceNumber.h index 23284c4d9a..a75f3478b8 100644 --- a/libraries/networking/src/udt/SequenceNumber.h +++ b/libraries/networking/src/udt/SequenceNumber.h @@ -43,7 +43,7 @@ public: return *this; } inline SequenceNumber& operator--() { - _value = (_value == 0) ? MAX : --_value; + _value = (_value == 0) ? MAX : _value - 1; return *this; } inline SequenceNumber operator++(int) { From 5f1affaff94454b4a79bf3d69f0ff070b88c0468 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 8 Sep 2015 00:51:54 -0700 Subject: [PATCH 540/549] Procedural skybox work --- cmake/macros/AutoScribeShader.cmake | 2 +- cmake/macros/SetupHifiLibrary.cmake | 6 +- examples/shaders/exampleSkyboxUserDataV2.json | 6 + .../shaders/shadertoys/relentlessSkybox.fs | 144 +++++++++ interface/CMakeLists.txt | 2 +- libraries/entities-renderer/CMakeLists.txt | 2 +- .../src/EntityTreeRenderer.cpp | 18 +- .../src/RenderableBoxEntityItem.cpp | 13 +- .../src/RenderableBoxEntityItem.h | 9 +- .../src/RenderableProceduralItem.h | 60 ---- .../src/RenderableSphereEntityItem.cpp | 13 +- .../src/RenderableSphereEntityItem.h | 10 +- libraries/gpu-networking/CMakeLists.txt | 11 + .../gpu-networking/GpuNetworkingLogging.cpp | 11 + .../src/gpu-networking/GpuNetworkingLogging.h | 11 + .../src/gpu-networking}/ShaderCache.cpp | 0 .../src/gpu-networking}/ShaderCache.h | 0 .../src/gpu-networking}/TextureCache.cpp | 21 +- .../src/gpu-networking/TextureCache.h | 167 +++++++++++ libraries/gpu/CMakeLists.txt | 4 + libraries/model/CMakeLists.txt | 2 +- libraries/model/src/model/Skybox.cpp | 71 +++-- libraries/model/src/model/Skybox.h | 9 +- libraries/model/src/model/Skybox.slf | 18 +- libraries/procedural/CMakeLists.txt | 10 + .../src/procedural/Procedural.cpp} | 130 ++++----- .../procedural/src/procedural/Procedural.h | 60 ++++ .../src/procedural/ProceduralShaders.h | 276 ++++++++++++++++++ libraries/render-utils/CMakeLists.txt | 2 +- libraries/render-utils/src/TextureCache.h | 173 +---------- libraries/render-utils/src/simple.slf | 37 ++- libraries/script-engine/CMakeLists.txt | 2 +- tests/gpu-test/CMakeLists.txt | 2 +- 33 files changed, 937 insertions(+), 365 deletions(-) create mode 100644 examples/shaders/exampleSkyboxUserDataV2.json create mode 100644 examples/shaders/shadertoys/relentlessSkybox.fs delete mode 100644 libraries/entities-renderer/src/RenderableProceduralItem.h create mode 100644 libraries/gpu-networking/CMakeLists.txt create mode 100644 libraries/gpu-networking/src/gpu-networking/GpuNetworkingLogging.cpp create mode 100644 libraries/gpu-networking/src/gpu-networking/GpuNetworkingLogging.h rename libraries/{render-utils/src => gpu-networking/src/gpu-networking}/ShaderCache.cpp (100%) rename libraries/{render-utils/src => gpu-networking/src/gpu-networking}/ShaderCache.h (100%) rename libraries/{render-utils/src => gpu-networking/src/gpu-networking}/TextureCache.cpp (97%) create mode 100644 libraries/gpu-networking/src/gpu-networking/TextureCache.h create mode 100644 libraries/procedural/CMakeLists.txt rename libraries/{entities-renderer/src/RenderableProceduralItem.cpp => procedural/src/procedural/Procedural.cpp} (66%) create mode 100644 libraries/procedural/src/procedural/Procedural.h create mode 100644 libraries/procedural/src/procedural/ProceduralShaders.h diff --git a/cmake/macros/AutoScribeShader.cmake b/cmake/macros/AutoScribeShader.cmake index bec80d55b7..90a304ac50 100755 --- a/cmake/macros/AutoScribeShader.cmake +++ b/cmake/macros/AutoScribeShader.cmake @@ -73,7 +73,7 @@ endfunction() macro(AUTOSCRIBE_SHADER_LIB) - + message("Autoscribe running for ${TARGET_NAME}") file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}") foreach(HIFI_LIBRARY ${ARGN}) #if (NOT TARGET ${HIFI_LIBRARY}) diff --git a/cmake/macros/SetupHifiLibrary.cmake b/cmake/macros/SetupHifiLibrary.cmake index aba8d500a5..2e943f9b12 100644 --- a/cmake/macros/SetupHifiLibrary.cmake +++ b/cmake/macros/SetupHifiLibrary.cmake @@ -9,7 +9,8 @@ macro(SETUP_HIFI_LIBRARY) - project(${TARGET_NAME}) + project(${TARGET_NAME}) + message("Setting up project ${TARGET_NAME}") # grab the implemenation and header files file(GLOB_RECURSE LIB_SRCS "src/*.h" "src/*.cpp" "src/*.c") @@ -33,5 +34,8 @@ macro(SETUP_HIFI_LIBRARY) foreach(QT_MODULE ${${TARGET_NAME}_DEPENDENCY_QT_MODULES}) target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE}) endforeach() + + # Don't make scribed shaders cumulative + set(AUTOSCRIBE_SHADER_LIB_SRC "") endmacro(SETUP_HIFI_LIBRARY) \ No newline at end of file diff --git a/examples/shaders/exampleSkyboxUserDataV2.json b/examples/shaders/exampleSkyboxUserDataV2.json new file mode 100644 index 0000000000..2839baea4c --- /dev/null +++ b/examples/shaders/exampleSkyboxUserDataV2.json @@ -0,0 +1,6 @@ +{ + "ProceduralEntity": + { + "shaderUrl": "https://s3.amazonaws.com/Oculus/shadertoys/relentlessSkybox.fs" + } +} \ No newline at end of file diff --git a/examples/shaders/shadertoys/relentlessSkybox.fs b/examples/shaders/shadertoys/relentlessSkybox.fs new file mode 100644 index 0000000000..79e38bf9aa --- /dev/null +++ b/examples/shaders/shadertoys/relentlessSkybox.fs @@ -0,0 +1,144 @@ +// srtuss, 2013 + +// collecting some design ideas for a new game project. +// no raymarching is used. + +// if i could add a custom soundtrack, it'd use this one (essential for desired sensation) +// http://www.youtube.com/watch?v=1uFAu65tZpo + +//#define GREEN_VERSION + +// ** improved camera shaking +// ** cleaned up code +// ** added stuff to the gates + +// ******************************************************************************************* +// Please do NOT use this shader in your own productions/videos/games without my permission! +// If you'd still like to do so, please drop me a mail (stral@aon.at) +// ******************************************************************************************* +float time = iGlobalTime; + +vec2 rotate(vec2 p, float a) { + return vec2(p.x * cos(a) - p.y * sin(a), p.x * sin(a) + p.y * cos(a)); +} + +float box(vec2 p, vec2 b, float r) { + return length(max(abs(p) - b, 0.0)) - r; +} + +// iq's ray-plane-intersection code +vec3 intersect(in vec3 o, in vec3 d, vec3 c, vec3 u, vec3 v) +{ + vec3 q = o - c; + return vec3( + dot(cross(u, v), q), + dot(cross(q, u), d), + dot(cross(v, q), d)) / dot(cross(v, u), d); +} + +// some noise functions for fast developing +float rand11(float p) { + return fract(sin(p * 591.32) * 43758.5357); +} +float rand12(vec2 p) { + return fract(sin(dot(p.xy, vec2(12.9898, 78.233))) * 43758.5357); +} +vec2 rand21(float p) { + return fract(vec2(sin(p * 591.32), cos(p * 391.32))); +} +vec2 rand22(in vec2 p) +{ + return fract(vec2(sin(p.x * 591.32 + p.y * 154.077), cos(p.x * 391.32 + p.y * 49.077))); +} + +float noise11(float p) { + float fl = floor(p); + return mix(rand11(fl), rand11(fl + 1.0), fract(p)); //smoothstep(0.0, 1.0, fract(p))); +} +float fbm11(float p) { + return noise11(p) * 0.5 + noise11(p * 2.0) * 0.25 + noise11(p * 5.0) * 0.125; +} +vec3 noise31(float p) { + return vec3(noise11(p), noise11(p + 18.952), noise11(p - 11.372)) * 2.0 - 1.0; +} + +// something that looks a bit like godrays coming from the surface +float sky(vec3 p) { + float a = atan(p.x, p.z); + float t = time * 0.1; + float v = rand11(floor(a * 4.0 + t)) * 0.5 + rand11(floor(a * 8.0 - t)) * 0.25 + + rand11(floor(a * 16.0 + t)) * 0.125; + return v; +} + +vec3 voronoi(in vec2 x) +{ + vec2 n = floor(x); // grid cell id + vec2 f = fract(x);// grid internal position + vec2 mg;// shortest distance... + vec2 mr;// ..and second shortest distance + float md = 8.0, md2 = 8.0; + for(int j = -1; j <= 1; j ++) + { + for(int i = -1; i <= 1; i ++) + { + vec2 g = vec2(float(i), float(j)); // cell id + vec2 o = rand22(n + g);// offset to edge point + vec2 r = g + o - f; + + float d = max(abs(r.x), abs(r.y));// distance to the edge + + if(d < md) + { md2 = md; md = d; mr = r; mg = g;} + else if(d < md2) + { md2 = d;} + } + } + return vec3(n + mg, md2 - md); +} + + + +vec3 getSkyboxColor() { + vec3 rd = normalize(_normal); + vec3 ro = vec3(0, 0, 1); + float inten = 0.0; + + // background + float sd = dot(rd, vec3(0.0, 1.0, 0.0)); + inten = pow(1.0 - abs(sd), 20.0) + pow(sky(rd), 5.0) * step(0.0, rd.y) * 0.2; + + vec3 its; + float v, g; + + // voronoi floor layers + for(int i = 0; i < 4; i ++) + { + float layer = float(i); + its = intersect(ro, rd, vec3(0.0, -5.0 - layer * 5.0, 0.0), vec3(1.0, 0.0, 0.0), vec3(0.0, 0.0, 1.0)); + if(its.x > 0.0) + { + vec3 vo = voronoi((its.yz) * 0.05 + 8.0 * rand21(float(i))); + v = exp(-100.0 * (vo.z - 0.02)); + + float fx = 0.0; + + // add some special fx to lowest layer + if(i == 3) + { + float crd = 0.0; //fract(time * 0.2) * 50.0 - 25.0; + float fxi = cos(vo.x * 0.2 + time * 1.5);//abs(crd - vo.x); + fx = clamp(smoothstep(0.9, 1.0, fxi), 0.0, 0.9) * 1.0 * rand12(vo.xy); + fx *= exp(-3.0 * vo.z) * 2.0; + } + inten += v * 0.1 + fx; + } + } + + inten *= 0.4 + (sin(time) * 0.5 + 0.5) * 0.6; + + vec3 ct = vec3(0.6, 0.8, 9.0); + // find a color for the computed intensity + vec3 col = pow(vec3(inten), ct); + return col; +} diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index d7ee9228f4..05a937eef8 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -113,7 +113,7 @@ endif() target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES}) # link required hifi libraries -link_hifi_libraries(shared octree environment gpu model render fbx networking entities avatars +link_hifi_libraries(shared octree environment gpu gpu-networking procedural model render fbx networking entities avatars audio audio-client animation script-engine physics render-utils entities-renderer ui auto-updater plugins display-plugins input-plugins) diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index c4dddb8971..3787beb32b 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -26,4 +26,4 @@ find_package(PolyVox REQUIRED) target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES}) -link_hifi_libraries(shared gpu script-engine render render-utils) +link_hifi_libraries(shared gpu gpu-networking procedural script-engine render render-utils) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 72400dcefb..fa8c0eb633 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "EntityTreeRenderer.h" @@ -454,13 +455,24 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrendOverrideEnvironmentData(); auto stage = scene->getSkyStage(); if (zone->getBackgroundMode() == BACKGROUND_MODE_SKYBOX) { - stage->getSkybox()->setColor(zone->getSkyboxProperties().getColorVec3()); + auto skybox = stage->getSkybox(); + skybox->setColor(zone->getSkyboxProperties().getColorVec3()); + static QString userData; + if (userData != zone->getUserData()) { + userData = zone->getUserData(); + QSharedPointer procedural(new Procedural(userData)); + if (procedural->_enabled) { + skybox->setProcedural(procedural); + } else { + skybox->setProcedural(QSharedPointer()); + } + } if (zone->getSkyboxProperties().getURL().isEmpty()) { - stage->getSkybox()->setCubemap(gpu::TexturePointer()); + skybox->setCubemap(gpu::TexturePointer()); } else { // Update the Texture of the Skybox with the one pointed by this zone auto cubeMap = DependencyManager::get()->getTexture(zone->getSkyboxProperties().getURL(), CUBE_TEXTURE); - stage->getSkybox()->setCubemap(cubeMap->getGPUTexture()); + skybox->setCubemap(cubeMap->getGPUTexture()); } stage->setBackgroundMode(model::SunSkyStage::SKY_BOX); } else { diff --git a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp index 738c677104..525226b0e8 100644 --- a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp @@ -21,6 +21,8 @@ #include #include "RenderableDebugableEntityItem.h" +#include "../render-utils/simple_vert.h" +#include "../render-utils/simple_frag.h" EntityItemPointer RenderableBoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { return std::make_shared(entityID, properties); @@ -42,11 +44,18 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { glm::vec4 cubeColor(toGlm(getXColor()), getLocalRenderAlpha()); if (!_procedural) { - _procedural.reset(new ProceduralInfo(this)); + _procedural.reset(new Procedural(this->getUserData())); + _procedural->_vertexSource = simple_vert; + _procedural->_fragmentSource = simple_frag; + _procedural->_state->setCullMode(gpu::State::CULL_NONE); + _procedural->_state->setDepthTest(true, true, gpu::LESS_EQUAL); + _procedural->_state->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); } if (_procedural->ready()) { - _procedural->prepare(batch); + _procedural->prepare(batch, this->getDimensions()); DependencyManager::get()->renderSolidCube(batch, 1.0f, _procedural->getColor(cubeColor)); } else { DependencyManager::get()->renderSolidCube(batch, 1.0f, cubeColor); diff --git a/libraries/entities-renderer/src/RenderableBoxEntityItem.h b/libraries/entities-renderer/src/RenderableBoxEntityItem.h index e317163683..838022c7d4 100644 --- a/libraries/entities-renderer/src/RenderableBoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderableBoxEntityItem.h @@ -13,10 +13,11 @@ #define hifi_RenderableBoxEntityItem_h #include -#include "RenderableEntityItem.h" -#include "RenderableProceduralItem.h" +#include -class RenderableBoxEntityItem : public BoxEntityItem, RenderableProceduralItem { +#include "RenderableEntityItem.h" + +class RenderableBoxEntityItem : public BoxEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); @@ -28,6 +29,8 @@ public: virtual void setUserData(const QString& value); SIMPLE_RENDERABLE() +private: + QSharedPointer _procedural; }; diff --git a/libraries/entities-renderer/src/RenderableProceduralItem.h b/libraries/entities-renderer/src/RenderableProceduralItem.h deleted file mode 100644 index 37e827d304..0000000000 --- a/libraries/entities-renderer/src/RenderableProceduralItem.h +++ /dev/null @@ -1,60 +0,0 @@ -// -// Created by Bradley Austin Davis on 2015/09/05 -// Copyright 2013-2015 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 -// - -#pragma once -#ifndef hifi_RenderableProcedrualItem_h -#define hifi_RenderableProcedrualItem_h - -#include -#include -#include -#include - -#include -#include -#include -#include - -class EntityItem; -class QJsonObject; - -class RenderableProceduralItem { -protected: - // FIXME better encapsulation - // FIXME better mechanism for extending to things rendered using shaders other than simple.slv - struct ProceduralInfo { - ProceduralInfo(EntityItem* entity); - void parse(); - void parse(const QJsonObject&); - bool ready(); - void prepare(gpu::Batch& batch); - glm::vec4 getColor(const glm::vec4& entityColor); - - bool _enabled{ false }; - uint8_t _version{ 1 }; - gpu::PipelinePointer _pipeline; - gpu::ShaderPointer _vertexShader; - gpu::ShaderPointer _fragmentShader; - gpu::ShaderPointer _shader; - QString _shaderSource; - QString _shaderPath; - QUrl _shaderUrl; - quint64 _shaderModified{ 0 }; - bool _pipelineDirty{ true }; - int32_t _timeSlot{ gpu::Shader::INVALID_LOCATION }; - int32_t _scaleSlot{ gpu::Shader::INVALID_LOCATION }; - uint64_t _start{ 0 }; - NetworkShaderPointer _networkShader; - EntityItem* _entity; - QJsonObject _uniforms; - }; - - QSharedPointer _procedural; -}; - -#endif diff --git a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp index 3b58397a82..82257c67fb 100644 --- a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp @@ -21,6 +21,8 @@ #include #include "RenderableDebugableEntityItem.h" +#include "../render-utils/simple_vert.h" +#include "../render-utils/simple_frag.h" EntityItemPointer RenderableSphereEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { return std::make_shared(entityID, properties); @@ -47,12 +49,19 @@ void RenderableSphereEntityItem::render(RenderArgs* args) { static const int SLICES = 15, STACKS = 15; if (!_procedural) { - _procedural.reset(new ProceduralInfo(this)); + _procedural.reset(new Procedural(getUserData())); + _procedural->_vertexSource = simple_vert; + _procedural->_fragmentSource = simple_frag; + _procedural->_state->setCullMode(gpu::State::CULL_NONE); + _procedural->_state->setDepthTest(true, true, gpu::LESS_EQUAL); + _procedural->_state->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); } glm::vec4 sphereColor(toGlm(getXColor()), getLocalRenderAlpha()); if (_procedural->ready()) { - _procedural->prepare(batch); + _procedural->prepare(batch, getDimensions()); DependencyManager::get()->renderSphere(batch, 0.5f, SLICES, STACKS, _procedural->getColor(sphereColor)); } else { DependencyManager::get()->renderSolidSphere(batch, 0.5f, SLICES, STACKS, sphereColor); diff --git a/libraries/entities-renderer/src/RenderableSphereEntityItem.h b/libraries/entities-renderer/src/RenderableSphereEntityItem.h index 5036354c04..293ae79029 100644 --- a/libraries/entities-renderer/src/RenderableSphereEntityItem.h +++ b/libraries/entities-renderer/src/RenderableSphereEntityItem.h @@ -13,10 +13,11 @@ #define hifi_RenderableSphereEntityItem_h #include -#include "RenderableEntityItem.h" -#include "RenderableProceduralItem.h" +#include -class RenderableSphereEntityItem : public SphereEntityItem, RenderableProceduralItem { +#include "RenderableEntityItem.h" + +class RenderableSphereEntityItem : public SphereEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); @@ -28,6 +29,9 @@ public: virtual void setUserData(const QString& value); SIMPLE_RENDERABLE(); + +private: + QSharedPointer _procedural; }; diff --git a/libraries/gpu-networking/CMakeLists.txt b/libraries/gpu-networking/CMakeLists.txt new file mode 100644 index 0000000000..836afac371 --- /dev/null +++ b/libraries/gpu-networking/CMakeLists.txt @@ -0,0 +1,11 @@ +set(TARGET_NAME gpu-networking) + +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library() + +add_dependency_external_projects(glm) +find_package(GLM REQUIRED) +target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) + +link_hifi_libraries(shared networking gpu) + diff --git a/libraries/gpu-networking/src/gpu-networking/GpuNetworkingLogging.cpp b/libraries/gpu-networking/src/gpu-networking/GpuNetworkingLogging.cpp new file mode 100644 index 0000000000..38da22969b --- /dev/null +++ b/libraries/gpu-networking/src/gpu-networking/GpuNetworkingLogging.cpp @@ -0,0 +1,11 @@ +// +// Created by Bradley Austin Davis on 2015/08/07 +// Copyright 2013-2015 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 "GpuNetworkingLogging.h" + +Q_LOGGING_CATEGORY(gpunetwork, "hifi.gpu-network") diff --git a/libraries/gpu-networking/src/gpu-networking/GpuNetworkingLogging.h b/libraries/gpu-networking/src/gpu-networking/GpuNetworkingLogging.h new file mode 100644 index 0000000000..7499340a9b --- /dev/null +++ b/libraries/gpu-networking/src/gpu-networking/GpuNetworkingLogging.h @@ -0,0 +1,11 @@ +// +// Created by Bradley Austin Davis on 2015/08/07 +// Copyright 2013-2015 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 + +Q_DECLARE_LOGGING_CATEGORY(gpunetwork) diff --git a/libraries/render-utils/src/ShaderCache.cpp b/libraries/gpu-networking/src/gpu-networking/ShaderCache.cpp similarity index 100% rename from libraries/render-utils/src/ShaderCache.cpp rename to libraries/gpu-networking/src/gpu-networking/ShaderCache.cpp diff --git a/libraries/render-utils/src/ShaderCache.h b/libraries/gpu-networking/src/gpu-networking/ShaderCache.h similarity index 100% rename from libraries/render-utils/src/ShaderCache.h rename to libraries/gpu-networking/src/gpu-networking/ShaderCache.h diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/gpu-networking/src/gpu-networking/TextureCache.cpp similarity index 97% rename from libraries/render-utils/src/TextureCache.cpp rename to libraries/gpu-networking/src/gpu-networking/TextureCache.cpp index c4fb4c9989..e2462946a4 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/gpu-networking/src/gpu-networking/TextureCache.cpp @@ -1,7 +1,4 @@ // -// TextureCache.cpp -// interface/src/renderer -// // Created by Andrzej Kapolka on 8/6/13. // Copyright 2013 High Fidelity, Inc. // @@ -21,13 +18,11 @@ #include #include #include -#include "PathUtils.h" +#include #include - - -#include "RenderUtilsLogging.h" +#include "GpuNetworkingLogging.h" TextureCache::TextureCache() { const qint64 TEXTURE_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE; @@ -255,7 +250,7 @@ void listSupportedImageFormats() { foreach(const QByteArray& f, supportedFormats) { formats += QString(f) + ","; } - qCDebug(renderutils) << "List of supported Image formats:" << formats; + qCDebug(gpunetwork) << "List of supported Image formats:" << formats; }); } @@ -323,9 +318,9 @@ void ImageReader::run() { if (originalWidth == 0 || originalHeight == 0 || imageFormat == QImage::Format_Invalid) { if (filenameExtension.empty()) { - qCDebug(renderutils) << "QImage failed to create from content, no file extension:" << _url; + qCDebug(gpunetwork) << "QImage failed to create from content, no file extension:" << _url; } else { - qCDebug(renderutils) << "QImage failed to create from content" << _url; + qCDebug(gpunetwork) << "QImage failed to create from content" << _url; } return; } @@ -333,7 +328,7 @@ void ImageReader::run() { int imageArea = image.width() * image.height(); auto ntex = dynamic_cast(&*texture); if (ntex && (ntex->getType() == CUBE_TEXTURE)) { - qCDebug(renderutils) << "Cube map size:" << _url << image.width() << image.height(); + qCDebug(gpunetwork) << "Cube map size:" << _url << image.width() << image.height(); } int opaquePixels = 0; @@ -384,7 +379,7 @@ void ImageReader::run() { } } if (opaquePixels == imageArea) { - qCDebug(renderutils) << "Image with alpha channel is completely opaque:" << _url; + qCDebug(gpunetwork) << "Image with alpha channel is completely opaque:" << _url; image = image.convertToFormat(QImage::Format_RGB888); } @@ -532,7 +527,7 @@ void ImageReader::run() { faces.push_back(image.copy(QRect(layout._faceZPos._x * faceWidth, layout._faceZPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZPos._horizontalMirror, layout._faceZPos._verticalMirror)); faces.push_back(image.copy(QRect(layout._faceZNeg._x * faceWidth, layout._faceZNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZNeg._horizontalMirror, layout._faceZNeg._verticalMirror)); } else { - qCDebug(renderutils) << "Failed to find a known cube map layout from this image:" << _url; + qCDebug(gpunetwork) << "Failed to find a known cube map layout from this image:" << _url; return; } diff --git a/libraries/gpu-networking/src/gpu-networking/TextureCache.h b/libraries/gpu-networking/src/gpu-networking/TextureCache.h new file mode 100644 index 0000000000..f0abda8e66 --- /dev/null +++ b/libraries/gpu-networking/src/gpu-networking/TextureCache.h @@ -0,0 +1,167 @@ +// +// Created by Andrzej Kapolka on 8/6/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 +// + +#ifndef hifi_TextureCache_h +#define hifi_TextureCache_h + +#include + +#include +#include +#include + +#include +#include + +namespace gpu { +class Batch; +} +class NetworkTexture; + +typedef QSharedPointer NetworkTexturePointer; + +enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, SPECULAR_TEXTURE, EMISSIVE_TEXTURE, SPLAT_TEXTURE, CUBE_TEXTURE }; + +/// Stores cached textures, including render-to-texture targets. +class TextureCache : public ResourceCache, public Dependency { + Q_OBJECT + SINGLETON_DEPENDENCY + +public: + /// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture + /// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and + /// the second, a set of random unit vectors to be used as noise gradients. + const gpu::TexturePointer& getPermutationNormalTexture(); + + /// Returns an opaque white texture (useful for a default). + const gpu::TexturePointer& getWhiteTexture(); + + /// Returns an opaque gray texture (useful for a default). + const gpu::TexturePointer& getGrayTexture(); + + /// Returns the a pale blue texture (useful for a normal map). + const gpu::TexturePointer& getBlueTexture(); + + /// Returns the a black texture (useful for a default). + const gpu::TexturePointer& getBlackTexture(); + + // Returns a map used to compress the normals through a fitting scale algorithm + const gpu::TexturePointer& getNormalFittingTexture(); + + /// Returns a texture version of an image file + static gpu::TexturePointer getImageTexture(const QString& path); + + /// Loads a texture from the specified URL. + NetworkTexturePointer getTexture(const QUrl& url, TextureType type = DEFAULT_TEXTURE, bool dilatable = false, + const QByteArray& content = QByteArray()); + +protected: + + virtual QSharedPointer createResource(const QUrl& url, + const QSharedPointer& fallback, bool delayLoad, const void* extra); + +private: + TextureCache(); + virtual ~TextureCache(); + friend class DilatableNetworkTexture; + + gpu::TexturePointer _permutationNormalTexture; + gpu::TexturePointer _whiteTexture; + gpu::TexturePointer _grayTexture; + gpu::TexturePointer _blueTexture; + gpu::TexturePointer _blackTexture; + gpu::TexturePointer _normalFittingTexture; + + QHash > _dilatableNetworkTextures; +}; + +/// A simple object wrapper for an OpenGL texture. +class Texture { +public: + friend class TextureCache; + friend class DilatableNetworkTexture; + Texture(); + ~Texture(); + + const gpu::TexturePointer& getGPUTexture() const { return _gpuTexture; } + +protected: + gpu::TexturePointer _gpuTexture; + +private: +}; + +/// A texture loaded from the network. + +class NetworkTexture : public Resource, public Texture { + Q_OBJECT + +public: + + NetworkTexture(const QUrl& url, TextureType type, const QByteArray& content); + + /// Checks whether it "looks like" this texture is translucent + /// (majority of pixels neither fully opaque or fully transparent). + bool isTranslucent() const { return _translucent; } + + /// Returns the lazily-computed average texture color. + const QColor& getAverageColor() const { return _averageColor; } + + int getOriginalWidth() const { return _originalWidth; } + int getOriginalHeight() const { return _originalHeight; } + int getWidth() const { return _width; } + int getHeight() const { return _height; } + TextureType getType() const { return _type; } +protected: + + virtual void downloadFinished(QNetworkReply* reply); + + Q_INVOKABLE void loadContent(const QByteArray& content); + // FIXME: This void* should be a gpu::Texture* but i cannot get it to work for now, moving on... + Q_INVOKABLE void setImage(const QImage& image, void* texture, bool translucent, const QColor& averageColor, int originalWidth, + int originalHeight); + + virtual void imageLoaded(const QImage& image); + + TextureType _type; + +private: + bool _translucent; + QColor _averageColor; + int _originalWidth; + int _originalHeight; + int _width; + int _height; +}; + +/// Caches derived, dilated textures. +class DilatableNetworkTexture : public NetworkTexture { + Q_OBJECT + +public: + + DilatableNetworkTexture(const QUrl& url, const QByteArray& content); + + /// Returns a pointer to a texture with the requested amount of dilation. + QSharedPointer getDilatedTexture(float dilation); + +protected: + + virtual void imageLoaded(const QImage& image); + virtual void reinsert(); + +private: + + QImage _image; + int _innerRadius; + int _outerRadius; + + QMap > _dilatedTextures; +}; + +#endif // hifi_TextureCache_h diff --git a/libraries/gpu/CMakeLists.txt b/libraries/gpu/CMakeLists.txt index 7a88580f7f..38fe5cb22f 100644 --- a/libraries/gpu/CMakeLists.txt +++ b/libraries/gpu/CMakeLists.txt @@ -7,6 +7,10 @@ setup_hifi_library() link_hifi_libraries(shared) +add_dependency_external_projects(glm) +find_package(GLM REQUIRED) +target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) + add_dependency_external_projects(glew) find_package(GLEW REQUIRED) add_definitions(-DGLEW_STATIC) diff --git a/libraries/model/CMakeLists.txt b/libraries/model/CMakeLists.txt index 701c132e61..8acb4b0a71 100755 --- a/libraries/model/CMakeLists.txt +++ b/libraries/model/CMakeLists.txt @@ -9,4 +9,4 @@ add_dependency_external_projects(glm) find_package(GLM REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) -link_hifi_libraries(shared gpu octree) +link_hifi_libraries(shared networking gpu gpu-networking procedural octree) diff --git a/libraries/model/src/model/Skybox.cpp b/libraries/model/src/model/Skybox.cpp index 314492881f..c17bf1df72 100755 --- a/libraries/model/src/model/Skybox.cpp +++ b/libraries/model/src/model/Skybox.cpp @@ -10,10 +10,12 @@ // #include "Skybox.h" -#include "gpu/Batch.h" -#include "gpu/Context.h" -#include "ViewFrustum.h" +#include +#include +#include +#include + #include "Skybox_vert.h" #include "Skybox_frag.h" @@ -38,19 +40,54 @@ void Skybox::setColor(const Color& color) { _color = color; } +void Skybox::setProcedural(QSharedPointer procedural) { + _procedural = procedural; + if (_procedural) { + _procedural->_vertexSource = Skybox_vert; + _procedural->_fragmentSource = Skybox_frag; + // No pipeline state customization + } +} + void Skybox::setCubemap(const gpu::TexturePointer& cubemap) { _cubemap = cubemap; } + void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Skybox& skybox) { + static gpu::BufferPointer theBuffer; + static gpu::Stream::FormatPointer theFormat; - if (skybox.getCubemap()) { - if (skybox.getCubemap()->isDefined()) { + if (skybox._procedural || skybox.getCubemap()) { + if (!theBuffer) { + const float CLIP = 1.0f; + const glm::vec2 vertices[4] = { { -CLIP, -CLIP }, { CLIP, -CLIP }, { -CLIP, CLIP }, { CLIP, CLIP } }; + theBuffer = std::make_shared(sizeof(vertices), (const gpu::Byte*) vertices); + theFormat = std::make_shared(); + theFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ)); + } - static gpu::PipelinePointer thePipeline; - static gpu::BufferPointer theBuffer; - static gpu::Stream::FormatPointer theFormat; + glm::mat4 projMat; + viewFrustum.evalProjectionMatrix(projMat); + + Transform viewTransform; + viewFrustum.evalViewTransform(viewTransform); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewTransform); + batch.setModelTransform(Transform()); // only for Mac + batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8); + batch.setInputFormat(theFormat); + + if (skybox._procedural && skybox._procedural->_enabled && skybox._procedural->ready()) { + if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) { + batch.setResourceTexture(0, skybox.getCubemap()); + } + + skybox._procedural->prepare(batch, glm::vec3(1)); + batch.draw(gpu::TRIANGLE_STRIP, 4); + } else if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) { static gpu::BufferPointer theConstants; + static gpu::PipelinePointer thePipeline; static int SKYBOX_CONSTANTS_SLOT = 0; // need to be defined by the compilation of the shader if (!thePipeline) { auto skyVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(Skybox_vert))); @@ -72,23 +109,10 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState)); - const float CLIP = 1.0f; - const glm::vec2 vertices[4] = { {-CLIP, -CLIP}, {CLIP, -CLIP}, {-CLIP, CLIP}, {CLIP, CLIP}}; - theBuffer = std::make_shared(sizeof(vertices), (const gpu::Byte*) vertices); - - theFormat = std::make_shared(); - theFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ)); - auto color = glm::vec4(1.0f); theConstants = std::make_shared(sizeof(color), (const gpu::Byte*) &color); } - glm::mat4 projMat; - viewFrustum.evalProjectionMatrix(projMat); - - Transform viewTransform; - viewFrustum.evalViewTransform(viewTransform); - if (glm::all(glm::equal(skybox.getColor(), glm::vec3(0.0f)))) { auto color = glm::vec4(1.0f); theConstants->setSubData(0, sizeof(color), (const gpu::Byte*) &color); @@ -96,13 +120,8 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky theConstants->setSubData(0, sizeof(Color), (const gpu::Byte*) &skybox.getColor()); } - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewTransform); - batch.setModelTransform(Transform()); // only for Mac batch.setPipeline(thePipeline); - batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8); batch.setUniformBuffer(SKYBOX_CONSTANTS_SLOT, theConstants, 0, theConstants->getSize()); - batch.setInputFormat(theFormat); batch.setResourceTexture(0, skybox.getCubemap()); batch.draw(gpu::TRIANGLE_STRIP, 4); } diff --git a/libraries/model/src/model/Skybox.h b/libraries/model/src/model/Skybox.h index 7a4550d75a..809ec7e3b0 100755 --- a/libraries/model/src/model/Skybox.h +++ b/libraries/model/src/model/Skybox.h @@ -11,12 +11,13 @@ #ifndef hifi_model_Skybox_h #define hifi_model_Skybox_h -#include "gpu/Texture.h" +#include +#include #include "Light.h" class ViewFrustum; -//class Transform; +struct Procedural; namespace gpu { class Batch; } namespace model { @@ -35,11 +36,13 @@ public: void setCubemap(const gpu::TexturePointer& cubemap); const gpu::TexturePointer& getCubemap() const { return _cubemap; } + void setProcedural(QSharedPointer procedural); + static void render(gpu::Batch& batch, const ViewFrustum& frustum, const Skybox& skybox); protected: gpu::TexturePointer _cubemap; - + QSharedPointer _procedural; Color _color{1.0f, 1.0f, 1.0f}; }; typedef std::shared_ptr< Skybox > SkyboxPointer; diff --git a/libraries/model/src/model/Skybox.slf b/libraries/model/src/model/Skybox.slf index 47444b21bd..382801f52d 100755 --- a/libraries/model/src/model/Skybox.slf +++ b/libraries/model/src/model/Skybox.slf @@ -22,13 +22,29 @@ uniform skyboxBuffer { }; in vec3 _normal; - out vec4 _fragColor; +//PROCEDURAL_COMMON_BLOCK + +#line 1001 +//PROCEDURAL_BLOCK + +#line 2033 void main(void) { + +#ifdef PROCEDURAL + + vec3 color = getSkyboxColor(); + _fragColor = vec4(color, 0.0); + +#else + vec3 coord = normalize(_normal); vec3 texel = texture(cubeMap, coord).rgb; vec3 color = texel * _skybox._color.rgb; vec3 pixel = pow(color, vec3(1.0/2.2)); // manual Gamma correction _fragColor = vec4(pixel, 0.0); + +#endif + } diff --git a/libraries/procedural/CMakeLists.txt b/libraries/procedural/CMakeLists.txt new file mode 100644 index 0000000000..bd53f0abb9 --- /dev/null +++ b/libraries/procedural/CMakeLists.txt @@ -0,0 +1,10 @@ +set(TARGET_NAME procedural) + +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library() + +add_dependency_external_projects(glm) +find_package(GLM REQUIRED) +target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) + +link_hifi_libraries(shared gpu networking gpu-networking) diff --git a/libraries/entities-renderer/src/RenderableProceduralItem.cpp b/libraries/procedural/src/procedural/Procedural.cpp similarity index 66% rename from libraries/entities-renderer/src/RenderableProceduralItem.cpp rename to libraries/procedural/src/procedural/Procedural.cpp index c88d1410a5..c8433ef341 100644 --- a/libraries/entities-renderer/src/RenderableProceduralItem.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -6,7 +6,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "RenderableProceduralItem.h" +#include "Procedural.h" #include #include @@ -14,14 +14,12 @@ #include #include -#include -#include -#include -#include +#include #include +#include +#include -#include "RenderableProceduralItemShader.h" -#include "../render-utils/simple_vert.h" +#include "ProceduralShaders.h" static const char* const UNIFORM_TIME_NAME= "iGlobalTime"; static const char* const UNIFORM_SCALE_NAME = "iWorldScale"; @@ -30,43 +28,46 @@ static const QString PROCEDURAL_USER_DATA_KEY = "ProceduralEntity"; static const QString URL_KEY = "shaderUrl"; static const QString VERSION_KEY = "version"; static const QString UNIFORMS_KEY = "uniforms"; +static const std::string PROCEDURAL_BLOCK = "//PROCEDURAL_BLOCK"; +static const std::string PROCEDURAL_COMMON_BLOCK = "//PROCEDURAL_COMMON_BLOCK"; +static const std::string PROCEDURAL_VERSION = "//PROCEDURAL_VERSION"; -RenderableProceduralItem::ProceduralInfo::ProceduralInfo(EntityItem* entity) : _entity(entity) { - parse(); + +// Example +//{ +// "ProceduralEntity": { +// "shaderUrl": "file:///C:/Users/bdavis/Git/hifi/examples/shaders/test.fs", +// } +//} +QJsonValue Procedural::getProceduralData(const QString& proceduralJson) { + if (proceduralJson.isEmpty()) { + return QJsonValue(); + } + + QJsonParseError parseError; + auto doc = QJsonDocument::fromJson(proceduralJson.toUtf8(), &parseError); + if (parseError.error != QJsonParseError::NoError) { + return QJsonValue(); + } + + return doc.object()[PROCEDURAL_USER_DATA_KEY]; } -void RenderableProceduralItem::ProceduralInfo::parse() { + +Procedural::Procedural(const QString& userDataJson) { + parse(userDataJson); + _state = std::make_shared(); +} + +void Procedural::parse(const QString& userDataJson) { _enabled = false; - QJsonObject userData; - { - const QString& userDataJson = _entity->getUserData(); - if (userDataJson.isEmpty()) { - return; - } - QJsonParseError parseError; - auto doc = QJsonDocument::fromJson(userDataJson.toUtf8(), &parseError); - if (parseError.error != QJsonParseError::NoError) { - return; - } - userData = doc.object(); + auto proceduralData = getProceduralData(userDataJson); + if (proceduralData.isObject()) { + parse(proceduralData.toObject()); } - - // Example - //{ - // "ProceduralEntity": { - // "shaderUrl": "file:///C:/Users/bdavis/Git/hifi/examples/shaders/test.fs", - // "color" : "#FFFFFF" - // } - //} - auto proceduralData = userData[PROCEDURAL_USER_DATA_KEY]; - if (proceduralData.isNull()) { - return; - } - - parse(proceduralData.toObject()); } -void RenderableProceduralItem::ProceduralInfo::parse(const QJsonObject& proceduralData) { +void Procedural::parse(const QJsonObject& proceduralData) { // grab the version number { auto version = proceduralData[VERSION_KEY]; @@ -106,7 +107,7 @@ void RenderableProceduralItem::ProceduralInfo::parse(const QJsonObject& procedur _enabled = true; } -bool RenderableProceduralItem::ProceduralInfo::ready() { +bool Procedural::ready() { if (!_enabled) { return false; } @@ -122,7 +123,7 @@ bool RenderableProceduralItem::ProceduralInfo::ready() { return false; } -void RenderableProceduralItem::ProceduralInfo::prepare(gpu::Batch& batch) { +void Procedural::prepare(gpu::Batch& batch, const glm::vec3& size) { if (_shaderUrl.isLocalFile()) { auto lastModified = QFileInfo(_shaderPath).lastModified().toMSecsSinceEpoch(); if (lastModified > _shaderModified) { @@ -139,31 +140,33 @@ void RenderableProceduralItem::ProceduralInfo::prepare(gpu::Batch& batch) { if (!_pipeline || _pipelineDirty) { _pipelineDirty = true; if (!_vertexShader) { - _vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert))); + _vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(_vertexSource)); } - QString framentShaderSource; - switch (_version) { - case 1: - framentShaderSource = SHADER_TEMPLATE_V1.arg(_shaderSource); - break; - default: - case 2: - framentShaderSource = SHADER_TEMPLATE_V2.arg(_shaderSource); - break; + // Build the fragment shader + std::string fragmentShaderSource = _fragmentSource; + size_t replaceIndex = fragmentShaderSource.find(PROCEDURAL_COMMON_BLOCK); + if (replaceIndex != std::string::npos) { + fragmentShaderSource.replace(replaceIndex, PROCEDURAL_COMMON_BLOCK.size(), SHADER_COMMON); } - _fragmentShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(framentShaderSource.toLocal8Bit().data()))); + + replaceIndex = fragmentShaderSource.find(PROCEDURAL_VERSION); + if (replaceIndex != std::string::npos) { + if (_version == 1) { + fragmentShaderSource.replace(replaceIndex, PROCEDURAL_VERSION.size(), "#define PROCEDURAL_V1 1"); + } else if (_version == 2) { + fragmentShaderSource.replace(replaceIndex, PROCEDURAL_VERSION.size(), "#define PROCEDURAL_V2 1"); + } + } + replaceIndex = fragmentShaderSource.find(PROCEDURAL_BLOCK); + if (replaceIndex != std::string::npos) { + fragmentShaderSource.replace(replaceIndex, PROCEDURAL_BLOCK.size(), _shaderSource.toLocal8Bit().data()); + } + qDebug() << "FragmentShader:\n" << fragmentShaderSource.c_str(); + _fragmentShader = gpu::ShaderPointer(gpu::Shader::createPixel(fragmentShaderSource)); _shader = gpu::ShaderPointer(gpu::Shader::createProgram(_vertexShader, _fragmentShader)); - gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT)); - gpu::Shader::makeProgram(*_shader, slotBindings); - auto state = std::make_shared(); - state->setCullMode(gpu::State::CULL_NONE); - state->setDepthTest(true, true, gpu::LESS_EQUAL); - state->setBlendFunction(false, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(_shader, state)); + gpu::Shader::makeProgram(*_shader); + _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(_shader, _state)); _timeSlot = _shader->getUniforms().findLocation(UNIFORM_TIME_NAME); _scaleSlot = _shader->getUniforms().findLocation(UNIFORM_SCALE_NAME); _start = usecTimestampNow(); @@ -221,15 +224,12 @@ void RenderableProceduralItem::ProceduralInfo::prepare(gpu::Batch& batch) { // Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds float time = (float)((usecTimestampNow() - _start) / USECS_PER_MSEC) / MSECS_PER_SECOND; batch._glUniform1f(_timeSlot, time); - // FIXME move into the 'set once' section, since this doesn't change over time - auto scale = _entity->getDimensions(); - batch._glUniform3f(_scaleSlot, scale.x, scale.y, scale.z); - batch.setResourceTexture(DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT, DependencyManager::get()->getNormalFittingTexture()); + batch._glUniform3f(_scaleSlot, size.x, size.y, size.z); } -glm::vec4 RenderableProceduralItem::ProceduralInfo::getColor(const glm::vec4& entityColor) { +glm::vec4 Procedural::getColor(const glm::vec4& entityColor) { if (_version == 1) { return glm::vec4(1); } diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h new file mode 100644 index 0000000000..bb6a0ad44d --- /dev/null +++ b/libraries/procedural/src/procedural/Procedural.h @@ -0,0 +1,60 @@ +// +// Created by Bradley Austin Davis on 2015/09/05 +// Copyright 2013-2015 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 +// + +#pragma once +#ifndef hifi_RenderableProcedrualItem_h +#define hifi_RenderableProcedrualItem_h + +#include +#include +#include +#include + +#include +#include +#include +#include + + +// FIXME better encapsulation +// FIXME better mechanism for extending to things rendered using shaders other than simple.slv +struct Procedural { + static QJsonValue getProceduralData(const QString& proceduralJson); + + Procedural(const QString& userDataJson); + void parse(const QString& userDataJson); + void parse(const QJsonObject&); + bool ready(); + void prepare(gpu::Batch& batch, const glm::vec3& size); + glm::vec4 getColor(const glm::vec4& entityColor); + + bool _enabled{ false }; + uint8_t _version{ 1 }; + + std::string _vertexSource; + std::string _fragmentSource; + + QString _shaderSource; + QString _shaderPath; + QUrl _shaderUrl; + quint64 _shaderModified{ 0 }; + bool _pipelineDirty{ true }; + int32_t _timeSlot{ gpu::Shader::INVALID_LOCATION }; + int32_t _scaleSlot{ gpu::Shader::INVALID_LOCATION }; + uint64_t _start{ 0 }; + NetworkShaderPointer _networkShader; + QJsonObject _uniforms; + + gpu::PipelinePointer _pipeline; + gpu::ShaderPointer _vertexShader; + gpu::ShaderPointer _fragmentShader; + gpu::ShaderPointer _shader; + gpu::StatePointer _state; +}; + +#endif diff --git a/libraries/procedural/src/procedural/ProceduralShaders.h b/libraries/procedural/src/procedural/ProceduralShaders.h new file mode 100644 index 0000000000..9943a322cc --- /dev/null +++ b/libraries/procedural/src/procedural/ProceduralShaders.h @@ -0,0 +1,276 @@ +// +// Created by Bradley Austin Davis on 2015/09/05 +// Copyright 2013-2015 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 +// + +// Shader includes portions of webgl-noise: +// Description : Array and textureless GLSL 2D/3D/4D simplex +// noise functions. +// Author : Ian McEwan, Ashima Arts. +// Maintainer : ijm +// Lastmod : 20110822 (ijm) +// License : Copyright (C) 2011 Ashima Arts. All rights reserved. +// Distributed under the MIT License. See LICENSE file. +// https://github.com/ashima/webgl-noise +// + + +const std::string SHADER_COMMON = R"SHADER( + +float mod289(float x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +vec2 mod289(vec2 x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +vec3 mod289(vec3 x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +vec4 mod289(vec4 x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +float permute(float x) { + return mod289(((x*34.0)+1.0)*x); +} + +vec3 permute(vec3 x) { + return mod289(((x*34.0)+1.0)*x); +} + +vec4 permute(vec4 x) { + return mod289(((x*34.0)+1.0)*x); +} + +float taylorInvSqrt(float r) { + return 1.79284291400159 - 0.85373472095314 * r; +} + +vec4 taylorInvSqrt(vec4 r) { + return 1.79284291400159 - 0.85373472095314 * r; +} + +vec4 grad4(float j, vec4 ip) { + const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0); + vec4 p, s; + + p.xyz = floor(fract(vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0; + p.w = 1.5 - dot(abs(p.xyz), ones.xyz); + s = vec4(lessThan(p, vec4(0.0))); + p.xyz = p.xyz + (s.xyz * 2.0 - 1.0) * s.www; + + return p; +} + +// (sqrt(5) - 1)/4 = F4, used once below +#define F4 0.309016994374947451 + +float snoise(vec4 v) { + const vec4 C = vec4(0.138196601125011, // (5 - sqrt(5))/20 G4 + 0.276393202250021, // 2 * G4 + 0.414589803375032, // 3 * G4 + -0.447213595499958); // -1 + 4 * G4 + + // First corner + vec4 i = floor(v + dot(v, vec4(F4))); + vec4 x0 = v - i + dot(i, C.xxxx); + + // Other corners + + // Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI) + vec4 i0; + vec3 isX = step(x0.yzw, x0.xxx); + vec3 isYZ = step(x0.zww, x0.yyz); + i0.x = isX.x + isX.y + isX.z; + i0.yzw = 1.0 - isX; + i0.y += isYZ.x + isYZ.y; + i0.zw += 1.0 - isYZ.xy; + i0.z += isYZ.z; + i0.w += 1.0 - isYZ.z; + + // i0 now contains the unique values 0,1,2,3 in each channel + vec4 i3 = clamp(i0, 0.0, 1.0); + vec4 i2 = clamp(i0 - 1.0, 0.0, 1.0); + vec4 i1 = clamp(i0 - 2.0, 0.0, 1.0); + + vec4 x1 = x0 - i1 + C.xxxx; + vec4 x2 = x0 - i2 + C.yyyy; + vec4 x3 = x0 - i3 + C.zzzz; + vec4 x4 = x0 + C.wwww; + + // Permutations + i = mod289(i); + float j0 = permute(permute(permute(permute(i.w) + i.z) + i.y) + i.x); + vec4 j1 = permute( + permute( + permute( + permute(i.w + vec4(i1.w, i2.w, i3.w, 1.0)) + i.z + + vec4(i1.z, i2.z, i3.z, 1.0)) + i.y + + vec4(i1.y, i2.y, i3.y, 1.0)) + i.x + + vec4(i1.x, i2.x, i3.x, 1.0)); + + // Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope + // 7*7*6 = 294, which is close to the ring size 17*17 = 289. + vec4 ip = vec4(1.0 / 294.0, 1.0 / 49.0, 1.0 / 7.0, 0.0); + + vec4 p0 = grad4(j0, ip); + vec4 p1 = grad4(j1.x, ip); + vec4 p2 = grad4(j1.y, ip); + vec4 p3 = grad4(j1.z, ip); + vec4 p4 = grad4(j1.w, ip); + + // Normalise gradients + vec4 norm = taylorInvSqrt( + vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + p4 *= taylorInvSqrt(dot(p4, p4)); + + // Mix contributions from the five corners + vec3 m0 = max(0.6 - vec3(dot(x0, x0), dot(x1, x1), dot(x2, x2)), 0.0); + vec2 m1 = max(0.6 - vec2(dot(x3, x3), dot(x4, x4)), 0.0); + m0 = m0 * m0; + m1 = m1 * m1; + return 49.0 + * (dot(m0 * m0, vec3(dot(p0, x0), dot(p1, x1), dot(p2, x2))) + + dot(m1 * m1, vec2(dot(p3, x3), dot(p4, x4)))); + +} + +float snoise(vec3 v) { + const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0); + const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); + + // First corner + vec3 i = floor(v + dot(v, C.yyy)); + vec3 x0 = v - i + dot(i, C.xxx); + + // Other corners + vec3 g = step(x0.yzx, x0.xyz); + vec3 l = 1.0 - g; + vec3 i1 = min(g.xyz, l.zxy); + vec3 i2 = max(g.xyz, l.zxy); + + vec3 x1 = x0 - i1 + C.xxx; + vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y + vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y + + // Permutations + i = mod289(i); + vec4 p = permute( + permute( + permute(i.z + vec4(0.0, i1.z, i2.z, 1.0)) + i.y + + vec4(0.0, i1.y, i2.y, 1.0)) + i.x + + vec4(0.0, i1.x, i2.x, 1.0)); + + // Gradients: 7x7 points over a square, mapped onto an octahedron. + // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) + float n_ = 0.142857142857; // 1.0/7.0 + vec3 ns = n_ * D.wyz - D.xzx; + + vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) + + vec4 x_ = floor(j * ns.z); + vec4 y_ = floor(j - 7.0 * x_); // mod(j,N) + + vec4 x = x_ * ns.x + ns.yyyy; + vec4 y = y_ * ns.x + ns.yyyy; + vec4 h = 1.0 - abs(x) - abs(y); + + vec4 b0 = vec4(x.xy, y.xy); + vec4 b1 = vec4(x.zw, y.zw); + + //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; + //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; + vec4 s0 = floor(b0) * 2.0 + 1.0; + vec4 s1 = floor(b1) * 2.0 + 1.0; + vec4 sh = -step(h, vec4(0.0)); + + vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; + vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww; + + vec3 p0 = vec3(a0.xy, h.x); + vec3 p1 = vec3(a0.zw, h.y); + vec3 p2 = vec3(a1.xy, h.z); + vec3 p3 = vec3(a1.zw, h.w); + + //Normalise gradients + vec4 norm = taylorInvSqrt( + vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + + // Mix final noise value + vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), + 0.0); + m = m * m; + return 42.0 + * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))); +} + +float snoise(vec2 v) { + const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 + 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) + -0.577350269189626, // -1.0 + 2.0 * C.x + 0.024390243902439); // 1.0 / 41.0 + // First corner + vec2 i = floor(v + dot(v, C.yy)); + vec2 x0 = v - i + dot(i, C.xx); + + // Other corners + vec2 i1; + i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); + vec4 x12 = x0.xyxy + C.xxzz; + x12.xy -= i1; + + // Permutations + i = mod289(i); // Avoid truncation effects in permutation + vec3 p = permute( + permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0)); + + vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), + 0.0); + m = m * m; + m = m * m; + + // Gradients: 41 points uniformly over a line, mapped onto a diamond. + // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) + + vec3 x = 2.0 * fract(p * C.www) - 1.0; + vec3 h = abs(x) - 0.5; + vec3 ox = floor(x + 0.5); + vec3 a0 = x - ox; + + // Normalise gradients implicitly by scaling m + // Approximation of: m *= inversesqrt( a0*a0 + h*h ); + m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h); + + // Compute final noise value at P + vec3 g; + g.x = a0.x * x0.x + h.x * x0.y; + g.yz = a0.yz * x12.xz + h.yz * x12.yw; + return 130.0 * dot(m, g); +} + +// TODO add more uniforms +uniform float iGlobalTime; // shader playback time (in seconds) +uniform vec3 iWorldScale; // the dimensions of the object being rendered + +// TODO add support for textures +// TODO document available inputs other than the uniforms +// TODO provide world scale in addition to the untransformed position + +#define PROCEDURAL 1 + +//PROCEDURAL_VERSION +)SHADER"; diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index 0ea71e54e3..4d33c6f1c1 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -40,4 +40,4 @@ add_dependency_external_projects(oglplus) find_package(OGLPLUS REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${OGLPLUS_INCLUDE_DIRS}) -link_hifi_libraries(animation fbx shared gpu model render environment) +link_hifi_libraries(shared gpu gpu-networking procedural model render environment animation fbx) diff --git a/libraries/render-utils/src/TextureCache.h b/libraries/render-utils/src/TextureCache.h index eeb17f07b9..23ac11d7b0 100644 --- a/libraries/render-utils/src/TextureCache.h +++ b/libraries/render-utils/src/TextureCache.h @@ -1,171 +1,2 @@ -// -// TextureCache.h -// interface/src/renderer -// -// Created by Andrzej Kapolka on 8/6/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 -// - -#ifndef hifi_TextureCache_h -#define hifi_TextureCache_h - -#include -#include - -#include -#include -#include - -#include -#include - -namespace gpu { -class Batch; -} -class NetworkTexture; - -typedef QSharedPointer NetworkTexturePointer; - -enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, SPECULAR_TEXTURE, EMISSIVE_TEXTURE, SPLAT_TEXTURE, CUBE_TEXTURE }; - -/// Stores cached textures, including render-to-texture targets. -class TextureCache : public ResourceCache, public Dependency { - Q_OBJECT - SINGLETON_DEPENDENCY - -public: - /// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture - /// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and - /// the second, a set of random unit vectors to be used as noise gradients. - const gpu::TexturePointer& getPermutationNormalTexture(); - - /// Returns an opaque white texture (useful for a default). - const gpu::TexturePointer& getWhiteTexture(); - - /// Returns an opaque gray texture (useful for a default). - const gpu::TexturePointer& getGrayTexture(); - - /// Returns the a pale blue texture (useful for a normal map). - const gpu::TexturePointer& getBlueTexture(); - - /// Returns the a black texture (useful for a default). - const gpu::TexturePointer& getBlackTexture(); - - // Returns a map used to compress the normals through a fitting scale algorithm - const gpu::TexturePointer& getNormalFittingTexture(); - - /// Returns a texture version of an image file - static gpu::TexturePointer getImageTexture(const QString& path); - - /// Loads a texture from the specified URL. - NetworkTexturePointer getTexture(const QUrl& url, TextureType type = DEFAULT_TEXTURE, bool dilatable = false, - const QByteArray& content = QByteArray()); - -protected: - - virtual QSharedPointer createResource(const QUrl& url, - const QSharedPointer& fallback, bool delayLoad, const void* extra); - -private: - TextureCache(); - virtual ~TextureCache(); - friend class DilatableNetworkTexture; - - gpu::TexturePointer _permutationNormalTexture; - gpu::TexturePointer _whiteTexture; - gpu::TexturePointer _grayTexture; - gpu::TexturePointer _blueTexture; - gpu::TexturePointer _blackTexture; - gpu::TexturePointer _normalFittingTexture; - - QHash > _dilatableNetworkTextures; -}; - -/// A simple object wrapper for an OpenGL texture. -class Texture { -public: - friend class TextureCache; - friend class DilatableNetworkTexture; - Texture(); - ~Texture(); - - const gpu::TexturePointer& getGPUTexture() const { return _gpuTexture; } - -protected: - gpu::TexturePointer _gpuTexture; - -private: -}; - -/// A texture loaded from the network. - -class NetworkTexture : public Resource, public Texture { - Q_OBJECT - -public: - - NetworkTexture(const QUrl& url, TextureType type, const QByteArray& content); - - /// Checks whether it "looks like" this texture is translucent - /// (majority of pixels neither fully opaque or fully transparent). - bool isTranslucent() const { return _translucent; } - - /// Returns the lazily-computed average texture color. - const QColor& getAverageColor() const { return _averageColor; } - - int getOriginalWidth() const { return _originalWidth; } - int getOriginalHeight() const { return _originalHeight; } - int getWidth() const { return _width; } - int getHeight() const { return _height; } - TextureType getType() const { return _type; } -protected: - - virtual void downloadFinished(QNetworkReply* reply); - - Q_INVOKABLE void loadContent(const QByteArray& content); - // FIXME: This void* should be a gpu::Texture* but i cannot get it to work for now, moving on... - Q_INVOKABLE void setImage(const QImage& image, void* texture, bool translucent, const QColor& averageColor, int originalWidth, - int originalHeight); - - virtual void imageLoaded(const QImage& image); - - TextureType _type; - -private: - bool _translucent; - QColor _averageColor; - int _originalWidth; - int _originalHeight; - int _width; - int _height; -}; - -/// Caches derived, dilated textures. -class DilatableNetworkTexture : public NetworkTexture { - Q_OBJECT - -public: - - DilatableNetworkTexture(const QUrl& url, const QByteArray& content); - - /// Returns a pointer to a texture with the requested amount of dilation. - QSharedPointer getDilatedTexture(float dilation); - -protected: - - virtual void imageLoaded(const QImage& image); - virtual void reinsert(); - -private: - - QImage _image; - int _innerRadius; - int _outerRadius; - - QMap > _dilatedTextures; -}; - -#endif // hifi_TextureCache_h +// Compatibility +#include diff --git a/libraries/render-utils/src/simple.slf b/libraries/render-utils/src/simple.slf index 31d33a73e4..5901a72838 100644 --- a/libraries/render-utils/src/simple.slf +++ b/libraries/render-utils/src/simple.slf @@ -18,12 +18,39 @@ // the interpolated normal in vec3 _normal; in vec3 _color; +in vec2 _texCoord0; +in vec4 _position; +//PROCEDURAL_COMMON_BLOCK + +#line 1001 +//PROCEDURAL_BLOCK + +#line 2030 void main(void) { Material material = getMaterial(); - packDeferredFragment( - normalize(_normal.xyz), - glowIntensity, - _color.rgb, - DEFAULT_SPECULAR, DEFAULT_SHININESS); + vec3 normal = normalize(_normal.xyz); + vec3 diffuse = _color.rgb; + vec3 specular = DEFAULT_SPECULAR; + float shininess = DEFAULT_SHININESS; + float emissiveAmount = 0.0; + +#ifdef PROCEDURAL + +#ifdef PROCEDURAL_V1 + specular = getProceduralColor().rgb; + emissiveAmount = 1.0; +#else + emissiveAmount = getProceduralColors(diffuse, specular, shininess); +#endif + +#endif + + if (emissiveAmount > 0.0) { + packDeferredFragmentLightmap( + normal, glowIntensity, diffuse, specular, shininess, specular); + } else { + packDeferredFragment( + normal, glowIntensity, diffuse, specular, shininess); + } } diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 139b99e426..1acfb57829 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -7,4 +7,4 @@ add_dependency_external_projects(glm) find_package(GLM REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) -link_hifi_libraries(shared octree gpu model fbx entities animation audio physics) +link_hifi_libraries(shared networking octree gpu gpu-networking procedural model fbx entities animation audio physics) diff --git a/tests/gpu-test/CMakeLists.txt b/tests/gpu-test/CMakeLists.txt index abdbfc07f9..3d42364132 100644 --- a/tests/gpu-test/CMakeLists.txt +++ b/tests/gpu-test/CMakeLists.txt @@ -10,6 +10,6 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") #include_oglplus() # link in the shared libraries -link_hifi_libraries(render-utils gpu shared networking fbx model animation script-engine) +link_hifi_libraries(networking gpu gpu-networking procedural shared fbx model animation script-engine render-utils ) copy_dlls_beside_windows_executable() \ No newline at end of file From b8bf9a1104d1112f39eae8a632d8c90e1cff8295 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Sep 2015 14:51:51 -0700 Subject: [PATCH 541/549] fix OBJReader loading with URL --- libraries/fbx/src/OBJReader.cpp | 25 +++++++++----------- libraries/fbx/src/OBJReader.h | 6 ++--- libraries/render-utils/src/GeometryCache.cpp | 2 +- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 3eff3bdec5..1dfb7a4587 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -194,10 +194,10 @@ void OBJFace::addFrom(const OBJFace* face, int index) { // add using data from f } bool OBJReader::isValidTexture(const QByteArray &filename) { - if (!_url) { + if (_url.isEmpty()) { return false; } - QUrl candidateUrl = _url->resolved(QUrl(filename)); + QUrl candidateUrl = _url.resolved(QUrl(filename)); QNetworkReply *netReply = request(candidateUrl, true); bool isValid = netReply->isFinished() && (netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200); netReply->deleteLater(); @@ -330,7 +330,7 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi } QByteArray groupName = tokenizer.getDatum(); currentGroup = groupName; - } else if (token == "mtllib" && _url) { + } else if (token == "mtllib" && !_url.isEmpty()) { if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } @@ -340,7 +340,7 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi } librariesSeen[libraryName] = true; // Throw away any path part of libraryName, and merge against original url. - QUrl libraryUrl = _url->resolved(QUrl(libraryName).fileName()); + QUrl libraryUrl = _url.resolved(QUrl(libraryName).fileName()); #ifdef WANT_DEBUG qCDebug(modelformat) << "OBJ Reader new library:" << libraryName << " at:" << libraryUrl; #endif @@ -415,17 +415,14 @@ done: } -FBXGeometry* OBJReader::readOBJ(const QByteArray& model, const QVariantHash& mapping) { - QBuffer buffer(const_cast(&model)); +FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, const QUrl& url) { + + QBuffer buffer { &model }; buffer.open(QIODevice::ReadOnly); - return readOBJ(&buffer, mapping, nullptr); -} - - -FBXGeometry* OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, QUrl* url) { + FBXGeometry* geometryPtr = new FBXGeometry(); FBXGeometry& geometry = *geometryPtr; - OBJTokenizer tokenizer(device); + OBJTokenizer tokenizer { &buffer }; float scaleGuess = 1.0f; _url = url; @@ -463,8 +460,8 @@ FBXGeometry* OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, // Some .obj files use the convention that a group with uv coordinates that doesn't define a material, should use // a texture with the same basename as the .obj file. - if (url) { - QString filename = url->fileName(); + if (!url.isEmpty()) { + QString filename = url.fileName(); int extIndex = filename.lastIndexOf('.'); // by construction, this does not fail QString basename = filename.remove(extIndex + 1, sizeof("obj")); OBJMaterial& preDefinedMaterial = materials[SMART_DEFAULT_MATERIAL_NAME]; diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index df4c88553e..0e59c5ad8a 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -71,10 +71,10 @@ public: QHash materials; QNetworkReply* request(QUrl& url, bool isTest); - FBXGeometry* readOBJ(const QByteArray& model, const QVariantHash& mapping); - FBXGeometry* readOBJ(QIODevice* device, const QVariantHash& mapping, QUrl* url); + FBXGeometry* readOBJ(QByteArray& model, const QVariantHash& mapping, const QUrl& url = QUrl()); + private: - QUrl* _url = nullptr; + QUrl _url; QHash librariesSeen; bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess); diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index db7c25012c..a58df10cc6 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1703,7 +1703,7 @@ void GeometryReader::run() { const float lightmapLevel = 1.0f; fbxgeo = readFBX(_data, _mapping, _url.path(), grabLightmaps, lightmapLevel); } else if (_url.path().toLower().endsWith(".obj")) { - fbxgeo = OBJReader().readOBJ(_data, _mapping); + fbxgeo = OBJReader().readOBJ(_data, _mapping, _url); } else { QString errorStr("usupported format"); emit onError(NetworkGeometry::ModelParseError, errorStr); From a6395e9438ed18e5bb63908eadd52443534f4a5e Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 8 Sep 2015 14:54:22 -0700 Subject: [PATCH 542/549] add a boom box entity script --- examples/entityScripts/boombox.js | 124 ++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 examples/entityScripts/boombox.js diff --git a/examples/entityScripts/boombox.js b/examples/entityScripts/boombox.js new file mode 100644 index 0000000000..dab83038b7 --- /dev/null +++ b/examples/entityScripts/boombox.js @@ -0,0 +1,124 @@ +// +// boombox.js +// examples/entityScripts +// +// Created by Brad Hefta-Gaub on 9/3/15. +// Copyright 2015 High Fidelity, Inc. +// +// This is an example of an entity script which when assigned to an entity, will detect when the entity is being touched by the avatars hands +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { + Script.include("../libraries/utils.js"); + + var _this; + var BOOMBOX_USER_DATA_KEY = "boombox"; + + // this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember + // our this object, so we can access it in cases where we're called without a this (like in the case of various global signals) + DetectTouched = function() { + _this = this; + _this.beingTouched = false; + _this.isPlaying = false; + _this.injector = null; + }; + + DetectTouched.prototype = { + + // update() will be called regulary, because we've hooked the update signal in our preload() function. + // we will check the avatars hand positions and if either hand is in our bounding box, we will notice that + update: function() { + // because the update() signal doesn't have a valid this, we need to use our memorized _this to access our entityID + var entityID = _this.entityID; + + var leftHandPosition = MyAvatar.getLeftPalmPosition(); + var rightHandPosition = MyAvatar.getRightPalmPosition(); + var props = Entities.getEntityProperties(entityID); + var entityMinPoint = props.boundingBox.brn; + var entityMaxPoint = props.boundingBox.tfl; + + // this is our assumed boombox data if it's not known + var defaultBoomboxData = { isPlaying: false, avatarID: null }; + + // this handy function getEntityCustomData() is available in utils.js and it will return just the specific section + // of user data we asked for. If it's not available it returns our default data. + var boomboxData = getEntityCustomData(BOOMBOX_USER_DATA_KEY, entityID, defaultBoomboxData); + + // Only allow interaction if no one else is interacting with the boombox or if we are... + if (!boomboxData.isPlaying || boomboxData.avatarID == MyAvatar.sessionUUID) { + + // If we were not previously being touched, and we just got touched, then we do our touching action. + if (pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint) || pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint)) { + + if (!_this.beingTouched) { + print("I was just touched..."); + + // remember we're being grabbed so we can detect being released + _this.beingTouched = true; + + // determine what to do based on if we are currently playing + if (!_this.isPlaying) { + // if we are not currently playing, then start playing. + print("Start playing..."); + + _this.isPlaying = true; + + if (_this.injector == null) { + _this.injector = Audio.playSound(_this.song, { + position: props.position, // position of boombox entity + volume: 0.5, + loop: true + }); + } else { + _this.injector.restart(); + } + setEntityCustomData(BOOMBOX_USER_DATA_KEY, entityID, { isPlaying: true, avatarID: MyAvatar.sessionUUID }); + + } else { + // if we are currently playing, then stop playing + print("Stop playing..."); + _this.isPlaying = false; + _this.injector.stop(); + + setEntityCustomData(BOOMBOX_USER_DATA_KEY, entityID, { isPlaying: false, avatarID: null }); + } // endif (!isPlaying) + + } // endif !beingTouched + } else if (_this.beingTouched) { + // if we are not being grabbed, and we previously were, then we were just released, remember that + // and print out a message + _this.beingTouched = false; + print("I'm am no longer being touched..."); + } + + } else { + // end if for -- only interact if no one else is... + print("someone else is playing the boombox..."); + } + }, + + // preload() will be called when the entity has become visible (or known) to the interface + // it gives us a chance to set our local JavaScript object up. In this case it means: + // * remembering our entityID, so we can access it in cases where we're called without an entityID + // * connecting to the update signal so we can check our grabbed state + preload: function(entityID) { + print("preload!"); + this.entityID = entityID; + Script.update.connect(this.update); + this.song = SoundCache.getSound("http://hifi-public.s3.amazonaws.com/ryan/freaks7.wav"); + }, + + // unload() will be called when our entity is no longer available. It may be because we were deleted, + // or because we've left the domain or quit the application. In all cases we want to unhook our connection + // to the update signal + unload: function(entityID) { + Script.update.disconnect(this.update); + }, + }; + + // entity scripts always need to return a newly constructed object of our type + return new DetectTouched(); +}) From 255f896f7be9e97d3009b0deb51fc36070f23b32 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Sep 2015 15:21:34 -0700 Subject: [PATCH 543/549] remove extra cmake debug --- cmake/macros/AutoScribeShader.cmake | 1 - cmake/macros/SetupHifiLibrary.cmake | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/cmake/macros/AutoScribeShader.cmake b/cmake/macros/AutoScribeShader.cmake index 90a304ac50..6dc4899d29 100755 --- a/cmake/macros/AutoScribeShader.cmake +++ b/cmake/macros/AutoScribeShader.cmake @@ -73,7 +73,6 @@ endfunction() macro(AUTOSCRIBE_SHADER_LIB) - message("Autoscribe running for ${TARGET_NAME}") file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}") foreach(HIFI_LIBRARY ${ARGN}) #if (NOT TARGET ${HIFI_LIBRARY}) diff --git a/cmake/macros/SetupHifiLibrary.cmake b/cmake/macros/SetupHifiLibrary.cmake index 2e943f9b12..ccb5ca2484 100644 --- a/cmake/macros/SetupHifiLibrary.cmake +++ b/cmake/macros/SetupHifiLibrary.cmake @@ -10,8 +10,7 @@ macro(SETUP_HIFI_LIBRARY) project(${TARGET_NAME}) - message("Setting up project ${TARGET_NAME}") - + # grab the implemenation and header files file(GLOB_RECURSE LIB_SRCS "src/*.h" "src/*.cpp" "src/*.c") list(APPEND ${TARGET_NAME}_SRCS ${LIB_SRCS}) From e1a31f4dbe61ea6892b20a6bb2783b30e3feb271 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Sep 2015 15:23:26 -0700 Subject: [PATCH 544/549] put back TextureCache headers --- libraries/gpu-networking/src/gpu-networking/TextureCache.cpp | 3 +++ libraries/gpu-networking/src/gpu-networking/TextureCache.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/libraries/gpu-networking/src/gpu-networking/TextureCache.cpp b/libraries/gpu-networking/src/gpu-networking/TextureCache.cpp index ea0abb6af3..6063ff6fa4 100644 --- a/libraries/gpu-networking/src/gpu-networking/TextureCache.cpp +++ b/libraries/gpu-networking/src/gpu-networking/TextureCache.cpp @@ -1,4 +1,7 @@ // +// TextureCache.cpp +// libraries/gpu-networking/src +// // Created by Andrzej Kapolka on 8/6/13. // Copyright 2013 High Fidelity, Inc. // diff --git a/libraries/gpu-networking/src/gpu-networking/TextureCache.h b/libraries/gpu-networking/src/gpu-networking/TextureCache.h index 5c5d992a53..4e104ab783 100644 --- a/libraries/gpu-networking/src/gpu-networking/TextureCache.h +++ b/libraries/gpu-networking/src/gpu-networking/TextureCache.h @@ -1,4 +1,7 @@ // +// TextureCache.h +// libraries/gpu-networking/src +// // Created by Andrzej Kapolka on 8/6/13. // Copyright 2013 High Fidelity, Inc. // From c670c9a0d55af846826eed5017f0699ed75e5c27 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Sep 2015 15:31:37 -0700 Subject: [PATCH 545/549] fix for AnimNodeLoader use of Resource loaded --- libraries/animation/src/AnimNodeLoader.cpp | 8 ++++---- libraries/animation/src/AnimNodeLoader.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/animation/src/AnimNodeLoader.cpp b/libraries/animation/src/AnimNodeLoader.cpp index 5f0260db6d..866f443005 100644 --- a/libraries/animation/src/AnimNodeLoader.cpp +++ b/libraries/animation/src/AnimNodeLoader.cpp @@ -381,8 +381,8 @@ AnimNodeLoader::AnimNodeLoader(const QUrl& url) : _resource(nullptr) { _resource = new Resource(url); - connect(_resource, SIGNAL(loaded(QNetworkReply&)), SLOT(onRequestDone(QNetworkReply&))); - connect(_resource, SIGNAL(failed(QNetworkReply::NetworkError)), SLOT(onRequestError(QNetworkReply::NetworkError))); + connect(_resource, &Resource::loaded, this, &AnimNodeLoader::onRequestDone); + connect(_resource, &Resource::failed, this, &AnimNodeLoader::onRequestError); } AnimNode::Pointer AnimNodeLoader::load(const QByteArray& contents, const QUrl& jsonUrl) { @@ -420,8 +420,8 @@ AnimNode::Pointer AnimNodeLoader::load(const QByteArray& contents, const QUrl& j return loadNode(rootVal.toObject(), jsonUrl); } -void AnimNodeLoader::onRequestDone(QNetworkReply& request) { - auto node = load(request.readAll(), _url); +void AnimNodeLoader::onRequestDone(const QByteArray& data) { + auto node = load(data, _url); if (node) { emit success(node); } else { diff --git a/libraries/animation/src/AnimNodeLoader.h b/libraries/animation/src/AnimNodeLoader.h index 71b5552879..713d980f06 100644 --- a/libraries/animation/src/AnimNodeLoader.h +++ b/libraries/animation/src/AnimNodeLoader.h @@ -36,7 +36,7 @@ protected: static AnimNode::Pointer load(const QByteArray& contents, const QUrl& jsonUrl); protected slots: - void onRequestDone(QNetworkReply& request); + void onRequestDone(const QByteArray& data); void onRequestError(QNetworkReply::NetworkError error); protected: From 572b120bf0af9c1ccdc20cca487f9024ae790083 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 8 Sep 2015 15:57:31 -0700 Subject: [PATCH 546/549] removed print statements --- examples/controllers/handControllerGrab.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 87b21602c5..2ebea75abc 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -138,7 +138,6 @@ controller.prototype.checkForIntersections = function(origin, direction) { if (intersection.intersects && intersection.properties.collisionsWillMove === 1) { var handPosition = Controller.getSpatialControlPosition(this.palm); this.distanceToEntity = Vec3.distance(handPosition, intersection.properties.position); - print("distance to entity " + JSON.stringify(this.distanceToEntity)); Entities.editEntity(this.pointer, { linePoints: [ ZERO_VEC, @@ -191,7 +190,6 @@ controller.prototype.hidePointer = function() { controller.prototype.letGo = function() { if (this.grabbedEntity && this.actionID) { - print("DELETE ACTION") this.deactivateEntity(this.grabbedEntity); Entities.deleteAction(this.grabbedEntity, this.actionID); } From 8c4d7b98fd0d84a55454c58350eefbd38485c6fb Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 8 Sep 2015 16:01:07 -0700 Subject: [PATCH 547/549] fix header comment --- examples/entityScripts/boombox.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/entityScripts/boombox.js b/examples/entityScripts/boombox.js index dab83038b7..7056250997 100644 --- a/examples/entityScripts/boombox.js +++ b/examples/entityScripts/boombox.js @@ -5,7 +5,8 @@ // Created by Brad Hefta-Gaub on 9/3/15. // Copyright 2015 High Fidelity, Inc. // -// This is an example of an entity script which when assigned to an entity, will detect when the entity is being touched by the avatars hands +// This is an example of a boom box entity script which when assigned to an entity, will detect when the entity is being touched by the avatars hands +// and start to play a boom box song // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html From ca6c413221d06d489920adfae48fa4bc2a368c53 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 8 Sep 2015 16:02:10 -0700 Subject: [PATCH 548/549] tweak THE_SONG --- examples/entityScripts/boombox.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/entityScripts/boombox.js b/examples/entityScripts/boombox.js index 7056250997..d1d18ec615 100644 --- a/examples/entityScripts/boombox.js +++ b/examples/entityScripts/boombox.js @@ -17,6 +17,7 @@ var _this; var BOOMBOX_USER_DATA_KEY = "boombox"; + var THE_SONG = "http://hifi-public.s3.amazonaws.com/ryan/freaks7.wav"; // this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember // our this object, so we can access it in cases where we're called without a this (like in the case of various global signals) @@ -109,7 +110,7 @@ print("preload!"); this.entityID = entityID; Script.update.connect(this.update); - this.song = SoundCache.getSound("http://hifi-public.s3.amazonaws.com/ryan/freaks7.wav"); + this.song = SoundCache.getSound(THE_SONG); }, // unload() will be called when our entity is no longer available. It may be because we were deleted, From a3feff1bd424e74a390d06f081c6d3dca52dfdbf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Sep 2015 16:19:15 -0700 Subject: [PATCH 549/549] put DomainServerConnectionToken back in NON_SOURCED --- libraries/networking/src/udt/PacketHeaders.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 819a65dc26..7e00acfdc0 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -25,7 +25,7 @@ const QSet NON_SOURCED_PACKETS = QSet() << PacketType::DomainServerRequireDTLS << PacketType::DomainConnectRequest << PacketType::DomainList << PacketType::DomainConnectionDenied << PacketType::DomainServerPathQuery << PacketType::DomainServerPathResponse - << PacketType::DomainServerAddedNode + << PacketType::DomainServerAddedNode << PacketType::DomainServerConnectionToken << PacketType::DomainSettingsRequest << PacketType::DomainSettings << PacketType::ICEServerPeerInformation << PacketType::ICEServerQuery << PacketType::ICEServerHeartbeat << PacketType::ICEPing << PacketType::ICEPingReply @@ -90,7 +90,7 @@ QString nameForPacketType(PacketType packetType) { PACKET_TYPE_NAME_LOOKUP(PacketType::ICEPingReply); PACKET_TYPE_NAME_LOOKUP(PacketType::EntityAdd); PACKET_TYPE_NAME_LOOKUP(PacketType::EntityEdit); - PACKET_TYPE_NAME_LOOKUP(PacketType::DomainServerConnectionToken); + PACKET_TYPE_NAME_LOOKUP(PacketType::DomainServerConnectionToken); default: return QString("Type: ") + QString::number((int)packetType); }