complete check in and heartbeat via DTLS

This commit is contained in:
Stephen Birarda 2014-04-04 09:56:57 -07:00
parent 7b6ce77690
commit efd176f93c
8 changed files with 76 additions and 19 deletions

View file

@ -483,6 +483,9 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
if (nodeInterestList.size() > 0) {
DTLSServerSession* dtlsSession = _isUsingDTLS ? _dtlsSessions[senderSockAddr] : NULL;
// if the node has any interest types, send back those nodes as well
foreach (const SharedNodePointer& otherNode, nodeList->getNodeHash()) {
@ -516,7 +519,11 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
// we need to break here and start a new packet
// so send the current one
nodeList->writeDatagram(broadcastPacket, node, senderSockAddr);
if (!dtlsSession) {
nodeList->writeDatagram(broadcastPacket, node, senderSockAddr);
} else {
dtlsSession->writeDatagram(broadcastPacket);
}
// reset the broadcastPacket structure
broadcastPacket.resize(numBroadcastPacketLeadBytes);
@ -527,10 +534,14 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
broadcastPacket.append(nodeByteArray);
}
}
// always write the last broadcastPacket
if (!dtlsSession) {
nodeList->writeDatagram(broadcastPacket, node, senderSockAddr);
} else {
dtlsSession->writeDatagram(broadcastPacket);
}
}
// always write the last broadcastPacket
nodeList->writeDatagram(broadcastPacket, node, senderSockAddr);
}
void DomainServer::readAvailableDatagrams() {
@ -640,12 +651,12 @@ void DomainServer::readAvailableDTLSDatagrams() {
}
} else {
// pull the data from this user off the stack and process it
int receiveCode = gnutls_record_recv(*existingSession->getGnuTLSSession(),
peekDatagram.data(), peekDatagram.size());
if (receiveCode > 0) {
processDatagram(peekDatagram, senderHifiSockAddr);
} else if (gnutls_error_is_fatal(receiveCode)) {
qDebug() << "Fatal error -" << gnutls_strerror(receiveCode) << "- during DTLS handshake with"
int receivedBytes = gnutls_record_recv(*existingSession->getGnuTLSSession(),
peekDatagram.data(), peekDatagram.size());
if (receivedBytes > 0) {
processDatagram(peekDatagram.left(receivedBytes), senderHifiSockAddr);
} else if (gnutls_error_is_fatal(receivedBytes)) {
qDebug() << "Fatal error -" << gnutls_strerror(receivedBytes) << "- during DTLS handshake with"
<< senderHifiSockAddr;
}
}

View file

@ -11,6 +11,8 @@
#include "NodeList.h"
#include "DTLSSession.h"
#define DTLS_VERBOSE_DEBUG 0
int DTLSSession::socketPullTimeout(gnutls_transport_ptr_t ptr, unsigned int ms) {
DTLSSession* session = static_cast<DTLSSession*>(ptr);
QUdpSocket& dtlsSocket = session->_dtlsSocket;
@ -47,14 +49,19 @@ ssize_t DTLSSession::socketPull(gnutls_transport_ptr_t ptr, void* buffer, size_t
pulledSockAddr.getAddressPointer(), pulledSockAddr.getPortPointer());
if (bytesReceived == -1) {
// no data to pull, return -1
#if DTLS_VERBOSE_DEBUG
qDebug() << "Received no data on call to readDatagram";
#endif
return bytesReceived;
}
if (pulledSockAddr == session->_destinationSocket) {
// bytes received from the correct sender, return number of bytes received
#if DTLS_VERBOSE_DEBUG
qDebug() << "Received" << bytesReceived << "on DTLS socket from" << pulledSockAddr;
qDebug() << QByteArray(reinterpret_cast<char*>(buffer), bytesReceived).toHex();
#endif
return bytesReceived;
}
@ -69,8 +76,10 @@ ssize_t DTLSSession::socketPush(gnutls_transport_ptr_t ptr, const void* buffer,
DTLSSession* session = static_cast<DTLSSession*>(ptr);
QUdpSocket& dtlsSocket = session->_dtlsSocket;
#if DTLS_VERBOSE_DEBUG
qDebug() << "Pushing a message of size" << size << "to" << session->_destinationSocket;
qDebug() << QByteArray(reinterpret_cast<const char*>(buffer), size).toHex();
#endif
return dtlsSocket.writeDatagram(reinterpret_cast<const char*>(buffer), size,
session->_destinationSocket.getAddress(), session->_destinationSocket.getPort());
}
@ -93,4 +102,9 @@ DTLSSession::DTLSSession(int end, QUdpSocket& dtlsSocket, HifiSockAddr& destinat
gnutls_transport_set_push_function(_gnutlsSession, socketPush);
gnutls_transport_set_pull_function(_gnutlsSession, socketPull);
gnutls_transport_set_pull_timeout_function(_gnutlsSession, socketPullTimeout);
}
qint64 DTLSSession::writeDatagram(const QByteArray& datagram) {
// we don't need to put a hash in this packet, so just send it off
return gnutls_record_send(_gnutlsSession, datagram.data(), datagram.size());
}

View file

@ -24,6 +24,8 @@ public:
static ssize_t socketPull(gnutls_transport_ptr_t ptr, void* buffer, size_t size);
static ssize_t socketPush(gnutls_transport_ptr_t ptr, const void* buffer, size_t size);
qint64 writeDatagram(const QByteArray& datagram);
gnutls_session_t* getGnuTLSSession() { return &_gnutlsSession; }
bool completedHandshake() const { return _completedHandshake; }

View file

@ -115,8 +115,6 @@ void DomainHandler::setHostname(const QString& hostname) {
void DomainHandler::completeDTLSHandshake() {
int handshakeReturn = gnutls_handshake(*_dtlsSession->getGnuTLSSession());
qDebug() << "handshake return is" << handshakeReturn;
if (handshakeReturn == 0) {
// we've shaken hands, so we're good to go now
_dtlsSession->setCompletedHandshake(true);
@ -125,6 +123,9 @@ void DomainHandler::completeDTLSHandshake() {
delete _handshakeTimer;
_handshakeTimer = NULL;
// emit a signal so NodeList can handle incoming DTLS packets
emit completedDTLSHandshake();
} else if (gnutls_error_is_fatal(handshakeReturn)) {
// this was a fatal error handshaking, so remove this session
qDebug() << "Fatal error -" << gnutls_strerror(handshakeReturn)

View file

@ -60,7 +60,8 @@ private slots:
signals:
void hostnameChanged(const QString& hostname);
void connectedToDomain(const QString& hostname);
void initializedDTLSSession();
void completedDTLSHandshake();
private:
void reset();
void initializeDTLSSession();

View file

@ -173,7 +173,7 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) {
}
qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr,
const QUuid& connectionSecret) {
const QUuid& connectionSecret) {
QByteArray datagramCopy = datagram;
if (!connectionSecret.isNull()) {

View file

@ -65,6 +65,9 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned
// clear our NodeList when logout is requested
connect(&AccountManager::getInstance(), &AccountManager::logoutComplete , this, &NodeList::reset);
// perform a function when DTLS handshake is completed
connect(&_domainHandler, &DomainHandler::completedDTLSHandshake, this, &NodeList::completedDTLSHandshake);
}
qint64 NodeList::sendStatsToDomainServer(const QJsonObject& statsObject) {
@ -111,6 +114,28 @@ void NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer&
}
}
void NodeList::completedDTLSHandshake() {
// at this point, we've got a DTLS socket
// make this NodeList the handler of DTLS packets
connect(_dtlsSocket, &QUdpSocket::readyRead, this, &NodeList::processAvailableDTLSDatagrams);
}
void NodeList::processAvailableDTLSDatagrams() {
while (_dtlsSocket->hasPendingDatagrams()) {
QByteArray dtlsPacket(_dtlsSocket->pendingDatagramSize(), 0);
// pull the data from this user off the stack and process it
int receivedBytes = gnutls_record_recv(*_domainHandler.getDTLSSession()->getGnuTLSSession(),
dtlsPacket.data(), dtlsPacket.size());
if (receivedBytes > 0) {
// successful data receive, hand this off to processNodeData
processNodeData(_domainHandler.getSockAddr(), dtlsPacket.left(receivedBytes));
} else if (gnutls_error_is_fatal(receivedBytes)) {
qDebug() << "Fatal error -" << gnutls_strerror(receivedBytes) << "- receiving DTLS packet from domain-server.";
}
}
}
void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet) {
switch (packetTypeForPacket(packet)) {
case PacketTypeDomainList: {
@ -342,8 +367,8 @@ void NodeList::sendDomainServerCheckIn() {
// pack our data to send to the domain-server
packetStream << _ownerType << _publicSockAddr
<< HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort())
<< (quint8) _nodeTypesOfInterest.size();
<< HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort())
<< (quint8) _nodeTypesOfInterest.size();
// copy over the bytes for node types of interest, if required
foreach (NodeType_t nodeTypeOfInterest, _nodeTypesOfInterest) {
@ -353,7 +378,7 @@ void NodeList::sendDomainServerCheckIn() {
if (!isUsingDTLS) {
writeDatagram(domainServerPacket, _domainHandler.getSockAddr(), QUuid());
} else {
gnutls_record_send(*dtlsSession->getGnuTLSSession(), domainServerPacket.data(), domainServerPacket.size());
dtlsSession->writeDatagram(domainServerPacket);
}

View file

@ -67,6 +67,7 @@ public:
void resetNodeInterestSet() { _nodeTypesOfInterest.clear(); }
void processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet);
int processDomainServerList(const QByteArray& packet);
void setAssignmentServerSocket(const HifiSockAddr& serverSocket) { _assignmentServerSocket = serverSocket; }
@ -82,6 +83,8 @@ public slots:
void reset();
void sendDomainServerCheckIn();
void pingInactiveNodes();
void completedDTLSHandshake();
void processAvailableDTLSDatagrams();
signals:
void limitOfSilentDomainCheckInsReached();
private: