void CDatagrams::onQKR(CEndPoint& addr, G2Packet* pPacket)
{
	if(!Neighbours.isG2Hub())
	{
		return;
	}

	CEndPoint oRequestedAddress = addr;
	CEndPoint oSendingAddress = addr;

	if(pPacket->m_bCompound)
	{
		char szType[9];
		quint32 nLength = 0, nNext = 0;

		while(pPacket->readPacket(&szType[0], nLength))
		{
			nNext = pPacket->m_nPosition + nLength;

			if(strcmp("SNA", szType) == 0 && nLength >= 4)
			{
				if(nLength >= 16)
				{
					Q_IPV6ADDR ip;
					pPacket->read(&ip, 16);
					oSendingAddress.setAddress(ip);
				}
				else
				{
					quint32	nIp = pPacket->readIntBE<quint32>();
					oSendingAddress.setAddress(nIp);
				}
			}
			else if(strcmp("RNA", szType) == 0 && nLength >= 6)
			{
				if(nLength >= 18)
				{
					pPacket->readHostAddress(&oRequestedAddress, false);
				}
				else
				{
					pPacket->readHostAddress(&oRequestedAddress);
				}
			}
			pPacket->m_nPosition = nNext;
		}
	}

	if(!oRequestedAddress.port() || oRequestedAddress.isFirewalled())
	{
		return;
	}

	G2Packet* pAns = G2Packet::newPacket("QKA", true);
	quint32 nKey = QueryKeys.create(oRequestedAddress);
	pAns->writePacket("QK", 4);
	pAns->writeIntLE<quint32>(nKey);
	G2Packet* pSNA = G2Packet::newPacket("SNA");
	pSNA->writeHostAddress(&oSendingAddress);
	pAns->writePacket(pSNA);
	pSNA->release();

	sendPacket(oRequestedAddress, pAns, false);
	pAns->release();

#if LOG_QUERY_HANDLING
	systemLog.postLog(LogSeverity::Debug, "Node %s asked for a query key (0x%08x) for node %s", qPrintable(addr.toStringWithPort()), nKey, qPrintable(oRequestedAddress.toStringWithPort()));
#endif // LOG_QUERY_HANDLING
}
bool CSearchManager::OnQueryAcknowledge(G2Packet* pPacket, CEndPoint& addr, QUuid& oGUID)
{
	if(!pPacket->m_bCompound)
	{
		return false;
	}

	pPacket->SkipCompound();			// skip children to get search GUID
	if(pPacket->GetRemaining() < 16)	// must be at least 16 bytes for GUID
	{
		return false;
	}

	oGUID = pPacket->ReadGUID();		// Read search GUID

	QMutexLocker l(&m_pSection);

	if(CManagedSearch* pSearch = Find(oGUID))	// is it our Query Ack?
	{
		// YES, this is ours, let's parse the packet and process it

		CEndPoint oFromIp = addr;
		QList<QHostAddress>  lDone;
		quint32 nRetryAfter = 0;
		qint64 tAdjust = 0;
		quint32 tNow = time(0);

		quint32 nHubs = 0, nLeaves = 0, nSuggestedHubs = 0;

		pPacket->m_nPosition = 0;	// reset position

		char szType[9];
		quint32 nLength = 0, nNext = 0;

		while(pPacket->ReadPacket(&szType[0], nLength))
		{
			nNext = pPacket->m_nPosition + nLength;

			if(strcmp("D", szType) == 0 && nLength >= 4)
			{
				QHostAddress ha;
				if( nLength >= 16 )
				{
					// IPv6
					Q_IPV6ADDR nIP;
					pPacket->Read(&nIP, 16);
					ha.setAddress(nIP);

					if( nLength >= 18 )
					{
						quint16 nPort = pPacket->ReadIntLE<quint16>();
						CEndPoint a(nIP, nPort);
						HostCache.Add(a, tNow);
					}

					if(nLength >= 20)
					{
						nLeaves += pPacket->ReadIntLE<quint16>();
					}
				}
				else
				{
					// IPv4
					quint32 nIP = pPacket->ReadIntBE<quint32>();
					ha.setAddress(nIP);

					if(nLength >= 6)
					{
						quint16 nPort = pPacket->ReadIntLE<quint16>();
						CEndPoint a(nIP, nPort);
						HostCache.Add(a, tNow);
					}

					if(nLength >= 8)
					{
						nLeaves += pPacket->ReadIntLE<quint16>();
					}
				}
				lDone.append(ha);

				nHubs++;
			}
			else if(strcmp("S", szType) == 0 && nLength >= 6)
			{
				CEndPoint a;
				pPacket->ReadHostAddress(&a, !(nLength >= 18));
				quint32 tSeen = (nLength >= (a.protocol() == 0 ? 10 : 22)) ? pPacket->ReadIntLE<quint32>() + tAdjust : tNow;

				HostCache.Add(a, tSeen);
				nSuggestedHubs++;
			}
			else if(strcmp("TS", szType) == 0 && nLength >= 4)
			{
				tAdjust = tNow - pPacket->ReadIntLE<quint32>();
			}
			else if(strcmp("RA", szType) == 0 && nLength >= 2)
			{
				if(nLength >= 4)
				{
					nRetryAfter = pPacket->ReadIntLE<quint32>();
				}
				else if(nLength >= 2)
				{
					nRetryAfter = pPacket->ReadIntLE<quint16>();
				}

				CHostCacheHost* pHost = HostCache.Find(oFromIp);
				if(pHost)
				{
					pHost->m_tRetryAfter = tNow + nRetryAfter;
				}
			}
			else if(strcmp("FR", szType) == 0 && nLength >= 4)
			{
				if( nLength >= 16 )
				{
					Q_IPV6ADDR ip;
					pPacket->Read(&ip, 16);
					oFromIp.setAddress(ip);
				}
				else
				{
					quint32 nFromIp = pPacket->ReadIntBE<quint32>();
					oFromIp.setAddress(nFromIp);
				}
			}

			pPacket->m_nPosition = nNext;
		}

		// we already know QA GUID

		systemLog.postLog(LogSeverity::Debug, "Processing query acknowledge from %s (time adjust %+d seconds): %d hubs, %d leaves, %d suggested hubs, retry after %d seconds.",
			   addr.toString().toAscii().constData(), int(tAdjust), nHubs, nLeaves, nSuggestedHubs, nRetryAfter);
		//qDebug("Processing query acknowledge from %s (time adjust %+d seconds): %d hubs, %d leaves, %d suggested hubs, retry after %d seconds.",
		//	   addr.toString().toAscii().constData(), int(tAdjust), nHubs, nLeaves, nSuggestedHubs, nRetryAfter);

		pSearch->m_nHubs += nHubs;
		pSearch->m_nLeaves += nLeaves;

		pSearch->OnHostAcknowledge(oFromIp, tNow);

		for(int i = 0; i < lDone.size(); i++)
		{
			pSearch->OnHostAcknowledge(lDone[i], tNow);
		}

		emit pSearch->StatsUpdated();

		return false;
	}

	// not our ack - tell caller to route it
	return true;

}