// // This file is part of the aMule Project. // // Copyright (c) 2003-2006 Angel Vidal (Kry) ( kry@amule.org ) // Copyright (c) 2003-2006 aMule Team ( admin@amule.org / http://www.amule.org ) // Copyright (c) 2002-2004 Merkur ( devs@emule-project.net / http://www.emule-project.net ) // // Any parts of this program derived from the xMule, lMule or eMule project, // or contributed by third-party developers are copyrighted by their // respective authors. // // 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA // #include "AICHSyncThread.h" #include // Needed for unicode2char #include "SHAHashSet.h" #include "CFile.h" // Needed for CFile #include "KnownFile.h" #include "SHA.h" #include "amule.h" #include "SharedFileList.h" #include "KnownFileList.h" #include "Preferences.h" #include "Logger.h" #include #include #include wxMutex CAICHSyncThread::s_mutex; CAICHSyncThread* CAICHSyncThread::s_thread; bool CAICHSyncThread::Start() { wxMutexLocker lock( s_mutex ); // Check if the hasher is running already. if ( s_thread ) { AddDebugLogLineM( true, logAICHThread, wxT("Start() called while thread is active!") ); return false; } s_thread = new CAICHSyncThread(); wxThreadError state = s_thread->Create(); if (state != wxTHREAD_NO_ERROR) { AddDebugLogLineM(true, logAICHThread, wxString::Format(wxT("Error while creating AICH thread: %d"), state)); // Delete() must be called in this case acording to the docs. s_thread->Delete(); delete s_thread; s_thread = NULL; return false; } // The threads shouldn't be hugging the CPU, as it will already be hugging the HD s_thread->SetPriority(WXTHREAD_MIN_PRIORITY); state = s_thread->Run(); if (state != wxTHREAD_NO_ERROR) { AddDebugLogLineM(true, logAICHThread, wxString::Format(wxT("Error while attempting to run AICH thread: %d"), state)); // Delete() must be called in this case acording to the docs. s_thread->Delete(); delete s_thread; s_thread = NULL; return false; } return true; } bool CAICHSyncThread::Stop() { { wxMutexLocker lock(s_mutex); // Are there any threads to kill? if ( !s_thread ) { AddDebugLogLineM( true, logAICHThread, wxT("Warning, attempted to stop non-existing thread!") ); return false; } AddLogLineM( false, _("AICH Thread: Signaling for thread to terminate.") ); // Tell the thread to terminate, this function returns immediatly s_thread->Delete(); } // Wait for all threads to die while ( IsRunning() ) { // Sleep for 1/100 of a second to avoid clobbering the mutex MilliSleep(10); // Flush any pending log-entries caused by the thread. CLogger::FlushPendingEntries(); } return true; } bool CAICHSyncThread::IsRunning() { wxMutexLocker lock( s_mutex ); return s_thread; } CAICHSyncThread::CAICHSyncThread() : wxThread( wxTHREAD_DETACHED ) { } CAICHSyncThread::~CAICHSyncThread() { wxMutexLocker lock( s_mutex ); s_thread = NULL; AddLogLineM( false, _("AICH Thread: Terminated.") ); } void* CAICHSyncThread::Entry() { AddLogLineM( false, _("AICH Thread: Syncronization thread started.") ); // We collect all masterhashs which we find in the known2.met and store them in a list typedef std::list HashList; HashList hashlist; wxString fullpath = theApp.ConfigDir + KNOWN2_MET_FILENAME; CFile file; if ( wxFileExists( fullpath ) ) { if ( !file.Open( fullpath, CFile::read_write ) ) { AddDebugLogLineM( true, logAICHThread, wxT("Error, failed to open hashlist file!") ); return 0; } } else { if (!file.Create(fullpath)) { AddDebugLogLineM( true, logAICHThread, wxT("Error, failed to create hashlist file!") ); return 0; } } try { while ( !file.Eof() ) { // Read the next hash hashlist.push_back( CAICHHash( &file ) ); // skip the rest of this hashset uint16 nHashCount = file.ReadUInt16(); file.Seek( nHashCount * HASHSIZE, wxFromCurrent ); } } catch (const CEOFException&) { AddDebugLogLineM(true, logAICHThread, wxT("Hashlist corrupted, removing file.")); file.Close(); wxRemoveFile(fullpath); return 0; } catch (const CIOFailureException& e) { AddDebugLogLineM(true, logAICHThread, wxT("IO failure while reading hashlist (Aborting): ") + e.what()); return 0; } file.Close(); AddLogLineM( false, _("AICH Thread: Masterhashes of known files have been loaded.") ); std::list queue; // Now we check that all files which are in the sharedfilelist have a corresponding hash in our list // those how don't are added to the hashinglist for ( uint32 i = 0; i < theApp.sharedfiles->GetCount(); ++i) { // Check for termination if ( TestDestroy() ) { return 0; } const CKnownFile* cur_file = theApp.sharedfiles->GetFileByIndex(i); if ( cur_file && !cur_file->IsPartFile() ) { CAICHHashSet* hashset = cur_file->GetAICHHashset(); if ( hashset->GetStatus() == AICH_HASHSETCOMPLETE ) { HashList::iterator it = std::find( hashlist.begin(), hashlist.end(), hashset->GetMasterHash() ); if ( it != hashlist.end() ) continue; } hashset->SetStatus( AICH_ERROR ); queue.push_back( (CKnownFile*)cur_file ); } } if ( !queue.empty() ) { AddLogLineM( false, wxString::Format( _("AICH Thread: Starting to hash files. %li files found."), (long int)queue.size() ) ); while ( !queue.empty() && !TestDestroy() ) { CKnownFile* pCurFile = queue.front(); queue.pop_front(); AddLogLineM( false, CFormat( _("AICH Thread: Hashing file: %s, total files left: %li") ) % pCurFile->GetFileName() % queue.size() ); // Just to be sure that the file hasnt been deleted lately if ( !(theApp.knownfiles->IsKnownFile(pCurFile) && theApp.sharedfiles->GetFileByID(pCurFile->GetFileHash())) ) continue; if ( !pCurFile->CreateAICHHashSetOnly() ) { AddDebugLogLineM( true, logAICHThread, wxT("Failed to create hashset for file ") + pCurFile->GetFileName() ); } } AddLogLineM( false, _("AICH Thread: Hashing completed.") ); } else { AddLogLineM( false, _("AICH Thread: No new files found.") ); } return 0; }