void CDatagrams::sendPacket(CEndPoint& oAddr, G2Packet* pPacket, bool bAck, DatagramWatcher* pWatcher, void* pParam)
{
	if(!m_bActive)
	{
		return;
	}

	QMutexLocker l(&m_pSection);

	Q_UNUSED(pWatcher);
	Q_UNUSED(pParam);

	if(m_FreeDatagramOut.isEmpty())
	{
		systemLog.postLog(LogSeverity::Debug, QString("UDP out frames exhausted"));

		if( !bAck ) // if caller does not want ACK, drop the packet here
			return; // TODO: needs more testing

		remove(m_SendCache.last());

	}

	if(m_FreeBuffer.isEmpty())
	{
		removeOldIn(false);

		if(m_FreeBuffer.isEmpty())
		{
			systemLog.postLog(LogSeverity::Debug, QString("UDP out discarded, out of buffers"));
			return;
		}
	}

	DatagramOut* pDatagramOut = m_FreeDatagramOut.takeFirst();
	pDatagramOut->create(oAddr, pPacket, m_nSequence++, m_FreeBuffer.takeFirst(), (bAck && (m_nInFrags > 0))); // to prevent net spam when unable to receive datagrams

	m_SendCache.prepend(pDatagramOut);
	m_SendCacheMap[pDatagramOut->m_nSequence] = pDatagramOut;

	// TODO: Notify the listener if we have one.

#ifdef DEBUG_UDP
	systemLog.postLog(LogSeverity::Debug, "UDP queued for %s seq %u parts %u", oAddr.toString().toLocal8Bit().constData(), pDatagramOut->m_nSequence, pDatagramOut->m_nCount);
#endif

	//emit SendQueueUpdated();
	__FlushSendCache();
}
void CDatagrams::onQKA(CEndPoint& addr, G2Packet* pPacket)
{
	if ( !pPacket->m_bCompound )
	{
		return;
	}

	quint32 nKey = 0;
	QHostAddress nKeyHost;

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

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

		if(strcmp("QK", szType) == 0 && nLength >= 4)
		{
			nKey = pPacket->readIntLE<quint32>();
		}
		else if(strcmp("SNA", szType) == 0 && nLength >= 4)
		{
			if(nLength >= 16)
			{
				Q_IPV6ADDR ip;
				pPacket->read(&ip, 16);
				nKeyHost.setAddress(ip);
			}
			else
			{
				quint32 nIp = pPacket->readIntBE<quint32>();
				nKeyHost.setAddress(nIp);
			}
		}
		pPacket->m_nPosition = nNext;
	}

	hostCache.m_pSection.lock();
	CHostCacheHost* pCache = hostCache.add( addr, common::getTNowUTC() );
	if ( pCache )
	{
		if( !nKey ) // null QK means a hub does not want to be queried or just downgraded
		{
			hostCache.remove( pCache );
		}
		else
		{
			pCache->setKey( nKey );
		}
	}
	hostCache.m_pSection.unlock();

#if LOG_QUERY_HANDLING
	systemLog.postLog(LogSeverity::Debug, QString("Got a query key for %1 = 0x%2").arg(addr.toString().toLocal8Bit().constData()).arg(nKey));
	//qDebug("Got a query key for %s = 0x%x", addr.toString().toLocal8Bit().constData(), nKey);
#endif // LOG_QUERY_HANDLING

	if(Neighbours.isG2Hub() && !nKeyHost.isNull() && nKeyHost != ((QHostAddress)Network.m_oAddress))
	{
		G2Packet* pQNA = G2Packet::newPacket("QNA");
		pQNA->writeHostAddress(&addr);
		pPacket->prependPacket(pQNA);

		Neighbours.m_pSection.lock();
		CNeighbour* pNode = Neighbours.find(nKeyHost, dpG2);
		if( pNode )
		{
			((CG2Node*)pNode)->sendPacket(pPacket, true, false);
		}
		Neighbours.m_pSection.unlock();
	}
}
Esempio n. 3
0
bool CNetwork::routePacket(QUuid& pTargetGUID, G2Packet* pPacket, bool bLockNeighbours, bool bBuffered)
{
	CG2Node* pNode = 0;
	CEndPoint pAddr;

	if(m_oRoutingTable.find(pTargetGUID, &pNode, &pAddr))
	{
		if(pNode)
		{
			if( bLockNeighbours )
			{
				Neighbours.m_pSection.lock();
			}

			if( Neighbours.neighbourExists(pNode) )
			{
				pNode->sendPacket(pPacket, bBuffered, false);
				systemLog.postLog(LogSeverity::Debug, QString("CNetwork::RoutePacket %1 Packet: %2 routed to neighbour: %3").arg(pTargetGUID.toString()).arg(pPacket->getType()).arg(pNode->m_oAddress.toString().toLocal8Bit().constData()));
			}

			if( bLockNeighbours )
			{
				Neighbours.m_pSection.unlock();
			}
			return true;
		}
		else if(pAddr.isValid())
		{
			Datagrams.sendPacket(pAddr, pPacket, true);
			systemLog.postLog(LogSeverity::Debug, QString("CNetwork::RoutePacket %1 Packet: %2 routed to remote node: %3").arg(pTargetGUID.toString()).arg(pPacket->getType()).arg(pAddr.toString().toLocal8Bit().constData()));
			return true;
		}
		systemLog.postLog(LogSeverity::Debug, QString("CNetwork::RoutePacket - No node and no address!"));
	}

	systemLog.postLog(LogSeverity::Debug, QString("CNetwork::RoutePacket %1 Packet: %2 DROPPED!").arg(pTargetGUID.toString()).arg(pPacket->getType()));
	return false;
}
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;

}