Beispiel #1
0
bool CAICHHashSet::CreatePartRecoveryData(uint64 nPartStartPos, CFileDataIO* fileDataOut, bool bDbgDontLoad)
{
	wxASSERT( m_pOwner );
	if (m_pOwner->IsPartFile() || m_eStatus != AICH_HASHSETCOMPLETE) {
		wxFAIL;
		return false;
	}
	if (m_pHashTree.m_nDataSize <= EMBLOCKSIZE) {
		wxFAIL;
		return false;
	}
	if (!bDbgDontLoad) {
		if (!LoadHashSet()) {
			AddDebugLogLineN(logSHAHashSet,
				CFormat(wxT("Created RecoveryData error: failed to load hashset. File: %s")) % m_pOwner->GetFileName());
			SetStatus(AICH_ERROR);
			return false;
		}
	}
	bool bResult;
	uint8 nLevel = 0;
	uint32 nPartSize = min<uint64>(PARTSIZE, m_pOwner->GetFileSize()-nPartStartPos);
	m_pHashTree.FindHash(nPartStartPos, nPartSize,&nLevel);
	uint16 nHashsToWrite = (nLevel-1) + nPartSize/EMBLOCKSIZE + ((nPartSize % EMBLOCKSIZE != 0 )? 1:0);
	const bool bUse32BitIdentifier = m_pOwner->IsLargeFile();

	if (bUse32BitIdentifier) {
		fileDataOut->WriteUInt16(0); // no 16bit hashs to write
	}

	fileDataOut->WriteUInt16(nHashsToWrite);
	uint64 nCheckFilePos = fileDataOut->GetPosition();
	if (m_pHashTree.CreatePartRecoveryData(nPartStartPos, nPartSize, fileDataOut, 0, bUse32BitIdentifier)) {
		if (nHashsToWrite*(HASHSIZE+(bUse32BitIdentifier? 4u:2u)) != fileDataOut->GetPosition() - nCheckFilePos) {
			wxFAIL;
			AddDebugLogLineN( logSHAHashSet,
				CFormat(wxT("Created RecoveryData has wrong length. File: %s")) % m_pOwner->GetFileName() );
			bResult = false;
			SetStatus(AICH_ERROR);
		} else {
			bResult = true;
		}
	} else {
		AddDebugLogLineN(logSHAHashSet,
			CFormat(wxT("Failed to create RecoveryData for '%s'")) % m_pOwner->GetFileName());
		bResult = false;
		SetStatus(AICH_ERROR);
	}
	if (!bUse32BitIdentifier) {
		fileDataOut->WriteUInt16(0); // no 32bit hashs to write
	}

	if (!bDbgDontLoad) {
		FreeHashSet();
	}
	return bResult;
}
Beispiel #2
0
bool CAICHRecoveryHashSet::CreatePartRecoveryData(uint64 nPartStartPos, CFileDataIO* fileDataOut, bool bDbgDontLoad){
	ASSERT( m_pOwner );
	if (m_pOwner->IsPartFile() || m_eStatus != AICH_HASHSETCOMPLETE){
		ASSERT( false );
		return false;
	}
	if (m_pHashTree.m_nDataSize <= EMBLOCKSIZE){
		ASSERT( false );
		return false;
	}
	if (!bDbgDontLoad){
		if (!LoadHashSet()){
			theApp.QueueDebugLogLine(/*DLP_VERYHIGH,*/ false, _T("Created RecoveryData error: failed to load hashset (file: %s)"), m_pOwner->GetFileName() );
			SetStatus(AICH_ERROR);
			return false;
		}
	}
	bool bResult;
	uint8 nLevel = 0;
	uint32 nPartSize = (uint32)min(PARTSIZE, (uint64)m_pOwner->GetFileSize()-nPartStartPos);
	m_pHashTree.FindHash(nPartStartPos, nPartSize,&nLevel);
	uint16 nHashsToWrite = (uint16)((nLevel-1) + nPartSize/EMBLOCKSIZE + ((nPartSize % EMBLOCKSIZE != 0 )? 1:0));
	const bool bUse32BitIdentifier = m_pOwner->IsLargeFile();

	if (bUse32BitIdentifier)
		fileDataOut->WriteUInt16(0); // no 16bit hashs to write
	fileDataOut->WriteUInt16(nHashsToWrite);
	uint32 nCheckFilePos = (UINT)fileDataOut->GetPosition();
	if (m_pHashTree.CreatePartRecoveryData(nPartStartPos, nPartSize, fileDataOut, 0, bUse32BitIdentifier)){
		if (nHashsToWrite*(HASHSIZE+(bUse32BitIdentifier? 4:2)) != fileDataOut->GetPosition() - nCheckFilePos){
			ASSERT( false );
			theApp.QueueDebugLogLine(/*DLP_VERYHIGH,*/ false, _T("Created RecoveryData has wrong length (file: %s)"), m_pOwner->GetFileName() );
			bResult = false;
			SetStatus(AICH_ERROR);
		}
		else
			bResult = true;
	}
	else{
		theApp.QueueDebugLogLine(/*DLP_VERYHIGH,*/ false, _T("Failed to create RecoveryData for %s"), m_pOwner->GetFileName() );
		bResult = false;
		SetStatus(AICH_ERROR);
	}
	if (!bUse32BitIdentifier)
		fileDataOut->WriteUInt16(0); // no 32bit hashs to write

	if (!bDbgDontLoad){
		FreeHashSet();
	}
	return bResult;
}
Beispiel #3
0
void CAICHRecoveryHashSet::UntrustedHashReceived(const CAICHHash& Hash, uint32 dwFromIP){
	switch(GetStatus()){
		case AICH_EMPTY:
		case AICH_UNTRUSTED:
		case AICH_TRUSTED:
			break;
		default:
			return;
	}
	bool bFound = false;
	bool bAdded = false;
	for (int i = 0; i < m_aUntrustedHashs.GetCount(); i++){
		if (m_aUntrustedHashs[i].m_Hash == Hash){
			bAdded = m_aUntrustedHashs[i].AddSigningIP(dwFromIP, false);
			bFound = true;
			break;
		}
	}
	if (!bFound)
	{
		for (int i = 0; i < m_aUntrustedHashs.GetCount(); i++)
		{
			if (!m_aUntrustedHashs[i].AddSigningIP(dwFromIP, true))
			{
				AddDebugLogLine(DLP_LOW, false, _T("Received different AICH hashs for file %s from IP/20 %s, ignored"), (m_pOwner != NULL) ? m_pOwner->GetFileName() : _T(""), dwFromIP); 
				// nothing changed, so we can return early without any rechecks
				return;
			}
		}
		bAdded = true;
		CAICHUntrustedHash uhToAdd;
		uhToAdd.m_Hash = Hash;
		uhToAdd.AddSigningIP(dwFromIP, false);
		m_aUntrustedHashs.Add(uhToAdd);
	}

	uint32 nSigningIPsTotal = 0;	// unique clients who send us a hash
	int nMostTrustedPos = (-1);  // the hash which most clients send us
	uint32 nMostTrustedIPs = 0;
	for (uint32 i = 0; i < (uint32)m_aUntrustedHashs.GetCount(); i++){
		nSigningIPsTotal += m_aUntrustedHashs[i].m_adwIpsSigning.GetCount();
		if ((uint32)m_aUntrustedHashs[i].m_adwIpsSigning.GetCount() > nMostTrustedIPs){
			nMostTrustedIPs = m_aUntrustedHashs[i].m_adwIpsSigning.GetCount();
			nMostTrustedPos = i;
		}
	}
	if (nMostTrustedPos == (-1) || nSigningIPsTotal == 0){
		ASSERT( false );
		return;
	}
	// the check if we trust any hash
	if ( thePrefs.IsTrustingEveryHash() ||
		(nMostTrustedIPs >= MINUNIQUEIPS_TOTRUST && (100 * nMostTrustedIPs)/nSigningIPsTotal >= MINPERCENTAGE_TOTRUST)){
		//trusted
			//theApp.QueueDebugLogLine(false, _T("AICH Hash received: %s (%sadded), We have now %u hash from %u unique IPs. We trust the Hash %s from %u clients (%u%%). Added IP:%s, file: %s")
			//, Hash.GetString(), bAdded? _T(""):_T("not "), m_aUntrustedHashs.GetCount(), nSigningIPsTotal, m_aUntrustedHashs[nMostTrustedPos].m_Hash.GetString()
			//, nMostTrustedIPs, (100 * nMostTrustedIPs)/nSigningIPsTotal, ipstr(dwFromIP & 0x00F0FFFF), m_pOwner->GetFileName());
		
		SetStatus(AICH_TRUSTED);
		if (!HasValidMasterHash() || GetMasterHash() != m_aUntrustedHashs[nMostTrustedPos].m_Hash){
			SetMasterHash(m_aUntrustedHashs[nMostTrustedPos].m_Hash, AICH_TRUSTED);
			FreeHashSet();
		}
	}
	else{
		// untrusted
		//theApp.QueueDebugLogLine(false, _T("AICH Hash received: %s (%sadded), We have now %u hash from %u unique IPs. Best Hash (%s) is from %u clients (%u%%) - but we dont trust it yet. Added IP:%s, file: %s")
		//	, Hash.GetString(), bAdded? _T(""):_T("not "), m_aUntrustedHashs.GetCount(), nSigningIPsTotal, m_aUntrustedHashs[nMostTrustedPos].m_Hash.GetString()
		//	, nMostTrustedIPs, (100 * nMostTrustedIPs)/nSigningIPsTotal, ipstr(dwFromIP & 0x00F0FFFF), m_pOwner->GetFileName());
		
		SetStatus(AICH_UNTRUSTED);
		if (!HasValidMasterHash() || GetMasterHash() != m_aUntrustedHashs[nMostTrustedPos].m_Hash){
			SetMasterHash(m_aUntrustedHashs[nMostTrustedPos].m_Hash, AICH_UNTRUSTED);
			FreeHashSet();
		}
	}
}
Beispiel #4
0
// this function is only allowed to be called right after successfully calculating the hashset (!)
// will delete the hashset, after saving to free the memory
bool CAICHRecoveryHashSet::SaveHashSet(){
	if (m_eStatus != AICH_HASHSETCOMPLETE){
		ASSERT( false );
		return false;
	}
	if ( !m_pHashTree.m_bHashValid || m_pHashTree.m_nDataSize != m_pOwner->GetFileSize()){
		ASSERT( false );
		return false;
	}
	CSingleLock lockKnown2Met(&m_mutKnown2File, false);
	if (!lockKnown2Met.Lock(5000)){
		return false;
	}

	CString fullpath = thePrefs.GetMuleDirectory(EMULE_CONFIGDIR);
	fullpath.Append(KNOWN2_MET_FILENAME);
	CSafeFile file;
	CFileException fexp;
	if (!file.Open(fullpath,CFile::modeCreate|CFile::modeReadWrite|CFile::modeNoTruncate|CFile::osSequentialScan|CFile::typeBinary|CFile::shareDenyNone, &fexp)){
		if (fexp.m_cause != CFileException::fileNotFound){
			CString strError(_T("Failed to load ") KNOWN2_MET_FILENAME _T(" file"));
			TCHAR szError[MAX_CFEXP_ERRORMSG];
			if (fexp.GetErrorMessage(szError, ARRSIZE(szError))){
				strError += _T(" - ");
				strError += szError;
			}
			theApp.QueueLogLine(true, _T("%s"), strError);
		}
		return false;
	}
	try {
		//setvbuf(file.m_pStream, NULL, _IOFBF, 16384);
		uint8 header = file.ReadUInt8();
		if (header != KNOWN2_MET_VERSION){
			AfxThrowFileException(CFileException::endOfFile, 0, file.GetFileName());
		}
		// first we check if the hashset we want to write is already stored
		if (m_liAICHHashsStored.Find(m_pHashTree.m_Hash) != NULL)
		{
			theApp.QueueDebugLogLine(false, _T("AICH Hashset to write should be already present in known2.met - %s"), m_pHashTree.m_Hash.GetString());
			// this hashset if already available, no need to save it again
			return true;
		}		
		/*CAICHHash CurrentHash;	
		while (file.GetPosition() < nExistingSize){
			CurrentHash.Read(&file);
			if (m_pHashTree.m_Hash == CurrentHash){
				// this hashset if already available, no need to save it again
				return true;
			}
			nHashCount = file.ReadUInt32();
			if (file.GetPosition() + nHashCount*HASHSIZE > nExistingSize){
				AfxThrowFileException(CFileException::endOfFile, 0, file.GetFileName());
			}
			// skip the rest of this hashset
			file.Seek(nHashCount*HASHSIZE, CFile::current);
		}*/

		// write hashset
		uint32 nExistingSize = (UINT)file.GetLength();
		file.SeekToEnd();

		m_pHashTree.m_Hash.Write(&file);
		uint32 nHashCount = (uint32)((PARTSIZE/EMBLOCKSIZE + ((PARTSIZE % EMBLOCKSIZE != 0)? 1 : 0)) * (m_pHashTree.m_nDataSize/PARTSIZE));
		if (m_pHashTree.m_nDataSize % PARTSIZE != 0)
			nHashCount += (uint32)((m_pHashTree.m_nDataSize % PARTSIZE)/EMBLOCKSIZE + (((m_pHashTree.m_nDataSize % PARTSIZE) % EMBLOCKSIZE != 0)? 1 : 0));
		file.WriteUInt32(nHashCount);
		if (!m_pHashTree.WriteLowestLevelHashs(&file, 0, true, true)){
			// thats bad... really
			file.SetLength(nExistingSize);
			theApp.QueueDebugLogLine(true, _T("Failed to save HashSet: WriteLowestLevelHashs() failed!"));
			return false;
		}
		if (file.GetLength() != nExistingSize + (nHashCount+1)*HASHSIZE + 4){
			// thats even worse
			file.SetLength(nExistingSize);
			theApp.QueueDebugLogLine(true, _T("Failed to save HashSet: Calculated and real size of hashset differ!"));
			return false;
		}
		CAICHRecoveryHashSet::AddStoredAICHHash(m_pHashTree.m_Hash);
		theApp.QueueDebugLogLine(false, _T("Successfully saved eMuleAC Hashset, %u Hashs + 1 Masterhash written"), nHashCount);
	    file.Flush();
	    file.Close();
	}
	catch(CFileException* error){
		if (error->m_cause == CFileException::endOfFile)
			theApp.QueueLogLine(true, GetResString(IDS_ERR_MET_BAD), KNOWN2_MET_FILENAME);
		else{
			TCHAR buffer[MAX_CFEXP_ERRORMSG];
			error->GetErrorMessage(buffer, ARRSIZE(buffer));
			theApp.QueueLogLine(true,GetResString(IDS_ERR_SERVERMET_UNKNOWN),buffer);
		}
		error->Delete();
		return false;
	}
	FreeHashSet();
	return true;
}
Beispiel #5
0
CAICHRecoveryHashSet::~CAICHRecoveryHashSet(void)
{
	FreeHashSet();
}
Beispiel #6
0
void CAICHHashSet::UntrustedHashReceived(const CAICHHash& Hash, uint32 dwFromIP)
{
	switch(GetStatus()) {
		case AICH_EMPTY:
		case AICH_UNTRUSTED:
		case AICH_TRUSTED:
			break;
		default:
			return;
	}
	bool bFound = false;
	bool bAdded = false;
	for (uint32 i = 0; i < m_aUntrustedHashs.size(); ++i) {
		if (m_aUntrustedHashs[i].m_Hash == Hash) {
			bAdded = m_aUntrustedHashs[i].AddSigningIP(dwFromIP);
			bFound = true;
			break;
		}
	}
	if (!bFound) {
		bAdded = true;
		CAICHUntrustedHash uhToAdd;
		uhToAdd.m_Hash = Hash;
		uhToAdd.AddSigningIP(dwFromIP);
		m_aUntrustedHashs.push_back(uhToAdd);
	}

	uint32 nSigningIPsTotal = 0;	// unique clients who send us a hash
	int nMostTrustedPos = (-1);  // the hash which most clients send us
	uint32 nMostTrustedIPs = 0;
	for (uint32 i = 0; i < (uint32)m_aUntrustedHashs.size(); ++i) {
		nSigningIPsTotal += m_aUntrustedHashs[i].m_adwIpsSigning.size();
		if ((uint32)m_aUntrustedHashs[i].m_adwIpsSigning.size() > nMostTrustedIPs) {
			nMostTrustedIPs = m_aUntrustedHashs[i].m_adwIpsSigning.size();
			nMostTrustedPos = i;
		}
	}
	if (nMostTrustedPos == (-1) || nSigningIPsTotal == 0) {
		wxFAIL;
		return;
	}
	// the check if we trust any hash
	if ( thePrefs::IsTrustingEveryHash() ||
		(nMostTrustedIPs >= MINUNIQUEIPS_TOTRUST && (100 * nMostTrustedIPs)/nSigningIPsTotal >= MINPERCENTAGE_TOTRUST)) {
		//trusted
		AddDebugLogLineM(false, logSHAHashSet, 
			CFormat(wxT("AICH Hash received (%sadded), We have now %u hash(es) from %u unique IP(s). ")
			   		wxT("We trust the Hash %s from %u client(s) (%u%%). File: %s"))
				% (bAdded ? wxT("") : wxT("not "))
				% m_aUntrustedHashs.size()
				% nSigningIPsTotal
				% m_aUntrustedHashs[nMostTrustedPos].m_Hash.GetString()
				% nMostTrustedIPs
				% ((100 * nMostTrustedIPs) / nSigningIPsTotal)
				% m_pOwner->GetFileName());
			
		SetStatus(AICH_TRUSTED);
		if (!HasValidMasterHash() || GetMasterHash() != m_aUntrustedHashs[nMostTrustedPos].m_Hash) {
			SetMasterHash(m_aUntrustedHashs[nMostTrustedPos].m_Hash, AICH_TRUSTED);
			FreeHashSet();
		}
	} else {
		// untrusted
		AddDebugLogLineM(false, logSHAHashSet,
			CFormat(wxT("AICH Hash received (%sadded), We have now %u hash(es) from %u unique IP(s). ")
					wxT("Best Hash %s from %u clients (%u%%) - but we dont trust it yet. File: %s"))
				% (bAdded ? wxT(""): wxT("not "))
				% m_aUntrustedHashs.size()
				% nSigningIPsTotal
				% m_aUntrustedHashs[nMostTrustedPos].m_Hash.GetString()
				% nMostTrustedIPs
				% ((100 * nMostTrustedIPs) / nSigningIPsTotal)
				% m_pOwner->GetFileName());
					
		SetStatus(AICH_UNTRUSTED);
		if (!HasValidMasterHash() || GetMasterHash() != m_aUntrustedHashs[nMostTrustedPos].m_Hash) {
			SetMasterHash(m_aUntrustedHashs[nMostTrustedPos].m_Hash, AICH_UNTRUSTED);
			FreeHashSet();
		}
	}
}
Beispiel #7
0
// this function is only allowed to be called right after successfully calculating the hashset (!)
// will delete the hashset, after saving to free the memory
bool CAICHHashSet::SaveHashSet()
{
	if (m_eStatus != AICH_HASHSETCOMPLETE) {
		wxFAIL;
		return false;
	}
	if ( !m_pHashTree.m_bHashValid || m_pHashTree.m_nDataSize != m_pOwner->GetFileSize()) {
		wxFAIL;
		return false;
	}


	try {
		const wxString fullpath = theApp->ConfigDir + KNOWN2_MET_FILENAME;
		const bool exists = wxFile::Exists(fullpath);

		CFile file(fullpath, exists ? CFile::read_write : CFile::write);
		if (!file.IsOpened()) {
			AddDebugLogLineM( true, logSHAHashSet, wxT("Failed to save HashSet: opening met file failed!"));
			return false;
		}

		uint64 nExistingSize = file.GetLength();
		if (nExistingSize) {
			uint8 header = file.ReadUInt8();
			if (header != KNOWN2_MET_VERSION) {
				AddDebugLogLineM( true, logSHAHashSet, wxT("Saving failed: Current file is not a met-file!"));
				return false;
			}
			
			AddDebugLogLineM( false, logSHAHashSet, wxString::Format(wxT("Met file is version 0x%2.2x."),header));
		} else {
			file.WriteUInt8(KNOWN2_MET_VERSION);
			// Update the recorded size, in order for the sanity check below to work.
			nExistingSize += 1;
		}

		// first we check if the hashset we want to write is already stored
		CAICHHash CurrentHash;
		while (file.GetPosition() < nExistingSize) {
			CurrentHash.Read(&file);
			if (m_pHashTree.m_Hash == CurrentHash) {
				// this hashset if already available, no need to save it again
				return true;
			}
			uint32 nHashCount = file.ReadUInt32();
			if (file.GetPosition() + nHashCount*HASHSIZE > nExistingSize) {
				AddDebugLogLineM( true, logSHAHashSet, wxT("Saving failed: File contains fewer entries than specified!"));
				return false;
			}
			// skip the rest of this hashset
			file.Seek(nHashCount*HASHSIZE, wxFromCurrent);
		}

		// write hashset
		m_pHashTree.m_Hash.Write(&file);
		uint32 nHashCount = (PARTSIZE/EMBLOCKSIZE + ((PARTSIZE % EMBLOCKSIZE != 0)? 1 : 0)) * (m_pHashTree.m_nDataSize/PARTSIZE);
		if (m_pHashTree.m_nDataSize % PARTSIZE != 0) {
			nHashCount += (m_pHashTree.m_nDataSize % PARTSIZE)/EMBLOCKSIZE + (((m_pHashTree.m_nDataSize % PARTSIZE) % EMBLOCKSIZE != 0)? 1 : 0);
		}
		file.WriteUInt32(nHashCount);
		if (!m_pHashTree.WriteLowestLevelHashs(&file, 0, true, true)) {
			// thats bad... really
			file.SetLength(nExistingSize);
			AddDebugLogLineM( true, logSHAHashSet, wxT("Failed to save HashSet: WriteLowestLevelHashs() failed!"));
			return false;
		}
		if (file.GetLength() != nExistingSize + (nHashCount+1)*HASHSIZE + 4) {
			// thats even worse
			file.SetLength(nExistingSize);
			AddDebugLogLineM( true, logSHAHashSet, wxT("Failed to save HashSet: Calculated and real size of hashset differ!"));
			return false;
		}
		AddDebugLogLineM( false, logSHAHashSet, wxString::Format(wxT("Sucessfully saved eMuleAC Hashset, %u Hashs + 1 Masterhash written"), nHashCount));
	} catch (const CSafeIOException& e) {
		AddDebugLogLineM(true, logSHAHashSet, wxT("IO error while saving AICH HashSet: ") + e.what());
		return false;
	}
			
	FreeHashSet();
	return true;
}
Beispiel #8
0
CAICHHashSet::~CAICHHashSet(void)
{
	FreeHashSet();
}