From 87d6c0085fa49f77359ba2595c126142eafa3bf6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 17 Oct 2013 15:11:02 -0700 Subject: [PATCH] add a fallback if STUN to outside server isn't possible --- domain-server/src/DomainServer.cpp | 13 ++++ libraries/shared/src/NodeList.cpp | 98 +++++++++++++++++------------- libraries/shared/src/NodeList.h | 1 + 3 files changed, 71 insertions(+), 41 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 240befe800..bcac22c9cf 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -518,6 +518,19 @@ int DomainServer::run() { int numBytesPrivateSocket = unpackSocket(packetData + packetIndex, (sockaddr*) &nodePublicAddress); packetIndex += numBytesPrivateSocket; + if (nodePublicAddress.sin_addr.s_addr == 0) { + // this node wants to use us its STUN server + // so set the node public address to whatever we perceive the public address to be + + nodePublicAddress = senderAddress; + + // if the sender is on our box then leave its public address to 0 so that + // other users attempt to reach it on the same address they have for the domain-server + if (senderAddress.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { + nodePublicAddress.sin_addr.s_addr = 0; + } + } + int numBytesPublicSocket = unpackSocket(packetData + packetIndex, (sockaddr*) &nodeLocalAddress); packetIndex += numBytesPublicSocket; diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 12ad03e177..6510276f9a 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -74,7 +74,8 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) : _checkInPacket(NULL), _numBytesCheckInPacket(0), _publicAddress(), - _publicPort(0) + _publicPort(0), + _shouldUseDomainServerAsSTUN(0) { } @@ -311,53 +312,68 @@ void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNo const uint32_t RFC_5389_MAGIC_COOKIE = 0x2112A442; const int NUM_BYTES_STUN_HEADER = 20; +const int NUM_STUN_REQUESTS_BEFORE_FALLBACK = 5; 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]; + static int failedStunRequests = 0; - 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; - unsigned char transactionID[NUM_TRANSACTION_ID_BYTES]; - loadRandomIdentifier(transactionID, NUM_TRANSACTION_ID_BYTES); - memcpy(stunRequestPacket + packetIndex, &transactionID, sizeof(transactionID)); - - // lookup the IP for the STUN server - static QHostInfo stunInfo = QHostInfo::fromName(STUN_SERVER_HOSTNAME); - - for (int i = 0; i < stunInfo.addresses().size(); i++) { - if (stunInfo.addresses()[i].protocol() == QAbstractSocket::IPv4Protocol) { - QString stunIPAddress = stunInfo.addresses()[i].toString(); - - qDebug("Sending a stun request to %s\n", stunIPAddress.toLocal8Bit().constData()); - - _nodeSocket.send(stunIPAddress.toLocal8Bit().constData(), - STUN_SERVER_PORT, - stunRequestPacket, - sizeof(stunRequestPacket)); - - break; + if (failedStunRequests < NUM_STUN_REQUESTS_BEFORE_FALLBACK) { + 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; + unsigned char transactionID[NUM_TRANSACTION_ID_BYTES]; + loadRandomIdentifier(transactionID, NUM_TRANSACTION_ID_BYTES); + memcpy(stunRequestPacket + packetIndex, &transactionID, sizeof(transactionID)); + + // lookup the IP for the STUN server + static QHostInfo stunInfo = QHostInfo::fromName(STUN_SERVER_HOSTNAME); + + for (int i = 0; i < stunInfo.addresses().size(); i++) { + if (stunInfo.addresses()[i].protocol() == QAbstractSocket::IPv4Protocol) { + QString stunIPAddress = stunInfo.addresses()[i].toString(); + + qDebug("Sending a stun request to %s\n", stunIPAddress.toLocal8Bit().constData()); + + _nodeSocket.send(stunIPAddress.toLocal8Bit().constData(), + STUN_SERVER_PORT, + stunRequestPacket, + sizeof(stunRequestPacket)); + + break; + } } + + failedStunRequests++; + + return; } + + // if we're here this was the last failed STUN request + // use our DS as our stun server + qDebug("Failed to lookup public address via STUN server at %s:%hu. Using DS for STUN.\n", + STUN_SERVER_HOSTNAME, STUN_SERVER_PORT); + _shouldUseDomainServerAsSTUN = true; } void NodeList::processSTUNResponse(unsigned char* packetData, size_t dataBytes) { @@ -455,7 +471,7 @@ void NodeList::sendDomainServerCheckIn() { printedDomainServerIP = true; } - if (_publicAddress.isNull()) { + if (_publicAddress.isNull() && !_shouldUseDomainServerAsSTUN) { // we don't know our public socket and we need to send it to the domain server // send a STUN request to figure it out sendSTUNRequest(); diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index ff931dfe8e..ed7f0e637a 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -170,6 +170,7 @@ private: int _numBytesCheckInPacket; QHostAddress _publicAddress; uint16_t _publicPort; + bool _shouldUseDomainServerAsSTUN; void activateSocketFromPingReply(sockaddr *nodeAddress); void timePingReply(sockaddr *nodeAddress, unsigned char *packetData);