void NodeList::pingPunchForDomainServer() { // make sure if we're here that we actually still need to ping the domain-server if (_domainHandler.getIP().isNull() && _domainHandler.getICEPeer().hasSockets()) { // check if we've hit the number of pings we'll send to the DS before we consider it a fail const int NUM_DOMAIN_SERVER_PINGS_BEFORE_RESET = 2000 / UDP_PUNCH_PING_INTERVAL_MS; if (_domainHandler.getICEPeer().getConnectionAttempts() == 0) { qCDebug(networking) << "Sending ping packets to establish connectivity with domain-server with ID" << uuidStringWithoutCurlyBraces(_domainHandler.getICEDomainID()); } else { if (_domainHandler.getICEPeer().getConnectionAttempts() % NUM_DOMAIN_SERVER_PINGS_BEFORE_RESET == 0) { // if we have then nullify the domain handler's network peer and send a fresh ICE heartbeat qCDebug(networking) << "No ping replies received from domain-server with ID" << uuidStringWithoutCurlyBraces(_domainHandler.getICEClientID()) << "-" << "re-sending ICE query."; _domainHandler.getICEPeer().softReset(); handleICEConnectionToDomainServer(); return; } } flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::SendPingsToDS); // send the ping packet to the local and public sockets for this node auto localPingPacket = constructICEPingPacket(PingType::Local, _sessionUUID); sendPacket(std::move(localPingPacket), _domainHandler.getICEPeer().getLocalSocket()); auto publicPingPacket = constructICEPingPacket(PingType::Public, _sessionUUID); sendPacket(std::move(publicPingPacket), _domainHandler.getICEPeer().getPublicSocket()); _domainHandler.getICEPeer().incrementConnectionAttempts(); } }
void NodeList::sendDomainServerCheckIn() { if (_publicSockAddr.isNull() && !_hasCompletedInitialSTUNFailure) { // 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(); } else if (_domainHandler.getIP().isNull() && _domainHandler.requiresICE()) { handleICEConnectionToDomainServer(); } else if (!_domainHandler.getIP().isNull()) { bool isUsingDTLS = false; PacketType domainPacketType = !_domainHandler.isConnected() ? PacketTypeDomainConnectRequest : PacketTypeDomainListRequest; if (!_domainHandler.isConnected()) { qDebug() << "Sending connect request to domain-server at" << _domainHandler.getHostname(); } // construct the DS check in packet QUuid packetUUID = _sessionUUID; if (domainPacketType == PacketTypeDomainConnectRequest) { if (!_domainHandler.getAssignmentUUID().isNull()) { // this is a connect request and we're an assigned node // so set our packetUUID as the assignment UUID packetUUID = _domainHandler.getAssignmentUUID(); } else if (_domainHandler.requiresICE()) { // this is a connect request and we're an interface client // that used ice to discover the DS // so send our ICE client UUID with the connect request packetUUID = _domainHandler.getICEClientID(); } } QByteArray domainServerPacket = byteArrayWithPopulatedHeader(domainPacketType, packetUUID); QDataStream packetStream(&domainServerPacket, QIODevice::Append); // pack our data to send to the domain-server packetStream << _ownerType << _publicSockAddr << _localSockAddr << _nodeTypesOfInterest.toList(); // if this is a connect request, and we can present a username signature, send it along if (!_domainHandler.isConnected()) { DataServerAccountInfo& accountInfo = AccountManager::getInstance().getAccountInfo(); packetStream << accountInfo.getUsername(); const QByteArray& usernameSignature = AccountManager::getInstance().getAccountInfo().getUsernameSignature(); if (!usernameSignature.isEmpty()) { qDebug() << "Including username signature in domain connect request."; packetStream << usernameSignature; } } 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 says that emit limitOfSilentDomainCheckInsReached(); } // increment the count of un-replied check-ins _numNoReplyDomainCheckIns++; } }
void NodeList::sendDomainServerCheckIn() { if (_isShuttingDown) { qCDebug(networking) << "Refusing to send a domain-server check in while shutting down."; return; } if (_publicSockAddr.isNull()) { // we don't know our public socket and we need to send it to the domain server qCDebug(networking) << "Waiting for inital public socket from STUN. Will not send domain-server check in."; } else if (_domainHandler.getIP().isNull() && _domainHandler.requiresICE()) { qCDebug(networking) << "Waiting for ICE discovered domain-server socket. Will not send domain-server check in."; handleICEConnectionToDomainServer(); } else if (!_domainHandler.getIP().isNull()) { bool isUsingDTLS = false; PacketType domainPacketType = !_domainHandler.isConnected() ? PacketType::DomainConnectRequest : PacketType::DomainListRequest; if (!_domainHandler.isConnected()) { qCDebug(networking) << "Sending connect request to domain-server at" << _domainHandler.getHostname(); // is this our localhost domain-server? // if so we need to make sure we have an up-to-date local port in case it restarted if (_domainHandler.getSockAddr().getAddress() == QHostAddress::LocalHost || _domainHandler.getHostname() == "localhost") { quint16 domainPort = DEFAULT_DOMAIN_SERVER_PORT; getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, domainPort); qCDebug(networking) << "Local domain-server port read from shared memory (or default) is" << domainPort; _domainHandler.setPort(domainPort); } } // check if we're missing a keypair we need to verify ourselves with the domain-server auto& accountManager = AccountManager::getInstance(); const QUuid& connectionToken = _domainHandler.getConnectionToken(); // we assume that we're on the same box as the DS if it has the same local address and // it didn't present us with a connection token to use for username signature bool localhostDomain = _domainHandler.getSockAddr().getAddress() == QHostAddress::LocalHost || (_domainHandler.getSockAddr().getAddress() == _localSockAddr.getAddress() && connectionToken.isNull()); bool requiresUsernameSignature = !_domainHandler.isConnected() && !connectionToken.isNull() && !localhostDomain; if (requiresUsernameSignature && !accountManager.getAccountInfo().hasPrivateKey()) { qWarning() << "A keypair is required to present a username signature to the domain-server" << "but no keypair is present. Waiting for keypair generation to complete."; accountManager.generateNewUserKeypair(); // don't send the check in packet - wait for the keypair first return; } auto domainPacket = NLPacket::create(domainPacketType); QDataStream packetStream(domainPacket.get()); if (domainPacketType == PacketType::DomainConnectRequest) { QUuid connectUUID; if (!_domainHandler.getAssignmentUUID().isNull()) { // this is a connect request and we're an assigned node // so set our packetUUID as the assignment UUID connectUUID = _domainHandler.getAssignmentUUID(); } else if (_domainHandler.requiresICE()) { // this is a connect request and we're an interface client // that used ice to discover the DS // so send our ICE client UUID with the connect request connectUUID = _domainHandler.getICEClientID(); } // pack the connect UUID for this connect request packetStream << connectUUID; } // pack our data to send to the domain-server packetStream << _ownerType << _publicSockAddr << _localSockAddr << _nodeTypesOfInterest.toList(); if (!_domainHandler.isConnected()) { DataServerAccountInfo& accountInfo = accountManager.getAccountInfo(); packetStream << accountInfo.getUsername(); // if this is a connect request, and we can present a username signature, send it along if (requiresUsernameSignature && accountManager.getAccountInfo().hasPrivateKey()) { const QByteArray& usernameSignature = accountManager.getAccountInfo().getUsernameSignature(connectionToken); packetStream << usernameSignature; } } flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::SendDSCheckIn); if (!isUsingDTLS) { sendPacket(std::move(domainPacket), _domainHandler.getSockAddr()); } 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 says that emit limitOfSilentDomainCheckInsReached(); } // increment the count of un-replied check-ins _numNoReplyDomainCheckIns++; } }