From cca1c30207d5502a0806e24bdc99b0eab65f3b1b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 2 Oct 2014 13:39:58 -0700 Subject: [PATCH] build out more of the ice-server, make connect requests from NodeList --- ice-server/src/IceServer.cpp | 54 +++++++++- ice-server/src/IceServer.h | 11 +- libraries/networking/src/DomainHandler.cpp | 2 + libraries/networking/src/DomainHandler.h | 3 + libraries/networking/src/NetworkPeer.cpp | 7 ++ libraries/networking/src/NetworkPeer.h | 9 ++ libraries/networking/src/Node.h | 3 - libraries/networking/src/NodeList.cpp | 115 ++++++++++++--------- libraries/networking/src/NodeList.h | 2 + libraries/networking/src/PacketHeaders.h | 3 +- 10 files changed, 154 insertions(+), 55 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 6543c41c31..cea05ebe30 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -9,10 +9,62 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "IceServer.h" IceServer::IceServer(int argc, char* argv[]) : - QCoreApplication(argc, argv) + QCoreApplication(argc, argv), + _serverSocket() { + // start the ice-server socket + qDebug() << "ice-server socket is listening on" << ICE_SERVER_DEFAULT_PORT; + _serverSocket.bind(QHostAddress::AnyIPv4, ICE_SERVER_DEFAULT_PORT); + // call our process datagrams slot when the UDP socket has packets ready + connect(&_serverSocket, &QUdpSocket::readyRead, this, &IceServer::processDatagrams); +} + +void IceServer::processDatagrams() { + HifiSockAddr sendingSockAddr; + QByteArray incomingPacket; + + while (_serverSocket.hasPendingDatagrams()) { + incomingPacket.resize(_serverSocket.pendingDatagramSize()); + + _serverSocket.readDatagram(incomingPacket.data(), incomingPacket.size(), + sendingSockAddr.getAddressPointer(), sendingSockAddr.getPortPointer()); + + + if (packetTypeForPacket(incomingPacket) == PacketTypeIceServerHeartbeat) { + QUuid senderUUID = uuidFromPacketHeader(incomingPacket); + + // pull the public and private sock addrs for this peer + HifiSockAddr publicSocket, localSocket; + + QDataStream hearbeatStream(incomingPacket); + hearbeatStream.skipRawData(numBytesForPacketHeader(incomingPacket)); + + hearbeatStream >> publicSocket >> localSocket; + + // make sure we have this sender in our peer hash + SharedNetworkPeer matchingPeer = _activePeers.value(senderUUID); + + if (!matchingPeer) { + // if we don't have this sender we need to create them now + matchingPeer = SharedNetworkPeer(new NetworkPeer(senderUUID, publicSocket, localSocket)); + + 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); + } + + // check if this node also included a UUID that they would like to connect to + QUuid connectRequestUUID; + hearbeatStream >> connectRequestUUID; + } + } } diff --git a/ice-server/src/IceServer.h b/ice-server/src/IceServer.h index 7d56737ca1..3db9a6b2e2 100644 --- a/ice-server/src/IceServer.h +++ b/ice-server/src/IceServer.h @@ -12,11 +12,20 @@ #ifndef hifi_IceServer_h #define hifi_IceServer_h -#include +#include +#include +#include + +#include class IceServer : public QCoreApplication { public: IceServer(int argc, char* argv[]); +private slots: + void processDatagrams(); +private: + QHash _activePeers; + QUdpSocket _serverSocket; }; #endif // hifi_IceServer_h \ No newline at end of file diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 9c0ae55d7e..b13f598a08 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -25,6 +25,7 @@ DomainHandler::DomainHandler(QObject* parent) : _uuid(), _sockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)), _assignmentUUID(), + _requiresICE(true), _isConnected(false), _handshakeTimer(NULL), _settingsObject(), @@ -35,6 +36,7 @@ DomainHandler::DomainHandler(QObject* parent) : void DomainHandler::clearConnectionInfo() { _uuid = QUuid(); + _requiresICE = true; _isConnected = false; emit disconnectedFromDomain(); diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index bfdb5d7f38..9733a8bff3 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -54,6 +54,8 @@ public: const QUuid& getAssignmentUUID() const { return _assignmentUUID; } void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; } + bool requiresICE() const { return _requiresICE; } + bool isConnected() const { return _isConnected; } void setIsConnected(bool isConnected); @@ -85,6 +87,7 @@ private: QString _hostname; HifiSockAddr _sockAddr; QUuid _assignmentUUID; + bool _requiresICE; bool _isConnected; QTimer* _handshakeTimer; QJsonObject _settingsObject; diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index bb26b2a119..57a4a97331 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -63,4 +63,11 @@ void NetworkPeer::activatePublicSocket() { void NetworkPeer::activateSymmetricSocket() { qDebug() << "Activating symmetric socket for network peer with ID" << uuidStringWithoutCurlyBraces(_uuid); _activeSocket = &_symmetricSocket; +} + +QDebug operator<<(QDebug debug, const NetworkPeer &peer) { + debug << uuidStringWithoutCurlyBraces(peer.getUUID()) + << "- public:" << peer.getPublicSocket() + << "- local:" << peer.getLocalSocket(); + return debug; } \ No newline at end of file diff --git a/libraries/networking/src/NetworkPeer.h b/libraries/networking/src/NetworkPeer.h index b4e472b80c..ae1812cf87 100644 --- a/libraries/networking/src/NetworkPeer.h +++ b/libraries/networking/src/NetworkPeer.h @@ -17,10 +17,16 @@ #include "HifiSockAddr.h" +const QString ICE_SERVER_HOSTNAME = "localhost"; +const int ICE_SERVER_DEFAULT_PORT = 7337; + class NetworkPeer : public QObject { public: NetworkPeer(const QUuid& uuid, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket); + const QUuid& getUUID() const { return _uuid; } + void setUUID(const QUuid& uuid) { _uuid = uuid; } + const HifiSockAddr& getPublicSocket() const { return _publicSocket; } void setPublicSocket(const HifiSockAddr& publicSocket); const HifiSockAddr& getLocalSocket() const { return _localSocket; } @@ -43,4 +49,7 @@ protected: HifiSockAddr* _activeSocket; }; +QDebug operator<<(QDebug debug, const NetworkPeer &peer); +typedef QSharedPointer SharedNetworkPeer; + #endif // hifi_NetworkPeer_h \ No newline at end of file diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 8f276f4e1d..f300499add 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -57,9 +57,6 @@ public: char getType() const { return _type; } void setType(char type) { _type = type; } - const QUuid& getUUID() const { return _uuid; } - void setUUID(const QUuid& uuid) { _uuid = uuid; } - quint64 getWakeTimestamp() const { return _wakeTimestamp; } void setWakeTimestamp(quint64 wakeTimestamp) { _wakeTimestamp = wakeTimestamp; } diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 3a1ed79f77..451b30c58b 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -243,61 +243,78 @@ void NodeList::sendDomainServerCheckIn() { // send a STUN request to figure it out sendSTUNRequest(); } else if (!_domainHandler.getIP().isNull()) { - - bool isUsingDTLS = false; - PacketType domainPacketType = !_domainHandler.isConnected() + if (!_domainHandler.isConnected() && _domainHandler.requiresICE()) { + sendICERequestForDomainConnection(); + } else { + bool isUsingDTLS = false; + + PacketType domainPacketType = !_domainHandler.isConnected() ? PacketTypeDomainConnectRequest : PacketTypeDomainListRequest; - - if (!_domainHandler.isConnected()) { - qDebug() << "Sending connect request to domain-server at" << _domainHandler.getHostname(); + + if (!_domainHandler.isConnected()) { + qDebug() << "Sending connect request to domain-server at" << _domainHandler.getHostname(); + } + + // construct the DS check in packet + QUuid packetUUID = _sessionUUID; + + if (!_domainHandler.getAssignmentUUID().isNull() && domainPacketType == PacketTypeDomainConnectRequest) { + // this is a connect request and we're an assigned node + // so set our packetUUID as the assignment UUID + packetUUID = _domainHandler.getAssignmentUUID(); + } + + QByteArray domainServerPacket = byteArrayWithPopulatedHeader(domainPacketType, packetUUID); + QDataStream packetStream(&domainServerPacket, QIODevice::Append); + + // pack our data to send to the domain-server + packetStream << _ownerType << _publicSockAddr + << HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort()) + << (quint8) _nodeTypesOfInterest.size(); + + // copy over the bytes for node types of interest, if required + foreach (NodeType_t nodeTypeOfInterest, _nodeTypesOfInterest) { + packetStream << nodeTypeOfInterest; + } + + if (!isUsingDTLS) { + writeDatagram(domainServerPacket, _domainHandler.getSockAddr(), QUuid()); + } + + const int NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST = 5; + static unsigned int numDomainCheckins = 0; + + // send a STUN request every Nth domain server check in so we update our public socket, if required + if (numDomainCheckins++ % NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST == 0) { + sendSTUNRequest(); + } + + if (_numNoReplyDomainCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { + // we haven't heard back from DS in MAX_SILENT_DOMAIN_SERVER_CHECK_INS + // so emit our signal that indicates that + emit limitOfSilentDomainCheckInsReached(); + } + + // increment the count of un-replied check-ins + _numNoReplyDomainCheckIns++; } - - // construct the DS check in packet - QUuid packetUUID = _sessionUUID; - - if (!_domainHandler.getAssignmentUUID().isNull() && domainPacketType == PacketTypeDomainConnectRequest) { - // this is a connect request and we're an assigned node - // so set our packetUUID as the assignment UUID - packetUUID = _domainHandler.getAssignmentUUID(); - } - - QByteArray domainServerPacket = byteArrayWithPopulatedHeader(domainPacketType, packetUUID); - QDataStream packetStream(&domainServerPacket, QIODevice::Append); - - // pack our data to send to the domain-server - packetStream << _ownerType << _publicSockAddr - << HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort()) - << (quint8) _nodeTypesOfInterest.size(); - - // copy over the bytes for node types of interest, if required - foreach (NodeType_t nodeTypeOfInterest, _nodeTypesOfInterest) { - packetStream << nodeTypeOfInterest; - } - - if (!isUsingDTLS) { - writeDatagram(domainServerPacket, _domainHandler.getSockAddr(), QUuid()); - } - - const int NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST = 5; - static unsigned int numDomainCheckins = 0; - - // send a STUN request every Nth domain server check in so we update our public socket, if required - if (numDomainCheckins++ % NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST == 0) { - sendSTUNRequest(); - } - - if (_numNoReplyDomainCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { - // we haven't heard back from DS in MAX_SILENT_DOMAIN_SERVER_CHECK_INS - // so emit our signal that indicates that - emit limitOfSilentDomainCheckInsReached(); - } - - // increment the count of un-replied check-ins - _numNoReplyDomainCheckIns++; } } +void NodeList::sendICERequestForDomainConnection() { + QByteArray iceRequestByteArray = byteArrayWithPopulatedHeader(PacketTypeIceServerHeartbeat); + QDataStream iceDataStream(&iceRequestByteArray, QIODevice::Append); + + iceDataStream << _publicSockAddr << HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort()); + iceDataStream << _domainHandler.getUUID(); + + qDebug() << "Sending packet to ICE server to request connection info for peer with ID" + << uuidStringWithoutCurlyBraces(_domainHandler.getUUID()); + + _nodeSocket.writeDatagram(iceRequestByteArray, QHostAddress::LocalHost, ICE_SERVER_DEFAULT_PORT); +} + int NodeList::processDomainServerList(const QByteArray& packet) { // this is a packet from the domain server, reset the count of un-replied check-ins _numNoReplyDomainCheckIns = 0; diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 8293d0a05a..ad0f74e517 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -91,6 +91,8 @@ private: void sendSTUNRequest(); bool processSTUNResponse(const QByteArray& packet); + void sendICERequestForDomainConnection(); + void processDomainServerAuthRequest(const QByteArray& packet); void requestAuthForDomainServer(); void activateSocketFromNodeCommunication(const QByteArray& packet, const SharedNodePointer& sendingNode); diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 207cf680d3..aaab9c2928 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -70,7 +70,8 @@ enum PacketType { PacketTypeVoxelEditNack, PacketTypeParticleEditNack, PacketTypeEntityEditNack, // 48 - PacketTypeSignedTransactionPayment + PacketTypeSignedTransactionPayment, + PacketTypeIceServerHeartbeat }; typedef char PacketVersion;