mirror of
https://github.com/overte-org/overte.git
synced 2025-08-07 09:09:53 +02:00
request and store domain public key in ice-server memory
This commit is contained in:
parent
9f9ef8764d
commit
ddf4f029d9
2 changed files with 116 additions and 23 deletions
|
@ -9,14 +9,18 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <QTimer>
|
#include "IceServer.h"
|
||||||
|
|
||||||
|
#include <QtCore/QJsonDocument>
|
||||||
|
#include <QtCore/QTimer>
|
||||||
|
#include <QtNetwork/QNetworkReply>
|
||||||
|
#include <QtNetwork/QNetworkRequest>
|
||||||
|
|
||||||
#include <LimitedNodeList.h>
|
#include <LimitedNodeList.h>
|
||||||
|
#include <NetworkingConstants.h>
|
||||||
#include <udt/PacketHeaders.h>
|
#include <udt/PacketHeaders.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
#include "IceServer.h"
|
|
||||||
|
|
||||||
const int CLEAR_INACTIVE_PEERS_INTERVAL_MSECS = 1 * 1000;
|
const int CLEAR_INACTIVE_PEERS_INTERVAL_MSECS = 1 * 1000;
|
||||||
const int PEER_SILENCE_THRESHOLD_MSECS = 5 * 1000;
|
const int PEER_SILENCE_THRESHOLD_MSECS = 5 * 1000;
|
||||||
|
|
||||||
|
@ -70,9 +74,10 @@ void IceServer::processPacket(std::unique_ptr<udt::Packet> packet) {
|
||||||
|
|
||||||
if (nlPacket->getType() == PacketType::ICEServerHeartbeat) {
|
if (nlPacket->getType() == PacketType::ICEServerHeartbeat) {
|
||||||
SharedNetworkPeer peer = addOrUpdateHeartbeatingPeer(*nlPacket);
|
SharedNetworkPeer peer = addOrUpdateHeartbeatingPeer(*nlPacket);
|
||||||
|
if (peer) {
|
||||||
// so that we can send packets to the heartbeating peer when we need, we need to activate a socket now
|
// so that we can send packets to the heartbeating peer when we need, we need to activate a socket now
|
||||||
peer->activateMatchingOrNewSymmetricSocket(nlPacket->getSenderSockAddr());
|
peer->activateMatchingOrNewSymmetricSocket(nlPacket->getSenderSockAddr());
|
||||||
|
}
|
||||||
} else if (nlPacket->getType() == PacketType::ICEServerQuery) {
|
} else if (nlPacket->getType() == PacketType::ICEServerQuery) {
|
||||||
QDataStream heartbeatStream(nlPacket.get());
|
QDataStream heartbeatStream(nlPacket.get());
|
||||||
|
|
||||||
|
@ -114,31 +119,107 @@ SharedNetworkPeer IceServer::addOrUpdateHeartbeatingPeer(NLPacket& packet) {
|
||||||
// pull the UUID, public and private sock addrs for this peer
|
// pull the UUID, public and private sock addrs for this peer
|
||||||
QUuid senderUUID;
|
QUuid senderUUID;
|
||||||
HifiSockAddr publicSocket, localSocket;
|
HifiSockAddr publicSocket, localSocket;
|
||||||
|
QByteArray signature;
|
||||||
|
|
||||||
QDataStream heartbeatStream(&packet);
|
QDataStream heartbeatStream(&packet);
|
||||||
|
heartbeatStream >> senderUUID >> publicSocket >> localSocket;
|
||||||
heartbeatStream >> senderUUID;
|
|
||||||
heartbeatStream >> publicSocket >> localSocket;
|
|
||||||
|
|
||||||
// make sure we have this sender in our peer hash
|
auto signedPlaintext = QByteArray::fromRawData(packet.getPayload(), heartbeatStream.device()->pos());
|
||||||
SharedNetworkPeer matchingPeer = _activePeers.value(senderUUID);
|
heartbeatStream >> signature;
|
||||||
|
|
||||||
if (!matchingPeer) {
|
// make sure this is a verified heartbeat before performing any more processing
|
||||||
// if we don't have this sender we need to create them now
|
if (isVerifiedHeartbeat(senderUUID, signedPlaintext, signature)) {
|
||||||
matchingPeer = QSharedPointer<NetworkPeer>::create(senderUUID, publicSocket, localSocket);
|
// make sure we have this sender in our peer hash
|
||||||
_activePeers.insert(senderUUID, matchingPeer);
|
SharedNetworkPeer matchingPeer = _activePeers.value(senderUUID);
|
||||||
|
|
||||||
qDebug() << "Added a new network peer" << *matchingPeer;
|
if (!matchingPeer) {
|
||||||
|
// if we don't have this sender we need to create them now
|
||||||
|
matchingPeer = QSharedPointer<NetworkPeer>::create(senderUUID, publicSocket, localSocket);
|
||||||
|
_activePeers.insert(senderUUID, matchingPeer);
|
||||||
|
|
||||||
|
qDebug() << "Added a new network peer" << *matchingPeer;
|
||||||
|
} else {
|
||||||
|
// we already had the peer so just potentially update their sockets
|
||||||
|
matchingPeer->setPublicSocket(publicSocket);
|
||||||
|
matchingPeer->setLocalSocket(localSocket);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update our last heard microstamp for this network peer to now
|
||||||
|
matchingPeer->setLastHeardMicrostamp(usecTimestampNow());
|
||||||
|
|
||||||
|
return matchingPeer;
|
||||||
} else {
|
} else {
|
||||||
// we already had the peer so just potentially update their sockets
|
// not verified, return the empty peer object
|
||||||
matchingPeer->setPublicSocket(publicSocket);
|
return SharedNetworkPeer();
|
||||||
matchingPeer->setLocalSocket(localSocket);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// update our last heard microstamp for this network peer to now
|
bool IceServer::isVerifiedHeartbeat(const QUuid& domainID, const QByteArray& plaintext, const QByteArray& signature) {
|
||||||
matchingPeer->setLastHeardMicrostamp(usecTimestampNow());
|
// check if we have a private key for this domain ID - if we do not then fire off the request for it
|
||||||
|
auto it = _domainPublicKeys.find(domainID);
|
||||||
|
if (it != _domainPublicKeys.end()) {
|
||||||
|
|
||||||
return matchingPeer;
|
return true;
|
||||||
|
} else {
|
||||||
|
// we don't have a public key for this domain so we can't verify this heartbeat
|
||||||
|
// ask the metaverse API for the right public key and return false to indicate that this is not verified
|
||||||
|
requestDomainPublicKey(domainID);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IceServer::requestDomainPublicKey(const QUuid& domainID) {
|
||||||
|
// send a request to the metaverse API for the public key for this domain
|
||||||
|
QNetworkAccessManager* manager = new QNetworkAccessManager { this };
|
||||||
|
connect(manager, &QNetworkAccessManager::finished, this, &IceServer::publicKeyReplyFinished);
|
||||||
|
|
||||||
|
QUrl publicKeyURL { NetworkingConstants::METAVERSE_SERVER_URL };
|
||||||
|
QString publicKeyPath = QString("/api/v1/domains/%1/public_key").arg(uuidStringWithoutCurlyBraces(domainID));
|
||||||
|
publicKeyURL.setPath(publicKeyPath);
|
||||||
|
|
||||||
|
QNetworkRequest publicKeyRequest { publicKeyURL };
|
||||||
|
publicKeyRequest.setAttribute(QNetworkRequest::User, domainID);
|
||||||
|
|
||||||
|
qDebug() << "Requesting public key for domain with ID" << domainID;
|
||||||
|
|
||||||
|
manager->get(publicKeyRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IceServer::publicKeyReplyFinished(QNetworkReply* reply) {
|
||||||
|
// get the domain ID from the QNetworkReply attribute
|
||||||
|
QUuid domainID = reply->request().attribute(QNetworkRequest::User).toUuid();
|
||||||
|
|
||||||
|
if (reply->error() == QNetworkReply::NoError) {
|
||||||
|
// pull out the public key and store it for this domain
|
||||||
|
|
||||||
|
// the response should be JSON
|
||||||
|
QJsonDocument responseDocument = QJsonDocument::fromJson(reply->readAll());
|
||||||
|
|
||||||
|
static const QString DATA_KEY = "data";
|
||||||
|
static const QString PUBLIC_KEY_KEY = "public_key";
|
||||||
|
static const QString STATUS_KEY = "status";
|
||||||
|
static const QString SUCCESS_VALUE = "success";
|
||||||
|
|
||||||
|
auto responseObject = responseDocument.object();
|
||||||
|
if (responseObject[STATUS_KEY].toString() == SUCCESS_VALUE) {
|
||||||
|
auto dataObject = responseObject[DATA_KEY].toObject();
|
||||||
|
if (dataObject.contains(PUBLIC_KEY_KEY)) {
|
||||||
|
_domainPublicKeys.emplace(domainID,
|
||||||
|
QByteArray::fromBase64(dataObject[PUBLIC_KEY_KEY].toString().toUtf8()));
|
||||||
|
} else {
|
||||||
|
qWarning() << "There was no public key present in response for domain with ID" << domainID;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qWarning() << "The metaverse API did not return success for public key request for domain with ID" << domainID;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// there was a problem getting the public key for the domain
|
||||||
|
// log it since it will be re-requested on the next heartbeat
|
||||||
|
|
||||||
|
qWarning() << "Error retreiving public key for domain with ID" << domainID << "-" << reply->errorString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IceServer::sendPeerInformationPacket(const NetworkPeer& peer, const HifiSockAddr* destinationSockAddr) {
|
void IceServer::sendPeerInformationPacket(const NetworkPeer& peer, const HifiSockAddr* destinationSockAddr) {
|
||||||
|
|
|
@ -16,13 +16,15 @@
|
||||||
#include <QtCore/QSharedPointer>
|
#include <QtCore/QSharedPointer>
|
||||||
#include <QUdpSocket>
|
#include <QUdpSocket>
|
||||||
|
|
||||||
|
#include <UUIDHasher.h>
|
||||||
|
|
||||||
#include <NetworkPeer.h>
|
#include <NetworkPeer.h>
|
||||||
#include <HTTPConnection.h>
|
#include <HTTPConnection.h>
|
||||||
#include <HTTPManager.h>
|
#include <HTTPManager.h>
|
||||||
#include <NLPacket.h>
|
#include <NLPacket.h>
|
||||||
#include <udt/Socket.h>
|
#include <udt/Socket.h>
|
||||||
|
|
||||||
typedef QHash<QUuid, SharedNetworkPeer> NetworkPeerHash;
|
class QNetworkReply;
|
||||||
|
|
||||||
class IceServer : public QCoreApplication, public HTTPRequestHandler {
|
class IceServer : public QCoreApplication, public HTTPRequestHandler {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -31,6 +33,7 @@ public:
|
||||||
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false);
|
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false);
|
||||||
private slots:
|
private slots:
|
||||||
void clearInactivePeers();
|
void clearInactivePeers();
|
||||||
|
void publicKeyReplyFinished(QNetworkReply* reply);
|
||||||
private:
|
private:
|
||||||
bool packetVersionMatch(const udt::Packet& packet);
|
bool packetVersionMatch(const udt::Packet& packet);
|
||||||
void processPacket(std::unique_ptr<udt::Packet> packet);
|
void processPacket(std::unique_ptr<udt::Packet> packet);
|
||||||
|
@ -38,10 +41,19 @@ private:
|
||||||
SharedNetworkPeer addOrUpdateHeartbeatingPeer(NLPacket& incomingPacket);
|
SharedNetworkPeer addOrUpdateHeartbeatingPeer(NLPacket& incomingPacket);
|
||||||
void sendPeerInformationPacket(const NetworkPeer& peer, const HifiSockAddr* destinationSockAddr);
|
void sendPeerInformationPacket(const NetworkPeer& peer, const HifiSockAddr* destinationSockAddr);
|
||||||
|
|
||||||
|
bool isVerifiedHeartbeat(const QUuid& domainID, const QByteArray& plaintext, const QByteArray& signature);
|
||||||
|
void requestDomainPublicKey(const QUuid& domainID);
|
||||||
|
|
||||||
QUuid _id;
|
QUuid _id;
|
||||||
udt::Socket _serverSocket;
|
udt::Socket _serverSocket;
|
||||||
|
|
||||||
|
using NetworkPeerHash = QHash<QUuid, SharedNetworkPeer>;
|
||||||
NetworkPeerHash _activePeers;
|
NetworkPeerHash _activePeers;
|
||||||
|
|
||||||
HTTPManager _httpManager;
|
HTTPManager _httpManager;
|
||||||
|
|
||||||
|
using DomainPublicKeyHash = std::unordered_map<QUuid, QByteArray>;
|
||||||
|
DomainPublicKeyHash _domainPublicKeys;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_IceServer_h
|
#endif // hifi_IceServer_h
|
||||||
|
|
Loading…
Reference in a new issue