mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 02:03:11 +02:00
Merge branch 'master' into fix_spinbox
This commit is contained in:
commit
2e44220b80
51 changed files with 1245 additions and 488 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -91,3 +91,6 @@ interface/compiledResources
|
||||||
|
|
||||||
# GPUCache
|
# GPUCache
|
||||||
interface/resources/GPUCache/*
|
interface/resources/GPUCache/*
|
||||||
|
|
||||||
|
# package lock file for JSDoc tool
|
||||||
|
tools/jsdoc/package-lock.json
|
||||||
|
|
|
@ -380,7 +380,7 @@ void Agent::executeScript() {
|
||||||
|
|
||||||
using namespace recording;
|
using namespace recording;
|
||||||
static const FrameType AVATAR_FRAME_TYPE = Frame::registerFrameType(AvatarData::FRAME_NAME);
|
static const FrameType AVATAR_FRAME_TYPE = Frame::registerFrameType(AvatarData::FRAME_NAME);
|
||||||
Frame::registerFrameHandler(AVATAR_FRAME_TYPE, [this, scriptedAvatar](Frame::ConstPointer frame) {
|
Frame::registerFrameHandler(AVATAR_FRAME_TYPE, [scriptedAvatar](Frame::ConstPointer frame) {
|
||||||
|
|
||||||
auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>();
|
auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>();
|
||||||
bool useFrameSkeleton = recordingInterface->getPlayerUseSkeletonModel();
|
bool useFrameSkeleton = recordingInterface->getPlayerUseSkeletonModel();
|
||||||
|
|
|
@ -901,7 +901,7 @@ void AssetServer::handleAssetUpload(QSharedPointer<ReceivedMessage> message, Sha
|
||||||
|
|
||||||
|
|
||||||
if (canWriteToAssetServer) {
|
if (canWriteToAssetServer) {
|
||||||
qCDebug(asset_server) << "Starting an UploadAssetTask for upload from" << uuidStringWithoutCurlyBraces(message->getSourceID());
|
qCDebug(asset_server) << "Starting an UploadAssetTask for upload from" << message->getSourceID();
|
||||||
|
|
||||||
auto task = new UploadAssetTask(message, senderNode, _filesDirectory, _filesizeLimit);
|
auto task = new UploadAssetTask(message, senderNode, _filesDirectory, _filesizeLimit);
|
||||||
_transferTaskPool.start(task);
|
_transferTaskPool.start(task);
|
||||||
|
|
|
@ -117,12 +117,13 @@ void AudioMixer::queueAudioPacket(QSharedPointer<ReceivedMessage> message, Share
|
||||||
void AudioMixer::queueReplicatedAudioPacket(QSharedPointer<ReceivedMessage> message) {
|
void AudioMixer::queueReplicatedAudioPacket(QSharedPointer<ReceivedMessage> message) {
|
||||||
// make sure we have a replicated node for the original sender of the packet
|
// make sure we have a replicated node for the original sender of the packet
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
QUuid nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
// Node ID is now part of user data, since replicated audio packets are non-sourced.
|
||||||
|
QUuid nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
||||||
|
|
||||||
auto replicatedNode = nodeList->addOrUpdateNode(nodeID, NodeType::Agent,
|
auto replicatedNode = nodeList->addOrUpdateNode(nodeID, NodeType::Agent,
|
||||||
message->getSenderSockAddr(), message->getSenderSockAddr(),
|
message->getSenderSockAddr(), message->getSenderSockAddr(),
|
||||||
true, true);
|
Node::NULL_LOCAL_ID, true, true);
|
||||||
replicatedNode->setLastHeardMicrostamp(usecTimestampNow());
|
replicatedNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||||
|
|
||||||
// construct a "fake" audio received message from the byte array and packet list information
|
// construct a "fake" audio received message from the byte array and packet list information
|
||||||
|
@ -136,7 +137,7 @@ void AudioMixer::queueReplicatedAudioPacket(QSharedPointer<ReceivedMessage> mess
|
||||||
|
|
||||||
auto replicatedMessage = QSharedPointer<ReceivedMessage>::create(audioData, rewrittenType,
|
auto replicatedMessage = QSharedPointer<ReceivedMessage>::create(audioData, rewrittenType,
|
||||||
versionForPacketType(rewrittenType),
|
versionForPacketType(rewrittenType),
|
||||||
message->getSenderSockAddr(), nodeID);
|
message->getSenderSockAddr(), Node::NULL_LOCAL_ID);
|
||||||
|
|
||||||
getOrCreateClientData(replicatedNode.data())->queuePacket(replicatedMessage, replicatedNode);
|
getOrCreateClientData(replicatedNode.data())->queuePacket(replicatedMessage, replicatedNode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ SharedNodePointer addOrUpdateReplicatedNode(const QUuid& nodeID, const HifiSockA
|
||||||
auto replicatedNode = DependencyManager::get<NodeList>()->addOrUpdateNode(nodeID, NodeType::Agent,
|
auto replicatedNode = DependencyManager::get<NodeList>()->addOrUpdateNode(nodeID, NodeType::Agent,
|
||||||
senderSockAddr,
|
senderSockAddr,
|
||||||
senderSockAddr,
|
senderSockAddr,
|
||||||
true, true);
|
Node::NULL_LOCAL_ID, true, true);
|
||||||
|
|
||||||
replicatedNode->setLastHeardMicrostamp(usecTimestampNow());
|
replicatedNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||||
|
|
||||||
|
@ -112,8 +112,8 @@ void AvatarMixer::handleReplicatedPacket(QSharedPointer<ReceivedMessage> message
|
||||||
void AvatarMixer::handleReplicatedBulkAvatarPacket(QSharedPointer<ReceivedMessage> message) {
|
void AvatarMixer::handleReplicatedBulkAvatarPacket(QSharedPointer<ReceivedMessage> message) {
|
||||||
while (message->getBytesLeftToRead()) {
|
while (message->getBytesLeftToRead()) {
|
||||||
// first, grab the node ID for this replicated avatar
|
// first, grab the node ID for this replicated avatar
|
||||||
|
// Node ID is now part of user data, since ReplicatedBulkAvatarPacket is non-sourced.
|
||||||
auto nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
auto nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
||||||
|
|
||||||
// make sure we have an upstream replicated node that matches
|
// make sure we have an upstream replicated node that matches
|
||||||
auto replicatedNode = addOrUpdateReplicatedNode(nodeID, message->getSenderSockAddr());
|
auto replicatedNode = addOrUpdateReplicatedNode(nodeID, message->getSenderSockAddr());
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ void AvatarMixer::handleReplicatedBulkAvatarPacket(QSharedPointer<ReceivedMessag
|
||||||
// construct a "fake" avatar data received message from the byte array and packet list information
|
// construct a "fake" avatar data received message from the byte array and packet list information
|
||||||
auto replicatedMessage = QSharedPointer<ReceivedMessage>::create(avatarByteArray, PacketType::AvatarData,
|
auto replicatedMessage = QSharedPointer<ReceivedMessage>::create(avatarByteArray, PacketType::AvatarData,
|
||||||
versionForPacketType(PacketType::AvatarData),
|
versionForPacketType(PacketType::AvatarData),
|
||||||
message->getSenderSockAddr(), nodeID);
|
message->getSenderSockAddr(), Node::NULL_LOCAL_ID);
|
||||||
|
|
||||||
// queue up the replicated avatar data with the client data for the replicated node
|
// queue up the replicated avatar data with the client data for the replicated node
|
||||||
auto start = usecTimestampNow();
|
auto start = usecTimestampNow();
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
#include <AccountManager.h>
|
#include <AccountManager.h>
|
||||||
#include <Assignment.h>
|
#include <Assignment.h>
|
||||||
|
@ -26,7 +27,7 @@ using SharedAssignmentPointer = QSharedPointer<Assignment>;
|
||||||
DomainGatekeeper::DomainGatekeeper(DomainServer* server) :
|
DomainGatekeeper::DomainGatekeeper(DomainServer* server) :
|
||||||
_server(server)
|
_server(server)
|
||||||
{
|
{
|
||||||
|
initLocalIDManagement();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainGatekeeper::addPendingAssignedNode(const QUuid& nodeUUID, const QUuid& assignmentUUID,
|
void DomainGatekeeper::addPendingAssignedNode(const QUuid& nodeUUID, const QUuid& assignmentUUID,
|
||||||
|
@ -451,11 +452,12 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
|
||||||
return SharedNodePointer();
|
return SharedNodePointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid hintNodeID;
|
QUuid existingNodeID;
|
||||||
|
|
||||||
// in case this is a node that's failing to connect
|
// in case this is a node that's failing to connect
|
||||||
// double check we don't have the same node whose sockets match exactly already in the list
|
// double check we don't have the same node whose sockets match exactly already in the list
|
||||||
limitedNodeList->eachNodeBreakable([&](const SharedNodePointer& node){
|
limitedNodeList->eachNodeBreakable([&](const SharedNodePointer& node){
|
||||||
|
|
||||||
if (node->getPublicSocket() == nodeConnection.publicSockAddr && node->getLocalSocket() == nodeConnection.localSockAddr) {
|
if (node->getPublicSocket() == nodeConnection.publicSockAddr && node->getLocalSocket() == nodeConnection.localSockAddr) {
|
||||||
// we have a node that already has these exact sockets - this can occur if a node
|
// we have a node that already has these exact sockets - this can occur if a node
|
||||||
// is failing to connect to the domain
|
// is failing to connect to the domain
|
||||||
|
@ -465,15 +467,20 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
|
||||||
auto existingNodeData = static_cast<DomainServerNodeData*>(node->getLinkedData());
|
auto existingNodeData = static_cast<DomainServerNodeData*>(node->getLinkedData());
|
||||||
|
|
||||||
if (existingNodeData->getUsername() == username) {
|
if (existingNodeData->getUsername() == username) {
|
||||||
hintNodeID = node->getUUID();
|
qDebug() << "Deleting existing connection from same sockaddr: " << node->getUUID();
|
||||||
|
existingNodeID = node->getUUID();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!existingNodeID.isNull()) {
|
||||||
|
limitedNodeList->killNodeWithUUID(existingNodeID);
|
||||||
|
}
|
||||||
|
|
||||||
// add the connecting node (or re-use the matched one from eachNodeBreakable above)
|
// add the connecting node (or re-use the matched one from eachNodeBreakable above)
|
||||||
SharedNodePointer newNode = addVerifiedNodeFromConnectRequest(nodeConnection, hintNodeID);
|
SharedNodePointer newNode = addVerifiedNodeFromConnectRequest(nodeConnection);
|
||||||
|
|
||||||
// set the edit rights for this user
|
// set the edit rights for this user
|
||||||
newNode->setPermissions(userPerms);
|
newNode->setPermissions(userPerms);
|
||||||
|
@ -523,8 +530,10 @@ SharedNodePointer DomainGatekeeper::addVerifiedNodeFromConnectRequest(const Node
|
||||||
|
|
||||||
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
|
|
||||||
|
Node::LocalID newLocalID = findOrCreateLocalID(nodeID);
|
||||||
SharedNodePointer newNode = limitedNodeList->addOrUpdateNode(nodeID, nodeConnection.nodeType,
|
SharedNodePointer newNode = limitedNodeList->addOrUpdateNode(nodeID, nodeConnection.nodeType,
|
||||||
nodeConnection.publicSockAddr, nodeConnection.localSockAddr);
|
nodeConnection.publicSockAddr, nodeConnection.localSockAddr,
|
||||||
|
newLocalID);
|
||||||
|
|
||||||
// So that we can send messages to this node at will - we need to activate the correct socket on this node now
|
// 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);
|
newNode->activateMatchingOrNewSymmetricSocket(discoveredSocket);
|
||||||
|
@ -1014,3 +1023,31 @@ void DomainGatekeeper::refreshGroupsCache() {
|
||||||
_server->_settingsManager.debugDumpGroupsState();
|
_server->_settingsManager.debugDumpGroupsState();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DomainGatekeeper::initLocalIDManagement() {
|
||||||
|
std::uniform_int_distribution<quint16> sixteenBitRand;
|
||||||
|
std::random_device randomDevice;
|
||||||
|
std::default_random_engine engine { randomDevice() };
|
||||||
|
_currentLocalID = sixteenBitRand(engine);
|
||||||
|
// Ensure increment is odd.
|
||||||
|
_idIncrement = sixteenBitRand(engine) | 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node::LocalID DomainGatekeeper::findOrCreateLocalID(const QUuid& uuid) {
|
||||||
|
auto existingLocalIDIt = _uuidToLocalID.find(uuid);
|
||||||
|
if (existingLocalIDIt != _uuidToLocalID.end()) {
|
||||||
|
return existingLocalIDIt->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(_localIDs.size() < std::numeric_limits<LocalIDs::value_type>::max() - 2);
|
||||||
|
|
||||||
|
Node::LocalID newLocalID;
|
||||||
|
do {
|
||||||
|
newLocalID = _currentLocalID;
|
||||||
|
_currentLocalID += _idIncrement;
|
||||||
|
} while (newLocalID == Node::NULL_LOCAL_ID || _localIDs.find(newLocalID) != _localIDs.end());
|
||||||
|
|
||||||
|
_uuidToLocalID.emplace(uuid, newLocalID);
|
||||||
|
_localIDs.insert(newLocalID);
|
||||||
|
return newLocalID;
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#define hifi_DomainGatekeeper_h
|
#define hifi_DomainGatekeeper_h
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
#include <QtNetwork/QNetworkReply>
|
#include <QtNetwork/QNetworkReply>
|
||||||
|
@ -41,6 +42,8 @@ public:
|
||||||
|
|
||||||
void removeICEPeer(const QUuid& peerUUID) { _icePeers.remove(peerUUID); }
|
void removeICEPeer(const QUuid& peerUUID) { _icePeers.remove(peerUUID); }
|
||||||
|
|
||||||
|
Node::LocalID findOrCreateLocalID(const QUuid& uuid);
|
||||||
|
|
||||||
static void sendProtocolMismatchConnectionDenial(const HifiSockAddr& senderSockAddr);
|
static void sendProtocolMismatchConnectionDenial(const HifiSockAddr& senderSockAddr);
|
||||||
public slots:
|
public slots:
|
||||||
void processConnectRequestPacket(QSharedPointer<ReceivedMessage> message);
|
void processConnectRequestPacket(QSharedPointer<ReceivedMessage> message);
|
||||||
|
@ -120,6 +123,16 @@ private:
|
||||||
void getGroupMemberships(const QString& username);
|
void getGroupMemberships(const QString& username);
|
||||||
// void getIsGroupMember(const QString& username, const QUuid groupID);
|
// void getIsGroupMember(const QString& username, const QUuid groupID);
|
||||||
void getDomainOwnerFriendsList();
|
void getDomainOwnerFriendsList();
|
||||||
|
|
||||||
|
// Local ID management.
|
||||||
|
void initLocalIDManagement();
|
||||||
|
using UUIDToLocalID = std::unordered_map<QUuid, Node::LocalID> ;
|
||||||
|
using LocalIDs = std::unordered_set<Node::LocalID>;
|
||||||
|
LocalIDs _localIDs;
|
||||||
|
UUIDToLocalID _uuidToLocalID;
|
||||||
|
|
||||||
|
Node::LocalID _currentLocalID;
|
||||||
|
Node::LocalID _idIncrement;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -593,8 +593,8 @@ bool DomainServer::isPacketVerified(const udt::Packet& packet) {
|
||||||
|
|
||||||
if (!PacketTypeEnum::getNonSourcedPackets().contains(headerType)) {
|
if (!PacketTypeEnum::getNonSourcedPackets().contains(headerType)) {
|
||||||
// this is a sourced packet - first check if we have a node that matches
|
// this is a sourced packet - first check if we have a node that matches
|
||||||
QUuid sourceID = NLPacket::sourceIDInHeader(packet);
|
Node::LocalID localSourceID = NLPacket::sourceIDInHeader(packet);
|
||||||
SharedNodePointer sourceNode = nodeList->nodeWithUUID(sourceID);
|
SharedNodePointer sourceNode = nodeList->nodeWithLocalID(localSourceID);
|
||||||
|
|
||||||
if (sourceNode) {
|
if (sourceNode) {
|
||||||
// unverified DS packets (due to a lack of connection secret between DS + node)
|
// unverified DS packets (due to a lack of connection secret between DS + node)
|
||||||
|
@ -612,14 +612,12 @@ bool DomainServer::isPacketVerified(const udt::Packet& packet) {
|
||||||
return nodeList->isPacketVerifiedWithSource(packet, sourceNode.data());
|
return nodeList->isPacketVerifiedWithSource(packet, sourceNode.data());
|
||||||
} else {
|
} else {
|
||||||
HIFI_FDEBUG("Packet of type" << headerType
|
HIFI_FDEBUG("Packet of type" << headerType
|
||||||
<< "received from unmatched IP for UUID" << uuidStringWithoutCurlyBraces(sourceID));
|
<< "received from unmatched IP for UUID" << uuidStringWithoutCurlyBraces(sourceNode->getUUID()));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
HIFI_FDEBUG("Packet of type" << headerType
|
HIFI_FDEBUG("Packet of type" << headerType
|
||||||
<< "received from unknown node with UUID" << uuidStringWithoutCurlyBraces(sourceID));
|
<< "received from unknown node with UUID" << uuidStringWithoutCurlyBraces(sourceNode->getUUID()));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -683,6 +681,10 @@ void DomainServer::setupNodeListAndAssignments() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create our own short session ID.
|
||||||
|
Node::LocalID serverSessionLocalID = _gatekeeper.findOrCreateLocalID(nodeList->getSessionUUID());
|
||||||
|
nodeList->setSessionLocalID(serverSessionLocalID);
|
||||||
|
|
||||||
if (isMetaverseDomain) {
|
if (isMetaverseDomain) {
|
||||||
// see if we think we're a temp domain (we have an API key) or a full domain
|
// see if we think we're a temp domain (we have an API key) or a full domain
|
||||||
const auto& temporaryDomainKey = DependencyManager::get<AccountManager>()->getTemporaryDomainKey(getID());
|
const auto& temporaryDomainKey = DependencyManager::get<AccountManager>()->getTemporaryDomainKey(getID());
|
||||||
|
@ -1112,7 +1114,8 @@ void DomainServer::handleConnectedNode(SharedNodePointer newNode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const HifiSockAddr &senderSockAddr) {
|
void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const HifiSockAddr &senderSockAddr) {
|
||||||
const int NUM_DOMAIN_LIST_EXTENDED_HEADER_BYTES = NUM_BYTES_RFC4122_UUID + NUM_BYTES_RFC4122_UUID + 2;
|
const int NUM_DOMAIN_LIST_EXTENDED_HEADER_BYTES = NUM_BYTES_RFC4122_UUID + NLPacket::NUM_BYTES_LOCALID +
|
||||||
|
NUM_BYTES_RFC4122_UUID + NLPacket::NUM_BYTES_LOCALID + 4;
|
||||||
|
|
||||||
// setup the extended header for the domain list packets
|
// setup the extended header for the domain list packets
|
||||||
// this data is at the beginning of each of the domain list packets
|
// this data is at the beginning of each of the domain list packets
|
||||||
|
@ -1122,7 +1125,9 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
|
||||||
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
|
|
||||||
extendedHeaderStream << limitedNodeList->getSessionUUID();
|
extendedHeaderStream << limitedNodeList->getSessionUUID();
|
||||||
|
extendedHeaderStream << limitedNodeList->getSessionLocalID();
|
||||||
extendedHeaderStream << node->getUUID();
|
extendedHeaderStream << node->getUUID();
|
||||||
|
extendedHeaderStream << node->getLocalID();
|
||||||
extendedHeaderStream << node->getPermissions();
|
extendedHeaderStream << node->getPermissions();
|
||||||
|
|
||||||
auto domainListPackets = NLPacketList::create(PacketType::DomainList, extendedHeader);
|
auto domainListPackets = NLPacketList::create(PacketType::DomainList, extendedHeader);
|
||||||
|
@ -2841,7 +2846,7 @@ void DomainServer::updateReplicationNodes(ReplicationServerDirection direction)
|
||||||
// manually add the replication node to our node list
|
// manually add the replication node to our node list
|
||||||
auto node = nodeList->addOrUpdateNode(QUuid::createUuid(), replicationServer.nodeType,
|
auto node = nodeList->addOrUpdateNode(QUuid::createUuid(), replicationServer.nodeType,
|
||||||
replicationServer.sockAddr, replicationServer.sockAddr,
|
replicationServer.sockAddr, replicationServer.sockAddr,
|
||||||
false, direction == Upstream);
|
Node::NULL_LOCAL_ID, false, direction == Upstream);
|
||||||
node->setIsForcedNeverSilent(true);
|
node->setIsForcedNeverSilent(true);
|
||||||
|
|
||||||
qDebug() << "Adding" << (direction == Upstream ? "upstream" : "downstream")
|
qDebug() << "Adding" << (direction == Upstream ? "upstream" : "downstream")
|
||||||
|
@ -2903,7 +2908,7 @@ void DomainServer::updateReplicatedNodes() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
nodeList->eachMatchingNode([this](const SharedNodePointer& otherNode) -> bool {
|
nodeList->eachMatchingNode([](const SharedNodePointer& otherNode) -> bool {
|
||||||
return otherNode->getType() == NodeType::Agent;
|
return otherNode->getType() == NodeType::Agent;
|
||||||
}, [this](const SharedNodePointer& otherNode) {
|
}, [this](const SharedNodePointer& otherNode) {
|
||||||
auto shouldReplicate = shouldReplicateNode(*otherNode);
|
auto shouldReplicate = shouldReplicateNode(*otherNode);
|
||||||
|
@ -3141,13 +3146,12 @@ void DomainServer::processNodeDisconnectRequestPacket(QSharedPointer<ReceivedMes
|
||||||
// This packet has been matched to a source node and they're asking not to be in the domain anymore
|
// This packet has been matched to a source node and they're asking not to be in the domain anymore
|
||||||
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
|
|
||||||
const QUuid& nodeUUID = message->getSourceID();
|
auto localID = message->getSourceID();
|
||||||
|
qDebug() << "Received a disconnect request from node with local ID" << localID;
|
||||||
qDebug() << "Received a disconnect request from node with UUID" << nodeUUID;
|
|
||||||
|
|
||||||
// we want to check what type this node was before going to kill it so that we can avoid sending the RemovedNode
|
// we want to check what type this node was before going to kill it so that we can avoid sending the RemovedNode
|
||||||
// packet to nodes that don't care about this type
|
// packet to nodes that don't care about this type
|
||||||
auto nodeToKill = limitedNodeList->nodeWithUUID(nodeUUID);
|
auto nodeToKill = limitedNodeList->nodeWithLocalID(localID);
|
||||||
|
|
||||||
if (nodeToKill) {
|
if (nodeToKill) {
|
||||||
handleKillNode(nodeToKill);
|
handleKillNode(nodeToKill);
|
||||||
|
@ -3415,7 +3419,7 @@ void DomainServer::handleDomainContentReplacementFromURLRequest(QSharedPointer<R
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::handleOctreeFileReplacementRequest(QSharedPointer<ReceivedMessage> message) {
|
void DomainServer::handleOctreeFileReplacementRequest(QSharedPointer<ReceivedMessage> message) {
|
||||||
auto node = DependencyManager::get<NodeList>()->nodeWithUUID(message->getSourceID());
|
auto node = DependencyManager::get<NodeList>()->nodeWithLocalID(message->getSourceID());
|
||||||
if (node->getCanReplaceContent()) {
|
if (node->getCanReplaceContent()) {
|
||||||
handleOctreeFileReplacement(message->readAll());
|
handleOctreeFileReplacement(message->readAll());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1099,10 +1099,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
auto audioScriptingInterface = DependencyManager::get<AudioScriptingInterface>();
|
auto audioScriptingInterface = DependencyManager::get<AudioScriptingInterface>();
|
||||||
auto myAvatarPosition = DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldPosition();
|
auto myAvatarPosition = DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldPosition();
|
||||||
float distance = glm::distance(myAvatarPosition, position);
|
float distance = glm::distance(myAvatarPosition, position);
|
||||||
bool shouldMute = !audioClient->isMuted() && (distance < radius);
|
|
||||||
|
|
||||||
if (shouldMute) {
|
if (distance < radius) {
|
||||||
audioClient->toggleMute();
|
audioClient->setMuted(true);
|
||||||
audioScriptingInterface->environmentMuted();
|
audioScriptingInterface->environmentMuted();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1527,7 +1526,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
|
|
||||||
if (state) {
|
if (state) {
|
||||||
if (action == controller::toInt(controller::Action::TOGGLE_MUTE)) {
|
if (action == controller::toInt(controller::Action::TOGGLE_MUTE)) {
|
||||||
DependencyManager::get<AudioClient>()->toggleMute();
|
auto audioClient = DependencyManager::get<AudioClient>();
|
||||||
|
audioClient->setMuted(!audioClient->isMuted());
|
||||||
} else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) {
|
} else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) {
|
||||||
cycleCamera();
|
cycleCamera();
|
||||||
} else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) {
|
} else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) {
|
||||||
|
@ -3465,7 +3465,8 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
|
|
||||||
case Qt::Key_M:
|
case Qt::Key_M:
|
||||||
if (isMeta) {
|
if (isMeta) {
|
||||||
DependencyManager::get<AudioClient>()->toggleMute();
|
auto audioClient = DependencyManager::get<AudioClient>();
|
||||||
|
audioClient->setMuted(!audioClient->isMuted());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -5120,7 +5121,7 @@ void Application::update(float deltaTime) {
|
||||||
if (menu->isOptionChecked(MenuOption::AutoMuteAudio) && !audioClient->isMuted()) {
|
if (menu->isOptionChecked(MenuOption::AutoMuteAudio) && !audioClient->isMuted()) {
|
||||||
if (_lastFaceTrackerUpdate > 0
|
if (_lastFaceTrackerUpdate > 0
|
||||||
&& ((usecTimestampNow() - _lastFaceTrackerUpdate) > MUTE_MICROPHONE_AFTER_USECS)) {
|
&& ((usecTimestampNow() - _lastFaceTrackerUpdate) > MUTE_MICROPHONE_AFTER_USECS)) {
|
||||||
audioClient->toggleMute();
|
audioClient->setMuted(true);
|
||||||
_lastFaceTrackerUpdate = 0;
|
_lastFaceTrackerUpdate = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -31,10 +31,41 @@ using namespace crashpad;
|
||||||
static const std::string BACKTRACE_URL { CMAKE_BACKTRACE_URL };
|
static const std::string BACKTRACE_URL { CMAKE_BACKTRACE_URL };
|
||||||
static const std::string BACKTRACE_TOKEN { CMAKE_BACKTRACE_TOKEN };
|
static const std::string BACKTRACE_TOKEN { CMAKE_BACKTRACE_TOKEN };
|
||||||
|
|
||||||
|
static std::wstring gIPCPipe;
|
||||||
|
|
||||||
extern QString qAppFileName();
|
extern QString qAppFileName();
|
||||||
|
|
||||||
// crashpad::AnnotationList* crashpadAnnotations { nullptr };
|
// crashpad::AnnotationList* crashpadAnnotations { nullptr };
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
LONG WINAPI vectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo) {
|
||||||
|
static const DWORD EXTERNAL_EXCEPTION_CODE{ 0xe06d7363 };
|
||||||
|
static const DWORD HEAP_CORRUPTION_CODE{ 0xc0000374 };
|
||||||
|
|
||||||
|
auto exceptionCode = pExceptionInfo->ExceptionRecord->ExceptionCode;
|
||||||
|
if (exceptionCode == EXTERNAL_EXCEPTION_CODE) {
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exceptionCode == HEAP_CORRUPTION_CODE) {
|
||||||
|
qCritical() << "VectoredExceptionHandler: Heap corruption:" << QString::number(exceptionCode, 16);
|
||||||
|
|
||||||
|
CrashpadClient client;
|
||||||
|
if (gIPCPipe.length()) {
|
||||||
|
bool rc = client.SetHandlerIPCPipe(gIPCPipe);
|
||||||
|
qCritical() << "SetHandlerIPCPipe = " << rc;
|
||||||
|
} else {
|
||||||
|
qCritical() << "No IPC Pipe was previously defined for crash handler.";
|
||||||
|
}
|
||||||
|
qCritical() << "Calling DumpAndCrash()";
|
||||||
|
client.DumpAndCrash(pExceptionInfo);
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
bool startCrashHandler() {
|
bool startCrashHandler() {
|
||||||
if (BACKTRACE_URL.empty() || BACKTRACE_TOKEN.empty()) {
|
if (BACKTRACE_URL.empty() || BACKTRACE_TOKEN.empty()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -76,7 +107,12 @@ bool startCrashHandler() {
|
||||||
// Enable automated uploads.
|
// Enable automated uploads.
|
||||||
database->GetSettings()->SetUploadsEnabled(true);
|
database->GetSettings()->SetUploadsEnabled(true);
|
||||||
|
|
||||||
return client.StartHandler(handler, db, db, BACKTRACE_URL, annotations, arguments, true, true);
|
bool result = client.StartHandler(handler, db, db, BACKTRACE_URL, annotations, arguments, true, true);
|
||||||
|
gIPCPipe = client.GetHandlerIPCPipe();
|
||||||
|
|
||||||
|
AddVectoredExceptionHandler(0, vectoredExceptionHandler);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCrashAnnotation(std::string name, std::string value) {
|
void setCrashAnnotation(std::string name, std::string value) {
|
||||||
|
|
|
@ -750,32 +750,32 @@ Menu::Menu() {
|
||||||
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashPureVirtualFunction);
|
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashPureVirtualFunction);
|
||||||
connect(action, &QAction::triggered, qApp, []() { crash::pureVirtualCall(); });
|
connect(action, &QAction::triggered, qApp, []() { crash::pureVirtualCall(); });
|
||||||
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashPureVirtualFunctionThreaded);
|
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashPureVirtualFunctionThreaded);
|
||||||
connect(action, &QAction::triggered, qApp, []() { std::thread([]() { crash::pureVirtualCall(); }); });
|
connect(action, &QAction::triggered, qApp, []() { std::thread(crash::pureVirtualCall).join(); });
|
||||||
|
|
||||||
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashDoubleFree);
|
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashDoubleFree);
|
||||||
connect(action, &QAction::triggered, qApp, []() { crash::doubleFree(); });
|
connect(action, &QAction::triggered, qApp, []() { crash::doubleFree(); });
|
||||||
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashDoubleFreeThreaded);
|
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashDoubleFreeThreaded);
|
||||||
connect(action, &QAction::triggered, qApp, []() { std::thread([]() { crash::doubleFree(); }); });
|
connect(action, &QAction::triggered, qApp, []() { std::thread(crash::doubleFree).join(); });
|
||||||
|
|
||||||
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashAbort);
|
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashAbort);
|
||||||
connect(action, &QAction::triggered, qApp, []() { crash::doAbort(); });
|
connect(action, &QAction::triggered, qApp, []() { crash::doAbort(); });
|
||||||
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashAbortThreaded);
|
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashAbortThreaded);
|
||||||
connect(action, &QAction::triggered, qApp, []() { std::thread([]() { crash::doAbort(); }); });
|
connect(action, &QAction::triggered, qApp, []() { std::thread(crash::doAbort).join(); });
|
||||||
|
|
||||||
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNullDereference);
|
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNullDereference);
|
||||||
connect(action, &QAction::triggered, qApp, []() { crash::nullDeref(); });
|
connect(action, &QAction::triggered, qApp, []() { crash::nullDeref(); });
|
||||||
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNullDereferenceThreaded);
|
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNullDereferenceThreaded);
|
||||||
connect(action, &QAction::triggered, qApp, []() { std::thread([]() { crash::nullDeref(); }); });
|
connect(action, &QAction::triggered, qApp, []() { std::thread(crash::nullDeref).join(); });
|
||||||
|
|
||||||
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashOutOfBoundsVectorAccess);
|
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashOutOfBoundsVectorAccess);
|
||||||
connect(action, &QAction::triggered, qApp, []() { crash::outOfBoundsVectorCrash(); });
|
connect(action, &QAction::triggered, qApp, []() { crash::outOfBoundsVectorCrash(); });
|
||||||
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashOutOfBoundsVectorAccessThreaded);
|
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashOutOfBoundsVectorAccessThreaded);
|
||||||
connect(action, &QAction::triggered, qApp, []() { std::thread([]() { crash::outOfBoundsVectorCrash(); }); });
|
connect(action, &QAction::triggered, qApp, []() { std::thread(crash::outOfBoundsVectorCrash).join(); });
|
||||||
|
|
||||||
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNewFault);
|
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNewFault);
|
||||||
connect(action, &QAction::triggered, qApp, []() { crash::newFault(); });
|
connect(action, &QAction::triggered, qApp, []() { crash::newFault(); });
|
||||||
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNewFaultThreaded);
|
action = addActionToQMenuAndActionHash(crashMenu, MenuOption::CrashNewFaultThreaded);
|
||||||
connect(action, &QAction::triggered, qApp, []() { std::thread([]() { crash::newFault(); }); });
|
connect(action, &QAction::triggered, qApp, []() { std::thread(crash::newFault).join(); });
|
||||||
|
|
||||||
// Developer > Log...
|
// Developer > Log...
|
||||||
addActionToQMenuAndActionHash(developerMenu, MenuOption::Log, Qt::CTRL | Qt::SHIFT | Qt::Key_L,
|
addActionToQMenuAndActionHash(developerMenu, MenuOption::Log, Qt::CTRL | Qt::SHIFT | Qt::Key_L,
|
||||||
|
|
|
@ -71,7 +71,7 @@ void OctreePacketProcessor::processPacket(QSharedPointer<ReceivedMessage> messag
|
||||||
if (message->getVersion() != versionForPacketType(message->getType())) {
|
if (message->getVersion() != versionForPacketType(message->getType())) {
|
||||||
static QMultiMap<QUuid, PacketType> versionDebugSuppressMap;
|
static QMultiMap<QUuid, PacketType> versionDebugSuppressMap;
|
||||||
|
|
||||||
const QUuid& senderUUID = message->getSourceID();
|
const QUuid& senderUUID = sendingNode->getUUID();
|
||||||
if (!versionDebugSuppressMap.contains(senderUUID, packetType)) {
|
if (!versionDebugSuppressMap.contains(senderUUID, packetType)) {
|
||||||
|
|
||||||
qDebug() << "Was stats packet? " << wasStatsPacket;
|
qDebug() << "Was stats packet? " << wasStatsPacket;
|
||||||
|
|
|
@ -50,110 +50,162 @@ float Audio::loudnessToLevel(float loudness) {
|
||||||
|
|
||||||
Audio::Audio() : _devices(_contextIsHMD) {
|
Audio::Audio() : _devices(_contextIsHMD) {
|
||||||
auto client = DependencyManager::get<AudioClient>().data();
|
auto client = DependencyManager::get<AudioClient>().data();
|
||||||
connect(client, &AudioClient::muteToggled, this, &Audio::onMutedChanged);
|
connect(client, &AudioClient::muteToggled, this, &Audio::setMuted);
|
||||||
connect(client, &AudioClient::noiseReductionChanged, this, &Audio::onNoiseReductionChanged);
|
connect(client, &AudioClient::noiseReductionChanged, this, &Audio::enableNoiseReduction);
|
||||||
connect(client, &AudioClient::inputLoudnessChanged, this, &Audio::onInputLoudnessChanged);
|
connect(client, &AudioClient::inputLoudnessChanged, this, &Audio::onInputLoudnessChanged);
|
||||||
connect(client, &AudioClient::inputVolumeChanged, this, &Audio::onInputVolumeChanged);
|
connect(client, &AudioClient::inputVolumeChanged, this, &Audio::setInputVolume);
|
||||||
connect(this, &Audio::contextChanged, &_devices, &AudioDevices::onContextChanged);
|
connect(this, &Audio::contextChanged, &_devices, &AudioDevices::onContextChanged);
|
||||||
enableNoiseReduction(enableNoiseReductionSetting.get());
|
enableNoiseReduction(enableNoiseReductionSetting.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Audio::startRecording(const QString& filepath) {
|
bool Audio::startRecording(const QString& filepath) {
|
||||||
auto client = DependencyManager::get<AudioClient>().data();
|
auto client = DependencyManager::get<AudioClient>().data();
|
||||||
return client->startRecording(filepath);
|
return resultWithWriteLock<bool>([&] {
|
||||||
|
return client->startRecording(filepath);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Audio::getRecording() {
|
bool Audio::getRecording() {
|
||||||
auto client = DependencyManager::get<AudioClient>().data();
|
auto client = DependencyManager::get<AudioClient>().data();
|
||||||
return client->getRecording();
|
return resultWithReadLock<bool>([&] {
|
||||||
|
return client->getRecording();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::stopRecording() {
|
void Audio::stopRecording() {
|
||||||
auto client = DependencyManager::get<AudioClient>().data();
|
auto client = DependencyManager::get<AudioClient>().data();
|
||||||
client->stopRecording();
|
withWriteLock([&] {
|
||||||
|
client->stopRecording();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Audio::isMuted() const {
|
||||||
|
return resultWithReadLock<bool>([&] {
|
||||||
|
return _isMuted;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::setMuted(bool isMuted) {
|
void Audio::setMuted(bool isMuted) {
|
||||||
if (_isMuted != isMuted) {
|
bool changed = false;
|
||||||
auto client = DependencyManager::get<AudioClient>().data();
|
withWriteLock([&] {
|
||||||
QMetaObject::invokeMethod(client, "toggleMute");
|
if (_isMuted != isMuted) {
|
||||||
|
_isMuted = isMuted;
|
||||||
|
auto client = DependencyManager::get<AudioClient>().data();
|
||||||
|
QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted), Q_ARG(bool, false));
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (changed) {
|
||||||
|
emit mutedChanged(isMuted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::onMutedChanged() {
|
bool Audio::noiseReductionEnabled() const {
|
||||||
bool isMuted = DependencyManager::get<AudioClient>()->isMuted();
|
return resultWithReadLock<bool>([&] {
|
||||||
if (_isMuted != isMuted) {
|
return _enableNoiseReduction;
|
||||||
_isMuted = isMuted;
|
});
|
||||||
emit mutedChanged(_isMuted);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::enableNoiseReduction(bool enable) {
|
void Audio::enableNoiseReduction(bool enable) {
|
||||||
if (_enableNoiseReduction != enable) {
|
bool changed = false;
|
||||||
auto client = DependencyManager::get<AudioClient>().data();
|
withWriteLock([&] {
|
||||||
QMetaObject::invokeMethod(client, "setNoiseReduction", Q_ARG(bool, enable));
|
if (_enableNoiseReduction != enable) {
|
||||||
enableNoiseReductionSetting.set(enable);
|
_enableNoiseReduction = enable;
|
||||||
|
auto client = DependencyManager::get<AudioClient>().data();
|
||||||
|
QMetaObject::invokeMethod(client, "setNoiseReduction", Q_ARG(bool, enable), Q_ARG(bool, false));
|
||||||
|
enableNoiseReductionSetting.set(enable);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (changed) {
|
||||||
|
emit noiseReductionChanged(enable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::onNoiseReductionChanged() {
|
float Audio::getInputVolume() const {
|
||||||
bool noiseReductionEnabled = DependencyManager::get<AudioClient>()->isNoiseReductionEnabled();
|
return resultWithReadLock<bool>([&] {
|
||||||
if (_enableNoiseReduction != noiseReductionEnabled) {
|
return _inputVolume;
|
||||||
_enableNoiseReduction = noiseReductionEnabled;
|
});
|
||||||
emit noiseReductionChanged(_enableNoiseReduction);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::setInputVolume(float volume) {
|
void Audio::setInputVolume(float volume) {
|
||||||
// getInputVolume will not reflect changes synchronously, so clamp beforehand
|
// getInputVolume will not reflect changes synchronously, so clamp beforehand
|
||||||
volume = glm::clamp(volume, 0.0f, 1.0f);
|
volume = glm::clamp(volume, 0.0f, 1.0f);
|
||||||
|
|
||||||
if (_inputVolume != volume) {
|
bool changed = false;
|
||||||
auto client = DependencyManager::get<AudioClient>().data();
|
withWriteLock([&] {
|
||||||
QMetaObject::invokeMethod(client, "setInputVolume", Q_ARG(float, volume));
|
if (_inputVolume != volume) {
|
||||||
|
_inputVolume = volume;
|
||||||
|
auto client = DependencyManager::get<AudioClient>().data();
|
||||||
|
QMetaObject::invokeMethod(client, "setInputVolume", Q_ARG(float, volume), Q_ARG(bool, false));
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (changed) {
|
||||||
|
emit inputVolumeChanged(volume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::onInputVolumeChanged(float volume) {
|
float Audio::getInputLevel() const {
|
||||||
if (_inputVolume != volume) {
|
return resultWithReadLock<bool>([&] {
|
||||||
_inputVolume = volume;
|
return _inputLevel;
|
||||||
emit inputVolumeChanged(_inputVolume);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::onInputLoudnessChanged(float loudness) {
|
void Audio::onInputLoudnessChanged(float loudness) {
|
||||||
float level = loudnessToLevel(loudness);
|
float level = loudnessToLevel(loudness);
|
||||||
|
bool changed = false;
|
||||||
if (_inputLevel != level) {
|
withWriteLock([&] {
|
||||||
_inputLevel = level;
|
if (_inputLevel != level) {
|
||||||
emit inputLevelChanged(_inputLevel);
|
_inputLevel = level;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (changed) {
|
||||||
|
emit inputLevelChanged(level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Audio::getContext() const {
|
QString Audio::getContext() const {
|
||||||
return _contextIsHMD ? Audio::HMD : Audio::DESKTOP;
|
return resultWithReadLock<QString>([&] {
|
||||||
|
return _contextIsHMD ? Audio::HMD : Audio::DESKTOP;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::onContextChanged() {
|
void Audio::onContextChanged() {
|
||||||
|
bool changed = false;
|
||||||
bool isHMD = qApp->isHMDMode();
|
bool isHMD = qApp->isHMDMode();
|
||||||
if (_contextIsHMD != isHMD) {
|
withWriteLock([&] {
|
||||||
_contextIsHMD = isHMD;
|
if (_contextIsHMD != isHMD) {
|
||||||
emit contextChanged(getContext());
|
_contextIsHMD = isHMD;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (changed) {
|
||||||
|
emit contextChanged(isHMD ? Audio::HMD : Audio::DESKTOP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::setReverb(bool enable) {
|
void Audio::setReverb(bool enable) {
|
||||||
DependencyManager::get<AudioClient>()->setReverb(enable);
|
withWriteLock([&] {
|
||||||
|
DependencyManager::get<AudioClient>()->setReverb(enable);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::setReverbOptions(const AudioEffectOptions* options) {
|
void Audio::setReverbOptions(const AudioEffectOptions* options) {
|
||||||
DependencyManager::get<AudioClient>()->setReverbOptions(options);
|
withWriteLock([&] {
|
||||||
|
DependencyManager::get<AudioClient>()->setReverbOptions(options);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::setInputDevice(const QAudioDeviceInfo& device, bool isHMD) {
|
void Audio::setInputDevice(const QAudioDeviceInfo& device, bool isHMD) {
|
||||||
_devices.chooseInputDevice(device, isHMD);
|
withWriteLock([&] {
|
||||||
|
_devices.chooseInputDevice(device, isHMD);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::setOutputDevice(const QAudioDeviceInfo& device, bool isHMD) {
|
void Audio::setOutputDevice(const QAudioDeviceInfo& device, bool isHMD) {
|
||||||
_devices.chooseOutputDevice(device, isHMD);
|
withWriteLock([&] {
|
||||||
|
_devices.chooseOutputDevice(device, isHMD);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,11 @@
|
||||||
#include "AudioEffectOptions.h"
|
#include "AudioEffectOptions.h"
|
||||||
#include "SettingHandle.h"
|
#include "SettingHandle.h"
|
||||||
#include "AudioFileWav.h"
|
#include "AudioFileWav.h"
|
||||||
|
#include <shared/ReadWriteLockable.h>
|
||||||
|
|
||||||
namespace scripting {
|
namespace scripting {
|
||||||
|
|
||||||
class Audio : public AudioScriptingInterface {
|
class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
SINGLETON_DEPENDENCY
|
SINGLETON_DEPENDENCY
|
||||||
|
|
||||||
|
@ -40,16 +41,13 @@ public:
|
||||||
|
|
||||||
virtual ~Audio() {}
|
virtual ~Audio() {}
|
||||||
|
|
||||||
bool isMuted() const { return _isMuted; }
|
bool isMuted() const;
|
||||||
bool noiseReductionEnabled() const { return _enableNoiseReduction; }
|
bool noiseReductionEnabled() const;
|
||||||
float getInputVolume() const { return _inputVolume; }
|
float getInputVolume() const;
|
||||||
float getInputLevel() const { return _inputLevel; }
|
float getInputLevel() const;
|
||||||
QString getContext() const;
|
QString getContext() const;
|
||||||
|
|
||||||
void setMuted(bool muted);
|
|
||||||
void enableNoiseReduction(bool enable);
|
|
||||||
void showMicMeter(bool show);
|
void showMicMeter(bool show);
|
||||||
void setInputVolume(float volume);
|
|
||||||
|
|
||||||
Q_INVOKABLE void setInputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
Q_INVOKABLE void setInputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
||||||
Q_INVOKABLE void setOutputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
Q_INVOKABLE void setOutputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
||||||
|
@ -72,9 +70,9 @@ public slots:
|
||||||
void onContextChanged();
|
void onContextChanged();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onMutedChanged();
|
void setMuted(bool muted);
|
||||||
void onNoiseReductionChanged();
|
void enableNoiseReduction(bool enable);
|
||||||
void onInputVolumeChanged(float volume);
|
void setInputVolume(float volume);
|
||||||
void onInputLoudnessChanged(float loudness);
|
void onInputLoudnessChanged(float loudness);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -531,8 +531,8 @@ private slots:
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Triggered when you change the domain you're visiting. <strong>Warning:</strong> Is not emitted if you go to domain that
|
* Triggered when you change the domain you're visiting. <strong>Warning:</strong> Is not emitted if you go to a domain
|
||||||
* isn't running.
|
* that isn't running.
|
||||||
* @function Window.domainChanged
|
* @function Window.domainChanged
|
||||||
* @param {string} domainURL - The domain's URL.
|
* @param {string} domainURL - The domain's URL.
|
||||||
* @returns {Signal}
|
* @returns {Signal}
|
||||||
|
|
|
@ -757,7 +757,7 @@ void AudioClient::Gate::flush() {
|
||||||
|
|
||||||
void AudioClient::handleNoisyMutePacket(QSharedPointer<ReceivedMessage> message) {
|
void AudioClient::handleNoisyMutePacket(QSharedPointer<ReceivedMessage> message) {
|
||||||
if (!_muted) {
|
if (!_muted) {
|
||||||
toggleMute();
|
setMuted(true);
|
||||||
|
|
||||||
// have the audio scripting interface emit a signal to say we were muted by the mixer
|
// have the audio scripting interface emit a signal to say we were muted by the mixer
|
||||||
emit mutedByMixer();
|
emit mutedByMixer();
|
||||||
|
@ -1384,15 +1384,21 @@ void AudioClient::sendMuteEnvironmentPacket() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::toggleMute() {
|
void AudioClient::setMuted(bool muted, bool emitSignal) {
|
||||||
_muted = !_muted;
|
if (_muted != muted) {
|
||||||
emit muteToggled();
|
_muted = muted;
|
||||||
|
if (emitSignal) {
|
||||||
|
emit muteToggled(_muted);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::setNoiseReduction(bool enable) {
|
void AudioClient::setNoiseReduction(bool enable, bool emitSignal) {
|
||||||
if (_isNoiseGateEnabled != enable) {
|
if (_isNoiseGateEnabled != enable) {
|
||||||
_isNoiseGateEnabled = enable;
|
_isNoiseGateEnabled = enable;
|
||||||
emit noiseReductionChanged();
|
if (emitSignal) {
|
||||||
|
emit noiseReductionChanged(_isNoiseGateEnabled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2018,9 +2024,11 @@ void AudioClient::startThread() {
|
||||||
moveToNewNamedThread(this, "Audio Thread", [this] { start(); });
|
moveToNewNamedThread(this, "Audio Thread", [this] { start(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::setInputVolume(float volume) {
|
void AudioClient::setInputVolume(float volume, bool emitSignal) {
|
||||||
if (_audioInput && volume != (float)_audioInput->volume()) {
|
if (_audioInput && volume != (float)_audioInput->volume()) {
|
||||||
_audioInput->setVolume(volume);
|
_audioInput->setVolume(volume);
|
||||||
emit inputVolumeChanged(_audioInput->volume());
|
if (emitSignal) {
|
||||||
|
emit inputVolumeChanged(_audioInput->volume());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,13 +189,13 @@ public slots:
|
||||||
void reset();
|
void reset();
|
||||||
void audioMixerKilled();
|
void audioMixerKilled();
|
||||||
|
|
||||||
void toggleMute();
|
void setMuted(bool muted, bool emitSignal = true);
|
||||||
bool isMuted() { return _muted; }
|
bool isMuted() { return _muted; }
|
||||||
|
|
||||||
virtual bool setIsStereoInput(bool stereo) override;
|
virtual bool setIsStereoInput(bool stereo) override;
|
||||||
virtual bool isStereoInput() override { return _isStereoInput; }
|
virtual bool isStereoInput() override { return _isStereoInput; }
|
||||||
|
|
||||||
void setNoiseReduction(bool isNoiseGateEnabled);
|
void setNoiseReduction(bool isNoiseGateEnabled, bool emitSignal = true);
|
||||||
bool isNoiseReductionEnabled() const { return _isNoiseGateEnabled; }
|
bool isNoiseReductionEnabled() const { return _isNoiseGateEnabled; }
|
||||||
|
|
||||||
bool getLocalEcho() { return _shouldEchoLocally; }
|
bool getLocalEcho() { return _shouldEchoLocally; }
|
||||||
|
@ -218,7 +218,7 @@ public slots:
|
||||||
bool switchAudioDevice(QAudio::Mode mode, const QString& deviceName);
|
bool switchAudioDevice(QAudio::Mode mode, const QString& deviceName);
|
||||||
|
|
||||||
float getInputVolume() const { return (_audioInput) ? (float)_audioInput->volume() : 0.0f; }
|
float getInputVolume() const { return (_audioInput) ? (float)_audioInput->volume() : 0.0f; }
|
||||||
void setInputVolume(float volume);
|
void setInputVolume(float volume, bool emitSignal = true);
|
||||||
void setReverb(bool reverb);
|
void setReverb(bool reverb);
|
||||||
void setReverbOptions(const AudioEffectOptions* options);
|
void setReverbOptions(const AudioEffectOptions* options);
|
||||||
|
|
||||||
|
@ -229,8 +229,8 @@ public slots:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void inputVolumeChanged(float volume);
|
void inputVolumeChanged(float volume);
|
||||||
void muteToggled();
|
void muteToggled(bool muted);
|
||||||
void noiseReductionChanged();
|
void noiseReductionChanged(bool noiseReductionEnabled);
|
||||||
void mutedByMixer();
|
void mutedByMixer();
|
||||||
void inputReceived(const QByteArray& inputSamples);
|
void inputReceived(const QByteArray& inputSamples);
|
||||||
void inputLoudnessChanged(float loudness);
|
void inputLoudnessChanged(float loudness);
|
||||||
|
|
|
@ -120,8 +120,8 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
|
||||||
// parse sequence number and track it
|
// parse sequence number and track it
|
||||||
quint16 sequence;
|
quint16 sequence;
|
||||||
message.readPrimitive(&sequence);
|
message.readPrimitive(&sequence);
|
||||||
SequenceNumberStats::ArrivalInfo arrivalInfo = _incomingSequenceNumberStats.sequenceNumberReceived(sequence,
|
SequenceNumberStats::ArrivalInfo arrivalInfo =
|
||||||
message.getSourceID());
|
_incomingSequenceNumberStats.sequenceNumberReceived(sequence, message.getSourceID());
|
||||||
QString codecInPacket = message.readString();
|
QString codecInPacket = message.readString();
|
||||||
|
|
||||||
packetReceivedUpdateTimingStats();
|
packetReceivedUpdateTimingStats();
|
||||||
|
@ -186,7 +186,7 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
|
||||||
_mismatchedAudioCodecCount = 0;
|
_mismatchedAudioCodecCount = 0;
|
||||||
|
|
||||||
// inform others of the mismatch
|
// inform others of the mismatch
|
||||||
auto sendingNode = DependencyManager::get<NodeList>()->nodeWithUUID(message.getSourceID());
|
auto sendingNode = DependencyManager::get<NodeList>()->nodeWithLocalID(message.getSourceID());
|
||||||
if (sendingNode) {
|
if (sendingNode) {
|
||||||
emit mismatchedAudioCodec(sendingNode, _selectedCodecName, codecInPacket);
|
emit mismatchedAudioCodec(sendingNode, _selectedCodecName, codecInPacket);
|
||||||
qDebug(audio) << "Codec mismatch threshold exceeded, SelectedAudioFormat(" << _selectedCodecName << " ) sent";
|
qDebug(audio) << "Codec mismatch threshold exceeded, SelectedAudioFormat(" << _selectedCodecName << " ) sent";
|
||||||
|
|
|
@ -278,7 +278,7 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) {
|
||||||
// FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces
|
// FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces
|
||||||
// and the current rendering load)
|
// and the current rendering load)
|
||||||
_webSurface->setMaxFps(DEFAULT_MAX_FPS);
|
_webSurface->setMaxFps(DEFAULT_MAX_FPS);
|
||||||
QObject::connect(_webSurface.data(), &OffscreenQmlSurface::rootContextCreated, [this](QQmlContext* surfaceContext) {
|
QObject::connect(_webSurface.data(), &OffscreenQmlSurface::rootContextCreated, [](QQmlContext* surfaceContext) {
|
||||||
// FIXME - Keyboard HMD only: Possibly add "HMDinfo" object to context for WebView.qml.
|
// FIXME - Keyboard HMD only: Possibly add "HMDinfo" object to context for WebView.qml.
|
||||||
surfaceContext->setContextProperty("desktop", QVariant());
|
surfaceContext->setContextProperty("desktop", QVariant());
|
||||||
// Let us interact with the keyboard
|
// Let us interact with the keyboard
|
||||||
|
|
|
@ -34,15 +34,16 @@ const QString GET_PLACE = "/api/v1/places/%1";
|
||||||
*
|
*
|
||||||
* @namespace location
|
* @namespace location
|
||||||
* @property {Uuid} domainID - A UUID uniquely identifying the domain you're visiting. Is {@link Uuid|Uuid.NULL} if you're not
|
* @property {Uuid} domainID - A UUID uniquely identifying the domain you're visiting. Is {@link Uuid|Uuid.NULL} if you're not
|
||||||
* connected to the domain.
|
* connected to the domain or are in a serverless domain.
|
||||||
* <em>Read-only.</em>
|
* <em>Read-only.</em>
|
||||||
* @property {Uuid} domainId - Synonym for <code>domainId</code>. <em>Read-only.</em> <strong>Deprecated:</strong> This property
|
* @property {Uuid} domainId - Synonym for <code>domainId</code>. <em>Read-only.</em> <strong>Deprecated:</strong> This property
|
||||||
* is deprecated and will soon be removed.
|
* is deprecated and will soon be removed.
|
||||||
* @property {string} hostname - The name of the domain for your current metaverse address (e.g., <code>"AvatarIsland"</code>,
|
* @property {string} hostname - The name of the domain for your current metaverse address (e.g., <code>"AvatarIsland"</code>,
|
||||||
* <code>localhost</code>, or an IP address).
|
* <code>localhost</code>, or an IP address). Is blank if you're in a serverless domain.
|
||||||
* <em>Read-only.</em>
|
* <em>Read-only.</em>
|
||||||
* @property {string} href - Your current metaverse address (e.g., <code>"hifi://avatarisland/15,-10,26/0,0,0,1"</code>)
|
* @property {string} href - Your current metaverse address (e.g., <code>"hifi://avatarisland/15,-10,26/0,0,0,1"</code>)
|
||||||
* regardless of whether or not you're connected to the domain.
|
* regardless of whether or not you're connected to the domain. Starts with <code>"file:///"</code> if you're in a
|
||||||
|
* serverless domain.
|
||||||
* <em>Read-only.</em>
|
* <em>Read-only.</em>
|
||||||
* @property {boolean} isConnected - <code>true</code> if you're connected to the domain in your current <code>href</code>
|
* @property {boolean} isConnected - <code>true</code> if you're connected to the domain in your current <code>href</code>
|
||||||
* metaverse address, otherwise <code>false</code>.
|
* metaverse address, otherwise <code>false</code>.
|
||||||
|
|
|
@ -45,6 +45,9 @@ public:
|
||||||
const QUuid& getUUID() const { return _uuid; }
|
const QUuid& getUUID() const { return _uuid; }
|
||||||
void setUUID(const QUuid& uuid);
|
void setUUID(const QUuid& uuid);
|
||||||
|
|
||||||
|
Node::LocalID getLocalID() const { return _localID; }
|
||||||
|
void setLocalID(Node::LocalID localID) { _localID = localID; }
|
||||||
|
|
||||||
QString getHostname() const { return _domainURL.host(); }
|
QString getHostname() const { return _domainURL.host(); }
|
||||||
|
|
||||||
const QHostAddress& getIP() const { return _sockAddr.getAddress(); }
|
const QHostAddress& getIP() const { return _sockAddr.getAddress(); }
|
||||||
|
@ -185,6 +188,7 @@ private:
|
||||||
void hardReset();
|
void hardReset();
|
||||||
|
|
||||||
QUuid _uuid;
|
QUuid _uuid;
|
||||||
|
Node::LocalID _localID;
|
||||||
QUrl _domainURL;
|
QUrl _domainURL;
|
||||||
HifiSockAddr _sockAddr;
|
HifiSockAddr _sockAddr;
|
||||||
QUuid _assignmentUUID;
|
QUuid _assignmentUUID;
|
||||||
|
|
94
libraries/networking/src/HMACAuth.cpp
Normal file
94
libraries/networking/src/HMACAuth.cpp
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
//
|
||||||
|
// HMACAuth.cpp
|
||||||
|
// libraries/networking/src
|
||||||
|
//
|
||||||
|
// Created by Simon Walton on 3/19/2018.
|
||||||
|
// Copyright 2018 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 <openssl/opensslv.h>
|
||||||
|
#include <openssl/hmac.h>
|
||||||
|
|
||||||
|
#include "HMACAuth.h"
|
||||||
|
|
||||||
|
#include <QUuid>
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000
|
||||||
|
HMACAuth::HMACAuth(AuthMethod authMethod)
|
||||||
|
: _hmacContext(HMAC_CTX_new())
|
||||||
|
, _authMethod(authMethod) { }
|
||||||
|
|
||||||
|
HMACAuth::~HMACAuth()
|
||||||
|
{
|
||||||
|
HMAC_CTX_free(_hmacContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
HMACAuth::HMACAuth(AuthMethod authMethod)
|
||||||
|
: _hmacContext(new HMAC_CTX())
|
||||||
|
, _authMethod(authMethod) {
|
||||||
|
HMAC_CTX_init(_hmacContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
HMACAuth::~HMACAuth() {
|
||||||
|
HMAC_CTX_cleanup(_hmacContext);
|
||||||
|
delete _hmacContext;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool HMACAuth::setKey(const char* keyValue, int keyLen) {
|
||||||
|
const EVP_MD* sslStruct = nullptr;
|
||||||
|
|
||||||
|
switch (_authMethod) {
|
||||||
|
case MD5:
|
||||||
|
sslStruct = EVP_md5();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SHA1:
|
||||||
|
sslStruct = EVP_sha1();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SHA224:
|
||||||
|
sslStruct = EVP_sha224();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SHA256:
|
||||||
|
sslStruct = EVP_sha256();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RIPEMD160:
|
||||||
|
sslStruct = EVP_ripemd160();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMutexLocker lock(&_lock);
|
||||||
|
return (bool) HMAC_Init_ex(_hmacContext, keyValue, keyLen, sslStruct, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HMACAuth::setKey(const QUuid& uidKey) {
|
||||||
|
const QByteArray rfcBytes(uidKey.toRfc4122());
|
||||||
|
return setKey(rfcBytes.constData(), rfcBytes.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HMACAuth::addData(const char* data, int dataLen) {
|
||||||
|
QMutexLocker lock(&_lock);
|
||||||
|
return (bool) HMAC_Update(_hmacContext, reinterpret_cast<const unsigned char*>(data), dataLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
HMACAuth::HMACHash HMACAuth::result() {
|
||||||
|
HMACHash hashValue(EVP_MAX_MD_SIZE);
|
||||||
|
unsigned int hashLen;
|
||||||
|
QMutexLocker lock(&_lock);
|
||||||
|
HMAC_Final(_hmacContext, &hashValue[0], &hashLen);
|
||||||
|
hashValue.resize((size_t) hashLen);
|
||||||
|
// Clear state for possible reuse.
|
||||||
|
HMAC_Init_ex(_hmacContext, nullptr, 0, nullptr, nullptr);
|
||||||
|
return hashValue;
|
||||||
|
}
|
40
libraries/networking/src/HMACAuth.h
Normal file
40
libraries/networking/src/HMACAuth.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
//
|
||||||
|
// HMACAuth.h
|
||||||
|
// libraries/networking/src
|
||||||
|
//
|
||||||
|
// Created by Simon Walton on 3/19/2018.
|
||||||
|
// Copyright 2018 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_HMACAuth_h
|
||||||
|
#define hifi_HMACAuth_h
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <QtCore/QMutex>
|
||||||
|
|
||||||
|
class QUuid;
|
||||||
|
|
||||||
|
class HMACAuth {
|
||||||
|
public:
|
||||||
|
enum AuthMethod { MD5, SHA1, SHA224, SHA256, RIPEMD160 };
|
||||||
|
using HMACHash = std::vector<unsigned char>;
|
||||||
|
|
||||||
|
explicit HMACAuth(AuthMethod authMethod = MD5);
|
||||||
|
~HMACAuth();
|
||||||
|
|
||||||
|
bool setKey(const char* keyValue, int keyLen);
|
||||||
|
bool setKey(const QUuid& uidKey);
|
||||||
|
bool addData(const char* data, int dataLen);
|
||||||
|
HMACHash result();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMutex _lock;
|
||||||
|
struct hmac_ctx_st* _hmacContext;
|
||||||
|
AuthMethod _authMethod;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_HMACAuth_h
|
|
@ -36,6 +36,7 @@
|
||||||
#include "HifiSockAddr.h"
|
#include "HifiSockAddr.h"
|
||||||
#include "NetworkLogging.h"
|
#include "NetworkLogging.h"
|
||||||
#include "udt/Packet.h"
|
#include "udt/Packet.h"
|
||||||
|
#include "HMACAuth.h"
|
||||||
|
|
||||||
static Setting::Handle<quint16> LIMITED_NODELIST_LOCAL_PORT("LimitedNodeList.LocalPort", 0);
|
static Setting::Handle<quint16> LIMITED_NODELIST_LOCAL_PORT("LimitedNodeList.LocalPort", 0);
|
||||||
|
|
||||||
|
@ -131,6 +132,16 @@ void LimitedNodeList::setSessionUUID(const QUuid& sessionUUID) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Node::LocalID LimitedNodeList::getSessionLocalID() const {
|
||||||
|
QReadLocker readLock { &_sessionUUIDLock };
|
||||||
|
return _sessionLocalID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimitedNodeList::setSessionLocalID(Node::LocalID sessionLocalID) {
|
||||||
|
QWriteLocker lock { &_sessionUUIDLock };
|
||||||
|
_sessionLocalID = sessionLocalID;
|
||||||
|
}
|
||||||
|
|
||||||
void LimitedNodeList::setPermissions(const NodePermissions& newPermissions) {
|
void LimitedNodeList::setPermissions(const NodePermissions& newPermissions) {
|
||||||
NodePermissions originalPermissions = _permissions;
|
NodePermissions originalPermissions = _permissions;
|
||||||
|
|
||||||
|
@ -229,13 +240,16 @@ bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) {
|
||||||
senderString = QString("%1:%2").arg(senderSockAddr.getAddress().toString()).arg(senderSockAddr.getPort());
|
senderString = QString("%1:%2").arg(senderSockAddr.getAddress().toString()).arg(senderSockAddr.getPort());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sourceID = NLPacket::sourceIDInHeader(packet);
|
SharedNodePointer sourceNode = nodeWithLocalID(NLPacket::sourceIDInHeader(packet));
|
||||||
|
if (sourceNode) {
|
||||||
|
sourceID = sourceNode->getUUID();
|
||||||
|
|
||||||
hasBeenOutput = sourcedVersionDebugSuppressMap.contains(sourceID, headerType);
|
hasBeenOutput = sourcedVersionDebugSuppressMap.contains(sourceID, headerType);
|
||||||
|
|
||||||
if (!hasBeenOutput) {
|
if (!hasBeenOutput) {
|
||||||
sourcedVersionDebugSuppressMap.insert(sourceID, headerType);
|
sourcedVersionDebugSuppressMap.insert(sourceID, headerType);
|
||||||
senderString = uuidStringWithoutCurlyBraces(sourceID.toString());
|
senderString = uuidStringWithoutCurlyBraces(sourceID.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,17 +302,20 @@ bool LimitedNodeList::packetSourceAndHashMatchAndTrackBandwidth(const udt::Packe
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
QUuid sourceID = NLPacket::sourceIDInHeader(packet);
|
NLPacket::LocalID sourceLocalID = Node::NULL_LOCAL_ID;
|
||||||
|
|
||||||
// check if we were passed a sourceNode hint or if we need to look it up
|
// check if we were passed a sourceNode hint or if we need to look it up
|
||||||
if (!sourceNode) {
|
if (!sourceNode) {
|
||||||
// figure out which node this is from
|
// figure out which node this is from
|
||||||
SharedNodePointer matchingNode = nodeWithUUID(sourceID);
|
sourceLocalID = NLPacket::sourceIDInHeader(packet);
|
||||||
|
|
||||||
|
SharedNodePointer matchingNode = nodeWithLocalID(sourceLocalID);
|
||||||
sourceNode = matchingNode.data();
|
sourceNode = matchingNode.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QUuid sourceID = sourceNode ? sourceNode->getUUID() : QUuid();
|
||||||
|
|
||||||
if (!sourceNode &&
|
if (!sourceNode &&
|
||||||
sourceID == getDomainUUID() &&
|
sourceLocalID == getDomainLocalID() &&
|
||||||
packet.getSenderSockAddr() == getDomainSockAddr() &&
|
packet.getSenderSockAddr() == getDomainSockAddr() &&
|
||||||
PacketTypeEnum::getDomainSourcedPackets().contains(headerType)) {
|
PacketTypeEnum::getDomainSourcedPackets().contains(headerType)) {
|
||||||
// This is a packet sourced by the domain server
|
// This is a packet sourced by the domain server
|
||||||
|
@ -314,7 +331,7 @@ bool LimitedNodeList::packetSourceAndHashMatchAndTrackBandwidth(const udt::Packe
|
||||||
if (verifiedPacket && !ignoreVerification) {
|
if (verifiedPacket && !ignoreVerification) {
|
||||||
|
|
||||||
QByteArray packetHeaderHash = NLPacket::verificationHashInHeader(packet);
|
QByteArray packetHeaderHash = NLPacket::verificationHashInHeader(packet);
|
||||||
QByteArray expectedHash = NLPacket::hashForPacketAndSecret(packet, sourceNode->getConnectionSecret());
|
QByteArray expectedHash = NLPacket::hashForPacketAndHMAC(packet, sourceNode->getAuthenticateHash());
|
||||||
|
|
||||||
// check if the md5 hash in the header matches the hash we would expect
|
// check if the md5 hash in the header matches the hash we would expect
|
||||||
if (packetHeaderHash != expectedHash) {
|
if (packetHeaderHash != expectedHash) {
|
||||||
|
@ -354,15 +371,15 @@ void LimitedNodeList::collectPacketStats(const NLPacket& packet) {
|
||||||
_numCollectedBytes += packet.getDataSize();
|
_numCollectedBytes += packet.getDataSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimitedNodeList::fillPacketHeader(const NLPacket& packet, const QUuid& connectionSecret) {
|
void LimitedNodeList::fillPacketHeader(const NLPacket& packet, HMACAuth* hmacAuth) {
|
||||||
if (!PacketTypeEnum::getNonSourcedPackets().contains(packet.getType())) {
|
if (!PacketTypeEnum::getNonSourcedPackets().contains(packet.getType())) {
|
||||||
packet.writeSourceID(getSessionUUID());
|
packet.writeSourceID(getSessionLocalID());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!connectionSecret.isNull()
|
if (hmacAuth
|
||||||
&& !PacketTypeEnum::getNonSourcedPackets().contains(packet.getType())
|
&& !PacketTypeEnum::getNonSourcedPackets().contains(packet.getType())
|
||||||
&& !PacketTypeEnum::getNonVerifiedPackets().contains(packet.getType())) {
|
&& !PacketTypeEnum::getNonVerifiedPackets().contains(packet.getType())) {
|
||||||
packet.writeVerificationHashGivenSecret(connectionSecret);
|
packet.writeVerificationHash(*hmacAuth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,17 +395,17 @@ qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const Node&
|
||||||
emit dataSent(destinationNode.getType(), packet.getDataSize());
|
emit dataSent(destinationNode.getType(), packet.getDataSize());
|
||||||
destinationNode.recordBytesSent(packet.getDataSize());
|
destinationNode.recordBytesSent(packet.getDataSize());
|
||||||
|
|
||||||
return sendUnreliablePacket(packet, *destinationNode.getActiveSocket(), destinationNode.getConnectionSecret());
|
return sendUnreliablePacket(packet, *destinationNode.getActiveSocket(), &destinationNode.getAuthenticateHash());
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const HifiSockAddr& sockAddr,
|
qint64 LimitedNodeList::sendUnreliablePacket(const NLPacket& packet, const HifiSockAddr& sockAddr,
|
||||||
const QUuid& connectionSecret) {
|
HMACAuth* hmacAuth) {
|
||||||
Q_ASSERT(!packet.isPartOfMessage());
|
Q_ASSERT(!packet.isPartOfMessage());
|
||||||
Q_ASSERT_X(!packet.isReliable(), "LimitedNodeList::sendUnreliablePacket",
|
Q_ASSERT_X(!packet.isReliable(), "LimitedNodeList::sendUnreliablePacket",
|
||||||
"Trying to send a reliable packet unreliably.");
|
"Trying to send a reliable packet unreliably.");
|
||||||
|
|
||||||
collectPacketStats(packet);
|
collectPacketStats(packet);
|
||||||
fillPacketHeader(packet, connectionSecret);
|
fillPacketHeader(packet, hmacAuth);
|
||||||
|
|
||||||
return _nodeSocket.writePacket(packet, sockAddr);
|
return _nodeSocket.writePacket(packet, sockAddr);
|
||||||
}
|
}
|
||||||
|
@ -401,7 +418,7 @@ qint64 LimitedNodeList::sendPacket(std::unique_ptr<NLPacket> packet, const Node&
|
||||||
emit dataSent(destinationNode.getType(), packet->getDataSize());
|
emit dataSent(destinationNode.getType(), packet->getDataSize());
|
||||||
destinationNode.recordBytesSent(packet->getDataSize());
|
destinationNode.recordBytesSent(packet->getDataSize());
|
||||||
|
|
||||||
return sendPacket(std::move(packet), *activeSocket, destinationNode.getConnectionSecret());
|
return sendPacket(std::move(packet), *activeSocket, &destinationNode.getAuthenticateHash());
|
||||||
} else {
|
} else {
|
||||||
qCDebug(networking) << "LimitedNodeList::sendPacket called without active socket for node" << destinationNode << "- not sending";
|
qCDebug(networking) << "LimitedNodeList::sendPacket called without active socket for node" << destinationNode << "- not sending";
|
||||||
return ERROR_SENDING_PACKET_BYTES;
|
return ERROR_SENDING_PACKET_BYTES;
|
||||||
|
@ -409,18 +426,18 @@ qint64 LimitedNodeList::sendPacket(std::unique_ptr<NLPacket> packet, const Node&
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 LimitedNodeList::sendPacket(std::unique_ptr<NLPacket> packet, const HifiSockAddr& sockAddr,
|
qint64 LimitedNodeList::sendPacket(std::unique_ptr<NLPacket> packet, const HifiSockAddr& sockAddr,
|
||||||
const QUuid& connectionSecret) {
|
HMACAuth* hmacAuth) {
|
||||||
Q_ASSERT(!packet->isPartOfMessage());
|
Q_ASSERT(!packet->isPartOfMessage());
|
||||||
if (packet->isReliable()) {
|
if (packet->isReliable()) {
|
||||||
collectPacketStats(*packet);
|
collectPacketStats(*packet);
|
||||||
fillPacketHeader(*packet, connectionSecret);
|
fillPacketHeader(*packet, hmacAuth);
|
||||||
|
|
||||||
auto size = packet->getDataSize();
|
auto size = packet->getDataSize();
|
||||||
_nodeSocket.writePacket(std::move(packet), sockAddr);
|
_nodeSocket.writePacket(std::move(packet), sockAddr);
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
} else {
|
} else {
|
||||||
return sendUnreliablePacket(*packet, sockAddr, connectionSecret);
|
return sendUnreliablePacket(*packet, sockAddr, hmacAuth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,13 +446,14 @@ qint64 LimitedNodeList::sendUnreliableUnorderedPacketList(NLPacketList& packetLi
|
||||||
|
|
||||||
if (activeSocket) {
|
if (activeSocket) {
|
||||||
qint64 bytesSent = 0;
|
qint64 bytesSent = 0;
|
||||||
auto connectionSecret = destinationNode.getConnectionSecret();
|
auto& connectionHash = destinationNode.getAuthenticateHash();
|
||||||
|
|
||||||
// close the last packet in the list
|
// close the last packet in the list
|
||||||
packetList.closeCurrentPacket();
|
packetList.closeCurrentPacket();
|
||||||
|
|
||||||
while (!packetList._packets.empty()) {
|
while (!packetList._packets.empty()) {
|
||||||
bytesSent += sendPacket(packetList.takeFront<NLPacket>(), *activeSocket, connectionSecret);
|
bytesSent += sendPacket(packetList.takeFront<NLPacket>(), *activeSocket,
|
||||||
|
&connectionHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit dataSent(destinationNode.getType(), bytesSent);
|
emit dataSent(destinationNode.getType(), bytesSent);
|
||||||
|
@ -448,14 +466,14 @@ qint64 LimitedNodeList::sendUnreliableUnorderedPacketList(NLPacketList& packetLi
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 LimitedNodeList::sendUnreliableUnorderedPacketList(NLPacketList& packetList, const HifiSockAddr& sockAddr,
|
qint64 LimitedNodeList::sendUnreliableUnorderedPacketList(NLPacketList& packetList, const HifiSockAddr& sockAddr,
|
||||||
const QUuid& connectionSecret) {
|
HMACAuth* hmacAuth) {
|
||||||
qint64 bytesSent = 0;
|
qint64 bytesSent = 0;
|
||||||
|
|
||||||
// close the last packet in the list
|
// close the last packet in the list
|
||||||
packetList.closeCurrentPacket();
|
packetList.closeCurrentPacket();
|
||||||
|
|
||||||
while (!packetList._packets.empty()) {
|
while (!packetList._packets.empty()) {
|
||||||
bytesSent += sendPacket(packetList.takeFront<NLPacket>(), sockAddr, connectionSecret);
|
bytesSent += sendPacket(packetList.takeFront<NLPacket>(), sockAddr, hmacAuth);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytesSent;
|
return bytesSent;
|
||||||
|
@ -483,7 +501,7 @@ qint64 LimitedNodeList::sendPacketList(std::unique_ptr<NLPacketList> packetList,
|
||||||
for (std::unique_ptr<udt::Packet>& packet : packetList->_packets) {
|
for (std::unique_ptr<udt::Packet>& packet : packetList->_packets) {
|
||||||
NLPacket* nlPacket = static_cast<NLPacket*>(packet.get());
|
NLPacket* nlPacket = static_cast<NLPacket*>(packet.get());
|
||||||
collectPacketStats(*nlPacket);
|
collectPacketStats(*nlPacket);
|
||||||
fillPacketHeader(*nlPacket, destinationNode.getConnectionSecret());
|
fillPacketHeader(*nlPacket, &destinationNode.getAuthenticateHash());
|
||||||
}
|
}
|
||||||
|
|
||||||
return _nodeSocket.writePacketList(std::move(packetList), *activeSocket);
|
return _nodeSocket.writePacketList(std::move(packetList), *activeSocket);
|
||||||
|
@ -506,7 +524,7 @@ qint64 LimitedNodeList::sendPacket(std::unique_ptr<NLPacket> packet, const Node&
|
||||||
auto& destinationSockAddr = (overridenSockAddr.isNull()) ? *destinationNode.getActiveSocket()
|
auto& destinationSockAddr = (overridenSockAddr.isNull()) ? *destinationNode.getActiveSocket()
|
||||||
: overridenSockAddr;
|
: overridenSockAddr;
|
||||||
|
|
||||||
return sendPacket(std::move(packet), destinationSockAddr, destinationNode.getConnectionSecret());
|
return sendPacket(std::move(packet), destinationSockAddr, &destinationNode.getAuthenticateHash());
|
||||||
}
|
}
|
||||||
|
|
||||||
int LimitedNodeList::updateNodeWithDataFromPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
|
int LimitedNodeList::updateNodeWithDataFromPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
|
||||||
|
@ -539,6 +557,13 @@ SharedNodePointer LimitedNodeList::nodeWithUUID(const QUuid& nodeUUID) {
|
||||||
return it == _nodeHash.cend() ? SharedNodePointer() : it->second;
|
return it == _nodeHash.cend() ? SharedNodePointer() : it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SharedNodePointer LimitedNodeList::nodeWithLocalID(Node::LocalID localID) const {
|
||||||
|
QReadLocker readLocker(&_nodeMutex);
|
||||||
|
|
||||||
|
LocalIDMapping::const_iterator idIter = _localIDMap.find(localID);
|
||||||
|
return idIter == _localIDMap.cend() ? nullptr : idIter->second;
|
||||||
|
}
|
||||||
|
|
||||||
void LimitedNodeList::eraseAllNodes() {
|
void LimitedNodeList::eraseAllNodes() {
|
||||||
QSet<SharedNodePointer> killedNodes;
|
QSet<SharedNodePointer> killedNodes;
|
||||||
|
|
||||||
|
@ -547,6 +572,8 @@ void LimitedNodeList::eraseAllNodes() {
|
||||||
// and then remove them from the hash
|
// and then remove them from the hash
|
||||||
QWriteLocker writeLocker(&_nodeMutex);
|
QWriteLocker writeLocker(&_nodeMutex);
|
||||||
|
|
||||||
|
_localIDMap.clear();
|
||||||
|
|
||||||
if (_nodeHash.size() > 0) {
|
if (_nodeHash.size() > 0) {
|
||||||
qCDebug(networking) << "LimitedNodeList::eraseAllNodes() removing all nodes from NodeList.";
|
qCDebug(networking) << "LimitedNodeList::eraseAllNodes() removing all nodes from NodeList.";
|
||||||
|
|
||||||
|
@ -569,9 +596,10 @@ void LimitedNodeList::reset() {
|
||||||
|
|
||||||
// we need to make sure any socket connections are gone so wait on that here
|
// we need to make sure any socket connections are gone so wait on that here
|
||||||
_nodeSocket.clearConnections();
|
_nodeSocket.clearConnections();
|
||||||
|
_connectionIDs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) {
|
bool LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID, ConnectionID newConnectionID) {
|
||||||
QReadLocker readLocker(&_nodeMutex);
|
QReadLocker readLocker(&_nodeMutex);
|
||||||
|
|
||||||
NodeHash::iterator it = _nodeHash.find(nodeUUID);
|
NodeHash::iterator it = _nodeHash.find(nodeUUID);
|
||||||
|
@ -585,7 +613,7 @@ bool LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) {
|
||||||
_nodeHash.unsafe_erase(it);
|
_nodeHash.unsafe_erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleNodeKill(matchingNode);
|
handleNodeKill(matchingNode, newConnectionID);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,7 +628,7 @@ void LimitedNodeList::processKillNode(ReceivedMessage& message) {
|
||||||
killNodeWithUUID(nodeUUID);
|
killNodeWithUUID(nodeUUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimitedNodeList::handleNodeKill(const SharedNodePointer& node) {
|
void LimitedNodeList::handleNodeKill(const SharedNodePointer& node, ConnectionID nextConnectionID) {
|
||||||
qCDebug(networking) << "Killed" << *node;
|
qCDebug(networking) << "Killed" << *node;
|
||||||
node->stopPingTimer();
|
node->stopPingTimer();
|
||||||
emit nodeKilled(node);
|
emit nodeKilled(node);
|
||||||
|
@ -608,11 +636,20 @@ void LimitedNodeList::handleNodeKill(const SharedNodePointer& node) {
|
||||||
if (auto activeSocket = node->getActiveSocket()) {
|
if (auto activeSocket = node->getActiveSocket()) {
|
||||||
_nodeSocket.cleanupConnection(*activeSocket);
|
_nodeSocket.cleanupConnection(*activeSocket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto it = _connectionIDs.find(node->getUUID());
|
||||||
|
if (it != _connectionIDs.end()) {
|
||||||
|
if (nextConnectionID == NULL_CONNECTION_ID) {
|
||||||
|
it->second++;
|
||||||
|
} else {
|
||||||
|
it->second = nextConnectionID;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType,
|
SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType,
|
||||||
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
|
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
|
||||||
bool isReplicated, bool isUpstream,
|
Node::LocalID localID, bool isReplicated, bool isUpstream,
|
||||||
const QUuid& connectionSecret, const NodePermissions& permissions) {
|
const QUuid& connectionSecret, const NodePermissions& permissions) {
|
||||||
QReadLocker readLocker(&_nodeMutex);
|
QReadLocker readLocker(&_nodeMutex);
|
||||||
NodeHash::const_iterator it = _nodeHash.find(uuid);
|
NodeHash::const_iterator it = _nodeHash.find(uuid);
|
||||||
|
@ -626,15 +663,22 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
|
||||||
matchingNode->setConnectionSecret(connectionSecret);
|
matchingNode->setConnectionSecret(connectionSecret);
|
||||||
matchingNode->setIsReplicated(isReplicated);
|
matchingNode->setIsReplicated(isReplicated);
|
||||||
matchingNode->setIsUpstream(isUpstream || NodeType::isUpstream(nodeType));
|
matchingNode->setIsUpstream(isUpstream || NodeType::isUpstream(nodeType));
|
||||||
|
matchingNode->setLocalID(localID);
|
||||||
|
|
||||||
return matchingNode;
|
return matchingNode;
|
||||||
} else {
|
} else {
|
||||||
|
auto it = _connectionIDs.find(uuid);
|
||||||
|
if (it == _connectionIDs.end()) {
|
||||||
|
_connectionIDs[uuid] = INITIAL_CONNECTION_ID;
|
||||||
|
}
|
||||||
|
|
||||||
// we didn't have this node, so add them
|
// we didn't have this node, so add them
|
||||||
Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket);
|
Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket);
|
||||||
newNode->setIsReplicated(isReplicated);
|
newNode->setIsReplicated(isReplicated);
|
||||||
newNode->setIsUpstream(isUpstream || NodeType::isUpstream(nodeType));
|
newNode->setIsUpstream(isUpstream || NodeType::isUpstream(nodeType));
|
||||||
newNode->setConnectionSecret(connectionSecret);
|
newNode->setConnectionSecret(connectionSecret);
|
||||||
newNode->setPermissions(permissions);
|
newNode->setPermissions(permissions);
|
||||||
|
newNode->setLocalID(localID);
|
||||||
|
|
||||||
// move the newly constructed node to the LNL thread
|
// move the newly constructed node to the LNL thread
|
||||||
newNode->moveToThread(thread());
|
newNode->moveToThread(thread());
|
||||||
|
@ -660,6 +704,7 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
|
||||||
|
|
||||||
auto oldSoloNode = previousSoloIt->second;
|
auto oldSoloNode = previousSoloIt->second;
|
||||||
|
|
||||||
|
_localIDMap.unsafe_erase(oldSoloNode->getLocalID());
|
||||||
_nodeHash.unsafe_erase(previousSoloIt);
|
_nodeHash.unsafe_erase(previousSoloIt);
|
||||||
handleNodeKill(oldSoloNode);
|
handleNodeKill(oldSoloNode);
|
||||||
|
|
||||||
|
@ -675,6 +720,7 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
|
||||||
#else
|
#else
|
||||||
_nodeHash.emplace(newNode->getUUID(), newNodePointer);
|
_nodeHash.emplace(newNode->getUUID(), newNodePointer);
|
||||||
#endif
|
#endif
|
||||||
|
_localIDMap.emplace(localID, newNodePointer);
|
||||||
readLocker.unlock();
|
readLocker.unlock();
|
||||||
|
|
||||||
qCDebug(networking) << "Added" << *newNode;
|
qCDebug(networking) << "Added" << *newNode;
|
||||||
|
@ -703,13 +749,13 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<NLPacket> LimitedNodeList::constructPingPacket(PingType_t pingType) {
|
std::unique_ptr<NLPacket> LimitedNodeList::constructPingPacket(const QUuid& nodeId, PingType_t pingType) {
|
||||||
int packetSize = sizeof(PingType_t) + sizeof(quint64);
|
int packetSize = sizeof(PingType_t) + sizeof(quint64) + sizeof(int64_t);
|
||||||
|
|
||||||
auto pingPacket = NLPacket::create(PacketType::Ping, packetSize);
|
auto pingPacket = NLPacket::create(PacketType::Ping, packetSize);
|
||||||
|
|
||||||
pingPacket->writePrimitive(pingType);
|
pingPacket->writePrimitive(pingType);
|
||||||
pingPacket->writePrimitive(usecTimestampNow());
|
pingPacket->writePrimitive(usecTimestampNow());
|
||||||
|
pingPacket->writePrimitive(_connectionIDs[nodeId]);
|
||||||
|
|
||||||
return pingPacket;
|
return pingPacket;
|
||||||
}
|
}
|
||||||
|
@ -802,6 +848,7 @@ void LimitedNodeList::removeSilentNodes() {
|
||||||
if (!node->isForcedNeverSilent()
|
if (!node->isForcedNeverSilent()
|
||||||
&& (usecTimestampNow() - node->getLastHeardMicrostamp()) > (NODE_SILENCE_THRESHOLD_MSECS * USECS_PER_MSEC)) {
|
&& (usecTimestampNow() - node->getLastHeardMicrostamp()) > (NODE_SILENCE_THRESHOLD_MSECS * USECS_PER_MSEC)) {
|
||||||
// call the NodeHash erase to get rid of this node
|
// call the NodeHash erase to get rid of this node
|
||||||
|
_localIDMap.unsafe_erase(node->getLocalID());
|
||||||
it = _nodeHash.unsafe_erase(it);
|
it = _nodeHash.unsafe_erase(it);
|
||||||
|
|
||||||
killedNodes.insert(node);
|
killedNodes.insert(node);
|
||||||
|
|
|
@ -66,6 +66,10 @@ const QHostAddress DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME = QHostAddress::Lo
|
||||||
|
|
||||||
const QString USERNAME_UUID_REPLACEMENT_STATS_KEY = "$username";
|
const QString USERNAME_UUID_REPLACEMENT_STATS_KEY = "$username";
|
||||||
|
|
||||||
|
using ConnectionID = int64_t;
|
||||||
|
const ConnectionID NULL_CONNECTION_ID { -1 };
|
||||||
|
const ConnectionID INITIAL_CONNECTION_ID { 0 };
|
||||||
|
|
||||||
typedef std::pair<QUuid, SharedNodePointer> UUIDNodePair;
|
typedef std::pair<QUuid, SharedNodePointer> UUIDNodePair;
|
||||||
typedef tbb::concurrent_unordered_map<QUuid, SharedNodePointer, UUIDHasher> NodeHash;
|
typedef tbb::concurrent_unordered_map<QUuid, SharedNodePointer, UUIDHasher> NodeHash;
|
||||||
|
|
||||||
|
@ -106,6 +110,8 @@ public:
|
||||||
Q_ENUM(ConnectionStep);
|
Q_ENUM(ConnectionStep);
|
||||||
QUuid getSessionUUID() const;
|
QUuid getSessionUUID() const;
|
||||||
void setSessionUUID(const QUuid& sessionUUID);
|
void setSessionUUID(const QUuid& sessionUUID);
|
||||||
|
Node::LocalID getSessionLocalID() const;
|
||||||
|
void setSessionLocalID(Node::LocalID localID);
|
||||||
|
|
||||||
void setPermissions(const NodePermissions& newPermissions);
|
void setPermissions(const NodePermissions& newPermissions);
|
||||||
bool isAllowedEditor() const { return _permissions.can(NodePermissions::Permission::canAdjustLocks); }
|
bool isAllowedEditor() const { return _permissions.can(NodePermissions::Permission::canAdjustLocks); }
|
||||||
|
@ -126,24 +132,23 @@ public:
|
||||||
|
|
||||||
virtual bool isDomainServer() const { return true; }
|
virtual bool isDomainServer() const { return true; }
|
||||||
virtual QUuid getDomainUUID() const { assert(false); return QUuid(); }
|
virtual QUuid getDomainUUID() const { assert(false); return QUuid(); }
|
||||||
|
virtual Node::LocalID getDomainLocalID() const { assert(false); return Node::NULL_LOCAL_ID; }
|
||||||
virtual HifiSockAddr getDomainSockAddr() const { assert(false); return HifiSockAddr(); }
|
virtual HifiSockAddr getDomainSockAddr() const { assert(false); return HifiSockAddr(); }
|
||||||
|
|
||||||
// use sendUnreliablePacket to send an unrelaible packet (that you do not need to move)
|
// use sendUnreliablePacket to send an unreliable packet (that you do not need to move)
|
||||||
// either to a node (via its active socket) or to a manual sockaddr
|
// either to a node (via its active socket) or to a manual sockaddr
|
||||||
qint64 sendUnreliablePacket(const NLPacket& packet, const Node& destinationNode);
|
qint64 sendUnreliablePacket(const NLPacket& packet, const Node& destinationNode);
|
||||||
qint64 sendUnreliablePacket(const NLPacket& packet, const HifiSockAddr& sockAddr,
|
qint64 sendUnreliablePacket(const NLPacket& packet, const HifiSockAddr& sockAddr, HMACAuth* hmacAuth = nullptr);
|
||||||
const QUuid& connectionSecret = QUuid());
|
|
||||||
|
|
||||||
// use sendPacket to send a moved unreliable or reliable NL packet to a node's active socket or manual sockaddr
|
// use sendPacket to send a moved unreliable or reliable NL packet to a node's active socket or manual sockaddr
|
||||||
qint64 sendPacket(std::unique_ptr<NLPacket> packet, const Node& destinationNode);
|
qint64 sendPacket(std::unique_ptr<NLPacket> packet, const Node& destinationNode);
|
||||||
qint64 sendPacket(std::unique_ptr<NLPacket> packet, const HifiSockAddr& sockAddr,
|
qint64 sendPacket(std::unique_ptr<NLPacket> packet, const HifiSockAddr& sockAddr, HMACAuth* hmacAuth = nullptr);
|
||||||
const QUuid& connectionSecret = QUuid());
|
|
||||||
|
|
||||||
// use sendUnreliableUnorderedPacketList to unreliably send separate packets from the packet list
|
// use sendUnreliableUnorderedPacketList to unreliably send separate packets from the packet list
|
||||||
// either to a node's active socket or to a manual sockaddr
|
// either to a node's active socket or to a manual sockaddr
|
||||||
qint64 sendUnreliableUnorderedPacketList(NLPacketList& packetList, const Node& destinationNode);
|
qint64 sendUnreliableUnorderedPacketList(NLPacketList& packetList, const Node& destinationNode);
|
||||||
qint64 sendUnreliableUnorderedPacketList(NLPacketList& packetList, const HifiSockAddr& sockAddr,
|
qint64 sendUnreliableUnorderedPacketList(NLPacketList& packetList, const HifiSockAddr& sockAddr,
|
||||||
const QUuid& connectionSecret = QUuid());
|
HMACAuth* hmacAuth = nullptr);
|
||||||
|
|
||||||
// use sendPacketList to send reliable packet lists (ordered or unordered) to a node's active socket
|
// use sendPacketList to send reliable packet lists (ordered or unordered) to a node's active socket
|
||||||
// or to a manual sock addr
|
// or to a manual sock addr
|
||||||
|
@ -155,11 +160,12 @@ public:
|
||||||
size_t size() const { QReadLocker readLock(&_nodeMutex); return _nodeHash.size(); }
|
size_t size() const { QReadLocker readLock(&_nodeMutex); return _nodeHash.size(); }
|
||||||
|
|
||||||
SharedNodePointer nodeWithUUID(const QUuid& nodeUUID);
|
SharedNodePointer nodeWithUUID(const QUuid& nodeUUID);
|
||||||
|
SharedNodePointer nodeWithLocalID(Node::LocalID localID) const;
|
||||||
|
|
||||||
SharedNodePointer addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType,
|
SharedNodePointer addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType,
|
||||||
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
|
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
|
||||||
bool isReplicated = false, bool isUpstream = false,
|
Node::LocalID localID = Node::NULL_LOCAL_ID, bool isReplicated = false,
|
||||||
const QUuid& connectionSecret = QUuid(),
|
bool isUpstream = false, const QUuid& connectionSecret = QUuid(),
|
||||||
const NodePermissions& permissions = DEFAULT_AGENT_PERMISSIONS);
|
const NodePermissions& permissions = DEFAULT_AGENT_PERMISSIONS);
|
||||||
|
|
||||||
static bool parseSTUNResponse(udt::BasePacket* packet, QHostAddress& newPublicAddress, uint16_t& newPublicPort);
|
static bool parseSTUNResponse(udt::BasePacket* packet, QHostAddress& newPublicAddress, uint16_t& newPublicPort);
|
||||||
|
@ -180,7 +186,7 @@ public:
|
||||||
void getPacketStats(float& packetsInPerSecond, float& bytesInPerSecond, float& packetsOutPerSecond, float& bytesOutPerSecond);
|
void getPacketStats(float& packetsInPerSecond, float& bytesInPerSecond, float& packetsOutPerSecond, float& bytesOutPerSecond);
|
||||||
void resetPacketStats();
|
void resetPacketStats();
|
||||||
|
|
||||||
std::unique_ptr<NLPacket> constructPingPacket(PingType_t pingType = PingType::Agnostic);
|
std::unique_ptr<NLPacket> constructPingPacket(const QUuid& nodeId, PingType_t pingType = PingType::Agnostic);
|
||||||
std::unique_ptr<NLPacket> constructPingReplyPacket(ReceivedMessage& message);
|
std::unique_ptr<NLPacket> constructPingReplyPacket(ReceivedMessage& message);
|
||||||
|
|
||||||
static std::unique_ptr<NLPacket> constructICEPingPacket(PingType_t pingType, const QUuid& iceID);
|
static std::unique_ptr<NLPacket> constructICEPingPacket(PingType_t pingType, const QUuid& iceID);
|
||||||
|
@ -319,7 +325,7 @@ public slots:
|
||||||
void startSTUNPublicSocketUpdate();
|
void startSTUNPublicSocketUpdate();
|
||||||
virtual void sendSTUNRequest();
|
virtual void sendSTUNRequest();
|
||||||
|
|
||||||
bool killNodeWithUUID(const QUuid& nodeUUID);
|
bool killNodeWithUUID(const QUuid& nodeUUID, ConnectionID newConnectionID = NULL_CONNECTION_ID);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void dataSent(quint8 channelType, int bytes);
|
void dataSent(quint8 channelType, int bytes);
|
||||||
|
@ -364,14 +370,14 @@ protected:
|
||||||
qint64 writePacket(const NLPacket& packet, const HifiSockAddr& destinationSockAddr,
|
qint64 writePacket(const NLPacket& packet, const HifiSockAddr& destinationSockAddr,
|
||||||
const QUuid& connectionSecret = QUuid());
|
const QUuid& connectionSecret = QUuid());
|
||||||
void collectPacketStats(const NLPacket& packet);
|
void collectPacketStats(const NLPacket& packet);
|
||||||
void fillPacketHeader(const NLPacket& packet, const QUuid& connectionSecret = QUuid());
|
void fillPacketHeader(const NLPacket& packet, HMACAuth* hmacAuth = nullptr);
|
||||||
|
|
||||||
void setLocalSocket(const HifiSockAddr& sockAddr);
|
void setLocalSocket(const HifiSockAddr& sockAddr);
|
||||||
|
|
||||||
bool packetSourceAndHashMatchAndTrackBandwidth(const udt::Packet& packet, Node* sourceNode = nullptr);
|
bool packetSourceAndHashMatchAndTrackBandwidth(const udt::Packet& packet, Node* sourceNode = nullptr);
|
||||||
void processSTUNResponse(std::unique_ptr<udt::BasePacket> packet);
|
void processSTUNResponse(std::unique_ptr<udt::BasePacket> packet);
|
||||||
|
|
||||||
void handleNodeKill(const SharedNodePointer& node);
|
void handleNodeKill(const SharedNodePointer& node, ConnectionID newConnectionID = NULL_CONNECTION_ID);
|
||||||
|
|
||||||
void stopInitialSTUNUpdate(bool success);
|
void stopInitialSTUNUpdate(bool success);
|
||||||
|
|
||||||
|
@ -418,6 +424,7 @@ protected:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unordered_map<QUuid, ConnectionID> _connectionIDs;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void flagTimeForConnectionStep(ConnectionStep connectionStep, quint64 timestamp);
|
void flagTimeForConnectionStep(ConnectionStep connectionStep, quint64 timestamp);
|
||||||
|
@ -427,6 +434,9 @@ private slots:
|
||||||
private:
|
private:
|
||||||
mutable QReadWriteLock _sessionUUIDLock;
|
mutable QReadWriteLock _sessionUUIDLock;
|
||||||
QUuid _sessionUUID;
|
QUuid _sessionUUID;
|
||||||
|
using LocalIDMapping = tbb::concurrent_unordered_map<Node::LocalID, SharedNodePointer>;
|
||||||
|
LocalIDMapping _localIDMap;
|
||||||
|
Node::LocalID _sessionLocalID { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_LimitedNodeList_h
|
#endif // hifi_LimitedNodeList_h
|
||||||
|
|
|
@ -11,10 +11,12 @@
|
||||||
|
|
||||||
#include "NLPacket.h"
|
#include "NLPacket.h"
|
||||||
|
|
||||||
|
#include "HMACAuth.h"
|
||||||
|
|
||||||
int NLPacket::localHeaderSize(PacketType type) {
|
int NLPacket::localHeaderSize(PacketType type) {
|
||||||
bool nonSourced = PacketTypeEnum::getNonSourcedPackets().contains(type);
|
bool nonSourced = PacketTypeEnum::getNonSourcedPackets().contains(type);
|
||||||
bool nonVerified = PacketTypeEnum::getNonVerifiedPackets().contains(type);
|
bool nonVerified = PacketTypeEnum::getNonVerifiedPackets().contains(type);
|
||||||
qint64 optionalSize = (nonSourced ? 0 : NUM_BYTES_RFC4122_UUID) + ((nonSourced || nonVerified) ? 0 : NUM_BYTES_MD5_HASH);
|
qint64 optionalSize = (nonSourced ? 0 : NUM_BYTES_LOCALID) + ((nonSourced || nonVerified) ? 0 : NUM_BYTES_MD5_HASH);
|
||||||
return sizeof(PacketType) + sizeof(PacketVersion) + optionalSize;
|
return sizeof(PacketType) + sizeof(PacketVersion) + optionalSize;
|
||||||
}
|
}
|
||||||
int NLPacket::totalHeaderSize(PacketType type, bool isPartOfMessage) {
|
int NLPacket::totalHeaderSize(PacketType type, bool isPartOfMessage) {
|
||||||
|
@ -139,28 +141,25 @@ PacketVersion NLPacket::versionInHeader(const udt::Packet& packet) {
|
||||||
return *reinterpret_cast<const PacketVersion*>(packet.getData() + headerOffset + sizeof(PacketType));
|
return *reinterpret_cast<const PacketVersion*>(packet.getData() + headerOffset + sizeof(PacketType));
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid NLPacket::sourceIDInHeader(const udt::Packet& packet) {
|
NLPacket::LocalID NLPacket::sourceIDInHeader(const udt::Packet& packet) {
|
||||||
int offset = Packet::totalHeaderSize(packet.isPartOfMessage()) + 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));
|
return *reinterpret_cast<const LocalID*>(packet.getData() + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray NLPacket::verificationHashInHeader(const udt::Packet& packet) {
|
QByteArray NLPacket::verificationHashInHeader(const udt::Packet& packet) {
|
||||||
int offset = Packet::totalHeaderSize(packet.isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID;
|
int offset = Packet::totalHeaderSize(packet.isPartOfMessage()) + sizeof(PacketType) +
|
||||||
|
sizeof(PacketVersion) + NUM_BYTES_LOCALID;
|
||||||
return QByteArray(packet.getData() + offset, NUM_BYTES_MD5_HASH);
|
return QByteArray(packet.getData() + offset, NUM_BYTES_MD5_HASH);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray NLPacket::hashForPacketAndSecret(const udt::Packet& packet, const QUuid& connectionSecret) {
|
QByteArray NLPacket::hashForPacketAndHMAC(const udt::Packet& packet, HMACAuth& hash) {
|
||||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
|
||||||
|
|
||||||
int offset = Packet::totalHeaderSize(packet.isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion)
|
int offset = Packet::totalHeaderSize(packet.isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion)
|
||||||
+ NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH;
|
+ NUM_BYTES_LOCALID + NUM_BYTES_MD5_HASH;
|
||||||
|
|
||||||
// add the packet payload and the connection UUID
|
// add the packet payload and the connection UUID
|
||||||
hash.addData(packet.getData() + offset, packet.getDataSize() - offset);
|
hash.addData(packet.getData() + offset, packet.getDataSize() - offset);
|
||||||
hash.addData(connectionSecret.toRfc4122());
|
auto hashResult { hash.result() };
|
||||||
|
return QByteArray((const char*) hashResult.data(), (int) hashResult.size());
|
||||||
// return the hash
|
|
||||||
return hash.result();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NLPacket::writeTypeAndVersion() {
|
void NLPacket::writeTypeAndVersion() {
|
||||||
|
@ -203,22 +202,24 @@ void NLPacket::readSourceID() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NLPacket::writeSourceID(const QUuid& sourceID) const {
|
void NLPacket::writeSourceID(LocalID sourceID) const {
|
||||||
Q_ASSERT(!PacketTypeEnum::getNonSourcedPackets().contains(_type));
|
Q_ASSERT(!PacketTypeEnum::getNonSourcedPackets().contains(_type));
|
||||||
|
|
||||||
auto offset = Packet::totalHeaderSize(isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion);
|
auto offset = Packet::totalHeaderSize(isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion);
|
||||||
memcpy(_packet.get() + offset, sourceID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID);
|
|
||||||
|
memcpy(_packet.get() + offset, &sourceID, sizeof(sourceID));
|
||||||
|
|
||||||
_sourceID = sourceID;
|
_sourceID = sourceID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NLPacket::writeVerificationHashGivenSecret(const QUuid& connectionSecret) const {
|
void NLPacket::writeVerificationHash(HMACAuth& hmacAuth) const {
|
||||||
Q_ASSERT(!PacketTypeEnum::getNonSourcedPackets().contains(_type) &&
|
Q_ASSERT(!PacketTypeEnum::getNonSourcedPackets().contains(_type) &&
|
||||||
!PacketTypeEnum::getNonVerifiedPackets().contains(_type));
|
!PacketTypeEnum::getNonVerifiedPackets().contains(_type));
|
||||||
|
|
||||||
auto offset = Packet::totalHeaderSize(isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion)
|
auto offset = Packet::totalHeaderSize(isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion)
|
||||||
+ NUM_BYTES_RFC4122_UUID;
|
+ NUM_BYTES_LOCALID;
|
||||||
QByteArray verificationHash = hashForPacketAndSecret(*this, connectionSecret);
|
|
||||||
|
QByteArray verificationHash = hashForPacketAndHMAC(*this, hmacAuth);
|
||||||
|
|
||||||
memcpy(_packet.get() + offset, verificationHash.data(), verificationHash.size());
|
memcpy(_packet.get() + offset, verificationHash.data(), verificationHash.size());
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,35 +18,35 @@
|
||||||
|
|
||||||
#include "udt/Packet.h"
|
#include "udt/Packet.h"
|
||||||
|
|
||||||
|
class HMACAuth;
|
||||||
|
|
||||||
class NLPacket : public udt::Packet {
|
class NLPacket : public udt::Packet {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
//
|
//
|
||||||
// | BYTE | BYTE | BYTE | BYTE |
|
// NLPacket format:
|
||||||
//
|
//
|
||||||
|
// | BYTE | BYTE | BYTE | BYTE |
|
||||||
// 0 1 2 3
|
// 0 1 2 3
|
||||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
// | Packet Type | Version | |
|
// | Packet Type | Version | Local Node ID - sourced only |
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
// | |
|
// | |
|
||||||
// | Node UUID - 16 bytes |
|
// | MD5 Verification - 16 bytes |
|
||||||
// | (ONLY FOR SOURCED PACKETS) |
|
// | (ONLY FOR VERIFIED PACKETS) |
|
||||||
// | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
||||||
// | | |
|
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
|
||||||
// | |
|
// | |
|
||||||
// | MD5 Verification - 16 bytes |
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
// | (ONLY FOR VERIFIED PACKETS) |
|
//
|
||||||
// | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
||||||
// | | |
|
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
|
||||||
// NLPacket Header Format
|
|
||||||
|
|
||||||
|
using LocalID = NetworkLocalID;
|
||||||
|
static const LocalID NULL_LOCAL_ID = 0;
|
||||||
|
|
||||||
|
static const int NUM_BYTES_LOCALID = sizeof(LocalID);
|
||||||
// this is used by the Octree classes - must be known at compile time
|
// this is used by the Octree classes - must be known at compile time
|
||||||
static const int MAX_PACKET_HEADER_SIZE =
|
static const int MAX_PACKET_HEADER_SIZE =
|
||||||
sizeof(udt::Packet::SequenceNumberAndBitField) + sizeof(udt::Packet::MessageNumberAndBitField) +
|
sizeof(udt::Packet::SequenceNumberAndBitField) + sizeof(udt::Packet::MessageNumberAndBitField) +
|
||||||
sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH;
|
sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_LOCALID + NUM_BYTES_MD5_HASH;
|
||||||
|
|
||||||
static std::unique_ptr<NLPacket> create(PacketType type, qint64 size = -1,
|
static std::unique_ptr<NLPacket> create(PacketType type, qint64 size = -1,
|
||||||
bool isReliable = false, bool isPartOfMessage = false, PacketVersion version = 0);
|
bool isReliable = false, bool isPartOfMessage = false, PacketVersion version = 0);
|
||||||
|
@ -69,9 +69,9 @@ public:
|
||||||
static PacketType typeInHeader(const udt::Packet& packet);
|
static PacketType typeInHeader(const udt::Packet& packet);
|
||||||
static PacketVersion versionInHeader(const udt::Packet& packet);
|
static PacketVersion versionInHeader(const udt::Packet& packet);
|
||||||
|
|
||||||
static QUuid sourceIDInHeader(const udt::Packet& packet);
|
static LocalID sourceIDInHeader(const udt::Packet& packet);
|
||||||
static QByteArray verificationHashInHeader(const udt::Packet& packet);
|
static QByteArray verificationHashInHeader(const udt::Packet& packet);
|
||||||
static QByteArray hashForPacketAndSecret(const udt::Packet& packet, const QUuid& connectionSecret);
|
static QByteArray hashForPacketAndHMAC(const udt::Packet& packet, HMACAuth& hash);
|
||||||
|
|
||||||
PacketType getType() const { return _type; }
|
PacketType getType() const { return _type; }
|
||||||
void setType(PacketType type);
|
void setType(PacketType type);
|
||||||
|
@ -79,10 +79,10 @@ public:
|
||||||
PacketVersion getVersion() const { return _version; }
|
PacketVersion getVersion() const { return _version; }
|
||||||
void setVersion(PacketVersion version);
|
void setVersion(PacketVersion version);
|
||||||
|
|
||||||
const QUuid& getSourceID() const { return _sourceID; }
|
LocalID getSourceID() const { return _sourceID; }
|
||||||
|
|
||||||
void writeSourceID(const QUuid& sourceID) const;
|
void writeSourceID(LocalID sourceID) const;
|
||||||
void writeVerificationHashGivenSecret(const QUuid& connectionSecret) const;
|
void writeVerificationHash(HMACAuth& hmacAuth) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ protected:
|
||||||
|
|
||||||
PacketType _type;
|
PacketType _type;
|
||||||
PacketVersion _version;
|
PacketVersion _version;
|
||||||
mutable QUuid _sourceID;
|
mutable LocalID _sourceID;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_NLPacket_h
|
#endif // hifi_NLPacket_h
|
||||||
|
|
|
@ -22,7 +22,7 @@ public:
|
||||||
bool isReliable = false, bool isOrdered = false);
|
bool isReliable = false, bool isOrdered = false);
|
||||||
|
|
||||||
PacketVersion getVersion() const { return _packetVersion; }
|
PacketVersion getVersion() const { return _packetVersion; }
|
||||||
const QUuid& getSourceID() const { return _sourceID; }
|
NLPacket::LocalID getSourceID() const { return _sourceID; }
|
||||||
|
|
||||||
qint64 getMaxSegmentSize() const override { return NLPacket::maxPayloadSize(_packetType, _isOrdered); }
|
qint64 getMaxSegmentSize() const override { return NLPacket::maxPayloadSize(_packetType, _isOrdered); }
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ private:
|
||||||
|
|
||||||
|
|
||||||
PacketVersion _packetVersion;
|
PacketVersion _packetVersion;
|
||||||
QUuid _sourceID;
|
NLPacket::LocalID _sourceID;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(QSharedPointer<NLPacketList>)
|
Q_DECLARE_METATYPE(QSharedPointer<NLPacketList>)
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <Trace.h>
|
#include <Trace.h>
|
||||||
#include "NodeType.h"
|
#include "NodeType.h"
|
||||||
|
|
||||||
|
const NetworkPeer::LocalID NetworkPeer::NULL_LOCAL_ID;
|
||||||
|
|
||||||
NetworkPeer::NetworkPeer(QObject* parent) :
|
NetworkPeer::NetworkPeer(QObject* parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <QtCore/QTimer>
|
#include <QtCore/QTimer>
|
||||||
#include <QtCore/QUuid>
|
#include <QtCore/QUuid>
|
||||||
|
|
||||||
|
#include "UUID.h"
|
||||||
#include "HifiSockAddr.h"
|
#include "HifiSockAddr.h"
|
||||||
|
|
||||||
const QString ICE_SERVER_HOSTNAME = "localhost";
|
const QString ICE_SERVER_HOSTNAME = "localhost";
|
||||||
|
@ -39,6 +40,12 @@ public:
|
||||||
const QUuid& getUUID() const { return _uuid; }
|
const QUuid& getUUID() const { return _uuid; }
|
||||||
void setUUID(const QUuid& uuid) { _uuid = uuid; }
|
void setUUID(const QUuid& uuid) { _uuid = uuid; }
|
||||||
|
|
||||||
|
using LocalID = NetworkLocalID;
|
||||||
|
static const LocalID NULL_LOCAL_ID = 0;
|
||||||
|
|
||||||
|
LocalID getLocalID() const { return _localID; }
|
||||||
|
void setLocalID(LocalID localID) { _localID = localID; }
|
||||||
|
|
||||||
void softReset();
|
void softReset();
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
@ -99,6 +106,7 @@ protected:
|
||||||
void setActiveSocket(HifiSockAddr* discoveredSocket);
|
void setActiveSocket(HifiSockAddr* discoveredSocket);
|
||||||
|
|
||||||
QUuid _uuid;
|
QUuid _uuid;
|
||||||
|
LocalID _localID { 0 };
|
||||||
|
|
||||||
HifiSockAddr _publicSocket;
|
HifiSockAddr _publicSocket;
|
||||||
HifiSockAddr _localSocket;
|
HifiSockAddr _localSocket;
|
||||||
|
|
|
@ -86,10 +86,10 @@ NodeType_t NodeType::fromString(QString type) {
|
||||||
|
|
||||||
|
|
||||||
Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket,
|
Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket,
|
||||||
const HifiSockAddr& localSocket, QObject* parent) :
|
const HifiSockAddr& localSocket, QObject* parent) :
|
||||||
NetworkPeer(uuid, publicSocket, localSocket, parent),
|
NetworkPeer(uuid, publicSocket, localSocket, parent),
|
||||||
_type(type),
|
_type(type),
|
||||||
_pingMs(-1), // "Uninitialized"
|
_authenticateHash(new HMACAuth), _pingMs(-1), // "Uninitialized"
|
||||||
_clockSkewUsec(0),
|
_clockSkewUsec(0),
|
||||||
_mutex(),
|
_mutex(),
|
||||||
_clockSkewMovingPercentile(30, 0.8f) // moving 80th percentile of 30 samples
|
_clockSkewMovingPercentile(30, 0.8f) // moving 80th percentile of 30 samples
|
||||||
|
@ -108,6 +108,7 @@ void Node::setType(char type) {
|
||||||
_symmetricSocket.setObjectName(typeString);
|
_symmetricSocket.setObjectName(typeString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Node::updateClockSkewUsec(qint64 clockSkewSample) {
|
void Node::updateClockSkewUsec(qint64 clockSkewSample) {
|
||||||
_clockSkewMovingPercentile.updatePercentile(clockSkewSample);
|
_clockSkewMovingPercentile.updatePercentile(clockSkewSample);
|
||||||
_clockSkewUsec = (quint64)_clockSkewMovingPercentile.getValueAtPercentile();
|
_clockSkewUsec = (quint64)_clockSkewMovingPercentile.getValueAtPercentile();
|
||||||
|
@ -168,6 +169,7 @@ QDataStream& operator<<(QDataStream& out, const Node& node) {
|
||||||
out << node._localSocket;
|
out << node._localSocket;
|
||||||
out << node._permissions;
|
out << node._permissions;
|
||||||
out << node._isReplicated;
|
out << node._isReplicated;
|
||||||
|
out << node._localID;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,6 +180,7 @@ QDataStream& operator>>(QDataStream& in, Node& node) {
|
||||||
in >> node._localSocket;
|
in >> node._localSocket;
|
||||||
in >> node._permissions;
|
in >> node._permissions;
|
||||||
in >> node._isReplicated;
|
in >> node._isReplicated;
|
||||||
|
in >> node._localID;
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +191,16 @@ QDebug operator<<(QDebug debug, const Node& node) {
|
||||||
} else {
|
} else {
|
||||||
debug.nospace() << " (" << node.getType() << ")";
|
debug.nospace() << " (" << node.getType() << ")";
|
||||||
}
|
}
|
||||||
debug << " " << node.getUUID().toString().toLocal8Bit().constData() << " ";
|
debug << " " << node.getUUID().toString().toLocal8Bit().constData() << "(" << node.getLocalID() << ") ";
|
||||||
debug.nospace() << node.getPublicSocket() << "/" << node.getLocalSocket();
|
debug.nospace() << node.getPublicSocket() << "/" << node.getLocalSocket();
|
||||||
return debug.nospace();
|
return debug.nospace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Node::setConnectionSecret(const QUuid& connectionSecret) {
|
||||||
|
if (_connectionSecret == connectionSecret) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_connectionSecret = connectionSecret;
|
||||||
|
_authenticateHash->setKey(_connectionSecret);
|
||||||
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "SimpleMovingAverage.h"
|
#include "SimpleMovingAverage.h"
|
||||||
#include "MovingPercentile.h"
|
#include "MovingPercentile.h"
|
||||||
#include "NodePermissions.h"
|
#include "NodePermissions.h"
|
||||||
|
#include "HMACAuth.h"
|
||||||
|
|
||||||
class Node : public NetworkPeer {
|
class Node : public NetworkPeer {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -55,7 +56,8 @@ public:
|
||||||
void setIsUpstream(bool isUpstream) { _isUpstream = isUpstream; }
|
void setIsUpstream(bool isUpstream) { _isUpstream = isUpstream; }
|
||||||
|
|
||||||
const QUuid& getConnectionSecret() const { return _connectionSecret; }
|
const QUuid& getConnectionSecret() const { return _connectionSecret; }
|
||||||
void setConnectionSecret(const QUuid& connectionSecret) { _connectionSecret = connectionSecret; }
|
void setConnectionSecret(const QUuid& connectionSecret);
|
||||||
|
HMACAuth& getAuthenticateHash() const { return *_authenticateHash; }
|
||||||
|
|
||||||
NodeData* getLinkedData() const { return _linkedData.get(); }
|
NodeData* getLinkedData() const { return _linkedData.get(); }
|
||||||
void setLinkedData(std::unique_ptr<NodeData> linkedData) { _linkedData = std::move(linkedData); }
|
void setLinkedData(std::unique_ptr<NodeData> linkedData) { _linkedData = std::move(linkedData); }
|
||||||
|
@ -97,6 +99,7 @@ private:
|
||||||
NodeType_t _type;
|
NodeType_t _type;
|
||||||
|
|
||||||
QUuid _connectionSecret;
|
QUuid _connectionSecret;
|
||||||
|
std::unique_ptr<HMACAuth> _authenticateHash;
|
||||||
std::unique_ptr<NodeData> _linkedData;
|
std::unique_ptr<NodeData> _linkedData;
|
||||||
bool _isReplicated { false };
|
bool _isReplicated { false };
|
||||||
int _pingMs;
|
int _pingMs;
|
||||||
|
|
|
@ -214,6 +214,20 @@ void NodeList::processPingPacket(QSharedPointer<ReceivedMessage> message, Shared
|
||||||
sendingNode->setSymmetricSocket(senderSockAddr);
|
sendingNode->setSymmetricSocket(senderSockAddr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t connectionID;
|
||||||
|
|
||||||
|
message->readPrimitive(&connectionID);
|
||||||
|
|
||||||
|
auto it = _connectionIDs.find(sendingNode->getUUID());
|
||||||
|
if (it != _connectionIDs.end()) {
|
||||||
|
if (connectionID > it->second) {
|
||||||
|
qDebug() << "Received a ping packet with a larger connection id (" << connectionID << ">" << it->second << ") from "
|
||||||
|
<< sendingNode->getUUID();
|
||||||
|
killNodeWithUUID(sendingNode->getUUID(), connectionID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::processPingReplyPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
|
void NodeList::processPingReplyPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
|
||||||
|
@ -610,13 +624,21 @@ void NodeList::processDomainServerList(QSharedPointer<ReceivedMessage> message)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// pull our owner UUID from the packet, it's always the first thing
|
Node::LocalID domainLocalID;
|
||||||
|
packetStream >> domainLocalID;
|
||||||
|
|
||||||
|
// pull our owner (ie. session) UUID from the packet, it's always the first thing
|
||||||
|
// The short (16 bit) ID comes next.
|
||||||
QUuid newUUID;
|
QUuid newUUID;
|
||||||
|
Node::LocalID newLocalID;
|
||||||
packetStream >> newUUID;
|
packetStream >> newUUID;
|
||||||
|
packetStream >> newLocalID;
|
||||||
|
setSessionLocalID(newLocalID);
|
||||||
setSessionUUID(newUUID);
|
setSessionUUID(newUUID);
|
||||||
|
|
||||||
// if this was the first domain-server list from this domain, we've now connected
|
// if this was the first domain-server list from this domain, we've now connected
|
||||||
if (!_domainHandler.isConnected()) {
|
if (!_domainHandler.isConnected()) {
|
||||||
|
_domainHandler.setLocalID(newLocalID);
|
||||||
_domainHandler.setUUID(domainUUID);
|
_domainHandler.setUUID(domainUUID);
|
||||||
_domainHandler.setIsConnected(true);
|
_domainHandler.setIsConnected(true);
|
||||||
|
|
||||||
|
@ -654,12 +676,14 @@ void NodeList::processDomainServerRemovedNode(QSharedPointer<ReceivedMessage> me
|
||||||
void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) {
|
void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) {
|
||||||
// setup variables to read into from QDataStream
|
// setup variables to read into from QDataStream
|
||||||
qint8 nodeType;
|
qint8 nodeType;
|
||||||
QUuid nodeUUID, connectionUUID;
|
QUuid nodeUUID, connectionSecretUUID;
|
||||||
HifiSockAddr nodePublicSocket, nodeLocalSocket;
|
HifiSockAddr nodePublicSocket, nodeLocalSocket;
|
||||||
NodePermissions permissions;
|
NodePermissions permissions;
|
||||||
bool isReplicated;
|
bool isReplicated;
|
||||||
|
Node::LocalID sessionLocalID;
|
||||||
|
|
||||||
packetStream >> nodeType >> nodeUUID >> nodePublicSocket >> nodeLocalSocket >> permissions >> isReplicated;
|
packetStream >> nodeType >> nodeUUID >> nodePublicSocket >> nodeLocalSocket >> permissions
|
||||||
|
>> isReplicated >> sessionLocalID;
|
||||||
|
|
||||||
// if the public socket address is 0 then it's reachable at the same IP
|
// if the public socket address is 0 then it's reachable at the same IP
|
||||||
// as the domain server
|
// as the domain server
|
||||||
|
@ -667,10 +691,10 @@ void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) {
|
||||||
nodePublicSocket.setAddress(_domainHandler.getIP());
|
nodePublicSocket.setAddress(_domainHandler.getIP());
|
||||||
}
|
}
|
||||||
|
|
||||||
packetStream >> connectionUUID;
|
packetStream >> connectionSecretUUID;
|
||||||
|
|
||||||
SharedNodePointer node = addOrUpdateNode(nodeUUID, nodeType, nodePublicSocket,
|
SharedNodePointer node = addOrUpdateNode(nodeUUID, nodeType, nodePublicSocket, nodeLocalSocket,
|
||||||
nodeLocalSocket, isReplicated, false, connectionUUID, permissions);
|
sessionLocalID, isReplicated, false, connectionSecretUUID, permissions);
|
||||||
|
|
||||||
// nodes that are downstream or upstream of our own type are kept alive when we hear about them from the domain server
|
// nodes that are downstream or upstream of our own type are kept alive when we hear about them from the domain server
|
||||||
// and always have their public socket as their active socket
|
// and always have their public socket as their active socket
|
||||||
|
@ -705,16 +729,18 @@ void NodeList::pingPunchForInactiveNode(const SharedNodePointer& node) {
|
||||||
if (node->getConnectionAttempts() > 0 && node->getConnectionAttempts() % NUM_DEBUG_CONNECTION_ATTEMPTS == 0) {
|
if (node->getConnectionAttempts() > 0 && node->getConnectionAttempts() % NUM_DEBUG_CONNECTION_ATTEMPTS == 0) {
|
||||||
qCDebug(networking) << "No response to UDP hole punch pings for node" << node->getUUID() << "in last second.";
|
qCDebug(networking) << "No response to UDP hole punch pings for node" << node->getUUID() << "in last second.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto nodeID = node->getUUID();
|
||||||
|
|
||||||
// send the ping packet to the local and public sockets for this node
|
// send the ping packet to the local and public sockets for this node
|
||||||
auto localPingPacket = constructPingPacket(PingType::Local);
|
auto localPingPacket = constructPingPacket(nodeID, PingType::Local);
|
||||||
sendPacket(std::move(localPingPacket), *node, node->getLocalSocket());
|
sendPacket(std::move(localPingPacket), *node, node->getLocalSocket());
|
||||||
|
|
||||||
auto publicPingPacket = constructPingPacket(PingType::Public);
|
auto publicPingPacket = constructPingPacket(nodeID, PingType::Public);
|
||||||
sendPacket(std::move(publicPingPacket), *node, node->getPublicSocket());
|
sendPacket(std::move(publicPingPacket), *node, node->getPublicSocket());
|
||||||
|
|
||||||
if (!node->getSymmetricSocket().isNull()) {
|
if (!node->getSymmetricSocket().isNull()) {
|
||||||
auto symmetricPingPacket = constructPingPacket(PingType::Symmetric);
|
auto symmetricPingPacket = constructPingPacket(nodeID, PingType::Symmetric);
|
||||||
sendPacket(std::move(symmetricPingPacket), *node, node->getSymmetricSocket());
|
sendPacket(std::move(symmetricPingPacket), *node, node->getSymmetricSocket());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -784,7 +810,7 @@ void NodeList::sendKeepAlivePings() {
|
||||||
auto type = node->getType();
|
auto type = node->getType();
|
||||||
return !node->isUpstream() && _nodeTypesOfInterest.contains(type) && !NodeType::isDownstream(type);
|
return !node->isUpstream() && _nodeTypesOfInterest.contains(type) && !NodeType::isDownstream(type);
|
||||||
}, [&](const SharedNodePointer& node) {
|
}, [&](const SharedNodePointer& node) {
|
||||||
sendPacket(constructPingPacket(), *node);
|
sendPacket(constructPingPacket(node->getUUID()), *node);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,7 @@ public:
|
||||||
|
|
||||||
virtual bool isDomainServer() const override { return false; }
|
virtual bool isDomainServer() const override { return false; }
|
||||||
virtual QUuid getDomainUUID() const override { return _domainHandler.getUUID(); }
|
virtual QUuid getDomainUUID() const override { return _domainHandler.getUUID(); }
|
||||||
|
virtual Node::LocalID getDomainLocalID() const override { return _domainHandler.getLocalID(); }
|
||||||
virtual HifiSockAddr getDomainSockAddr() const override { return _domainHandler.getSockAddr(); }
|
virtual HifiSockAddr getDomainSockAddr() const override { return _domainHandler.getSockAddr(); }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
|
@ -261,10 +261,9 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer<ReceivedMessage> recei
|
||||||
|
|
||||||
SharedNodePointer matchingNode;
|
SharedNodePointer matchingNode;
|
||||||
|
|
||||||
if (!receivedMessage->getSourceID().isNull()) {
|
if (receivedMessage->getSourceID() != Node::NULL_LOCAL_ID) {
|
||||||
matchingNode = nodeList->nodeWithUUID(receivedMessage->getSourceID());
|
matchingNode = nodeList->nodeWithLocalID(receivedMessage->getSourceID());
|
||||||
}
|
}
|
||||||
|
|
||||||
QMutexLocker packetListenerLocker(&_packetListenerLock);
|
QMutexLocker packetListenerLocker(&_packetListenerLock);
|
||||||
|
|
||||||
auto it = _messageListenerMap.find(receivedMessage->getType());
|
auto it = _messageListenerMap.find(receivedMessage->getType());
|
||||||
|
|
|
@ -43,7 +43,7 @@ ReceivedMessage::ReceivedMessage(NLPacket& packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
ReceivedMessage::ReceivedMessage(QByteArray byteArray, PacketType packetType, PacketVersion packetVersion,
|
ReceivedMessage::ReceivedMessage(QByteArray byteArray, PacketType packetType, PacketVersion packetVersion,
|
||||||
const HifiSockAddr& senderSockAddr, QUuid sourceID) :
|
const HifiSockAddr& senderSockAddr, NLPacket::LocalID sourceID) :
|
||||||
_data(byteArray),
|
_data(byteArray),
|
||||||
_headData(_data.mid(0, HEAD_DATA_SIZE)),
|
_headData(_data.mid(0, HEAD_DATA_SIZE)),
|
||||||
_numPackets(1),
|
_numPackets(1),
|
||||||
|
|
|
@ -25,7 +25,7 @@ public:
|
||||||
ReceivedMessage(const NLPacketList& packetList);
|
ReceivedMessage(const NLPacketList& packetList);
|
||||||
ReceivedMessage(NLPacket& packet);
|
ReceivedMessage(NLPacket& packet);
|
||||||
ReceivedMessage(QByteArray byteArray, PacketType packetType, PacketVersion packetVersion,
|
ReceivedMessage(QByteArray byteArray, PacketType packetType, PacketVersion packetVersion,
|
||||||
const HifiSockAddr& senderSockAddr, QUuid sourceID = QUuid());
|
const HifiSockAddr& senderSockAddr, NLPacket::LocalID sourceID = NLPacket::NULL_LOCAL_ID);
|
||||||
|
|
||||||
QByteArray getMessage() const { return _data; }
|
QByteArray getMessage() const { return _data; }
|
||||||
const char* getRawMessage() const { return _data.constData(); }
|
const char* getRawMessage() const { return _data.constData(); }
|
||||||
|
@ -40,7 +40,7 @@ public:
|
||||||
bool failed() const { return _failed; }
|
bool failed() const { return _failed; }
|
||||||
bool isComplete() const { return _isComplete; }
|
bool isComplete() const { return _isComplete; }
|
||||||
|
|
||||||
const QUuid& getSourceID() const { return _sourceID; }
|
NLPacket::LocalID getSourceID() const { return _sourceID; }
|
||||||
const HifiSockAddr& getSenderSockAddr() { return _senderSockAddr; }
|
const HifiSockAddr& getSenderSockAddr() { return _senderSockAddr; }
|
||||||
|
|
||||||
qint64 getPosition() const { return _position; }
|
qint64 getPosition() const { return _position; }
|
||||||
|
@ -93,7 +93,7 @@ private:
|
||||||
std::atomic<qint64> _position { 0 };
|
std::atomic<qint64> _position { 0 };
|
||||||
std::atomic<qint64> _numPackets { 0 };
|
std::atomic<qint64> _numPackets { 0 };
|
||||||
|
|
||||||
QUuid _sourceID;
|
NLPacket::LocalID _sourceID { NLPacket::NULL_LOCAL_ID };
|
||||||
PacketType _packetType;
|
PacketType _packetType;
|
||||||
PacketVersion _packetVersion;
|
PacketVersion _packetVersion;
|
||||||
HifiSockAddr _senderSockAddr;
|
HifiSockAddr _senderSockAddr;
|
||||||
|
|
|
@ -25,7 +25,7 @@ SequenceNumberStats::SequenceNumberStats(int statsHistoryLength, bool canDetectO
|
||||||
: _lastReceivedSequence(0),
|
: _lastReceivedSequence(0),
|
||||||
_missingSet(),
|
_missingSet(),
|
||||||
_stats(),
|
_stats(),
|
||||||
_lastSenderUUID(),
|
_lastSenderID(NULL_LOCAL_ID),
|
||||||
_statsHistory(statsHistoryLength),
|
_statsHistory(statsHistoryLength),
|
||||||
_lastUnreasonableSequence(0),
|
_lastUnreasonableSequence(0),
|
||||||
_consecutiveUnreasonableOnTime(0)
|
_consecutiveUnreasonableOnTime(0)
|
||||||
|
@ -35,7 +35,7 @@ SequenceNumberStats::SequenceNumberStats(int statsHistoryLength, bool canDetectO
|
||||||
void SequenceNumberStats::reset() {
|
void SequenceNumberStats::reset() {
|
||||||
_missingSet.clear();
|
_missingSet.clear();
|
||||||
_stats = PacketStreamStats();
|
_stats = PacketStreamStats();
|
||||||
_lastSenderUUID = QUuid();
|
_lastSenderID = NULL_LOCAL_ID;
|
||||||
_statsHistory.clear();
|
_statsHistory.clear();
|
||||||
_lastUnreasonableSequence = 0;
|
_lastUnreasonableSequence = 0;
|
||||||
_consecutiveUnreasonableOnTime = 0;
|
_consecutiveUnreasonableOnTime = 0;
|
||||||
|
@ -43,18 +43,18 @@ void SequenceNumberStats::reset() {
|
||||||
|
|
||||||
static const int UINT16_RANGE = std::numeric_limits<uint16_t>::max() + 1;
|
static const int UINT16_RANGE = std::numeric_limits<uint16_t>::max() + 1;
|
||||||
|
|
||||||
SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(quint16 incoming, QUuid senderUUID, const bool wantExtraDebugging) {
|
SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(quint16 incoming, NetworkLocalID senderID, const bool wantExtraDebugging) {
|
||||||
|
|
||||||
SequenceNumberStats::ArrivalInfo arrivalInfo;
|
SequenceNumberStats::ArrivalInfo arrivalInfo;
|
||||||
|
|
||||||
// if the sender node has changed, reset all stats
|
// if the sender node has changed, reset all stats
|
||||||
if (senderUUID != _lastSenderUUID) {
|
if (senderID != _lastSenderID) {
|
||||||
if (_stats._received > 0) {
|
if (_stats._received > 0) {
|
||||||
qCDebug(networking) << "sequence number stats was reset due to new sender node";
|
qCDebug(networking) << "sequence number stats was reset due to new sender node";
|
||||||
qCDebug(networking) << "previous:" << _lastSenderUUID << "current:" << senderUUID;
|
qCDebug(networking) << "previous:" << _lastSenderID << "current:" << senderID;
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
_lastSenderUUID = senderUUID;
|
_lastSenderID = senderID;
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine our expected sequence number... handle rollover appropriately
|
// determine our expected sequence number... handle rollover appropriately
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
#include "RingBufferHistory.h"
|
#include "RingBufferHistory.h"
|
||||||
#include <quuid.h>
|
#include "UUID.h"
|
||||||
|
|
||||||
const int MAX_REASONABLE_SEQUENCE_GAP = 1000;
|
const int MAX_REASONABLE_SEQUENCE_GAP = 1000;
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ public:
|
||||||
SequenceNumberStats(int statsHistoryLength = 0, bool canDetectOutOfSync = true);
|
SequenceNumberStats(int statsHistoryLength = 0, bool canDetectOutOfSync = true);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
ArrivalInfo sequenceNumberReceived(quint16 incoming, QUuid senderUUID = QUuid(), const bool wantExtraDebugging = false);
|
ArrivalInfo sequenceNumberReceived(quint16 incoming, NetworkLocalID senderID = NULL_LOCAL_ID, const bool wantExtraDebugging = false);
|
||||||
void pruneMissingSet(const bool wantExtraDebugging = false);
|
void pruneMissingSet(const bool wantExtraDebugging = false);
|
||||||
void pushStatsToHistory() { _statsHistory.insert(_stats); }
|
void pushStatsToHistory() { _statsHistory.insert(_stats); }
|
||||||
|
|
||||||
|
@ -100,7 +100,8 @@ private:
|
||||||
|
|
||||||
PacketStreamStats _stats;
|
PacketStreamStats _stats;
|
||||||
|
|
||||||
QUuid _lastSenderUUID;
|
NetworkLocalID _lastSenderID;
|
||||||
|
static const NetworkLocalID NULL_LOCAL_ID = (NetworkLocalID) 0;
|
||||||
|
|
||||||
RingBufferHistory<PacketStreamStats> _statsHistory;
|
RingBufferHistory<PacketStreamStats> _statsHistory;
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ int packetTypeMetaTypeId = qRegisterMetaType<PacketType>();
|
||||||
|
|
||||||
PacketVersion versionForPacketType(PacketType packetType) {
|
PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
switch (packetType) {
|
switch (packetType) {
|
||||||
|
case PacketType::StunResponse:
|
||||||
|
return 17;
|
||||||
case PacketType::DomainList:
|
case PacketType::DomainList:
|
||||||
return static_cast<PacketVersion>(DomainListVersion::GetMachineFingerprintFromUUIDSupport);
|
return static_cast<PacketVersion>(DomainListVersion::GetMachineFingerprintFromUUIDSupport);
|
||||||
case PacketType::EntityAdd:
|
case PacketType::EntityAdd:
|
||||||
|
@ -40,8 +42,21 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::FBXReaderNodeReparenting);
|
return static_cast<PacketVersion>(AvatarMixerPacketVersion::FBXReaderNodeReparenting);
|
||||||
case PacketType::MessagesData:
|
case PacketType::MessagesData:
|
||||||
return static_cast<PacketVersion>(MessageDataVersion::TextOrBinaryData);
|
return static_cast<PacketVersion>(MessageDataVersion::TextOrBinaryData);
|
||||||
|
// ICE packets
|
||||||
|
case PacketType::ICEServerPeerInformation:
|
||||||
|
return 17;
|
||||||
|
case PacketType::ICEServerHeartbeatACK:
|
||||||
|
return 17;
|
||||||
|
case PacketType::ICEServerQuery:
|
||||||
|
return 17;
|
||||||
case PacketType::ICEServerHeartbeat:
|
case PacketType::ICEServerHeartbeat:
|
||||||
return 18; // ICE Server Heartbeat signing
|
return 18; // ICE Server Heartbeat signing
|
||||||
|
case PacketType::ICEPing:
|
||||||
|
return static_cast<PacketVersion>(IcePingVersion::SendICEPeerID);
|
||||||
|
case PacketType::ICEPingReply:
|
||||||
|
return 17;
|
||||||
|
case PacketType::ICEServerHeartbeatDenied:
|
||||||
|
return 17;
|
||||||
case PacketType::AssetMappingOperation:
|
case PacketType::AssetMappingOperation:
|
||||||
case PacketType::AssetMappingOperationReply:
|
case PacketType::AssetMappingOperationReply:
|
||||||
return static_cast<PacketVersion>(AssetServerPacketVersion::RedirectedMappings);
|
return static_cast<PacketVersion>(AssetServerPacketVersion::RedirectedMappings);
|
||||||
|
@ -71,12 +86,12 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
case PacketType::MicrophoneAudioWithEcho:
|
case PacketType::MicrophoneAudioWithEcho:
|
||||||
case PacketType::AudioStreamStats:
|
case PacketType::AudioStreamStats:
|
||||||
return static_cast<PacketVersion>(AudioVersion::HighDynamicRangeVolume);
|
return static_cast<PacketVersion>(AudioVersion::HighDynamicRangeVolume);
|
||||||
case PacketType::ICEPing:
|
|
||||||
return static_cast<PacketVersion>(IcePingVersion::SendICEPeerID);
|
|
||||||
case PacketType::DomainSettings:
|
case PacketType::DomainSettings:
|
||||||
return 18; // replace min_avatar_scale and max_avatar_scale with min_avatar_height and max_avatar_height
|
return 18; // replace min_avatar_scale and max_avatar_scale with min_avatar_height and max_avatar_height
|
||||||
|
case PacketType::Ping:
|
||||||
|
return static_cast<PacketVersion>(PingVersion::IncludeConnectionID);
|
||||||
default:
|
default:
|
||||||
return 17;
|
return 19;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -323,4 +323,8 @@ enum class IcePingVersion : PacketVersion {
|
||||||
SendICEPeerID = 18
|
SendICEPeerID = 18
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class PingVersion : PacketVersion {
|
||||||
|
IncludeConnectionID = 18
|
||||||
|
};
|
||||||
|
|
||||||
#endif // hifi_PacketHeaders_h
|
#endif // hifi_PacketHeaders_h
|
||||||
|
|
|
@ -96,7 +96,7 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe
|
||||||
quint64 totalUncompress = 0;
|
quint64 totalUncompress = 0;
|
||||||
quint64 totalReadBitsteam = 0;
|
quint64 totalReadBitsteam = 0;
|
||||||
|
|
||||||
const QUuid& sourceUUID = message.getSourceID();
|
const QUuid& sourceUUID = sourceNode->getUUID();
|
||||||
|
|
||||||
int subsection = 1;
|
int subsection = 1;
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,8 @@
|
||||||
* of gimbal lock.
|
* of gimbal lock.
|
||||||
* @namespace Quat
|
* @namespace Quat
|
||||||
* @variation 0
|
* @variation 0
|
||||||
* @property IDENTITY {Quat} The identity rotation, i.e., no rotation. Its value is <code>{ x: 0, y: 0, z: 0, w: 1 }</code>.
|
* @property IDENTITY {Quat} <code>{ x: 0, y: 0, z: 0, w: 1 }</code> : The identity rotation, i.e., no rotation.
|
||||||
|
* <em>Read-only.</em>
|
||||||
* @example <caption>Print the <code>IDENTITY</code> value.</caption>
|
* @example <caption>Print the <code>IDENTITY</code> value.</caption>
|
||||||
* print(JSON.stringify(Quat.IDENTITY)); // { x: 0, y: 0, z: 0, w: 1 }
|
* print(JSON.stringify(Quat.IDENTITY)); // { x: 0, y: 0, z: 0, w: 1 }
|
||||||
* print(JSON.stringify(Quat.safeEulerAngles(Quat.IDENTITY))); // { x: 0, y: 0, z: 0 }
|
* print(JSON.stringify(Quat.safeEulerAngles(Quat.IDENTITY))); // { x: 0, y: 0, z: 0 }
|
||||||
|
|
|
@ -22,15 +22,7 @@
|
||||||
#include "GLMHelpers.h"
|
#include "GLMHelpers.h"
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* A 2-dimensional vector.
|
* A 3-dimensional vector. See also the {@link Vec3(0)|Vec3} object.
|
||||||
*
|
|
||||||
* @typedef {object} Vec2
|
|
||||||
* @property {number} x - X-coordinate of the vector.
|
|
||||||
* @property {number} y - Y-coordinate of the vector.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**jsdoc
|
|
||||||
* A 3-dimensional vector.
|
|
||||||
*
|
*
|
||||||
* @typedef {object} Vec3
|
* @typedef {object} Vec3
|
||||||
* @property {number} x - X-coordinate of the vector.
|
* @property {number} x - X-coordinate of the vector.
|
||||||
|
@ -39,17 +31,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* A 4-dimensional vector.
|
* A color vector. See also the {@link Vec3(0)|Vec3} object.
|
||||||
*
|
|
||||||
* @typedef {object} Vec4
|
|
||||||
* @property {number} x - X-coordinate of the vector.
|
|
||||||
* @property {number} y - Y-coordinate of the vector.
|
|
||||||
* @property {number} z - Z-coordinate of the vector.
|
|
||||||
* @property {number} w - W-coordinate of the vector.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**jsdoc
|
|
||||||
* A color vector.
|
|
||||||
*
|
*
|
||||||
* @typedef {object} Vec3Color
|
* @typedef {object} Vec3Color
|
||||||
* @property {number} x - Red component value. Integer in the range <code>0</code> - <code>255</code>.
|
* @property {number} x - Red component value. Integer in the range <code>0</code> - <code>255</code>.
|
||||||
|
@ -57,6 +39,51 @@
|
||||||
* @property {number} z - Blue component value. Integer in the range <code>0</code> - <code>255</code>.
|
* @property {number} z - Blue component value. Integer in the range <code>0</code> - <code>255</code>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* The Vec3 API facilities for generating and manipulating 3-dimensional vectors. High Fidelity uses a right-handed
|
||||||
|
* Cartesian coordinate system where the y-axis is the "up" and the negative z-axis is the "front" direction.
|
||||||
|
* <img alt="High Fidelity coordinate system"
|
||||||
|
* src="https://docs.highfidelity.com/user/pages/06.api-reference/43.vec3/opengl-coord-system.jpg" />
|
||||||
|
*
|
||||||
|
* @namespace Vec3
|
||||||
|
* @variation 0
|
||||||
|
* @property {Vec3} UNIT_X - <code>{ x: 1, y: 0, z: 0 }</code> : Unit vector in the x-axis direction. <em>Read-only.</em>
|
||||||
|
* @property {Vec3} UNIT_Y - <code>{ x: 0, y: 1, z: 0 }</code> : Unit vector in the y-axis direction. <em>Read-only.</em>
|
||||||
|
* @property {Vec3} UNIT_Z - <code>{ x: 0, y: 0, z: 1 }</code> : Unit vector in the z-axis direction. <em>Read-only.</em>
|
||||||
|
* @property {Vec3} UNIT_NEG_X - <code>{ x: -1, y: 0, z: 0 }</code> : Unit vector in the negative x-axis direction.
|
||||||
|
* <em>Read-only.</em>
|
||||||
|
* @property {Vec3} UNIT_NEG_Y - <code>{ x: 0, y: -1, z: 0 }</code> : Unit vector in the negative y-axis direction.
|
||||||
|
* <em>Read-only.</em>
|
||||||
|
* @property {Vec3} UNIT_NEG_Z - <code>{ x: 0, y: 0, z: -1 }</code> : Unit vector in the negative z-axis direction.
|
||||||
|
* <em>Read-only.</em>
|
||||||
|
* @property {Vec3} UNIT_XY - <code>{ x: 0.707107, y: 0.707107, z: 0 }</code> : Unit vector in the direction of the diagonal
|
||||||
|
* between the x and y axes. <em>Read-only.</em>
|
||||||
|
* @property {Vec3} UNIT_XZ - <code>{ x: 0.707107, y: 0, z: 0.707107 }</code> : Unit vector in the direction of the diagonal
|
||||||
|
* between the x and z axes. <em>Read-only.</em>
|
||||||
|
* @property {Vec3} UNIT_YZ - <code>{ x: 0, y: 0.707107, z: 0.707107 }</code> : Unit vector in the direction of the diagonal
|
||||||
|
* between the y and z axes. <em>Read-only.</em>
|
||||||
|
* @property {Vec3} UNIT_XYZ - <code>{ x: 0.577350, y: 0.577350, z: 0.577350 }</code> : Unit vector in the direction of the
|
||||||
|
* diagonal between the x, y, and z axes. <em>Read-only.</em>
|
||||||
|
* @property {Vec3} FLOAT_MAX - <code>{ x: 3.402823e+38, y: 3.402823e+38, z: 3.402823e+38 }</code> : Vector with all axis
|
||||||
|
* values set to the maximum floating point value. <em>Read-only.</em>
|
||||||
|
* @property {Vec3} FLOAT_MIN - <code>{ x: -3.402823e+38, y: -3.402823e+38, z: -3.402823e+38 }</code> : Vector with all axis
|
||||||
|
* values set to the negative of the maximum floating point value. <em>Read-only.</em>
|
||||||
|
* @property {Vec3} ZERO - <code>{ x: 0, y: 0, z: 0 }</code> : Vector with all axis values set to <code>0</code>.
|
||||||
|
* <em>Read-only.</em>
|
||||||
|
* @property {Vec3} ONE - <code>{ x: 1, y: 1, z: 1 }</code> : Vector with all axis values set to <code>1</code>.
|
||||||
|
* <em>Read-only.</em>
|
||||||
|
* @property {Vec3} TWO - <code>{ x: 2, y: 2, z: 2 }</code> : Vector with all axis values set to <code>2</code>.
|
||||||
|
* <em>Read-only.</em>
|
||||||
|
* @property {Vec3} HALF - <code>{ x: 0.5, y: 0.5, z: 0.5 }</code> : Vector with all axis values set to <code>0.5</code>.
|
||||||
|
* <em>Read-only.</em>
|
||||||
|
* @property {Vec3} RIGHT - <code>{ x: 1, y: 0, z: 0 }</code> : Unit vector in the "right" direction. Synonym for
|
||||||
|
* <code>UNIT_X</code>. <em>Read-only.</em>
|
||||||
|
* @property {Vec3} UP - <code>{ x: 0, y: 1, z: 0 }</code> : Unit vector in the "up" direction. Synonym for
|
||||||
|
* <code>UNIT_Y</code>. <em>Read-only.</em>
|
||||||
|
* @property {Vec3} FRONT - <code>{ x: 0, y: 0, z: -1 }</code> : Unit vector in the "front" direction. Synonym for
|
||||||
|
* <code>UNIT_NEG_Z</code>. <em>Read-only.</em>
|
||||||
|
*/
|
||||||
|
|
||||||
/// Scriptable interface a Vec3ernion helper class object. Used exclusively in the JavaScript API
|
/// Scriptable interface a Vec3ernion helper class object. Used exclusively in the JavaScript API
|
||||||
class Vec3 : public QObject, protected QScriptable {
|
class Vec3 : public QObject, protected QScriptable {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -81,27 +108,301 @@ class Vec3 : public QObject, protected QScriptable {
|
||||||
Q_PROPERTY(glm::vec3 FRONT READ FRONT CONSTANT)
|
Q_PROPERTY(glm::vec3 FRONT READ FRONT CONSTANT)
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Calculate the reflection of a vector in a plane.
|
||||||
|
* @function Vec3(0).reflect
|
||||||
|
* @param {Vec3} v - The vector to reflect.
|
||||||
|
* @param {Vec3} normal - The normal of the plane.
|
||||||
|
* @returns {Vec3} The vector reflected in the plane given by the normal.
|
||||||
|
* @example <caption>Reflect a vector in the x-z plane.</caption>
|
||||||
|
* var v = { x: 1, y: 2, z: 3 };
|
||||||
|
* var normal = Vec3.UNIT_Y;
|
||||||
|
* var reflected = Vec3.reflect(v, normal);
|
||||||
|
* print(JSON.stringify(reflected)); // {"x":1,"y":-2,"z":3}
|
||||||
|
*/
|
||||||
glm::vec3 reflect(const glm::vec3& v1, const glm::vec3& v2) { return glm::reflect(v1, v2); }
|
glm::vec3 reflect(const glm::vec3& v1, const glm::vec3& v2) { return glm::reflect(v1, v2); }
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Calculate the cross product of two vectors.
|
||||||
|
* @function Vec3(0).cross
|
||||||
|
* @param {Vec3} v1 - The first vector.
|
||||||
|
* @param {Vec3} v2 - The second vector.
|
||||||
|
* @returns {Vec3} The cross product of <code>v1</code> and <code>v2</code>.
|
||||||
|
* @example <caption>The cross product of x and y unit vectors is the z unit vector.</caption>
|
||||||
|
* var v1 = { x: 1, y: 0, z: 0 };
|
||||||
|
* var v2 = { x: 0, y: 1, z: 0 };
|
||||||
|
* var crossProduct = Vec3.cross(v1, v2);
|
||||||
|
* print(JSON.stringify(crossProduct)); // {"x":0,"y":0,"z":1}
|
||||||
|
*/
|
||||||
glm::vec3 cross(const glm::vec3& v1, const glm::vec3& v2) { return glm::cross(v1, v2); }
|
glm::vec3 cross(const glm::vec3& v1, const glm::vec3& v2) { return glm::cross(v1, v2); }
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Calculate the dot product of two vectors.
|
||||||
|
* @function Vec3(0).dot
|
||||||
|
* @param {Vec3} v1 - The first vector.
|
||||||
|
* @param {Vec3} v2 - The second vector.
|
||||||
|
* @returns {number} The dot product of <code>v1</code> and <code>v2</code>.
|
||||||
|
* @example <caption>The dot product of vectors at right angles is <code>0</code>.</caption>
|
||||||
|
* var v1 = { x: 1, y: 0, z: 0 };
|
||||||
|
* var v2 = { x: 0, y: 1, z: 0 };
|
||||||
|
* var dotProduct = Vec3.dot(v1, v2);
|
||||||
|
* print(dotProduct); // 0
|
||||||
|
*/
|
||||||
float dot(const glm::vec3& v1, const glm::vec3& v2) { return glm::dot(v1, v2); }
|
float dot(const glm::vec3& v1, const glm::vec3& v2) { return glm::dot(v1, v2); }
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Multiply a vector by a scale factor.
|
||||||
|
* @function Vec3(0).multiply
|
||||||
|
* @param {Vec3} v - The vector.
|
||||||
|
* @param {number} scale - The scale factor.
|
||||||
|
* @returns {Vec3} The vector with each ordinate value multiplied by the <code>scale</code>.
|
||||||
|
*/
|
||||||
glm::vec3 multiply(const glm::vec3& v1, float f) { return v1 * f; }
|
glm::vec3 multiply(const glm::vec3& v1, float f) { return v1 * f; }
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Multiply a vector by a scale factor.
|
||||||
|
* @function Vec3(0).multiply
|
||||||
|
* @param {number} scale - The scale factor.
|
||||||
|
* @param {Vec3} v - The vector.
|
||||||
|
* @returns {Vec3} The vector with each ordinate value multiplied by the <code>scale</code>.
|
||||||
|
*/
|
||||||
glm::vec3 multiply(float f, const glm::vec3& v1) { return v1 * f; }
|
glm::vec3 multiply(float f, const glm::vec3& v1) { return v1 * f; }
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Multiply two vectors.
|
||||||
|
* @function Vec3(0).multiplyVbyV
|
||||||
|
* @param {Vec3} v1 - The first vector.
|
||||||
|
* @param {Vec3} v2 - The second vector.
|
||||||
|
* @returns {Vec3} A vector formed by multiplying the ordinates of two vectors: <code>{ x: v1.x * v2.x, y: v1.y * v2.y,
|
||||||
|
* z: v1.z * v2.z }</code>.
|
||||||
|
* @example <caption>Multiply two vectors.</caption>
|
||||||
|
* var v1 = { x: 1, y: 2, z: 3 };
|
||||||
|
* var v2 = { x: 1, y: 2, z: 3 };
|
||||||
|
* var multiplied = Vec3.multiplyVbyV(v1, v2);
|
||||||
|
* print(JSON.stringify(multiplied)); // {"x":1,"y":4,"z":9}
|
||||||
|
*/
|
||||||
glm::vec3 multiplyVbyV(const glm::vec3& v1, const glm::vec3& v2) { return v1 * v2; }
|
glm::vec3 multiplyVbyV(const glm::vec3& v1, const glm::vec3& v2) { return v1 * v2; }
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Rotate a vector.
|
||||||
|
* @function Vec3(0).multiplyQbyV
|
||||||
|
* @param {Quat} q - The rotation to apply.
|
||||||
|
* @param {Vec3} v - The vector to rotate.
|
||||||
|
* @returns {Vec3} <code>v</code> rotated by <code>q</code>.
|
||||||
|
* @example <caption>Rotate the negative z-axis by 90 degrees about the x-axis.</caption>
|
||||||
|
* var v = Vec3.UNIT_NEG_Z;
|
||||||
|
* var q = Quat.fromPitchYawRollDegrees(90, 0, 0);
|
||||||
|
* var result = Vec3.multiplyQbyV(q, v);
|
||||||
|
* print(JSON.stringify(result)); // {"x":0,"y":1.000,"z":1.19e-7}
|
||||||
|
*/
|
||||||
glm::vec3 multiplyQbyV(const glm::quat& q, const glm::vec3& v) { return q * v; }
|
glm::vec3 multiplyQbyV(const glm::quat& q, const glm::vec3& v) { return q * v; }
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Calculate the sum of two vectors.
|
||||||
|
* @function Vec3(0).sum
|
||||||
|
* @param {Vec3} v1 - The first vector.
|
||||||
|
* @param {Vec3} v2 - The second vector.
|
||||||
|
* @returns {Vec3} The sum of the two vectors.
|
||||||
|
*/
|
||||||
glm::vec3 sum(const glm::vec3& v1, const glm::vec3& v2) { return v1 + v2; }
|
glm::vec3 sum(const glm::vec3& v1, const glm::vec3& v2) { return v1 + v2; }
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Calculate one vector subtracted from another.
|
||||||
|
* @function Vec3(0).subtract
|
||||||
|
* @param {Vec3} v1 - The first vector.
|
||||||
|
* @param {Vec3} v2 - The second vector.
|
||||||
|
* @returns {Vec3} The second vector subtracted from the first.
|
||||||
|
*/
|
||||||
glm::vec3 subtract(const glm::vec3& v1, const glm::vec3& v2) { return v1 - v2; }
|
glm::vec3 subtract(const glm::vec3& v1, const glm::vec3& v2) { return v1 - v2; }
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Calculate the length of a vector
|
||||||
|
* @function Vec3(0).length
|
||||||
|
* @param {Vec3} v - The vector.
|
||||||
|
* @returns {number} The length of the vector.
|
||||||
|
*/
|
||||||
float length(const glm::vec3& v) { return glm::length(v); }
|
float length(const glm::vec3& v) { return glm::length(v); }
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Calculate the distance between two points.
|
||||||
|
* @function Vec3(0).distance
|
||||||
|
* @param {Vec3} p1 - The first point.
|
||||||
|
* @param {Vec3} p2 - The second point.
|
||||||
|
* @returns {number} The distance between the two points.
|
||||||
|
* @example <caption>The distance between two points is aways positive.</caption>
|
||||||
|
* var p1 = { x: 0, y: 0, z: 0 };
|
||||||
|
* var p2 = { x: 0, y: 0, z: 10 };
|
||||||
|
* var distance = Vec3.distance(p1, p2);
|
||||||
|
* print(distance); // 10
|
||||||
|
*
|
||||||
|
* p2 = { x: 0, y: 0, z: -10 };
|
||||||
|
* distance = Vec3.distance(p1, p2);
|
||||||
|
* print(distance); // 10
|
||||||
|
*/
|
||||||
float distance(const glm::vec3& v1, const glm::vec3& v2) { return glm::distance(v1, v2); }
|
float distance(const glm::vec3& v1, const glm::vec3& v2) { return glm::distance(v1, v2); }
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Calculate the angle of rotation from one vector onto another, with the sign depending on a reference vector.
|
||||||
|
* @function Vec3(0).orientedAngle
|
||||||
|
* @param {Vec3} v1 - The first vector.
|
||||||
|
* @param {Vec3} v2 - The second vector.
|
||||||
|
* @param {Vec3} ref - Reference vector.
|
||||||
|
* @returns {number} The angle of rotation from the first vector to the second, in degrees, with a positive sign if the
|
||||||
|
* rotation axis aligns with the reference vector (has a positive dot product) otherwise a negative sign.
|
||||||
|
* @example <caption>Compare <code>Vec3.angle()</code> and <code>Vec3.orientedAngle()</code>.</caption>
|
||||||
|
* var v1 = { x: 5, y: 0, z: 0 };
|
||||||
|
* var v2 = { x: 5, y: 0, z: 5 };
|
||||||
|
* var angle = Vec3.getAngle(v1, v2);
|
||||||
|
* print(angle * 180 / Math.PI); // 45
|
||||||
|
*
|
||||||
|
* print(Vec3.orientedAngle(v1, v2, Vec3.UNIT_Y)); // -45
|
||||||
|
* print(Vec3.orientedAngle(v1, v2, Vec3.UNIT_NEG_Y)); // 45
|
||||||
|
* print(Vec3.orientedAngle(v1, v2, { x: 1, y: 2, z: -1 })); // -45
|
||||||
|
* print(Vec3.orientedAngle(v1, v2, { x: 1, y: -2, z: -1 })); // 45
|
||||||
|
*/
|
||||||
float orientedAngle(const glm::vec3& v1, const glm::vec3& v2, const glm::vec3& v3);
|
float orientedAngle(const glm::vec3& v1, const glm::vec3& v2, const glm::vec3& v3);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Normalize a vector so that its length is <code>1</code>.
|
||||||
|
* @function Vec3(0).normalize
|
||||||
|
* @param {Vec3} v - The vector to normalize.
|
||||||
|
* @returns {Vec3} The vector normalized to have a length of <code>1</code>.
|
||||||
|
* @example <caption>Normalize a vector.</caption>
|
||||||
|
* var v = { x: 10, y: 10, z: 0 };
|
||||||
|
* var normalized = Vec3.normalize(v);
|
||||||
|
* print(JSON.stringify(normalized)); // {"x":0.7071,"y":0.7071,"z":0}
|
||||||
|
* print(Vec3.length(normalized)); // 1
|
||||||
|
*/
|
||||||
glm::vec3 normalize(const glm::vec3& v) { return glm::normalize(v); };
|
glm::vec3 normalize(const glm::vec3& v) { return glm::normalize(v); };
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Calculate a linear interpolation between two vectors.
|
||||||
|
* @function Vec3(0).mix
|
||||||
|
* @param {Vec3} v1 - The first vector.
|
||||||
|
* @param {Vec3} v2 - The second vector.
|
||||||
|
* @param {number} factor - The interpolation factor in the range <code>0.0</code> to <code>1.0</code>.
|
||||||
|
* @returns {Vec3} The linear interpolation between the two vectors: <code>(1 - factor) * v1 + factor * v2</code>.
|
||||||
|
* @example <caption>Linear interpolation between two vectors.</caption>
|
||||||
|
* var v1 = { x: 10, y: 0, z: 0 };
|
||||||
|
* var v2 = { x: 0, y: 10, z: 0 };
|
||||||
|
* var interpolated = Vec3.mix(v1, v2, 0.75); // 1/4 of v1 and 3/4 of v2.
|
||||||
|
* print(JSON.stringify(interpolated)); // {"x":2.5,"y":7.5","z":0}
|
||||||
|
*/
|
||||||
glm::vec3 mix(const glm::vec3& v1, const glm::vec3& v2, float m) { return glm::mix(v1, v2, m); }
|
glm::vec3 mix(const glm::vec3& v1, const glm::vec3& v2, float m) { return glm::mix(v1, v2, m); }
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Print to the program log a text label followed by a vector value.
|
||||||
|
* @function Vec3(0).print
|
||||||
|
* @param {string} label - The label to print.
|
||||||
|
* @param {Vec3} v - The vector value to print.
|
||||||
|
* @example <caption>Two ways of printing a label and vector value.</caption>
|
||||||
|
* var v = { x: 1, y: 2, z: 3 };
|
||||||
|
* Vec3.print("Vector: ", v); // dvec3(1.000000, 2.000000, 3.000000)
|
||||||
|
* print("Vector: " + JSON.stringify(v)); // {"x":1,"y":2,"z":3}
|
||||||
|
*/
|
||||||
void print(const QString& label, const glm::vec3& v);
|
void print(const QString& label, const glm::vec3& v);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Test whether two vectors are equal. <strong>Note:</strong> The vectors must be exactly equal in order for
|
||||||
|
* <code>true</code> to be returned; it is often better to use {@link Vec3(0).withinEpsilon|withinEpsilon}.
|
||||||
|
* @function Vec3(0).equal
|
||||||
|
* @param {Vec3} v1 - The first vector.
|
||||||
|
* @param {Vec3} v2 - The second vector.
|
||||||
|
* @returns {boolean} <code>true</code> if the two vectors are exactly equal, otherwise <code>false</code>.
|
||||||
|
* @example <caption> Vectors are only equal if exactly the same.</caption>
|
||||||
|
* var v1 = { x: 10, y: 10, z: 10 };
|
||||||
|
* var v2 = { x: 10, y: 10, z: 10 };
|
||||||
|
* var equal = Vec3.equal(v1, v2);
|
||||||
|
* print(equal); // true
|
||||||
|
*
|
||||||
|
* v2 = { x: 10, y: 10, z: 10.0005 };
|
||||||
|
* equal = Vec3.equal(v1, v2);
|
||||||
|
* print(equal); // false
|
||||||
|
*/
|
||||||
bool equal(const glm::vec3& v1, const glm::vec3& v2) { return v1 == v2; }
|
bool equal(const glm::vec3& v1, const glm::vec3& v2) { return v1 == v2; }
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Test whether two vectors are equal within a tolerance. <strong>Note:</strong> It is often better to use this function
|
||||||
|
* than {@link Vec3(0).equal|equal}.
|
||||||
|
* @function Vec3(0).withinEpsilon
|
||||||
|
* @param {Vec3} v1 - The first vector.
|
||||||
|
* @param {Vec3} v2 - The second vector.
|
||||||
|
* @param {number} epsilon - The maximum distance between the two vectors.
|
||||||
|
* @returns {boolean} <code>true</code> if the distance between the points represented by the vectors is less than or equal
|
||||||
|
* to the <code>epsilon</code>, otherwise <code>false</code>.
|
||||||
|
* @example <caption>Testing vectors for near equality.</caption>
|
||||||
|
* var v1 = { x: 10, y: 10, z: 10 };
|
||||||
|
* var v2 = { x: 10, y: 10, z: 10.0005 };
|
||||||
|
* var equal = Vec3.equal(v1, v2);
|
||||||
|
* print(equal); // false
|
||||||
|
*
|
||||||
|
* equal = Vec3.withinEpsilon(v1, v2, 0.001);
|
||||||
|
* print(equal); // true
|
||||||
|
*/
|
||||||
bool withinEpsilon(const glm::vec3& v1, const glm::vec3& v2, float epsilon);
|
bool withinEpsilon(const glm::vec3& v1, const glm::vec3& v2, float epsilon);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Calculate polar coordinates (elevation, azimuth, radius) that transform the unit z-axis vector onto a point.
|
||||||
|
* @function Vec3(0).toPolar
|
||||||
|
* @param {Vec3} p - The point to calculate the polar coordinates for.
|
||||||
|
* @returns {Vec3} Vector of polar coordinates for the point: <code>x</code> elevation rotation about the x-axis in
|
||||||
|
* radians, <code>y</code> azimuth rotation about the y-axis in radians, and <code>z</code> scale.
|
||||||
|
* @example <caption>Polar coordinates for a point.</caption>
|
||||||
|
* var v = { x: 5, y: 2.5, z: 5 };
|
||||||
|
* var polar = Vec3.toPolar(v);
|
||||||
|
* print("Elevation: " + polar.x * 180 / Math.PI); // -19.471
|
||||||
|
* print("Azimuth: " + polar.y * 180 / Math.PI); // 45
|
||||||
|
* print("Radius: " + polar.z); // 7.5
|
||||||
|
*/
|
||||||
// FIXME misnamed, should be 'spherical' or 'euler' depending on the implementation
|
// FIXME misnamed, should be 'spherical' or 'euler' depending on the implementation
|
||||||
glm::vec3 toPolar(const glm::vec3& v);
|
glm::vec3 toPolar(const glm::vec3& v);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Calculate the coordinates of a point from polar coordinate transformation of the unit z-axis vector.
|
||||||
|
* @function Vec3(0).fromPolar
|
||||||
|
* @param {Vec3} polar - The polar coordinates of a point: <code>x</code> elevation rotation about the x-axis in radians,
|
||||||
|
* <code>y</code> azimuth rotation about the y-axis in radians, and <code>z</code> scale.
|
||||||
|
* @returns {Vec3} The coordinates of the point.
|
||||||
|
* @example <caption>Polar coordinates to Cartesian.</caption>
|
||||||
|
* var polar = { x: -19.471 * Math.PI / 180, y: 45 * Math.PI / 180, z: 7.5 };
|
||||||
|
* var p = Vec3.fromPolar(polar);
|
||||||
|
* print(JSON.stringify(p)); // {"x":5,"y":2.5,"z":5}
|
||||||
|
*/
|
||||||
|
// FIXME misnamed, should be 'spherical' or 'euler' depending on the implementation
|
||||||
glm::vec3 fromPolar(const glm::vec3& polar);
|
glm::vec3 fromPolar(const glm::vec3& polar);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Calculate the unit vector corresponding to polar coordinates elevation and azimuth transformation of the unit z-axis
|
||||||
|
* vector.
|
||||||
|
* @function Vec3(0).fromPolar
|
||||||
|
* @param {number} elevation - Rotation about the x-axis, in radians.
|
||||||
|
* @param {number} azimuth - Rotation about the y-axis, in radians.
|
||||||
|
* @returns {Vec3} Unit vector for the direction specified by <code>elevation</code> and <code>azimuth</code>.
|
||||||
|
* @example <caption>Polar coordinates to Cartesian.</caption>
|
||||||
|
* var elevation = -19.471 * Math.PI / 180;
|
||||||
|
* var rotation = 45 * Math.PI / 180;
|
||||||
|
* var p = Vec3.fromPolar(elevation, rotation);
|
||||||
|
* print(JSON.stringify(p)); // {"x":0.667,"y":0.333,"z":0.667}
|
||||||
|
*
|
||||||
|
* p = Vec3.multiply(7.5, p);
|
||||||
|
* print(JSON.stringify(p)); // {"x":5,"y":2.5,"z":5}
|
||||||
|
*/
|
||||||
|
// FIXME misnamed, should be 'spherical' or 'euler' depending on the implementation
|
||||||
glm::vec3 fromPolar(float elevation, float azimuth);
|
glm::vec3 fromPolar(float elevation, float azimuth);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Calculate the angle between two vectors.
|
||||||
|
* @function Vec3(0).getAngle
|
||||||
|
* @param {Vec3} v1 - The first vector.
|
||||||
|
* @param {Vec3} v2 - The second vector.
|
||||||
|
* @returns {number} The angle between the two vectors, in radians.
|
||||||
|
* @example <caption>Calculate the angle between two vectors.</caption>
|
||||||
|
* var v1 = { x: 10, y: 0, z: 0 };
|
||||||
|
* var v2 = { x: 0, y: 0, z: 10 };
|
||||||
|
* var angle = Vec3.getAngle(v1, v2);
|
||||||
|
* print(angle * 180 / Math.PI); // 90
|
||||||
|
*/
|
||||||
float getAngle(const glm::vec3& v1, const glm::vec3& v2);
|
float getAngle(const glm::vec3& v1, const glm::vec3& v2);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -44,6 +44,15 @@ void registerMetaTypes(QScriptEngine* engine);
|
||||||
QScriptValue mat4toScriptValue(QScriptEngine* engine, const glm::mat4& mat4);
|
QScriptValue mat4toScriptValue(QScriptEngine* engine, const glm::mat4& mat4);
|
||||||
void mat4FromScriptValue(const QScriptValue& object, glm::mat4& mat4);
|
void mat4FromScriptValue(const QScriptValue& object, glm::mat4& mat4);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* A 4-dimensional vector.
|
||||||
|
*
|
||||||
|
* @typedef {object} Vec4
|
||||||
|
* @property {number} x - X-coordinate of the vector.
|
||||||
|
* @property {number} y - Y-coordinate of the vector.
|
||||||
|
* @property {number} z - Z-coordinate of the vector.
|
||||||
|
* @property {number} w - W-coordinate of the vector.
|
||||||
|
*/
|
||||||
// Vec4
|
// Vec4
|
||||||
QScriptValue vec4toScriptValue(QScriptEngine* engine, const glm::vec4& vec4);
|
QScriptValue vec4toScriptValue(QScriptEngine* engine, const glm::vec4& vec4);
|
||||||
void vec4FromScriptValue(const QScriptValue& object, glm::vec4& vec4);
|
void vec4FromScriptValue(const QScriptValue& object, glm::vec4& vec4);
|
||||||
|
@ -59,6 +68,13 @@ QVariant vec3toVariant(const glm::vec3& vec3);
|
||||||
glm::vec3 vec3FromVariant(const QVariant &object, bool& valid);
|
glm::vec3 vec3FromVariant(const QVariant &object, bool& valid);
|
||||||
glm::vec3 vec3FromVariant(const QVariant &object);
|
glm::vec3 vec3FromVariant(const QVariant &object);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* A 2-dimensional vector.
|
||||||
|
*
|
||||||
|
* @typedef {object} Vec2
|
||||||
|
* @property {number} x - X-coordinate of the vector.
|
||||||
|
* @property {number} y - Y-coordinate of the vector.
|
||||||
|
*/
|
||||||
// Vec2
|
// Vec2
|
||||||
QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2);
|
QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2);
|
||||||
void vec2FromScriptValue(const QScriptValue &object, glm::vec2 &vec2);
|
void vec2FromScriptValue(const QScriptValue &object, glm::vec2 &vec2);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <QtCore/QUuid>
|
#include <QtCore/QUuid>
|
||||||
|
|
||||||
const int NUM_BYTES_RFC4122_UUID = 16;
|
const int NUM_BYTES_RFC4122_UUID = 16;
|
||||||
|
using NetworkLocalID = quint16;
|
||||||
|
|
||||||
QString uuidStringWithoutCurlyBraces(const QUuid& uuid);
|
QString uuidStringWithoutCurlyBraces(const QUuid& uuid);
|
||||||
|
|
||||||
|
|
454
server-console/package-lock.json
generated
454
server-console/package-lock.json
generated
|
@ -4,6 +4,12 @@
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/node": {
|
||||||
|
"version": "8.10.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.2.tgz",
|
||||||
|
"integrity": "sha512-A6Uv1anbsCvrRDtaUXS2xZ5tlzD+Kg7yMRlSLFDy3z0r7KlGXDzL14vELXIAgpk2aJbU3XeZZQRcEkLkowT92g==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"abbrev": {
|
"abbrev": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||||
|
@ -40,12 +46,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
|
||||||
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
|
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
|
||||||
},
|
},
|
||||||
"any-promise": {
|
|
||||||
"version": "1.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
|
|
||||||
"integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"array-find-index": {
|
"array-find-index": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.1.tgz",
|
||||||
|
@ -148,12 +148,6 @@
|
||||||
"lru-cache": "4.0.1"
|
"lru-cache": "4.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"balanced-match": {
|
|
||||||
"version": "0.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.3.0.tgz",
|
|
||||||
"integrity": "sha1-qRzdHr7xqGZZ5w/03vAWJfwtZ1Y=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"base64-js": {
|
"base64-js": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.0.tgz",
|
||||||
|
@ -217,16 +211,6 @@
|
||||||
"hoek": "2.16.3"
|
"hoek": "2.16.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
|
||||||
"version": "1.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.3.tgz",
|
|
||||||
"integrity": "sha1-Rr/1ARXUf8mriYVKu4fZgHihCZE=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"balanced-match": "0.3.0",
|
|
||||||
"concat-map": "0.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"buffers": {
|
"buffers": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
|
||||||
|
@ -515,29 +499,70 @@
|
||||||
"jsbn": "0.1.0"
|
"jsbn": "0.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"electron-download": {
|
"electron": {
|
||||||
"version": "2.1.1",
|
"version": "1.8.4",
|
||||||
"resolved": "https://registry.npmjs.org/electron-download/-/electron-download-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/electron/-/electron-1.8.4.tgz",
|
||||||
"integrity": "sha1-AH07HyrTco0nzP5PhJayY/kTijE=",
|
"integrity": "sha512-2f1cx0G3riMFODXFftF5AHXy+oHfhpntZHTDN66Hxtl09gmEr42B3piNEod9MEmw72f75LX2JfeYceqq1PF8cA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"debug": "2.2.0",
|
"@types/node": "8.10.2",
|
||||||
"home-path": "1.0.3",
|
"electron-download": "3.3.0",
|
||||||
|
"extract-zip": "1.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"electron-download": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/electron-download/-/electron-download-3.3.0.tgz",
|
||||||
|
"integrity": "sha1-LP1U1pZsAZxNSa1l++Zcyc3vaMg=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"fs-extra": "0.30.0",
|
||||||
|
"home-path": "1.0.5",
|
||||||
"minimist": "1.2.0",
|
"minimist": "1.2.0",
|
||||||
"mkdirp": "0.5.1",
|
"nugget": "2.0.1",
|
||||||
"mv": "2.1.1",
|
"path-exists": "2.1.0",
|
||||||
"nugget": "1.6.2",
|
"rc": "1.1.6",
|
||||||
"path-exists": "1.0.0",
|
"semver": "5.5.0",
|
||||||
"rc": "1.1.6"
|
"sumchecker": "1.3.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "2.2.0",
|
"version": "2.6.9",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
"integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"ms": "0.7.1"
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fs-extra": {
|
||||||
|
"version": "0.30.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz",
|
||||||
|
"integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "4.1.3",
|
||||||
|
"jsonfile": "2.2.3",
|
||||||
|
"klaw": "1.3.1",
|
||||||
|
"path-is-absolute": "1.0.0",
|
||||||
|
"rimraf": "2.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"semver": {
|
||||||
|
"version": "5.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
|
||||||
|
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"sumchecker": {
|
||||||
|
"version": "1.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-1.3.1.tgz",
|
||||||
|
"integrity": "sha1-ebs7RFbdBPGOvbwNcDodHa7FEF0=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"es6-promise": "4.2.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -579,9 +604,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"electron-packager": {
|
"electron-packager": {
|
||||||
"version": "11.0.0",
|
"version": "12.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/electron-packager/-/electron-packager-11.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/electron-packager/-/electron-packager-12.0.0.tgz",
|
||||||
"integrity": "sha512-ufyYMe3Gt6IEZm9RuG+KK3Nh+V2jZHWg9gihp8wylUNtleQihECIXtQdpPJxH9740XFERVPraNEaa7cZvDzpyw==",
|
"integrity": "sha1-uC0k14ovIUA7v9FmpbFWmJTVzQw=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"asar": "0.14.2",
|
"asar": "0.14.2",
|
||||||
|
@ -590,20 +615,25 @@
|
||||||
"electron-osx-sign": "0.4.8",
|
"electron-osx-sign": "0.4.8",
|
||||||
"extract-zip": "1.5.0",
|
"extract-zip": "1.5.0",
|
||||||
"fs-extra": "5.0.0",
|
"fs-extra": "5.0.0",
|
||||||
|
"galactus": "0.2.0",
|
||||||
"get-package-info": "1.0.0",
|
"get-package-info": "1.0.0",
|
||||||
"mz": "2.7.0",
|
|
||||||
"nodeify": "1.0.1",
|
"nodeify": "1.0.1",
|
||||||
"parse-author": "2.0.0",
|
"parse-author": "2.0.0",
|
||||||
"pify": "3.0.0",
|
"pify": "3.0.0",
|
||||||
"plist": "2.1.0",
|
"plist": "2.1.0",
|
||||||
"pruner": "0.0.7",
|
"rcedit": "1.0.0",
|
||||||
"rcedit": "0.9.0",
|
|
||||||
"resolve": "1.5.0",
|
"resolve": "1.5.0",
|
||||||
"sanitize-filename": "1.6.1",
|
"sanitize-filename": "1.6.1",
|
||||||
"semver": "5.5.0",
|
"semver": "5.5.0",
|
||||||
"yargs-parser": "8.1.0"
|
"yargs-parser": "9.0.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"camelcase": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
|
||||||
|
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||||
|
@ -726,6 +756,12 @@
|
||||||
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"rcedit": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/rcedit/-/rcedit-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-W7DNa34x/3OgWyDHsI172AG/Lr/lZ+PkavFkHj0QhhkBRcV9QTmRJE1tDKrWkx8XHPSBsmZkNv9OKue6pncLFQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "5.5.0",
|
"version": "5.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
|
||||||
|
@ -746,19 +782,18 @@
|
||||||
"resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz",
|
||||||
"integrity": "sha1-z+34jmDADdlpe2H90qg0OptoDq8=",
|
"integrity": "sha1-z+34jmDADdlpe2H90qg0OptoDq8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
},
|
||||||
|
"yargs-parser": {
|
||||||
|
"version": "9.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz",
|
||||||
|
"integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"camelcase": "4.1.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"electron-prebuilt": {
|
|
||||||
"version": "0.37.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/electron-prebuilt/-/electron-prebuilt-0.37.5.tgz",
|
|
||||||
"integrity": "sha1-OkGJgod4FdOnrB+bLi9KcPQg/3A=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"electron-download": "2.1.1",
|
|
||||||
"extract-zip": "1.5.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end-of-stream": {
|
"end-of-stream": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz",
|
||||||
|
@ -787,6 +822,12 @@
|
||||||
"is-arrayish": "0.2.1"
|
"is-arrayish": "0.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"es6-promise": {
|
||||||
|
"version": "4.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz",
|
||||||
|
"integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"escape-string-regexp": {
|
"escape-string-regexp": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||||
|
@ -873,6 +914,62 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"flora-colossus": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/flora-colossus/-/flora-colossus-0.0.2.tgz",
|
||||||
|
"integrity": "sha1-fRvimh8X+k8isb1hSC+Gw04HuQE=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"debug": "3.1.0",
|
||||||
|
"fs-extra": "4.0.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"debug": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fs-extra": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "4.1.3",
|
||||||
|
"jsonfile": "4.0.0",
|
||||||
|
"universalify": "0.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jsonfile": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||||
|
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "4.1.11"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"graceful-fs": {
|
||||||
|
"version": "4.1.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
|
||||||
|
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"forever-agent": {
|
"forever-agent": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
||||||
|
@ -904,6 +1001,63 @@
|
||||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"galactus": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/galactus/-/galactus-0.2.0.tgz",
|
||||||
|
"integrity": "sha1-w9Y7pVAkZv5A6mfMaJCFs90kqPw=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"debug": "3.1.0",
|
||||||
|
"flora-colossus": "0.0.2",
|
||||||
|
"fs-extra": "4.0.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"debug": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fs-extra": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "4.1.3",
|
||||||
|
"jsonfile": "4.0.0",
|
||||||
|
"universalify": "0.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jsonfile": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||||
|
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "4.1.11"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"graceful-fs": {
|
||||||
|
"version": "4.1.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
|
||||||
|
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"generate-function": {
|
"generate-function": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
|
||||||
|
@ -1107,9 +1261,9 @@
|
||||||
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
|
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
|
||||||
},
|
},
|
||||||
"home-path": {
|
"home-path": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/home-path/-/home-path-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/home-path/-/home-path-1.0.5.tgz",
|
||||||
"integrity": "sha1-ns5Z/sPwMubRC1Q0/uJk30wt4y8=",
|
"integrity": "sha1-eIspgVsS1Tus9XVkhHbm+QQdEz8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"hosted-git-info": {
|
"hosted-git-info": {
|
||||||
|
@ -1461,15 +1615,6 @@
|
||||||
"mime-db": "1.22.0"
|
"mime-db": "1.22.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimatch": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz",
|
|
||||||
"integrity": "sha1-UjYVelHk8ATBd/s8Un/33Xjw74M=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"brace-expansion": "1.1.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||||
|
@ -1723,61 +1868,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ms": {
|
"ms": {
|
||||||
"version": "0.7.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
|
|
||||||
"integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"mv": {
|
|
||||||
"version": "2.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz",
|
|
||||||
"integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"mkdirp": "0.5.1",
|
|
||||||
"ncp": "2.0.0",
|
|
||||||
"rimraf": "2.4.5"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"glob": {
|
|
||||||
"version": "6.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz",
|
|
||||||
"integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"inflight": "1.0.4",
|
|
||||||
"inherits": "2.0.1",
|
|
||||||
"minimatch": "3.0.0",
|
|
||||||
"once": "1.3.3",
|
|
||||||
"path-is-absolute": "1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rimraf": {
|
|
||||||
"version": "2.4.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz",
|
|
||||||
"integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"glob": "6.0.4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"mz": {
|
|
||||||
"version": "2.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
|
||||||
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"any-promise": "1.3.0",
|
|
||||||
"object-assign": "4.0.1",
|
|
||||||
"thenify-all": "1.6.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ncp": {
|
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
"integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=",
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node-notifier": {
|
"node-notifier": {
|
||||||
|
@ -1843,27 +1936,27 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nugget": {
|
"nugget": {
|
||||||
"version": "1.6.2",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/nugget/-/nugget-1.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/nugget/-/nugget-2.0.1.tgz",
|
||||||
"integrity": "sha1-iMpuA7pXBqmRc/XaCQJZPWvK4Qc=",
|
"integrity": "sha1-IBCVpIfhrTYIGzQy+jytpPjQcbA=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"debug": "2.2.0",
|
"debug": "2.6.9",
|
||||||
"minimist": "1.2.0",
|
"minimist": "1.2.0",
|
||||||
"pretty-bytes": "1.0.4",
|
"pretty-bytes": "1.0.4",
|
||||||
"progress-stream": "1.2.0",
|
"progress-stream": "1.2.0",
|
||||||
"request": "2.71.0",
|
"request": "2.71.0",
|
||||||
"single-line-log": "0.4.1",
|
"single-line-log": "1.1.2",
|
||||||
"throttleit": "0.0.2"
|
"throttleit": "0.0.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "2.2.0",
|
"version": "2.6.9",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
"integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"ms": "0.7.1"
|
"ms": "2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"throttleit": {
|
"throttleit": {
|
||||||
|
@ -1966,10 +2059,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"path-exists": {
|
"path-exists": {
|
||||||
"version": "1.0.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
|
||||||
"integrity": "sha1-1aiZjrce83p0w06w2eum6HjuoIE=",
|
"integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"pinkie-promise": "2.0.1"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"path-is-absolute": {
|
"path-is-absolute": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
@ -2070,46 +2166,6 @@
|
||||||
"is-promise": "1.0.1"
|
"is-promise": "1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pruner": {
|
|
||||||
"version": "0.0.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/pruner/-/pruner-0.0.7.tgz",
|
|
||||||
"integrity": "sha1-NF+8s+gHARY6HXrfVrrCKaWh5ME=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"fs-extra": "4.0.3"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"fs-extra": {
|
|
||||||
"version": "4.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz",
|
|
||||||
"integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"graceful-fs": "4.1.3",
|
|
||||||
"jsonfile": "4.0.0",
|
|
||||||
"universalify": "0.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"jsonfile": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
|
||||||
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"graceful-fs": "4.1.11"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"graceful-fs": {
|
|
||||||
"version": "4.1.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
|
|
||||||
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pseudomap": {
|
"pseudomap": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
|
||||||
|
@ -2153,12 +2209,6 @@
|
||||||
"strip-json-comments": "1.0.4"
|
"strip-json-comments": "1.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rcedit": {
|
|
||||||
"version": "0.9.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/rcedit/-/rcedit-0.9.0.tgz",
|
|
||||||
"integrity": "sha1-ORDfVzRTmeKwMl9KUZAH+J5V7xw=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"read-pkg": {
|
"read-pkg": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
|
||||||
|
@ -2288,10 +2338,13 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"single-line-log": {
|
"single-line-log": {
|
||||||
"version": "0.4.1",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-1.1.2.tgz",
|
||||||
"integrity": "sha1-h6VWSfdJ14PsDc2AToFA2Yc8fO4=",
|
"integrity": "sha1-wvg/Jzo+GhbtsJlWYdoO1e8DM2Q=",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"string-width": "1.0.1"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"sntp": {
|
"sntp": {
|
||||||
"version": "1.0.9",
|
"version": "1.0.9",
|
||||||
|
@ -2476,24 +2529,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"thenify": {
|
|
||||||
"version": "3.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz",
|
|
||||||
"integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"any-promise": "1.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"thenify-all": {
|
|
||||||
"version": "1.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
|
|
||||||
"integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"thenify": "3.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"throttleit": {
|
"throttleit": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz",
|
||||||
|
@ -2694,23 +2729,6 @@
|
||||||
"y18n": "3.2.1"
|
"y18n": "3.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"yargs-parser": {
|
|
||||||
"version": "8.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz",
|
|
||||||
"integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"camelcase": "4.1.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"camelcase": {
|
|
||||||
"version": "4.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
|
|
||||||
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
|
|
||||||
"dev": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"yauzl": {
|
"yauzl": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
""
|
""
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"electron-packager": "^11.0.0",
|
"electron-packager": "^12.0.0",
|
||||||
"electron-prebuilt": "0.37.5"
|
"electron": "1.8.4"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"always-tail": "0.2.0",
|
"always-tail": "0.2.0",
|
||||||
"cheerio": "^0.19.0",
|
"cheerio": "^0.19.0",
|
||||||
|
"electron-log": "1.1.1",
|
||||||
"extend": "^3.0.0",
|
"extend": "^3.0.0",
|
||||||
"fs-extra": "^1.0.0",
|
"fs-extra": "^1.0.0",
|
||||||
"node-notifier": "^5.2.1",
|
"node-notifier": "^5.2.1",
|
||||||
|
@ -32,7 +33,6 @@
|
||||||
"request": "^2.67.0",
|
"request": "^2.67.0",
|
||||||
"request-progress": "1.0.2",
|
"request-progress": "1.0.2",
|
||||||
"tar-fs": "^1.12.0",
|
"tar-fs": "^1.12.0",
|
||||||
"yargs": "^3.30.0",
|
"yargs": "^3.30.0"
|
||||||
"electron-log": "1.1.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ function ready() {
|
||||||
console.log("Ready");
|
console.log("Ready");
|
||||||
|
|
||||||
const electron = require('electron');
|
const electron = require('electron');
|
||||||
const remote = require('remote');
|
const remote = electron.remote;
|
||||||
window.$ = require('./vendor/jquery/jquery-2.1.4.min.js');
|
window.$ = require('./vendor/jquery/jquery-2.1.4.min.js');
|
||||||
|
|
||||||
$(".state").hide();
|
$(".state").hide();
|
||||||
|
|
|
@ -8,9 +8,9 @@ const nativeImage = electron.nativeImage;
|
||||||
const notifier = require('node-notifier');
|
const notifier = require('node-notifier');
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
const dialog = electron.dialog;
|
const dialog = electron.dialog;
|
||||||
const Menu = require('menu');
|
const Menu = electron.Menu;
|
||||||
const Tray = require('tray');
|
const Tray = electron.Tray;
|
||||||
const shell = require('shell');
|
const shell = electron.shell;
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
const childProcess = require('child_process');
|
const childProcess = require('child_process');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
|
@ -226,7 +226,7 @@ Process.prototype = extend(Process.prototype, {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
var signal = force ? 'SIGKILL' : null;
|
var signal = force ? 'SIGKILL' : 'SIGTERM';
|
||||||
this.child.kill(signal);
|
this.child.kill(signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue