void CDatagrams::onPing(CEndPoint& addr, G2Packet* pPacket)
{
	Q_UNUSED(pPacket);

	G2Packet* pNew = G2Packet::newPacket("PO", false);
	sendPacket(addr, pNew, false);
	pNew->release();
}
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
}
void CDatagrams::onCRAWLR(CEndPoint& addr, G2Packet* pPacket)
{
	QMutexLocker l2(&Neighbours.m_pSection);

//	bool bRLeaf = false;
//	bool bRNick = false;
//	bool bRGPS = false;
//	bool bRExt = false;

	if(!pPacket->m_bCompound)
	{
		return;
	}

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

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

		if(strcmp("RLEAF", szType) == 0)
		{
//			bRLeaf = true;
		}
		else if(strcmp("RNAME", szType) == 0)
		{
//			bRNick = true;
		}
		else if(strcmp("RGPS", szType) == 0)
		{
//			bRGPS = true;
		}
		else if(strcmp("REXT", szType) == 0)
		{
//			bRExt = true;
		}

		pPacket->m_nPosition = nNext;
	}

	G2Packet* pCA = G2Packet::newPacket("CRAWLA", true);

	G2Packet* pTmp = G2Packet::newPacket("SELF", true);
	if(Neighbours.isG2Hub())
	{
		pTmp->writePacket("HUB", 0);
	}
	else
	{
		pTmp->writePacket("LEAF", 0);
	}
	pTmp->writePacket("NA", ((Network.m_oAddress.protocol() == 0) ? 6 : 18))->writeHostAddress(&Network.m_oAddress);
	pTmp->writePacket("CV", CQuazaaGlobals::USER_AGENT_STRING().toUtf8().size())->writeString(CQuazaaGlobals::USER_AGENT_STRING(), false);
	pTmp->writePacket("V", 4)->writeString(CQuazaaGlobals::VENDOR_CODE(), false);;
	quint16 nLeaves = Neighbours.m_nLeavesConnectedG2;
	pTmp->writePacket("HS", 2)->writeIntLE(nLeaves);
	if(!quazaaSettings.Profile.GnutellaScreenName.isEmpty())
	{
		pTmp->writePacket("NAME", quazaaSettings.Profile.GnutellaScreenName.left(255).toUtf8().size())->writeString(quazaaSettings.Profile.GnutellaScreenName.left(255));
	}

	pCA->writePacket(pTmp);
	pTmp->release();

	for(QList<CNeighbour*>::iterator itNode = Neighbours.begin(); itNode != Neighbours.end(); ++itNode)
	{
		if((*itNode)->m_nProtocol != dpG2)
		{
			continue;
		}

		CG2Node* pNode = (CG2Node*) * itNode;
		if(pNode->m_nState == nsConnected)
		{
			if(pNode->m_nType == G2_HUB)
			{
				G2Packet* pNH = G2Packet::newPacket("NH");
				pNH->writePacket("NA", ((pNode->m_oAddress.protocol() == 0) ? 6 : 18))->writeHostAddress(&pNode->m_oAddress);
				pNH->writePacket("HS", 2)->writeIntLE(pNode->m_nLeafCount);
				pCA->writePacket(pNH);
				pNH->release();
			}
			else if(pNode->m_nType == G2_LEAF)
			{
				G2Packet* pNL = G2Packet::newPacket("NL");
				pNL->writePacket("NA", ((pNode->m_oAddress.protocol() == 0) ? 6 : 18))->writeHostAddress(&pNode->m_oAddress);
				pCA->writePacket(pNL);
				pNL->release();
			}
		}
	}

	sendPacket(addr, pCA, true);

	pCA->release();
}
void CDatagrams::onReceiveGND()
{
	GND_HEADER* pHeader = (GND_HEADER*)m_pRecvBuffer->data();
	QHostAddress nIp = *m_pHostAddress;
	quint32 nSeq = ((pHeader->nSequence << 16) & 0xFFFF0000) + (m_nPort & 0x0000FFFF);

#ifdef DEBUG_UDP
	systemLog.postLog(LogSeverity::Debug, "Received GND from %s:%u nSequence = %u nPart = %u nCount = %u", m_pHostAddress->toString().toLocal8Bit().constData(), m_nPort, pHeader->nSequence, pHeader->nPart, pHeader->nCount);
#endif

	DatagramIn* pDatagramIn = 0;

	if(m_RecvCache.contains(nIp) && m_RecvCache[nIp].contains(nSeq))
	{
		pDatagramIn = m_RecvCache[nIp][nSeq];

		// To give a chance for bigger packages ;)
		if(pDatagramIn->m_nLeft)
		{
			pDatagramIn->m_tStarted = time(0);
		}
	}
	else
	{
		QMutexLocker l(&m_pSection);

		if(!m_FreeDatagramIn.isEmpty())
		{
			pDatagramIn = m_FreeDatagramIn.takeFirst();
		}
		else
		{
			if(m_FreeDatagramIn.isEmpty())
			{
				removeOldIn(true);
				if(m_FreeDatagramIn.isEmpty())
				{
#ifdef DEBUG_UDP
					systemLog.postLog(LogSeverity::Debug, QString("UDP in frames exhausted"));
#endif
					m_nDiscarded++;
					return;
				}
			}

			pDatagramIn = m_FreeDatagramIn.takeFirst();
		}

		if(m_FreeBuffer.size() < pHeader->nCount)
		{
			m_nDiscarded++;
			m_FreeDatagramIn.append(pDatagramIn);
			removeOldIn(false);
			return;
		}

		pDatagramIn->create(CEndPoint(*m_pHostAddress, m_nPort), pHeader->nFlags, pHeader->nSequence, pHeader->nCount);

		for(int i = 0; i < pHeader->nCount; i++)
		{
			Q_ASSERT(pDatagramIn->m_pBuffer[i] == 0);
			pDatagramIn->m_pBuffer[i] = m_FreeBuffer.takeFirst();
		}

		m_RecvCache[nIp][nSeq] = pDatagramIn;
		m_RecvCacheTime.prepend(pDatagramIn);
	}

	// It is here, in case if we did not have free datagrams
	// ACK = I've received a datagram, and if you have received and rejected it, do not send ACK-a
	if(pHeader->nFlags & 0x02)
	{
		GND_HEADER* pAck = new GND_HEADER;

		memcpy(pAck, pHeader, sizeof(GND_HEADER));
		pAck->nCount = 0;
		pAck->nFlags = 0;

#ifdef DEBUG_UDP
		systemLog.postLog(LogSeverity::Debug, "Sending UDP ACK to %s:%u", m_pHostAddress->toString().toLocal8Bit().constData(), m_nPort);
#endif

		//m_pSocket->writeDatagram((char*)&oAck, sizeof(GND_HEADER), *m_pHostAddress, m_nPort);
		//m_mOutput.Add(sizeof(GND_HEADER));
		m_AckCache.append(qMakePair(CEndPoint(*m_pHostAddress, m_nPort), reinterpret_cast<char*>(pAck)));
		if( m_AckCache.count() == 1 )
			QMetaObject::invokeMethod(this, "flushSendCache", Qt::QueuedConnection);
	}

	if(pDatagramIn->add(pHeader->nPart, m_pRecvBuffer->data() + sizeof(GND_HEADER), m_pRecvBuffer->size() - sizeof(GND_HEADER)))
	{

		G2Packet* pPacket = 0;
		try
		{
			CEndPoint addr(*m_pHostAddress, m_nPort);
			pPacket = pDatagramIn->toG2Packet();
			if(pPacket)
			{
				onPacket(addr, pPacket);
			}
		}
		catch(...)
		{

		}
		if(pPacket)
		{
			pPacket->release();
		}

		m_pSection.lock();
		remove(pDatagramIn, true);
		m_pSection.unlock();
	}
}
void CDatagrams::onQuery(CEndPoint &addr, G2Packet *pPacket)
{
	CQueryPtr pQuery = CQuery::fromPacket(pPacket, &addr);

	if(pQuery.isNull())
	{
#if LOG_QUERY_HANDLING
		qDebug() << "Received malformed query from" << qPrintable(addr.toStringWithPort());
#endif // LOG_QUERY_HANDLING
		return;
	}

	if( !Neighbours.isG2Hub() )
	{
		// Stop receiving queries from others
		// We are here because we just downgraded to leaf mode
		// Shareaza should not retry with QK == 0
		// TODO: test this
#if LOG_QUERY_HANDLING
		systemLog.postLog(LogSeverity::Debug, "Sending null query key to %s because we're not a hub.", qPrintable(addr.toStringWithPort()));
#endif // LOG_QUERY_HANDLING

		G2Packet* pQKA = G2Packet::newPacket("QKA", true);
		pQKA->writePacket("QK", 4)->writeIntLE<quint32>(0);

		if( addr != pQuery->m_oEndpoint )
		{
			pQKA->writePacket("SNA", (pQuery->m_oEndpoint.protocol() == QAbstractSocket::IPv6Protocol ? 18 : 6))->writeHostAddress(&pQuery->m_oEndpoint);
		}

		sendPacket(pQuery->m_oEndpoint, pQKA);
		pQKA->release();

		return;
	}

	if(!QueryKeys.check(pQuery->m_oEndpoint, pQuery->m_nQueryKey))
	{
#if LOG_QUERY_HANDLING
		systemLog.postLog(LogSeverity::Debug, "Issuing query key correction for %s.", qPrintable(addr.toStringWithPort()));
#endif // LOG_QUERY_HANDLING

		G2Packet* pQKA = G2Packet::newPacket("QKA", true);
		pQKA->writePacket("QK", 4)->writeIntLE<quint32>(QueryKeys.create(pQuery->m_oEndpoint));

		if( addr != pQuery->m_oEndpoint )
		{
			pQKA->writePacket("SNA", (pQuery->m_oEndpoint.protocol() == QAbstractSocket::IPv6Protocol ? 18 : 6))->writeHostAddress(&pQuery->m_oEndpoint);
		}
		sendPacket(addr, pPacket);
		pQKA->release();

		return;
	}

	if( !Network.m_oRoutingTable.add(pQuery->m_oGUID, pQuery->m_oEndpoint) )
	{
#if LOG_QUERY_HANDLING
		qDebug() << "Query already processed, ignoring";
#endif // LOG_QUERY_HANDLING
		G2Packet* pQA = Neighbours.createQueryAck(pQuery->m_oGUID, false, 0, false);
		sendPacket(pQuery->m_oEndpoint, pQA, true);
		pQA->release();
		return;
	}

#if LOG_QUERY_HANDLING
	qDebug() << "Processing query from: " << qPrintable(addr.toStringWithPort());
#endif // LOG_QUERY_HANDLING

	// just in case
	if( pQuery->m_oEndpoint == Network.m_oAddress )
	{
		systemLog.postLog( LogSeverity::Error, Components::Network,
						   "Q2 received via UDP and return address points to us, changing return address to source %s",
						   qPrintable( addr.toStringWithPort() ) );
		G2Packet* pUDP = G2Packet::newPacket("UDP");
		pUDP->writeHostAddress(&addr);
		pUDP->writeIntLE<quint32>(0);
		pPacket->addOrReplaceChild("UDP", pUDP);
	}

	Neighbours.m_pSection.lock();
	G2Packet* pQA = Neighbours.createQueryAck(pQuery->m_oGUID);
	sendPacket(pQuery->m_oEndpoint, pQA, true);
	pQA->release();

	Neighbours.routeQuery(pQuery, pPacket);
	Neighbours.m_pSection.unlock();

	// local search
}