Merge pull request #12786 from huffman/fix/node-list-connections

Fix avatars not coming back when briefly disconnected from avatar mixer
This commit is contained in:
John Conklin II 2018-04-20 09:53:50 -07:00 committed by GitHub
commit 92bf99f436
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 64 additions and 16 deletions

View file

@ -451,11 +451,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 +466,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);

View file

@ -569,9 +569,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 +586,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 +601,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,6 +609,15 @@ 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,
@ -629,6 +639,11 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
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);
@ -703,13 +718,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;
} }

View file

@ -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;
@ -180,7 +184,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 +323,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);
@ -371,7 +375,7 @@ protected:
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 +422,7 @@ protected:
} }
} }
std::unordered_map<QUuid, ConnectionID> _connectionIDs;
private slots: private slots:
void flagTimeForConnectionStep(ConnectionStep connectionStep, quint64 timestamp); void flagTimeForConnectionStep(ConnectionStep connectionStep, quint64 timestamp);

View file

@ -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) {
@ -705,16 +719,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 +800,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);
}); });
} }

View file

@ -75,6 +75,8 @@ PacketVersion versionForPacketType(PacketType packetType) {
return static_cast<PacketVersion>(IcePingVersion::SendICEPeerID); 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 17;
} }

View file

@ -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