//this file is part of eMule
//Copyright (C)2002 Merkur ( devs@emule-project.net / http://www.emule-project.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "stdafx.h"
#include "emule.h"
#include "ClientUDPSocket.h"
#include "Packets.h"
#include "DownloadQueue.h"
#include "Statistics.h"
#include "PartFile.h"
#include "SharedFileList.h"
#include "UploadQueue.h"
#include "UpDownClient.h"
#include "Preferences.h"
#include "OtherFunctions.h"
#include "SafeFile.h"
#include "ClientList.h"
#include "Listensocket.h"
#include <zlib/zlib.h>
#include "kademlia/kademlia/Kademlia.h"
#include "kademlia/net/KademliaUDPListener.h"
#include "kademlia/io/IOException.h"
#include "IPFilter.h"
#include "Log.h"
#include "Neo/NeoOpCodes.h"// NEO: NXI - [NeoExtraInfo] <-- Xanatos --
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
#include "Neo/BandwidthControl/BandwidthControl.h"
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
#include "Neo/Argos.h"
#endif // ARGOS // NEO: NA END <-- Xanatos --
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
#include "Neo/Lancast.h"
#endif //LANCAST // NEO: NLC END <-- Xanatos --
#include "Neo/ClientFileStatus.h"// NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
#include "Neo/WebCache/WebCachedBlock.h" // yonatan http
#include "SafeFile.h" // yonatan http (for udp ohcbs)
#include "Neo/WebCache/WebCachedBlockList.h" // Superlexx - managed OHCB list
#endif // NEO: WC END <-- Xanatos --
#include "FirewallOpener.h" // NEO: IFWS - [ICSFirewall] <-- Xanatos --
#include "Neo/UPnP.h" // NEO: UPNP - [UPnPNat] <-- Xanatos --
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal] -- Xanatos -->
#include "kademlia/kademlia/Prefs.h"
#endif //NATTUNNELING // NEO: NATT END <-- Xanatos --
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
#include "Neo/AbstractSocket.h"
#include "Neo/NATSocket.h"
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


// CClientUDPSocket

CClientUDPSocket::CClientUDPSocket()
{
	m_bWouldBlock = false;
	m_port=0;
#ifdef NEO_DBT // NEO: NDBT - [NeoDownloadBandwidthThrottler] -- Xanatos -->
	m_pendingPackets = 0;
#endif // NEO_DBT // NEO: NDBT END <-- Xanatos --
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	lastPriorityPacket = NULL;
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

	mapping = NULL; // NEO: UPNP - [UPnPNat] <-- Xanatos --
}

CClientUDPSocket::~CClientUDPSocket()
{
//#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
    theApp.uploadBandwidthThrottler->RemoveFromAllQueues(this); // ZZ:UploadBandWithThrottler (UDP)
//#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
#ifdef NEO_DBT // NEO: NDBT - [NeoDownloadBandwidthThrottler] -- Xanatos -->
	theApp.downloadBandwidthThrottler->RemoveFromAllQueues(this);
	theApp.downloadqueue->RemoveFromProcessQueue(this);
#endif // NEO_DBT // NEO: NDBT END <-- Xanatos --

    POSITION pos = controlpacket_queue.GetHeadPosition();
	while (pos){
		UDPPack* p = controlpacket_queue.GetNext(pos);
		delete p->packet;
		delete p;
	}

#ifdef NEO_DBT // NEO: NDBT - [NeoDownloadBandwidthThrottler] -- Xanatos -->
	//receiveLocker.Lock();
	while (downloaddata_queue.GetCount()){
		CRawPacket* data = downloaddata_queue.RemoveHead();
		char *rawdata = data->DetachPacket(); // floating index initialized with begin of buffer
		delete [] rawdata;
		delete data;
	}
	//receiveLocker.Unlock();
#endif // NEO_DBT // NEO: NDBT END <-- Xanatos --

#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
	ASSERT(nat_socket_list.IsEmpty());
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --
}

#ifdef NEO_DBT // NEO: NDBT - [NeoDownloadBandwidthThrottler] -- Xanatos -->
int	CClientUDPSocket::Receive(uint32 size){
	ASSERT(m_pendingPackets);

	int recivedBytes = 0;

	static BYTE buffer[5000];
	SOCKADDR_IN sockAddr = {0};
	int iSockAddrLen = sizeof sockAddr;

	receiveLocker.Lock();
	for(;m_pendingPackets > 0 && recivedBytes < (int)size;m_pendingPackets--) {
	
		int length = ReceiveFrom(buffer, sizeof buffer, (SOCKADDR*)&sockAddr, &iSockAddrLen);
		CReceiveData* data = 0;
		if (length > 0) {
 #ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP]
			if(buffer[0] != OP_MODPROT || buffer[1] != OP_NAT_DATA) // Note: we don't count incomming nat traffic yet, it will be counted when the CEMSocket recive's is
 #endif //NATTUNNELING // NEO: UTCP END
			{
				theApp.bandwidthControl->AddDown(length, true);
				recivedBytes += length;
			}
			data = new CReceiveData((char*)buffer, length);
			data->sockAddr = sockAddr;
			downloaddata_queue.AddTail(data);
		}
		else if (length == SOCKET_ERROR) {
			DWORD dwError = WSAGetLastError();
			if (dwError == WSAEWOULDBLOCK) {
				m_pendingPackets = 0;
			}
			else {
				data = new CReceiveData((char*)buffer, 4);
				data->sockAddr = sockAddr;
				data->dwError = dwError;
				downloaddata_queue.AddTail(data);
			}
			break;
		}
	}
	receiveLocker.Unlock();

	return recivedBytes;
}

bool CClientUDPSocket::ProcessData(bool /*ignore*/){
	receiveLocker.Lock();
	while (downloaddata_queue.GetCount()){
		CReceiveData* data = downloaddata_queue.RemoveHead();
		int length  = data->size;
		SOCKADDR_IN sockAddr = data->sockAddr;
		BYTE* buffer = (BYTE*)data->DetachPacket(); // floating index initialized with begin of buffer
		DWORD dwError = data->dwError;
		receiveLocker.Unlock();

		ProcessReceivedData(buffer,length,sockAddr,dwError);

		delete [] buffer;
		delete data;
		receiveLocker.Lock();
	}
	bool ret = (onDownControlQueue && !thePrefs.IsDirectReceivingUDP());
	receiveLocker.Unlock();
	return ret;
}
#endif // NEO_DBT // NEO: NDBT END <-- Xanatos --

void CClientUDPSocket::OnReceive(int nErrorCode)
{
	if (nErrorCode)
	{
		if (thePrefs.GetVerbose())
			DebugLogError(_T("Error: Client UDP socket, error on receive event: %s"), GetErrorMessage(nErrorCode, 1));
	}
#ifdef NEO_DBT // NEO: NDBT - [NeoDownloadBandwidthThrottler] -- Xanatos -->
	else if(!thePrefs.IsDirectReceivingUDP()) { // NEO: NDR - [NeoDirectReciving]
		receiveLocker.Lock();
		m_pendingPackets ++;
		receiveLocker.Unlock();
		theApp.downloadqueue->AddToProcessQueue(this);
		theApp.downloadBandwidthThrottler->QueueForReceivingPacket(this);
	}
	else
#endif // NEO_DBT // NEO: NDBT END <-- Xanatos --
	{
		BYTE buffer[5000];
		SOCKADDR_IN sockAddr = {0};
		int iSockAddrLen = sizeof sockAddr;
		int length = ReceiveFrom(buffer, sizeof buffer, (SOCKADDR*)&sockAddr, &iSockAddrLen);

		// NEO: NDBT - [NeoDownloadBandwidthThrottler] -- Xanatos -->
		DWORD dwError = NULL;
#ifdef NEO_DBT
		if (length > 0) {
 #ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP]
			if(buffer[0] != OP_MODPROT || buffer[1] != OP_NAT_DATA) // Note: we don't count incomming nat traffic yet, it will be counted when the CEMSocket recive's is
 #endif //NATTUNNELING // NEO: UTCP END
			{
				theApp.bandwidthControl->AddDown(length, true); // NEO: NBC - [NeoBandwidthControl]
				if (thePrefs.IsIncludeOverhead())
					theApp.downloadBandwidthThrottler->DecreaseToReceive(length);
			}
		}else
#endif // NEO_DBT
			if(length == SOCKET_ERROR)
				dwError = WSAGetLastError();

		ProcessReceivedData(buffer,length,sockAddr,dwError);
		// NEO: NDBT END <-- Xanatos --
	}
}

void CClientUDPSocket::ProcessReceivedData(BYTE* buffer, int length, SOCKADDR_IN &sockAddr, DWORD dwError){ // NEO: NDBT - [NeoDownloadBandwidthThrottler] <-- Xanatos --
	int iSockAddrLen = sizeof sockAddr; // NEO: NDBT - [NeoDownloadBandwidthThrottler] <-- Xanatos --

	if (!((
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
	 !theApp.lancast->IsLanIP(sockAddr.sin_addr.S_un.S_addr) &&
#endif //LANCAST // NEO: NLC END <-- Xanatos --
	 theApp.ipfilter->IsFiltered(sockAddr.sin_addr.S_un.S_addr))
	 || theApp.clientlist->IsBannedClient(sockAddr.sin_addr.S_un.S_addr)))
    {
		BYTE* pBuffer;
		int nPacketLen = DecryptReceivedClient(buffer, length, &pBuffer, sockAddr.sin_addr.S_un.S_addr);
		if (nPacketLen >= 1)
		{
			CString strError;
			try
			{
				switch (pBuffer[0])
				{
					case OP_EMULEPROT:
					{
						if (nPacketLen >= 2)
							ProcessPacket(pBuffer+2, nPacketLen-2, pBuffer[1], sockAddr.sin_addr.S_un.S_addr, ntohs(sockAddr.sin_port));
						else
							throw CString(_T("eMule packet too short"));
						break;
					}
					case OP_KADEMLIAPACKEDPROT:
					{
						theStats.AddDownDataOverheadKad(nPacketLen);
						if (nPacketLen >= 2)
						{
							uint32 nNewSize = nPacketLen*10+300;
							byte* unpack = new byte[nNewSize];
							uLongf unpackedsize = nNewSize-2;
							int iZLibResult = uncompress(unpack+2, &unpackedsize, pBuffer+2, nPacketLen-2);
							if (iZLibResult == Z_OK)
							{
								unpack[0] = OP_KADEMLIAHEADER;
								unpack[1] = pBuffer[1];
								try
								{
									Kademlia::CKademlia::ProcessPacket(unpack, unpackedsize+2, ntohl(sockAddr.sin_addr.S_un.S_addr), ntohs(sockAddr.sin_port));
								}
								catch(...)
								{
									delete[] unpack;
									throw;
								}
							}
							else
							{
								delete[] unpack;
								CString strError;
								strError.Format(_T("Failed to uncompress Kad packet: zip error: %d (%hs)"), iZLibResult, zError(iZLibResult));
								throw strError;
							}
							delete[] unpack;
						}
						else
							throw CString(_T("Kad packet (compressed) too short"));
						break;
					}
					case OP_KADEMLIAHEADER:
					{
						theStats.AddDownDataOverheadKad(nPacketLen);
						if (nPacketLen >= 2)
							Kademlia::CKademlia::ProcessPacket(pBuffer, nPacketLen, ntohl(sockAddr.sin_addr.S_un.S_addr), ntohs(sockAddr.sin_port));
						else
							throw CString(_T("Kad packet too short"));
						break;
					}
					// NEO: NMP - [NeoModProt] -- Xanatos -->
					case OP_MODPROT:
					{
						if (nPacketLen >= 2)
							ProcessModPacket(pBuffer+2, nPacketLen-2, pBuffer[1], sockAddr.sin_addr.S_un.S_addr, ntohs(sockAddr.sin_port));
						else
							throw CString(_T("Mod packet too short"));
						break;
					}
					case OP_MODPACKEDPROT:
					{
						if (nPacketLen >= 2)
						{
							uint32 nNewSize = nPacketLen*10+300;
							byte* unpack = new byte[nNewSize];
							uLongf unpackedsize = nNewSize-2;
							int iZLibResult = uncompress(unpack+2, &unpackedsize, pBuffer+2, nPacketLen-2);
							if (iZLibResult == Z_OK)
							{
								unpack[0] = OP_MODPROT;
								unpack[1] = pBuffer[1];
								ProcessModPacket(unpack+2, unpackedsize, unpack[1], sockAddr.sin_addr.S_un.S_addr, ntohs(sockAddr.sin_port));
							}
							else
							{
								delete[] unpack;
								CString strError;
								strError.Format(_T("Failed to uncompress Mod packet: zip error: %d (%hs)"), iZLibResult, zError(iZLibResult));
								throw strError;
							}
							delete[] unpack;
						}
						else
							throw CString(_T("Mod protocol packet (compressed) too short"));
						break;
					}
					// NEO: NMP END <-- Xanatos --
					default:
					{
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
						if (thePrefs.IsArgosOpcodeDetection()){
							CUpDownClient* sender = theApp.clientlist->FindClientByIP_UDP(sockAddr.sin_addr.S_un.S_addr, ntohs(sockAddr.sin_port));
							TOpCode* OpCode = new TOpCode;
							OpCode->OpSource = OC_RAW_UDP;
							OpCode->OpCode = pBuffer[0];
							OpCode->OpValue = 0;
							if(sender)
								theApp.argos->AddClientToTest(sender,OpCode);
							else
								theApp.argos->AddClientToTest(sockAddr.sin_addr.S_un.S_addr,OpCode);
						}
#endif // ARGOS // NEO: NA END <-- Xanatos --
						CString strError;
						strError.Format(_T("Unknown protocol 0x%02x"), pBuffer[0]);
						throw strError;
					}
				}
			}
			catch(CFileException* error)
			{
				error->Delete();
				strError = _T("Invalid packet received");
			}
			catch(CMemoryException* error)
			{
				error->Delete();
				strError = _T("Memory exception");
			}
			catch(CString error)
			{
				strError = error;
			}
			catch(Kademlia::CIOException* error)
			{
				error->Delete();
				strError = _T("Invalid packet received");
			}
			catch(CException* error)
			{
				error->Delete();
				strError = _T("General packet error");
			}
#if !defined(_DEBUG) && !defined(_DEBUG_NEO) // NEO: ND - [NeoDebug] <-- Xanatos --
			catch(...)
			{
				strError = _T("Unknown exception");
				ASSERT(0);
			}
#endif // NEO: ND - [NeoDebug] <-- Xanatos --

			if (thePrefs.GetVerbose() && !strError.IsEmpty())
			{
				CString strClientInfo;
				CUpDownClient* client;
				if (pBuffer[0] == OP_EMULEPROT)
					client = theApp.clientlist->FindClientByIP_UDP(sockAddr.sin_addr.S_un.S_addr, ntohs(sockAddr.sin_port));
				else
					client = theApp.clientlist->FindClientByIP_KadPort(sockAddr.sin_addr.S_un.S_addr, ntohs(sockAddr.sin_port));
				if (client)
					strClientInfo = client->DbgGetClientInfo();
				else
					strClientInfo.Format(_T("%s:%u"), ipstr(sockAddr.sin_addr), ntohs(sockAddr.sin_port));

				DebugLogWarning(_T("Client UDP socket: prot=0x%02x  opcode=0x%02x  sizeaftercrypt=%u realsize=%u  %s: %s"), pBuffer[0], pBuffer[1], nPacketLen, length, strError, strClientInfo);
			}
		}
		else if (nPacketLen == SOCKET_ERROR)
		{
			//DWORD dwError = WSAGetLastError(); // NEO: NBC - [NeoBandwidthControl] <-- Xanatos --
			if (dwError == WSAECONNRESET)
			{
				// Depending on local and remote OS and depending on used local (remote?) router we may receive
				// WSAECONNRESET errors. According some KB articles, this is a special way of winsock to report 
				// that a sent UDP packet was not received by the remote host because it was not listening on 
				// the specified port -> no eMule running there.
				//
				// TODO: So, actually we should do something with this information and drop the related Kad node 
				// or eMule client...
				;
			}
			if (thePrefs.GetVerbose() && dwError != WSAECONNRESET)
			{
				CString strClientInfo;
				if (iSockAddrLen > 0 && sockAddr.sin_addr.S_un.S_addr != 0 && sockAddr.sin_addr.S_un.S_addr != INADDR_NONE)
					strClientInfo.Format(_T(" from %s:%u"), ipstr(sockAddr.sin_addr), ntohs(sockAddr.sin_port));
				DebugLogError(_T("Error: Client UDP socket, failed to receive data%s: %s"), strClientInfo, GetErrorMessage(dwError, 1));
			}
		}
	}
}

bool CClientUDPSocket::ProcessPacket(const BYTE* packet, UINT size, uint8 opcode, uint32 ip, uint16 port)
{
	switch(opcode)
	{
		case OP_REASKCALLBACKUDP:
		{
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_ReaskCallbackUDP", NULL, NULL, ip);
			theStats.AddDownDataOverheadOther(size);
			CUpDownClient* buddy = theApp.clientlist->GetBuddy();
			if( buddy )
			{
				if( size < 17 || buddy->socket == NULL )
					break;
				if (!md4cmp(packet, buddy->GetBuddyID()))
				{
					PokeUInt32(const_cast<BYTE*>(packet)+10, ip);
					PokeUInt16(const_cast<BYTE*>(packet)+14, port);
					Packet* response = new Packet(OP_EMULEPROT);
					response->opcode = OP_REASKCALLBACKTCP;
					response->pBuffer = new char[size];
					memcpy(response->pBuffer, packet+10, size-10);
					response->size = size-10;
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugSend("OP__ReaskCallbackTCP", buddy);
					theStats.AddUpDataOverheadFileRequest(response->size);
					buddy->socket->SendPacket(response);
				}
			}
			break;
		}
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
		case OP_MULTI_FILE_REASK: // NEO: MOD - [CodeImprovement]
#endif // WEBCACHE // NEO: WC END <-- Xanatos --
		case OP_REASKCALLBACKTCP: // NEO: MOD - [CodeImprovement] <-- Xanatos --
		case OP_REASKFILEPING:
		{
			theStats.AddDownDataOverheadFileRequest(size);
			CSafeMemFile data_in(packet, size);
			uchar reqfilehash[16];
			data_in.ReadHash16(reqfilehash);
			CKnownFile* reqfile = theApp.sharedfiles->GetFileByID(reqfilehash);

			bool bSenderMultipleIpUnknown = false;
			CUpDownClient* sender = theApp.uploadqueue->GetWaitingClientByIP_UDP(ip, port, true, &bSenderMultipleIpUnknown);
			if (!reqfile || reqfile->IsUnshared(true)) // NEO: USC - [UnShareCommand] <-- Xanatos --
			{
				if (thePrefs.GetDebugClientUDPLevel() > 0) {
					DebugRecv("OP_ReaskFilePing", NULL, reqfilehash, ip);
					DebugSend("OP__FileNotFound", NULL);
				}

				Packet* response = new Packet(OP_FILENOTFOUND,0,OP_EMULEPROT);
				theStats.AddUpDataOverheadFileRequest(response->size);
				if (sender != NULL)
					SendPacket(response, ip, port, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash());
				else
					SendPacket(response, ip, port, false, NULL);
				break;
			}

			if (sender)
			{

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
				if(thePrefs.IsAgressionDetection() == TRUE)
					if(sender->CheckUDPFileReaskPing())
					{
						// keep trace on this client
						sender->AddAskedCount();
						sender->SetLastUpRequest();

						Packet* response = new Packet(OP_QUEUEFULL,0,OP_EMULEPROT);
						theStats.AddUpDataOverheadFileRequest(response->size);
 						SendPacket(response, ip, port, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash());
						break;
					}
#endif //ARGOS // NEO: NA END <-- Xanatos --

				// NEO: FIX - [NewUploadState] -- Xanatos -->
				//Xman: we don't answer this client, to force a tcp connection, then we can add him to upload
				if(/*sender->m_bAddNextConnect*/ sender->GetUploadState() == US_PENDING && theApp.uploadqueue->AcceptNewClient(true)) 
					break;
				// NEO: FIX END <-- Xanatos --

				// NEO: FSUR - [FixStartupLoadReq] -- Xanatos -->
				//Xman: don't answer wrong filereaskpings, test if last action was OP_STARTUPLOADREQ.. must be on normal behavior
				if(sender->GetActiveUpReqFlag() != 1 /*OP_STARTUPLOADREQ*/)
					break;
				// NEO: FSUR END <-- Xanatos --

				if (thePrefs.GetDebugClientUDPLevel() > 0)
					DebugRecv("OP_ReaskFilePing", sender, reqfilehash);

				//Make sure we are still thinking about the same file
				if (md4cmp(reqfilehash, sender->GetUploadFileID()) == 0)
				{
					CClientFileStatus* status = sender->GetFileStatus(reqfile, true);  // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --

					sender->AddAskedCount();
					sender->SetLastUpRequest();
					//I messed up when I first added extended info to UDP
					//I should have originally used the entire ProcessExtenedInfo the first time.
					//So now I am forced to check UDPVersion to see if we are sending all the extended info.
					//For now on, we should not have to change anything here if we change
					//anything to the extended info data as this will be taken care of in ProcessExtendedInfo()
					//Update extended info. 
					if (sender->GetUDPVersion() > 3)
					{
						sender->ProcessExtendedInfo(&data_in, status, reqfile, true); // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
					}
					//Update our complete source counts.
					else if (sender->GetUDPVersion() > 2)
					{
						uint16 nCompleteCountLast = status->GetCompleteSourcesCount(); // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
						uint16 nCompleteCountNew = data_in.ReadUInt16();
						status->SetCompleteSourcesCount(nCompleteCountNew); // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
						if (nCompleteCountLast != nCompleteCountNew)
						{
							reqfile->UpdatePartsInfo();
						}
					}

#ifdef OLD_NEO_PROT // NEO: NMPo - [NeoModProtOld] -- Xanatos -->
					// NEO: XUDP - [UDPExtensions]
					if(sender->GetUDPxSupport()){
						sender->ReadModMultiPacket(&data_in,reqfile,status); // NEO: NMPm - [NeoModProtMultiPacket]
						// NEO: BPS - [BetterPassiveSourceFinding]
						if(reqfile->IsPartFile() && !(sender->GetDownloadState()==DS_ONQUEUE && reqfile==sender->GetRequestFile()))
							sender->ProcessModFileStatus(true, status, (CPartFile*)reqfile, true); // NEO: SCFS - [SmartClientFileStatus]
						// NEO: BPS END
					}
					// NEO: XUDP END
#endif // OLD_NEO_PROT // NEO: NMPo END <-- Xanatos --

					sender->SetLastSeen(); // NEO: NSS - [NeoSourceStorage] <-- Xanatos --

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
					if(opcode == OP_MULTI_FILE_REASK)
						sender->requestedFiles.AddFiles(&data_in, sender);
#endif // WEBCACHE // NEO: WC END <-- Xanatos --

					///////////////////// answer

					CSafeMemFile data_out(128);
					if(sender->GetUDPVersion() > 3)
					{
						// NEO: IPS - [InteligentPartSharing] -- Xanatos -->
						if (reqfile->IsPartFile())
							((CPartFile*)reqfile)->WritePartStatus(&data_out, status);
						else if(!reqfile->WritePartSelection(&data_out, status)) 
							data_out.WriteUInt16(0);
						// NEO: IPS END <-- Xanatos --
					}
					data_out.WriteUInt16((uint16)(theApp.uploadqueue->GetWaitingPosition(sender)));

#ifdef OLD_NEO_PROT // NEO: NMPo - [NeoModProtOld] -- Xanatos -->
					// NEO: EDT - [EstimatedDownloadTime]
					if (thePrefs.UseEstimatedDownloadTime() && sender->GetDownloadTimeVersion() && sender->GetNeoModProtVersion() == 0 && sender->GetUDPVersion() > 3)  // NEO: NMPm - [NeoModProtMultiPacket]
					{
						uint32 avg_value;
						uint32 err_value;
						sender->EstimateDownloadTime(avg_value, err_value);
						data_out.WriteUInt32(avg_value);
						data_out.WriteUInt32(err_value);
					}
					// NEO: EDT END
#endif // OLD_NEO_PROT // NEO: NMPo END <-- Xanatos --

					sender->SetLastL2HACExecution(); // NEO: L2H - [LowID2HighIDAutoCallback] <-- Xanatos --

#ifdef OLD_NEO_PROT // NEO: NMPo - [NeoModProtOld] -- Xanatos -->
					// NEO: XUDP - [UDPExtensions]
					if(sender->GetUDPxSupport())
						sender->WriteModMultiPacket(&data_out, reqfile, status, false, true); // NEO: NMPm - [NeoModProtMultiPacket]
					// NEO: XUDP END
#endif // OLD_NEO_PROT // NEO: NMPo END <-- Xanatos --

					if (thePrefs.GetDebugClientUDPLevel() > 0)
						DebugSend("OP__ReaskAck", sender);
					Packet* response = new Packet(&data_out, OP_EMULEPROT);
					response->opcode = OP_REASKACK;
					theStats.AddUpDataOverheadFileRequest(response->size);
					SendPacket(response, ip, port, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash());

#ifdef OLD_NEO_PROT // NEO: NMPo - [NeoModProtOld] -- Xanatos -->
					// NEO: NXI - [NeoExtraInfo]
					if(sender->GetNeoModProtVersion() == 0 && thePrefs.SendExtraInfo() && sender->GetExtraInfoVersion())
						sender->SendExtraInfoPacket(NIX_RANKING | NIX_SUI, true, ip, port);
					// NEO: NXI END
#endif // OLD_NEO_PROT // NEO: NMPo END <-- Xanatos --
				}
				else
				{
					DebugLogError(_T("Client UDP socket; ReaskFilePing; reqfile does not match"));
					TRACE(_T("reqfile:         %s\n"), DbgGetFileInfo(reqfile->GetFileHash()));
					TRACE(_T("sender->GetRequestFile(): %s\n"), sender->GetRequestFile() ? DbgGetFileInfo(sender->GetRequestFile()->GetFileHash()) : _T("(null)"));
				}
			}
			else
			{
				if (thePrefs.GetDebugClientUDPLevel() > 0)
					DebugRecv("OP_ReaskFilePing", NULL, reqfilehash, ip);

				if (!bSenderMultipleIpUnknown){
					if ((((uint32)theApp.uploadqueue->GetWaitingUserCount() + 50) > thePrefs.GetQueueSize())
					&& !(thePrefs.UseInfiniteQueue())) // NEO: TQ - [TweakUploadQueue] <-- Xanatos --
					{
						if (thePrefs.GetDebugClientUDPLevel() > 0)
							DebugSend("OP__QueueFull", NULL);
						Packet* response = new Packet(OP_QUEUEFULL,0,OP_EMULEPROT);
						theStats.AddUpDataOverheadFileRequest(response->size);
						SendPacket(response, ip, port, false, NULL); // we cannot answer this one encrypted since we dont know this client
					}
				}
				else{
					DebugLogWarning(_T("UDP Packet received - multiple clients with the same IP but different UDP port found. Possible UDP Portmapping problem, enforcing TCP connection. IP: %s, Port: %u"), ipstr(ip), port); 
				}
			}
			break;
		}
		case OP_QUEUEFULL:
		{
			theStats.AddDownDataOverheadFileRequest(size);
			CUpDownClient* sender = theApp.downloadqueue->GetDownloadClientByIP_UDP(ip, port, true);
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_QueueFull", sender, NULL, ip);
			if (sender && sender->UDPPacketPending()){
				sender->SetRemoteQueueFull(true);
				sender->UDPReaskACK(0);
				sender->SetRemoteEDT(0, EDT_UNDEFINED); // NEO: EDT - [EstimatedDownloadTime] <-- Xanatos --
			}
			else if (sender != NULL)
				DebugLogError(_T("Received UDP Packet (OP_QUEUEFULL) which was not requested (pendingflag == false); Ignored packet - %s"), sender->DbgGetClientInfo());
			break;
		}
		case OP_REASKACK:
		{
			theStats.AddDownDataOverheadFileRequest(size);
			CUpDownClient* sender = theApp.downloadqueue->GetDownloadClientByIP_UDP(ip, port, true);
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_ReaskAck", sender, NULL, ip);
			if (sender && sender->UDPPacketPending()){
				// NEO: SCFS - [SmartClientFileStatus] -- Xanatos -->
				CPartFile* reqfile = sender->GetRequestFile();
				if(reqfile == NULL) // just in case
					break;
				CClientFileStatus* status = sender->GetFileStatus(reqfile, true); 
				// NEO: SCFS END <-- Xanatos --
				CSafeMemFile data_in(packet, size);
				if ( sender->GetUDPVersion() > 3 )
				{
					sender->ProcessFileStatus(true, &data_in, status, reqfile); // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
				}
				uint16 nRank = data_in.ReadUInt16();
				sender->SetRemoteQueueFull(false);
				sender->UDPReaskACK(nRank);

#ifdef OLD_NEO_PROT // NEO: NMPo - [NeoModProtOld] -- Xanatos -->
				// NEO: EDT - [EstimatedDownloadTime]
				if (thePrefs.UseEstimatedDownloadTime() && sender->GetDownloadTimeVersion() > 0 && sender->GetNeoModProtVersion() == 0 && sender->GetUDPVersion() > 3) // NEO: NMPm - [NeoModProtMultiPacket]
				{
					uint32 avg_time = data_in.ReadUInt32();
					uint32 err_time = data_in.ReadUInt32();
					sender->SetRemoteEDT(avg_time, err_time);
				}
				// NEO: EDT END

				// NEO: XUDP - [UDPExtensions]
				if(sender->GetUDPxSupport()){
					sender->ReadModMultiPacket(&data_in,reqfile,status); // NEO: NMPm - [NeoModProtMultiPacket]
					sender->ProcessModFileStatus(true, status, reqfile); // NEO: SCFS - [SmartClientFileStatus]
				}
				// NEO: XUDP END
#endif // OLD_NEO_PROT // NEO: NMPo END <-- Xanatos --

				sender->AddAskedCountDown();
				sender->SetLastSeen(); // NEO: NSS - [NeoSourceStorage] <-- Xanatos --

				///////////////////// answer

				// NEO: NMPm - [NeoModProtMultiPacket] -- Xanatos -->
				CSafeMemFile data_out(128);
				data_out.WriteHash16(reqfile->GetFileHash());
			
				sender->WriteModMultiPacket(&data_out, reqfile, status, true, true); 

				if (thePrefs.GetDebugClientUDPLevel() > 0)
					DebugSend("OP__ModMultiPacket (UDP)", sender, reqfile->GetFileHash());
				Packet* response = new Packet(&data_out, OP_MODPROT);
				response->opcode = OP_MODMULTIPACKET;
				theStats.AddUpDataOverheadFileRequest(response->size);
				SendPacket(response, ip, port, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash());
				// NEO: NMPm END <-- Xanatos --

				// NEO: NXI - [NeoExtraInfo] -- Xanatos -->
				if(thePrefs.SendExtraInfo() && sender->GetExtraInfoVersion())
					sender->SendExtraInfoPacket(NIX_REQDOWN, true);
				// NEO: NXI END <-- Xanatos --

			}
			else if (sender != NULL)
				DebugLogError(_T("Received UDP Packet (OP_REASKACK) which was not requested (pendingflag == false); Ignored packet - %s"), sender->DbgGetClientInfo());
			break;
		}
		case OP_FILENOTFOUND:
		{
			theStats.AddDownDataOverheadFileRequest(size);
			CUpDownClient* sender = theApp.downloadqueue->GetDownloadClientByIP_UDP(ip, port, true);
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_FileNotFound", sender, NULL, ip);
			if (sender && sender->UDPPacketPending()){
				sender->UDPReaskFNF(); // may delete 'sender'!
				sender = NULL;
			}
			else if (sender != NULL)
				DebugLogError(_T("Received UDP Packet (OP_FILENOTFOUND) which was not requested (pendingflag == false); Ignored packet - %s"), sender->DbgGetClientInfo());
			break;
		}
		case OP_PORTTEST:
		{
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_PortTest", NULL, NULL, ip);
			theStats.AddDownDataOverheadOther(size);
			if (size == 1){
				if (packet[0] == 0x12){
					bool ret = theApp.listensocket->SendPortTestReply('1', true);
					AddDebugLogLine(true, _T("UDP Portcheck packet arrived - ACK sent back (status=%i)"), ret);
				}
			}
			break;
		}
		
		// NEO: NMP - [NeoModProt] -- Xanatos -->
#ifdef WEBCACHE // NEO: WC - [WebCache]
		case OP_HTTP_CACHED_BLOCK:
#endif // NEO: WC END
#ifdef OLD_NEO_PROT // NEO: NMPo - [NeoModProtOld]
		case OP_EXTRAINFO: // NEO: NXI - [NeoExtraInfo]
			ProcessModPacket(packet, size, opcode, ip, port); // for backwards compatybility
			break;
#endif // OLD_NEO_PROT // NEO: NMPo END
		// NEO: NMP END <-- Xanatos --

		default:
			theStats.AddDownDataOverheadOther(size);
			if (thePrefs.GetDebugClientUDPLevel() > 0)
			{
				CUpDownClient* sender = theApp.downloadqueue->GetDownloadClientByIP_UDP(ip, port, true);
				Debug(_T("Unknown client UDP packet: host=%s:%u (%s) opcode=0x%02x  size=%u\n"), ipstr(ip), port, sender ? sender->DbgGetClientInfo() : _T(""), opcode, size);
			}
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
			if (thePrefs.IsArgosOpcodeDetection()){
				CUpDownClient* sender = theApp.clientlist->FindClientByIP_UDP(ip, port);
				TOpCode* OpCode = new TOpCode;
				OpCode->OpSource = OC_PACKET_UDP;
				OpCode->OpCode = opcode;
				OpCode->OpValue = 0;
				if(sender)
					theApp.argos->AddClientToTest(sender,OpCode);
				else
					theApp.argos->AddClientToTest(ip,OpCode);
			}
#endif // ARGOS // NEO: NA END <-- Xanatos --
			return false;
	}
	return true;
}

void CClientUDPSocket::OnSend(int nErrorCode){
	if (nErrorCode){
		if (thePrefs.GetVerbose())
			DebugLogError(_T("Error: Client UDP socket, error on send event: %s"), GetErrorMessage(nErrorCode, 1));
		return;
	}

	m_bWouldBlock = false;
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	// NEO: NDS - [NeoDirectSending]
	if(thePrefs.IsDirectSendingUDP())
		Send(0x7fffffff,0);	
	else 
	// NEO: NDS END
	if(!thePrefs.UseBlockedQueue()){
		sendLocker.Lock();
		if(!controlpacket_queue.IsEmpty()) { // we dont use hyper sending
			sendLocker.Unlock(); // See the note above QueueForSendingControlPacket, for the unlock reason
			theApp.uploadBandwidthThrottler->QueueForSendingControlPacket(this); // reenter control queue
			return;
		}
		sendLocker.Unlock();
	}
#else
// ZZ:UploadBandWithThrottler (UDP) -->
	sendLocker.Lock();
	if(!controlpacket_queue.IsEmpty()) {
		theApp.uploadBandwidthThrottler->QueueForSendingControlPacket(this);
	}
    sendLocker.Unlock();
// <-- ZZ:UploadBandWithThrottler (UDP)
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
}

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
bool CClientUDPSocket::IsPrioritySend() {
	sendLocker.Lock();
	bool empty = (controlpacket_queue.GetCount() == 0);
	if (empty){
		sendLocker.Unlock();
		return false;
	}
	bool retVal = controlpacket_queue.GetHead()->priority;
	sendLocker.Unlock();
	return retVal;
}
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
SocketSentBytes CClientUDPSocket::Send(uint32 maxNumberOfBytesToSend, uint32 /*minFragSize*/, bool /*onlyAllowedToSendControlPacket*/, uint16 maxNumberOfPacketsToSend){
#else
SocketSentBytes CClientUDPSocket::SendControlData(uint32 maxNumberOfBytesToSend, uint32 /*minFragSize*/){ // ZZ:UploadBandWithThrottler (UDP)
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
// ZZ:UploadBandWithThrottler (UDP) -->
	// NOTE: *** This function is invoked from a *different* thread!
    sendLocker.Lock();

    uint32 sentBytes = 0;
// <-- ZZ:UploadBandWithThrottler (UDP)
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
    
	uint16 sentPackets = 0;

	for (;!controlpacket_queue.IsEmpty() && (sentPackets < maxNumberOfPacketsToSend || controlpacket_queue.GetHead()->priority)
										 && sentBytes < maxNumberOfBytesToSend;sentPackets++)
#else
	while (!controlpacket_queue.IsEmpty() && !IsBusy() && sentBytes < maxNumberOfBytesToSend) // ZZ:UploadBandWithThrottler (UDP)
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
	{
		UDPPack* cur_packet = controlpacket_queue.GetHead();
		if( GetTickCount() - cur_packet->dwTime > UDPMAXQUEUETIME )	{ // if the packet waited to long then drop it
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
			if (controlpacket_queue.GetHeadPosition() == lastPriorityPacket)
				lastPriorityPacket = NULL;
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
			controlpacket_queue.RemoveHead();
			delete cur_packet->packet;
			delete cur_packet;
			continue;
		}

//#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
//		if(!cur_packet->priority && sentBytes + cur_packet->packet->size+2 > maxNumberOfBytesToSend) // if we used up ur bandwidth and the packet is not urgent
//			break; // break sending
//#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

		uint32 nLen = cur_packet->packet->size+2;
		uchar* sendbuffer = new uchar[nLen];
		memcpy(sendbuffer,cur_packet->packet->GetUDPHeader(),2);
		memcpy(sendbuffer+2,cur_packet->packet->pBuffer,cur_packet->packet->size);
			
		if (cur_packet->bEncrypt && theApp.GetPublicIP() > 0){
			nLen = EncryptSendClient(&sendbuffer, nLen, cur_packet->achTargetClientHash);
			DEBUG_ONLY(  DebugLog(_T("Sent obfuscated UDP packet to clientIP: %s"), ipstr( cur_packet->dwIP)) );
		}

		int sendSuccess = SendTo((char*)sendbuffer, nLen, cur_packet->dwIP, cur_packet->nPort);

		delete[] sendbuffer;

        if (sendSuccess >= 0){
 #ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP]
			if(cur_packet->packet->GetUDPHeader()[0] != OP_MODPROT || cur_packet->packet->GetUDPHeader()[1] != OP_NAT_DATA) // Note: we don't count outgoing nat traffic yet, it was already counted when the CEMSocket sent it
			// Note: we won't get a buttleneck here as NAT packets are declared as priority packets and always send
 #endif //NATTUNNELING // NEO: UTCP END
	            sentBytes += sendSuccess; // ZZ:UploadBandWithThrottler (UDP)
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
			m_bWouldBlock = false;

			if (controlpacket_queue.GetHeadPosition() == lastPriorityPacket)
				lastPriorityPacket = NULL;
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
			controlpacket_queue.RemoveHead();
			delete cur_packet->packet;
			delete cur_packet;
        }else
			break; // Socket busy break now
	}

// ZZ:UploadBandWithThrottler (UDP) -->
#ifndef NEO_UBT // NEO: NUBT -- Xanatos -->
    if(!IsBusy() && !controlpacket_queue.IsEmpty()) {
        theApp.uploadBandwidthThrottler->QueueForSendingControlPacket(this);
    }
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
    sendLocker.Unlock();

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
    SocketSentBytes returnVal = { true, 0, sentBytes, 0, sentPackets };
#else
    SocketSentBytes returnVal = { true, 0, sentBytes };
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
    return returnVal;
// <-- ZZ:UploadBandWithThrottler (UDP)
}


int CClientUDPSocket::SendTo(char* lpBuf,int nBufLen,uint32 dwIP, uint16 nPort){
	// NOTE: *** This function is invoked from a *different* thread!
	uint32 result = CAsyncSocket::SendTo(lpBuf,nBufLen,nPort,ipstr(dwIP));
	if (result == (uint32)SOCKET_ERROR){
		uint32 error = GetLastError();
		if (error == WSAEWOULDBLOCK){
			m_bWouldBlock = true;
			return -1;
		}
		if (thePrefs.GetVerbose())
			DebugLogError(_T("Error: Client UDP socket, failed to send data to %s:%u: %s"), ipstr(dwIP), nPort, GetErrorMessage(error, 1));
		return 0;
	}
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
	else {
		theApp.bandwidthControl->AddUp(result,true);
 #ifdef NEO_UBT // NEO: NDS - [NeoDirectSending]
		if (thePrefs.IsDirectSendingUDP() && thePrefs.IsIncludeOverhead())
			theApp.uploadBandwidthThrottler->DecreaseToSend(result);
 #endif // NEO_UBT // NEO: NDS END
	}
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
	return result; // was 0
}

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
bool CClientUDPSocket::SendPacket(Packet* packet, uint32 dwIP, uint16 nPort, bool bEncrypt, const uchar* pachTargetClientHash, bool priority){
#else
bool CClientUDPSocket::SendPacket(Packet* packet, uint32 dwIP, uint16 nPort, bool bEncrypt, const uchar* pachTargetClientHash){
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
	UDPPack* newpending = new UDPPack;
	newpending->dwIP = dwIP;
	newpending->nPort = nPort;
	newpending->packet = packet;
	newpending->dwTime = GetTickCount();
	newpending->bEncrypt = bEncrypt && pachTargetClientHash != NULL;
	if (newpending->bEncrypt)
		md4cpy(newpending->achTargetClientHash, pachTargetClientHash);
	else
		md4clr(newpending->achTargetClientHash);
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	newpending->priority = priority;
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

// ZZ:UploadBandWithThrottler (UDP) -->
    sendLocker.Lock();
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	if (priority) {
		if (!lastPriorityPacket){
			controlpacket_queue.AddHead(newpending);
			lastPriorityPacket = controlpacket_queue.GetHeadPosition();
		}else {
			controlpacket_queue.InsertAfter(lastPriorityPacket, newpending);
			controlpacket_queue.GetNext(lastPriorityPacket);
		}
	}
	else
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
		controlpacket_queue.AddTail(newpending);
    sendLocker.Unlock();

#ifdef NEO_UBT // NEO: NDS - [NeoDirectSending] -- Xanatos -->
	if (thePrefs.IsDirectSendingUDP())
		Send(0x7fffffff,0);
	else
#endif // NEO_UBT // NEO: NDS END <-- Xanatos --
		theApp.uploadBandwidthThrottler->QueueForSendingControlPacket(this);
	return true;
// <-- ZZ:UploadBandWithThrottler (UDP)
}

// NEO: KAX - [KadAuxPort] -- Xanatos -->
bool CClientUDPSocket::Create(bool bKad)
{
	bool ret=true;

	uint16 port = bKad ? thePrefs.GetKADPort(true) : thePrefs.GetUDPPort(true); // NEO: NATS - [NatSupport] <-- Xanatos --
	if (port)
	{
		ret=CAsyncSocket::Create(port,SOCK_DGRAM,FD_READ|FD_WRITE,theApp.GetBindAddress()) != FALSE; // NEO: MOD - [BindToAdapter]
		if (ret)
			m_port = port;
	}

	if(ret)
	{
		m_port = port;
	
		// NEO: IFWS - [ICSFirewall] -- Xanatos -->
		if(thePrefs.GetICFSupport()){
			bool bResult = (theApp.m_pFirewallOpener->OpenPort(m_port, NAT_PROTOCOL_UDP, bKad ? EMULE_DEFAULTRULENAME_KAD : EMULE_DEFAULTRULENAME_UDP, thePrefs.GetICFClearOnClose() /*|| thePrefs.GetUseRandomPorts()*/));
			theApp.QueueLogLine(false, GetResString(bResult ? IDS_X_FO_TEMPUDP_S : IDS_X_FO_TEMPUDP_F), m_port);
		}
		// NEO: IFWS END <-- Xanatos --

		// NEO: UPNP - [UPnPNat] -- Xanatos -->
		if(mapping)
			theApp.RemoveUPnPNatPort(mapping);

		if (thePrefs.IsUPnPEnabled()){
			mapping = new MyUPnP::UPNPNAT_MAPPING;
			mapping->ref = &mapping;

			mapping->internalPort = mapping->externalPort = m_port;
			mapping->protocol = MyUPnP::UNAT_UDP;
			mapping->description = bKad ? EMULE_DEFAULTRULENAME_KAD : EMULE_DEFAULTRULENAME_UDP;
			if (theApp.AddUPnPNatPort(mapping, thePrefs.GetUPnPNatTryRandom()))
				m_port = mapping->externalPort;
		}
		// NEO: UPNP END <-- Xanatos --

		thePrefs.SetUDPPort(m_port,bKad); // NEO: NATS - [NatSupport] <-- Xanatos --
	}

	return ret;
}

bool CClientUDPSocket::Rebind(bool bKad)
{
	Close();

	if(!Create(bKad)){ 
		LogError(LOG_STATUSBAR, GetResString(IDS_MAIN_SOCKETERROR),bKad ? thePrefs.GetKADPort() : thePrefs.GetUDPPort(true)); // NEO: NATS - [NatSupport] <-- Xanatos --
		return false;
	}

	// NEO: NATS - [NatSupport]
	if(thePrefs.IsNATSupportEnabled())
		thePrefs.SetUDPPortPingTime(0); // force port recheck over buddy
	// NEO: NATS END

	return true;
}
// NEO: KAX END <-- Xanatos --

// NEO: NMP - [NeoModProt] -- Xanatos -->
bool CClientUDPSocket::ProcessModPacket(const BYTE* packet, UINT size, uint8 opcode, uint32 ip, uint16 port)
{
	switch(opcode)
	{
		// NEO: NATS - [NatSupport]
		case OP_UDP_PORTTEST:
		{
			thePrefs.SetIP(ip);
			// NEO: KAX - [KadAuxPort]
			if(((uint32)packet[0]) == 'KAD')
			{
				if(thePrefs.GetUDPPortPingFails() > 0 || thePrefs.GetKADPortEx() != port)
					ModLog(LOG_SUCCESS,GetResString(IDS_X_NAT_PORT_FOUND_KAD),port);
				thePrefs.SetUDPPort(port,true);
				thePrefs.SetUDPPingPending(false,true);
			}
			else
			// NEO: KAX END
			{
				if(thePrefs.GetUDPPortPingFails() > 0 || thePrefs.GetUDPPortEx() != port)
					ModLog(LOG_SUCCESS,GetResString(IDS_X_NAT_PORT_FOUND_UDP),port);
				thePrefs.SetUDPPort(port);
				thePrefs.SetUDPPingPending(false);
			}

			if(thePrefs.IsUDPPingPending() == false) // ping on booth ports recibed or only one port pinged
			{
				// reset fails
				thePrefs.ResetUDPPortPingFails(); 
				// and set timer for next ping
				thePrefs.SetUDPPortPingTime(::GetTickCount());
			}
			break;
		}
		// NEO: NATS END

#ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
		case OP_NAT_SYNC: // client request over our buddy an nat tunneling try 
		case OP_NAT_PING: // client trys to create a UDP tunel -> tunel established, send config
		{

 #ifdef NATSOCKET_DEBUG
			switch(opcode){
			case OP_NAT_SYNC: NATTrace(0,NLE_RECIVED,__FUNCTION__,"Nat Sync Packet");break;
			case OP_NAT_PING: NATTrace(0,NLE_RECIVED,__FUNCTION__,"Nat Ping Packet");break;
			}
 #endif //NATSOCKET_DEBUG

			// get the sending clinet or create a new one
			CUpDownClient* sender = theApp.clientlist->FindClientByNatIP_NatPort(ip, port);
			if( sender == NULL )
			{
				NATTrace(0,NLE_OTHER,__FUNCTION__,"Creating new cleint instance");

				//ASSERT(opcode != OP_NAT_PING_ACK); // ack's shouldn't arive from unknown clients
				sender = new CUpDownClient(NULL,0,1,0,0,false);
				sender->SetSourceFrom(SF_KADEMLIA);
				sender->SetNatTraversalSupport();
				theApp.clientlist->AddClient(sender,true);
				sender->SetConnectIP(ip);
				// sender->SetNatPort(port);
				sender->AddNatTraversalState(NT_ACCEPTOR);
			}
			sender->SetNatPort(port); // set a the propper, the old one may be not longer valid

			if((sender->GetNatTraversalState() & NT_TUNEL) && (::GetTickCount() - sender->GetNatTraversalState()) < SEC2MS(10)) // X-ToDo: is this time ok 
			{
				// this happens when the ping from the remote side manages to penetrate our nat befoure we send ping 
				// when this occurs we are behina Full Cone NAT, without knowing it
				// howeever it shouldn't happen as than we shold behave accordingly and prevent this situation
				NATTrace(0,NLE_OTHER,__FUNCTION__,"Dropping useles sync/ping");
				break;
			}

			sender->SetLastNatTraversalTry();

			theStats.AddDownDataOverheadOther(size);
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_Nat_Sync/Ping (UDP)", sender, NULL, ip);

			if(sender->ResetNatTraversalState(true)) // re reset the state cionditionaly, when to much fime pased since last try
				sender->AddNatTraversalState(NT_ACCEPTOR); // it must be a remote connection

			if(sender->CheckNatTraversalState() == false) // wrong state, no state at all or existing TCP socket
				break;

			bool bSendSync = false;
			CSafeMemFile data(packet,size);
			while (data.GetLength()-data.GetPosition())
			{
				uint8 opcode_in = data.ReadUInt8();
				uint8 length_in = data.ReadUInt8();
				switch (opcode_in)
				{
					case NULL: // in case the end of the packet dot used i future 
						break;
					case OP_NAT_SYNC_REQ:  // cleint wants a OP_NAT_SYNC from us over his budy to have our proper ip/port
					{
						NATTrace(0,NLE_OTHER,__FUNCTION__,"remote sync request recived");

						ASSERT(length_in == 16+4+2);

						Kademlia::CUInt128 uBuddy;
						data.ReadHash16(uBuddy.GetDataPtr());
						if(sender->HasValidBuddyID() == false)
							sender->SetBuddyID(uBuddy.GetData());
						else
							ASSERT(md4cmp(sender->GetBuddyID(),uBuddy.GetData()) == 0);

						uint32 buddyIp = data.ReadUInt32();
						uint16 buddyPort = data.ReadUInt16();
						if(buddyIp && buddyPort)
						{
							sender->SetBuddyIP(buddyIp);
							sender->SetBuddyPort(buddyPort);
							bSendSync = true;
						}
						// else // we could try to search for the buddy, but as we got this instantly we can be sure the remote side does not have one right now
						break;
					}
					case OP_NAT_OBFU:
					{
						ASSERT(length_in == 16 + 1);

						uchar achUserHash[16];
						data.ReadHash16(achUserHash);
						uint8 byCryptOptions = data.ReadUInt8();

						sender->SetUserHash(achUserHash);
						sender->SetCryptLayerSupport((byCryptOptions & 0x01) != 0);
						sender->SetCryptLayerRequest((byCryptOptions & 0x02) != 0);
						sender->SetCryptLayerRequires((byCryptOptions & 0x04) != 0);
						break;
					}
 					default:
					{
						DebugLog(_T("Unknown NAT sub opcode 0x%02x received"), opcode_in);
						data.Seek(length_in, CFile::current);
					}
				}
			}

			if(bSendSync && opcode == OP_NAT_SYNC) // a sync request is only allowed to be done from a buddy relayed sync
				sender->TryToSyncOverBuddy(true);

			if(opcode == OP_NAT_PING // if this packet comes directly form the other cleint
			 && (sender->GetNatTraversalState() & NT_CONF_SND) == 0 // and we don't already send the config, send  it
			 && sender->GetNatTraversalState() & NT_INITIALIZER) // the initialiser sends the first config, the acceptor send it only on reply
			 // Note: at this point we can choice to not send a config and remain in UDP mode for example for a file reask ping
			 // noweever the official emule client does not uses UDP when being firewalled to can get a reserved slot
			{
				sender->AddNatTraversalState(NT_CONF_SND);
				sender->SendNatConfig();
			}

			// send nat ping (ack)
			if((opcode == OP_NAT_SYNC || (sender->GetNatTraversalState() & NT_TUNEL) == 0) // if its a reuest or the first arried ping
			&& (sender->GetNatTraversalState() & NT_CONF_SND) == 0) // if we sent the config we don't need to ping back
 				sender->SendNatPing(); // answer with a secud ping to notyfy the other cleint that the tunel is active

			if(opcode == OP_NAT_PING){ // if this packet comes directly form the other cleint
				NATTrace(0,NLE_STATE,__FUNCTION__,"Nat Tunel established");
				sender->AddNatTraversalState(NT_TUNEL); // we got a ping Yea, we have a tunel
			}

			break;
		}
		case OP_NAT_CONFIG:
		{
			NATTrace(0,NLE_RECIVED,__FUNCTION__,"Nat Configurations");

			CUpDownClient* sender = theApp.clientlist->FindClientByNatIP_NatPort(ip, port);

			theStats.AddDownDataOverheadOther(size);
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_Nat_Sync_Cfg (UDP)", sender, NULL, ip);

			if( sender == NULL || sender->CheckNatTraversalState(port) == false)
				break;

			NATTrace(0,NLE_STATE,__FUNCTION__,"Nat Tunel established");
			sender->AddNatTraversalState(NT_TUNEL); // we got a ping Yea, we have a tunel

			// if the cleint does not have a socket
			if (sender->socket == NULL)
			{
				sender->socket = new CClientReqSocket(sender,true); // we create a new one
				sender->socket->Create(); // Note: a check is here useless as teh creation of an CNATSocket always success.
			}

			sender->ProcessNatConfigPacket(packet,size); // configure the socket
			sender->AddNatTraversalState(NT_CONF_RCV);

			if((sender->GetNatTraversalState() & NT_CONF_SND) == 0) // and we don't already send the config, send  it
			{
				sender->AddNatTraversalState(NT_CONF_SND);
				sender->SendNatConfig();
			}

			sender->socket->OnConnect(0);

			// if we initialised the connection than it is up to us to say hello
			if(sender->GetNatTraversalState() & NT_INITIALIZER)
				sender->SendHelloPacket();
			break;
		}

		// NEO: UTCP - [UserModeTCP]
		case OP_NAT_DATA:
		{
			NATTrace(0,NLE_RECIVED,__FUNCTION__,"Nat DATA Packet");

			if(size <= 4) // ACK (+ DATA)
				throw CString(_T("NAT UDP DATA packet to short!!!"));

			CNATSocket* source = FindNatSocket(ip, port);
			if( source == NULL ){
				NATTrace((uint32)source,NLE_STATE,__FUNCTION__,"Nat packet for an unexisting socket recived");
				SendPacket(new Packet(OP_NAT_RST,0,OP_MODPROT), ip, port, false, NULL, true); // send reset, to force the sender to close the connection
				break;
			}

			source->ProcessDataPacket(packet, size);
			break;
		}
		case OP_NAT_ACK:
		{
			NATTrace(0,NLE_RECIVED,__FUNCTION__,"Nat ACK Packet");

			if(size < 4+4) // ACK + Window
				throw CString(_T("NAT UDP ACK packet to short!!!"));

			CNATSocket* source = FindNatSocket(ip, port);
			if( source == NULL ){
				NATTrace((uint32)source,NLE_STATE,__FUNCTION__,"Nat packet for an unexisting socket recived");
				SendPacket(new Packet(OP_NAT_RST,0,OP_MODPROT), ip, port, false, NULL, true); // reset
				break;
			}

			source->ProcessAckPacket(packet, size);
			break;
		}
		case OP_NAT_RST:
		{
			NATTrace(0,NLE_RECIVED,__FUNCTION__,"NAT connection reset");

			CNATSocket* source = FindNatSocket(ip, port);
			if( source == NULL ){
				NATTrace((uint32)source,NLE_STATE,__FUNCTION__,"Nat packet for an unexisting socket recived");
				break;
			}

			int nErrorCode = 0;
			if(size >= 4) // in future we may add an error information here
				nErrorCode = PeekUInt32(packet);

			source->ShutDown(both);
			source->OnClose(nErrorCode);
			break;
		}
		// NEO: UTCP END
#endif //NATTUNNELING // NEO: NATT END

		// NEO: NMPm - [NeoModProtMultiPacket]
		case OP_MODMULTIPACKET:
		{
			theStats.AddDownDataOverheadFileRequest(size);
			CSafeMemFile data_in(packet, size);
			uchar reqfilehash[16];
			data_in.ReadHash16(reqfilehash);

			bool bSenderMultipleIpUnknown = false;
			CUpDownClient* sender = theApp.uploadqueue->GetWaitingClientByIP_UDP(ip, port, true, &bSenderMultipleIpUnknown);
			if (!sender)
				break;

			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_ModMultiPacket (UDP)", sender, reqfilehash);

			CKnownFile* reqfile = theApp.sharedfiles->GetFileByID(reqfilehash);
			if (!reqfile || reqfile->IsUnshared(true)) // NEO: USC - [UnShareCommand]
				break;


			//Make sure we are still thinking about the same file
			if (md4cmp(reqfilehash, sender->GetUploadFileID()))
			{
				DebugLogError(_T("Client UDP socket; ModMultiPacket; reqfile does not match"));
				TRACE(_T("reqfile:         %s\n"), DbgGetFileInfo(reqfile->GetFileHash()));
				TRACE(_T("sender->GetRequestFile(): %s\n"), sender->GetRequestFile() ? DbgGetFileInfo(sender->GetRequestFile()->GetFileHash()) : _T("(null)"));
				break;
			}
			
			CClientFileStatus* status = sender->GetFileStatus(reqfile, true);  // NEO: SCFS - [SmartClientFileStatus]
	
			sender->ReadModMultiPacket(&data_in,reqfile,status); // NEO: NMPm - [NeoModProtMultiPacket]
			// NEO: BPS - [BetterPassiveSourceFinding]
			if(reqfile->IsPartFile() && !(sender->GetDownloadState()==DS_ONQUEUE && reqfile==sender->GetRequestFile()))
				sender->ProcessModFileStatus(true, status, (CPartFile*)reqfile, true); // NEO: SCFS - [SmartClientFileStatus]
			// NEO: BPS END

			sender->SetLastSeen(); // NEO: NSS - [NeoSourceStorage] <-- Xanatos --


			///////////////////// answer

			CSafeMemFile data_out(128);
			
			sender->WriteModMultiPacket(&data_out, reqfile, status, false, true);
					
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugSend("OP_ModMultiPacketAns (UDP)", sender);

			Packet* response = new Packet(&data_out, OP_MODPROT);
			response->opcode = OP_MODMULTIPACKETANSWER;
			theStats.AddUpDataOverheadFileRequest(response->size);
			SendPacket(response, ip, port, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash());

			// NEO: NXI - [NeoExtraInfo]
			if(thePrefs.SendExtraInfo() && sender->GetExtraInfoVersion())
				sender->SendExtraInfoPacket(NIX_RANKING | NIX_SUI, true, ip, port);
			// NEO: NXI END
			break;
		}
		case OP_MODMULTIPACKETANSWER: 
		{
			theStats.AddDownDataOverheadFileRequest(size);
			CUpDownClient* sender = theApp.downloadqueue->GetDownloadClientByIP_UDP(ip, port, true);

			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_ModMultiPacketAns (UDP)", sender, NULL, ip);

			if (!sender)
				break;

			// NEO: SCFS - [SmartClientFileStatus]
			CPartFile* reqfile = sender->GetRequestFile();
			if(reqfile == NULL) // just in case
				break;

			CSafeMemFile data_in(packet, size);

			CClientFileStatus* status = sender->GetFileStatus(reqfile, true); 
			// NEO: SCFS END

			sender->ReadModMultiPacket(&data_in,reqfile,status);
			sender->ProcessModFileStatus(true, status, reqfile); // NEO: SCFS - [SmartClientFileStatus]

			break;
		}
		// NEO: NMPm END

		// NEO: NXI - [NeoExtraInfo]
		case OP_EXTRAINFO:{
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_ExtraInfo", NULL, NULL, ip);
			theStats.AddDownDataOverheadOther(size);
			CUpDownClient* sender = theApp.downloadqueue->GetDownloadClientByIP_UDP(ip, port, true);
			if (sender){
				CSafeMemFile data_in(packet, size);
				sender->ProcessExtraInfoPacket(&data_in, true);
			}
			break;
		}
		// NEO: NXI END

#ifdef WEBCACHE // NEO: WC - [WebCache]
		case OP_HTTP_CACHED_BLOCK:
		{
			theStats.AddDownDataOverheadOther(size);
			uint32 *id = (uint32*)(packet+50);
			CUpDownClient* sender = theApp.clientlist->FindClientByWebCacheUploadId( *id );

			if( sender ) 
			{
				if (thePrefs.GetDebugClientUDPLevel() > 0)
					DebugRecv("OP__Http_Cached_Block (UDP)", sender, NULL, ip);
				if( thePrefs.IsWebCacheDownloadEnabled() )
				{
					if (thePrefs.GetLogWebCacheEvents())
					AddDebugLogLine( false, _T("Received WCBlock - UDP") );
					new CWebCachedBlock( packet, size, sender ); // Starts DL or places block on queue
				}
			} 
			else 
				if (thePrefs.GetLogWebCacheEvents())
				AddDebugLogLine( false, _T("Received cached block info from unknown client (UDP)") );

			break;
		}
		//JP for a future version
		case OP_RESUME_SEND_OHCBS:
		{
			theStats.AddDownDataOverheadOther(size);
			uint32 *id = (uint32*)(packet);
			CUpDownClient* sender = theApp.clientlist->FindClientByWebCacheUploadId( *id );

			if( sender ) 
			{
				sender->m_bIsAcceptingOurOhcbs = true;
				if (thePrefs.GetLogWebCacheEvents())
					AddDebugLogLine( false, _T("Received OP_RESUME_SEND_OHCBS from %s "), sender->DbgGetClientInfo() );
			} 
			else 
				if (thePrefs.GetLogWebCacheEvents())
				AddDebugLogLine( false, _T("Received OP_RESUME_SEND_OHCBS from unknown client") );
			break;
		}
		case OP_XPRESS_MULTI_HTTP_CACHED_BLOCKS:
		case OP_MULTI_HTTP_CACHED_BLOCKS:
			{
				CSafeMemFile data(packet,size);
				CUpDownClient* sender = theApp.clientlist->FindClientByWebCacheUploadId( data.ReadUInt32() ); // data.ReadUInt32() is the uploadID
				if (!sender) 
					return false;
				DebugRecv("OP__Multi_Http_Cached_Blocks", sender);
				if (thePrefs.GetDebugClientTCPLevel() > 0)
					theStats.AddDownDataOverheadOther(size);
				if( thePrefs.IsWebCacheDownloadEnabled() && sender->SupportsWebCache() ) 
				{
					// CHECK HANDSHAKE?
					if (thePrefs.GetLogWebCacheEvents())
						AddDebugLogLine( false, _T("Received MultiWCBlocks - UDP") );
					return WebCachedBlockList.ProcessWCBlocks(packet, size, opcode, sender);
				}
				break;
			}
		case OP_MULTI_FILE_REASK:
			{
				ProcessPacket(packet,size,OP_MULTI_FILE_REASK,ip,port); // NEO: MOD - [CodeImprovement] <-- Xanatos --
				break;
			}
#endif // NEO: WC END <-- Xanatos --
		default:
			theStats.AddDownDataOverheadOther(size);
			if (thePrefs.GetDebugClientUDPLevel() > 0){
				CUpDownClient* sender = theApp.downloadqueue->GetDownloadClientByIP_UDP(ip, port, true);
				Debug(_T("Unknown client UDP MOD packet: host=%s:%u (%s) opcode=0x%02x  size=%u\n"), ipstr(ip), port, sender ? sender->DbgGetClientInfo() : _T(""), opcode, size);
			}
#ifdef ARGOS // NEO: NA - [NeoArgos]
			if (thePrefs.IsArgosOpcodeDetection()){
				CUpDownClient* sender = theApp.clientlist->FindClientByIP_UDP(ip, port);
				TOpCode* OpCode = new TOpCode;
				OpCode->OpSource = OC_PACKET_MOD_UDP;
				OpCode->OpCode = opcode;
				OpCode->OpValue = 0;
				if(sender)
					theApp.argos->AddClientToTest(sender,OpCode);
				else
					theApp.argos->AddClientToTest(ip,OpCode);
			}
#endif // ARGOS // NEO: NA END
			return false;
	}
	return true;
}
// NEO: NMP END <-- Xanatos --


#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
void CClientUDPSocket::ProcessNat()
{
	for (POSITION pos = nat_socket_list.GetHeadPosition(); pos; )
		nat_socket_list.GetNext(pos)->CheckForTimeOut();
}

void CClientUDPSocket::AddNatSocket(CNATSocket* toadd)
{
	nat_socket_list.AddTail(toadd);
}

void CClientUDPSocket::RemoveNatSocket(CNATSocket* todel)
{
	if(POSITION pos = nat_socket_list.Find(todel))
		nat_socket_list.RemoveAt(pos);
}

CNATSocket* CClientUDPSocket::FindNatSocket(uint32 natIP, uint16 natPort)
{
	for (POSITION pos = nat_socket_list.GetHeadPosition(); pos != NULL;)
	{
		CNATSocket* cur_socket = nat_socket_list.GetNext(pos);
		if (cur_socket->GetTargetIP() == natIP && cur_socket->GetTargetPort() == natPort)
			return cur_socket;
	}
	return NULL;
}
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --