mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-23 09:54:24 +02:00
handle receipt of new public socket and propogation to data-server
This commit is contained in:
parent
47137c72a5
commit
885030a10c
6 changed files with 197 additions and 136 deletions
|
@ -247,6 +247,8 @@ bool DomainServer::hasOAuthProviderAndAuthInformation() {
|
||||||
hasAttemptedAuthWithOAuthProvider = true;
|
hasAttemptedAuthWithOAuthProvider = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Missing OAuth provider URL, but a domain-server feature was required that requires authentication." <<
|
qDebug() << "Missing OAuth provider URL, but a domain-server feature was required that requires authentication." <<
|
||||||
"domain-server will now quit.";
|
"domain-server will now quit.";
|
||||||
|
@ -290,7 +292,8 @@ void DomainServer::setupDynamicIPAddressUpdating() {
|
||||||
_argumentVariantMap.value(ENABLE_DYNAMIC_IP_UPDATING_OPTION).toBool() &&
|
_argumentVariantMap.value(ENABLE_DYNAMIC_IP_UPDATING_OPTION).toBool() &&
|
||||||
hasOAuthProviderAndAuthInformation()) {
|
hasOAuthProviderAndAuthInformation()) {
|
||||||
|
|
||||||
const QUuid& domainID = LimitedNodeList::getInstance()->getSessionUUID();
|
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
|
||||||
|
const QUuid& domainID = nodeList->getSessionUUID();
|
||||||
|
|
||||||
if (!domainID.isNull()) {
|
if (!domainID.isNull()) {
|
||||||
qDebug() << "domain-server IP address will be updated for domain with ID"
|
qDebug() << "domain-server IP address will be updated for domain with ID"
|
||||||
|
@ -303,6 +306,9 @@ void DomainServer::setupDynamicIPAddressUpdating() {
|
||||||
connect(dynamicIPTimer, &QTimer::timeout, this, &DomainServer::requestCurrentIPAddressViaSTUN);
|
connect(dynamicIPTimer, &QTimer::timeout, this, &DomainServer::requestCurrentIPAddressViaSTUN);
|
||||||
dynamicIPTimer->start(STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS);
|
dynamicIPTimer->start(STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS);
|
||||||
|
|
||||||
|
// send public socket changes to the data server so nodes can find us at our new IP
|
||||||
|
connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendNewPublicSocketToDataServer);
|
||||||
|
|
||||||
// check our IP address right away
|
// check our IP address right away
|
||||||
requestCurrentIPAddressViaSTUN();
|
requestCurrentIPAddressViaSTUN();
|
||||||
|
|
||||||
|
@ -887,7 +893,22 @@ void DomainServer::transactionJSONCallback(const QJsonObject& data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::requestCurrentIPAddressViaSTUN() {
|
void DomainServer::requestCurrentIPAddressViaSTUN() {
|
||||||
|
LimitedNodeList::getInstance()->sendSTUNRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DomainServer::sendNewPublicSocketToDataServer(const HifiSockAddr& newPublicSockAddr) {
|
||||||
|
const QString DOMAIN_UPDATE = "/api/v1/domains/%1";
|
||||||
|
const QUuid& domainID = LimitedNodeList::getInstance()->getSessionUUID();
|
||||||
|
|
||||||
|
// setup the domain object to send to the data server
|
||||||
|
const QString DOMAIN_JSON_OBJECT = "{\"domain\":{\"network_address\":\"%1\"}}";
|
||||||
|
|
||||||
|
QString domainUpdateJSON = DOMAIN_JSON_OBJECT.arg(newPublicSockAddr.getAddress().toString());
|
||||||
|
|
||||||
|
AccountManager::getInstance().authenticatedRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)),
|
||||||
|
QNetworkAccessManager::PutOperation,
|
||||||
|
JSONCallbackParameters(),
|
||||||
|
domainUpdateJSON.toUtf8());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
|
void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
|
||||||
|
@ -895,32 +916,44 @@ void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiS
|
||||||
|
|
||||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||||
PacketType requestType = packetTypeForPacket(receivedPacket);
|
PacketType requestType = packetTypeForPacket(receivedPacket);
|
||||||
|
switch (requestType) {
|
||||||
|
case PacketTypeDomainConnectRequest:
|
||||||
|
handleConnectRequest(receivedPacket, senderSockAddr);
|
||||||
|
break;
|
||||||
|
case PacketTypeDomainListRequest: {
|
||||||
|
QUuid nodeUUID = uuidFromPacketHeader(receivedPacket);
|
||||||
|
|
||||||
if (requestType == PacketTypeDomainConnectRequest) {
|
if (!nodeUUID.isNull() && nodeList->nodeWithUUID(nodeUUID)) {
|
||||||
handleConnectRequest(receivedPacket, senderSockAddr);
|
NodeType_t throwawayNodeType;
|
||||||
} else if (requestType == PacketTypeDomainListRequest) {
|
HifiSockAddr nodePublicAddress, nodeLocalAddress;
|
||||||
QUuid nodeUUID = uuidFromPacketHeader(receivedPacket);
|
|
||||||
|
|
||||||
if (!nodeUUID.isNull() && nodeList->nodeWithUUID(nodeUUID)) {
|
int numNodeInfoBytes = parseNodeDataFromByteArray(throwawayNodeType, nodePublicAddress, nodeLocalAddress,
|
||||||
NodeType_t throwawayNodeType;
|
receivedPacket, senderSockAddr);
|
||||||
HifiSockAddr nodePublicAddress, nodeLocalAddress;
|
|
||||||
|
|
||||||
int numNodeInfoBytes = parseNodeDataFromByteArray(throwawayNodeType, nodePublicAddress, nodeLocalAddress,
|
SharedNodePointer checkInNode = nodeList->updateSocketsForNode(nodeUUID, nodePublicAddress, nodeLocalAddress);
|
||||||
receivedPacket, senderSockAddr);
|
|
||||||
|
|
||||||
SharedNodePointer checkInNode = nodeList->updateSocketsForNode(nodeUUID, nodePublicAddress, nodeLocalAddress);
|
// update last receive to now
|
||||||
|
quint64 timeNow = usecTimestampNow();
|
||||||
|
checkInNode->setLastHeardMicrostamp(timeNow);
|
||||||
|
|
||||||
// update last receive to now
|
sendDomainListToNode(checkInNode, senderSockAddr, nodeInterestListFromPacket(receivedPacket, numNodeInfoBytes));
|
||||||
quint64 timeNow = usecTimestampNow();
|
}
|
||||||
checkInNode->setLastHeardMicrostamp(timeNow);
|
|
||||||
|
|
||||||
sendDomainListToNode(checkInNode, senderSockAddr, nodeInterestListFromPacket(receivedPacket, numNodeInfoBytes));
|
break;
|
||||||
}
|
}
|
||||||
} else if (requestType == PacketTypeNodeJsonStats) {
|
case PacketTypeNodeJsonStats: {
|
||||||
SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket);
|
SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||||
if (matchingNode) {
|
if (matchingNode) {
|
||||||
reinterpret_cast<DomainServerNodeData*>(matchingNode->getLinkedData())->parseJSONStatsPacket(receivedPacket);
|
reinterpret_cast<DomainServerNodeData*>(matchingNode->getLinkedData())->parseJSONStatsPacket(receivedPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case PacketTypeStunResponse:
|
||||||
|
nodeList->processSTUNResponse(receivedPacket);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,9 @@ private slots:
|
||||||
void readAvailableDatagrams();
|
void readAvailableDatagrams();
|
||||||
void setupPendingAssignmentCredits();
|
void setupPendingAssignmentCredits();
|
||||||
void sendPendingTransactionsToServer();
|
void sendPendingTransactionsToServer();
|
||||||
|
|
||||||
void requestCurrentIPAddressViaSTUN();
|
void requestCurrentIPAddressViaSTUN();
|
||||||
|
void sendNewPublicSocketToDataServer(const HifiSockAddr& newPublicSockAddr);
|
||||||
private:
|
private:
|
||||||
void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid());
|
void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid());
|
||||||
bool optionallySetupOAuth();
|
bool optionallySetupOAuth();
|
||||||
|
|
|
@ -67,6 +67,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short
|
||||||
_nodeHashMutex(QMutex::Recursive),
|
_nodeHashMutex(QMutex::Recursive),
|
||||||
_nodeSocket(this),
|
_nodeSocket(this),
|
||||||
_dtlsSocket(NULL),
|
_dtlsSocket(NULL),
|
||||||
|
_publicSockAddr(),
|
||||||
_numCollectedPackets(0),
|
_numCollectedPackets(0),
|
||||||
_numCollectedBytes(0),
|
_numCollectedBytes(0),
|
||||||
_packetStatTimer()
|
_packetStatTimer()
|
||||||
|
@ -502,3 +503,115 @@ void LimitedNodeList::removeSilentNodes() {
|
||||||
|
|
||||||
_nodeHashMutex.unlock();
|
_nodeHashMutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uint32_t RFC_5389_MAGIC_COOKIE = 0x2112A442;
|
||||||
|
const int NUM_BYTES_STUN_HEADER = 20;
|
||||||
|
|
||||||
|
void LimitedNodeList::sendSTUNRequest() {
|
||||||
|
|
||||||
|
unsigned char stunRequestPacket[NUM_BYTES_STUN_HEADER];
|
||||||
|
|
||||||
|
int packetIndex = 0;
|
||||||
|
|
||||||
|
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE);
|
||||||
|
|
||||||
|
// leading zeros + message type
|
||||||
|
const uint16_t REQUEST_MESSAGE_TYPE = htons(0x0001);
|
||||||
|
memcpy(stunRequestPacket + packetIndex, &REQUEST_MESSAGE_TYPE, sizeof(REQUEST_MESSAGE_TYPE));
|
||||||
|
packetIndex += sizeof(REQUEST_MESSAGE_TYPE);
|
||||||
|
|
||||||
|
// message length (no additional attributes are included)
|
||||||
|
uint16_t messageLength = 0;
|
||||||
|
memcpy(stunRequestPacket + packetIndex, &messageLength, sizeof(messageLength));
|
||||||
|
packetIndex += sizeof(messageLength);
|
||||||
|
|
||||||
|
memcpy(stunRequestPacket + packetIndex, &RFC_5389_MAGIC_COOKIE_NETWORK_ORDER, sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER));
|
||||||
|
packetIndex += sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
|
||||||
|
|
||||||
|
// transaction ID (random 12-byte unsigned integer)
|
||||||
|
const uint NUM_TRANSACTION_ID_BYTES = 12;
|
||||||
|
QUuid randomUUID = QUuid::createUuid();
|
||||||
|
memcpy(stunRequestPacket + packetIndex, randomUUID.toRfc4122().data(), NUM_TRANSACTION_ID_BYTES);
|
||||||
|
|
||||||
|
// lookup the IP for the STUN server
|
||||||
|
static HifiSockAddr stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT);
|
||||||
|
|
||||||
|
_nodeSocket.writeDatagram((char*) stunRequestPacket, sizeof(stunRequestPacket),
|
||||||
|
stunSockAddr.getAddress(), stunSockAddr.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LimitedNodeList::processSTUNResponse(const QByteArray& packet) {
|
||||||
|
// check the cookie to make sure this is actually a STUN response
|
||||||
|
// and read the first attribute and make sure it is a XOR_MAPPED_ADDRESS
|
||||||
|
const int NUM_BYTES_MESSAGE_TYPE_AND_LENGTH = 4;
|
||||||
|
const uint16_t XOR_MAPPED_ADDRESS_TYPE = htons(0x0020);
|
||||||
|
|
||||||
|
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE);
|
||||||
|
|
||||||
|
int attributeStartIndex = NUM_BYTES_STUN_HEADER;
|
||||||
|
|
||||||
|
if (memcmp(packet.data() + NUM_BYTES_MESSAGE_TYPE_AND_LENGTH,
|
||||||
|
&RFC_5389_MAGIC_COOKIE_NETWORK_ORDER,
|
||||||
|
sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER)) == 0) {
|
||||||
|
|
||||||
|
// enumerate the attributes to find XOR_MAPPED_ADDRESS_TYPE
|
||||||
|
while (attributeStartIndex < packet.size()) {
|
||||||
|
if (memcmp(packet.data() + attributeStartIndex, &XOR_MAPPED_ADDRESS_TYPE, sizeof(XOR_MAPPED_ADDRESS_TYPE)) == 0) {
|
||||||
|
const int NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH = 4;
|
||||||
|
const int NUM_BYTES_FAMILY_ALIGN = 1;
|
||||||
|
const uint8_t IPV4_FAMILY_NETWORK_ORDER = htons(0x01) >> 8;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int byteIndex = attributeStartIndex + NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH + NUM_BYTES_FAMILY_ALIGN;
|
||||||
|
|
||||||
|
uint8_t addressFamily = 0;
|
||||||
|
memcpy(&addressFamily, packet.data() + byteIndex, sizeof(addressFamily));
|
||||||
|
|
||||||
|
byteIndex += sizeof(addressFamily);
|
||||||
|
|
||||||
|
if (addressFamily == IPV4_FAMILY_NETWORK_ORDER) {
|
||||||
|
// grab the X-Port
|
||||||
|
uint16_t xorMappedPort = 0;
|
||||||
|
memcpy(&xorMappedPort, packet.data() + byteIndex, sizeof(xorMappedPort));
|
||||||
|
|
||||||
|
uint16_t newPublicPort = ntohs(xorMappedPort) ^ (ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER) >> 16);
|
||||||
|
|
||||||
|
byteIndex += sizeof(xorMappedPort);
|
||||||
|
|
||||||
|
// grab the X-Address
|
||||||
|
uint32_t xorMappedAddress = 0;
|
||||||
|
memcpy(&xorMappedAddress, packet.data() + byteIndex, sizeof(xorMappedAddress));
|
||||||
|
|
||||||
|
uint32_t stunAddress = ntohl(xorMappedAddress) ^ ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
|
||||||
|
|
||||||
|
QHostAddress newPublicAddress = QHostAddress(stunAddress);
|
||||||
|
|
||||||
|
if (newPublicAddress != _publicSockAddr.getAddress() || newPublicPort != _publicSockAddr.getPort()) {
|
||||||
|
_publicSockAddr = HifiSockAddr(newPublicAddress, newPublicPort);
|
||||||
|
|
||||||
|
qDebug("New public socket received from STUN server is %s:%hu",
|
||||||
|
_publicSockAddr.getAddress().toString().toLocal8Bit().constData(),
|
||||||
|
_publicSockAddr.getPort());
|
||||||
|
|
||||||
|
emit publicSockAddrChanged(_publicSockAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// push forward attributeStartIndex by the length of this attribute
|
||||||
|
const int NUM_BYTES_ATTRIBUTE_TYPE = 2;
|
||||||
|
|
||||||
|
uint16_t attributeLength = 0;
|
||||||
|
memcpy(&attributeLength, packet.data() + attributeStartIndex + NUM_BYTES_ATTRIBUTE_TYPE,
|
||||||
|
sizeof(attributeLength));
|
||||||
|
attributeLength = ntohs(attributeLength);
|
||||||
|
|
||||||
|
attributeStartIndex += NUM_BYTES_MESSAGE_TYPE_AND_LENGTH + attributeLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -40,6 +40,9 @@ extern const QUrl DEFAULT_NODE_AUTH_URL;
|
||||||
|
|
||||||
const char DEFAULT_ASSIGNMENT_SERVER_HOSTNAME[] = "localhost";
|
const char DEFAULT_ASSIGNMENT_SERVER_HOSTNAME[] = "localhost";
|
||||||
|
|
||||||
|
const char STUN_SERVER_HOSTNAME[] = "stun.highfidelity.io";
|
||||||
|
const unsigned short STUN_SERVER_PORT = 3478;
|
||||||
|
|
||||||
class HifiSockAddr;
|
class HifiSockAddr;
|
||||||
|
|
||||||
typedef QSet<NodeType_t> NodeSet;
|
typedef QSet<NodeType_t> NodeSet;
|
||||||
|
@ -99,6 +102,9 @@ public:
|
||||||
|
|
||||||
void getPacketStats(float &packetsPerSecond, float &bytesPerSecond);
|
void getPacketStats(float &packetsPerSecond, float &bytesPerSecond);
|
||||||
void resetPacketStats();
|
void resetPacketStats();
|
||||||
|
|
||||||
|
virtual void sendSTUNRequest();
|
||||||
|
virtual bool processSTUNResponse(const QByteArray& packet);
|
||||||
public slots:
|
public slots:
|
||||||
void reset();
|
void reset();
|
||||||
void eraseAllNodes();
|
void eraseAllNodes();
|
||||||
|
@ -110,6 +116,7 @@ signals:
|
||||||
void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID);
|
void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID);
|
||||||
void nodeAdded(SharedNodePointer);
|
void nodeAdded(SharedNodePointer);
|
||||||
void nodeKilled(SharedNodePointer);
|
void nodeKilled(SharedNodePointer);
|
||||||
|
void publicSockAddrChanged(const HifiSockAddr& publicSockAddr);
|
||||||
protected:
|
protected:
|
||||||
static LimitedNodeList* _sharedInstance;
|
static LimitedNodeList* _sharedInstance;
|
||||||
|
|
||||||
|
@ -130,6 +137,7 @@ protected:
|
||||||
QMutex _nodeHashMutex;
|
QMutex _nodeHashMutex;
|
||||||
QUdpSocket _nodeSocket;
|
QUdpSocket _nodeSocket;
|
||||||
QUdpSocket* _dtlsSocket;
|
QUdpSocket* _dtlsSocket;
|
||||||
|
HifiSockAddr _publicSockAddr;
|
||||||
int _numCollectedPackets;
|
int _numCollectedPackets;
|
||||||
int _numCollectedBytes;
|
int _numCollectedBytes;
|
||||||
QElapsedTimer _packetStatTimer;
|
QElapsedTimer _packetStatTimer;
|
||||||
|
|
|
@ -57,7 +57,6 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned
|
||||||
_domainHandler(this),
|
_domainHandler(this),
|
||||||
_numNoReplyDomainCheckIns(0),
|
_numNoReplyDomainCheckIns(0),
|
||||||
_assignmentServerSocket(),
|
_assignmentServerSocket(),
|
||||||
_publicSockAddr(),
|
|
||||||
_hasCompletedInitialSTUNFailure(false),
|
_hasCompletedInitialSTUNFailure(false),
|
||||||
_stunRequestsSinceSuccess(0)
|
_stunRequestsSinceSuccess(0)
|
||||||
{
|
{
|
||||||
|
@ -195,47 +194,16 @@ void NodeList::addSetOfNodeTypesToNodeInterestSet(const NodeSet& setOfNodeTypes)
|
||||||
_nodeTypesOfInterest.unite(setOfNodeTypes);
|
_nodeTypesOfInterest.unite(setOfNodeTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t RFC_5389_MAGIC_COOKIE = 0x2112A442;
|
|
||||||
const int NUM_BYTES_STUN_HEADER = 20;
|
|
||||||
const unsigned int NUM_STUN_REQUESTS_BEFORE_FALLBACK = 5;
|
const unsigned int NUM_STUN_REQUESTS_BEFORE_FALLBACK = 5;
|
||||||
|
|
||||||
void NodeList::sendSTUNRequest() {
|
void NodeList::sendSTUNRequest() {
|
||||||
const char STUN_SERVER_HOSTNAME[] = "stun.highfidelity.io";
|
|
||||||
const unsigned short STUN_SERVER_PORT = 3478;
|
|
||||||
|
|
||||||
unsigned char stunRequestPacket[NUM_BYTES_STUN_HEADER];
|
|
||||||
|
|
||||||
int packetIndex = 0;
|
|
||||||
|
|
||||||
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE);
|
|
||||||
|
|
||||||
// leading zeros + message type
|
|
||||||
const uint16_t REQUEST_MESSAGE_TYPE = htons(0x0001);
|
|
||||||
memcpy(stunRequestPacket + packetIndex, &REQUEST_MESSAGE_TYPE, sizeof(REQUEST_MESSAGE_TYPE));
|
|
||||||
packetIndex += sizeof(REQUEST_MESSAGE_TYPE);
|
|
||||||
|
|
||||||
// message length (no additional attributes are included)
|
|
||||||
uint16_t messageLength = 0;
|
|
||||||
memcpy(stunRequestPacket + packetIndex, &messageLength, sizeof(messageLength));
|
|
||||||
packetIndex += sizeof(messageLength);
|
|
||||||
|
|
||||||
memcpy(stunRequestPacket + packetIndex, &RFC_5389_MAGIC_COOKIE_NETWORK_ORDER, sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER));
|
|
||||||
packetIndex += sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
|
|
||||||
|
|
||||||
// transaction ID (random 12-byte unsigned integer)
|
|
||||||
const uint NUM_TRANSACTION_ID_BYTES = 12;
|
|
||||||
QUuid randomUUID = QUuid::createUuid();
|
|
||||||
memcpy(stunRequestPacket + packetIndex, randomUUID.toRfc4122().data(), NUM_TRANSACTION_ID_BYTES);
|
|
||||||
|
|
||||||
// lookup the IP for the STUN server
|
|
||||||
static HifiSockAddr stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT);
|
|
||||||
|
|
||||||
if (!_hasCompletedInitialSTUNFailure) {
|
if (!_hasCompletedInitialSTUNFailure) {
|
||||||
qDebug("Sending intial stun request to %s", stunSockAddr.getAddress().toString().toLocal8Bit().constData());
|
qDebug() << "Sending intial stun request to" << STUN_SERVER_HOSTNAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
_nodeSocket.writeDatagram((char*) stunRequestPacket, sizeof(stunRequestPacket),
|
LimitedNodeList::sendSTUNRequest();
|
||||||
stunSockAddr.getAddress(), stunSockAddr.getPort());
|
|
||||||
|
|
||||||
_stunRequestsSinceSuccess++;
|
_stunRequestsSinceSuccess++;
|
||||||
|
|
||||||
|
@ -255,79 +223,16 @@ void NodeList::sendSTUNRequest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::processSTUNResponse(const QByteArray& packet) {
|
bool NodeList::processSTUNResponse(const QByteArray& packet) {
|
||||||
// check the cookie to make sure this is actually a STUN response
|
if (LimitedNodeList::processSTUNResponse(packet)) {
|
||||||
// and read the first attribute and make sure it is a XOR_MAPPED_ADDRESS
|
// reset the number of failed STUN requests since last success
|
||||||
const int NUM_BYTES_MESSAGE_TYPE_AND_LENGTH = 4;
|
_stunRequestsSinceSuccess = 0;
|
||||||
const uint16_t XOR_MAPPED_ADDRESS_TYPE = htons(0x0020);
|
|
||||||
|
|
||||||
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE);
|
_hasCompletedInitialSTUNFailure = true;
|
||||||
|
|
||||||
int attributeStartIndex = NUM_BYTES_STUN_HEADER;
|
return true;
|
||||||
|
} else {
|
||||||
if (memcmp(packet.data() + NUM_BYTES_MESSAGE_TYPE_AND_LENGTH,
|
return false;
|
||||||
&RFC_5389_MAGIC_COOKIE_NETWORK_ORDER,
|
|
||||||
sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER)) == 0) {
|
|
||||||
|
|
||||||
// enumerate the attributes to find XOR_MAPPED_ADDRESS_TYPE
|
|
||||||
while (attributeStartIndex < packet.size()) {
|
|
||||||
if (memcmp(packet.data() + attributeStartIndex, &XOR_MAPPED_ADDRESS_TYPE, sizeof(XOR_MAPPED_ADDRESS_TYPE)) == 0) {
|
|
||||||
const int NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH = 4;
|
|
||||||
const int NUM_BYTES_FAMILY_ALIGN = 1;
|
|
||||||
const uint8_t IPV4_FAMILY_NETWORK_ORDER = htons(0x01) >> 8;
|
|
||||||
|
|
||||||
// reset the number of failed STUN requests since last success
|
|
||||||
_stunRequestsSinceSuccess = 0;
|
|
||||||
|
|
||||||
int byteIndex = attributeStartIndex + NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH + NUM_BYTES_FAMILY_ALIGN;
|
|
||||||
|
|
||||||
uint8_t addressFamily = 0;
|
|
||||||
memcpy(&addressFamily, packet.data() + byteIndex, sizeof(addressFamily));
|
|
||||||
|
|
||||||
byteIndex += sizeof(addressFamily);
|
|
||||||
|
|
||||||
if (addressFamily == IPV4_FAMILY_NETWORK_ORDER) {
|
|
||||||
// grab the X-Port
|
|
||||||
uint16_t xorMappedPort = 0;
|
|
||||||
memcpy(&xorMappedPort, packet.data() + byteIndex, sizeof(xorMappedPort));
|
|
||||||
|
|
||||||
uint16_t newPublicPort = ntohs(xorMappedPort) ^ (ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER) >> 16);
|
|
||||||
|
|
||||||
byteIndex += sizeof(xorMappedPort);
|
|
||||||
|
|
||||||
// grab the X-Address
|
|
||||||
uint32_t xorMappedAddress = 0;
|
|
||||||
memcpy(&xorMappedAddress, packet.data() + byteIndex, sizeof(xorMappedAddress));
|
|
||||||
|
|
||||||
uint32_t stunAddress = ntohl(xorMappedAddress) ^ ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
|
|
||||||
|
|
||||||
QHostAddress newPublicAddress = QHostAddress(stunAddress);
|
|
||||||
|
|
||||||
if (newPublicAddress != _publicSockAddr.getAddress() || newPublicPort != _publicSockAddr.getPort()) {
|
|
||||||
_publicSockAddr = HifiSockAddr(newPublicAddress, newPublicPort);
|
|
||||||
|
|
||||||
qDebug("New public socket received from STUN server is %s:%hu",
|
|
||||||
_publicSockAddr.getAddress().toString().toLocal8Bit().constData(),
|
|
||||||
_publicSockAddr.getPort());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
_hasCompletedInitialSTUNFailure = true;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// push forward attributeStartIndex by the length of this attribute
|
|
||||||
const int NUM_BYTES_ATTRIBUTE_TYPE = 2;
|
|
||||||
|
|
||||||
uint16_t attributeLength = 0;
|
|
||||||
memcpy(&attributeLength, packet.data() + attributeStartIndex + NUM_BYTES_ATTRIBUTE_TYPE,
|
|
||||||
sizeof(attributeLength));
|
|
||||||
attributeLength = ntohs(attributeLength);
|
|
||||||
|
|
||||||
attributeStartIndex += NUM_BYTES_MESSAGE_TYPE_AND_LENGTH + attributeLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,8 +89,9 @@ private:
|
||||||
NodeList(char ownerType, unsigned short socketListenPort, unsigned short dtlsListenPort);
|
NodeList(char ownerType, unsigned short socketListenPort, unsigned short dtlsListenPort);
|
||||||
NodeList(NodeList const&); // Don't implement, needed to avoid copies of singleton
|
NodeList(NodeList const&); // Don't implement, needed to avoid copies of singleton
|
||||||
void operator=(NodeList const&); // Don't implement, needed to avoid copies of singleton
|
void operator=(NodeList const&); // Don't implement, needed to avoid copies of singleton
|
||||||
|
|
||||||
void sendSTUNRequest();
|
void sendSTUNRequest();
|
||||||
void processSTUNResponse(const QByteArray& packet);
|
bool processSTUNResponse(const QByteArray& packet);
|
||||||
|
|
||||||
void processDomainServerAuthRequest(const QByteArray& packet);
|
void processDomainServerAuthRequest(const QByteArray& packet);
|
||||||
void requestAuthForDomainServer();
|
void requestAuthForDomainServer();
|
||||||
|
@ -102,7 +103,6 @@ private:
|
||||||
DomainHandler _domainHandler;
|
DomainHandler _domainHandler;
|
||||||
int _numNoReplyDomainCheckIns;
|
int _numNoReplyDomainCheckIns;
|
||||||
HifiSockAddr _assignmentServerSocket;
|
HifiSockAddr _assignmentServerSocket;
|
||||||
HifiSockAddr _publicSockAddr;
|
|
||||||
bool _hasCompletedInitialSTUNFailure;
|
bool _hasCompletedInitialSTUNFailure;
|
||||||
unsigned int _stunRequestsSinceSuccess;
|
unsigned int _stunRequestsSinceSuccess;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue