diff --git a/libretroshare/src/ft/ftcontroller.cc b/libretroshare/src/ft/ftcontroller.cc index 0f92f6f64..a466a9173 100644 --- a/libretroshare/src/ft/ftcontroller.cc +++ b/libretroshare/src/ft/ftcontroller.cc @@ -1395,7 +1395,7 @@ bool ftController::FileCancel(std::string hash) return true; } -bool ftController::FileControl(std::string hash, uint32_t flags) +bool ftController::FileControl(const std::string& hash, uint32_t flags) { //#ifdef CONTROL_DEBUG std::cerr << "ftController::FileControl(" << hash << ","; diff --git a/libretroshare/src/ft/ftcontroller.h b/libretroshare/src/ft/ftcontroller.h index 87d05ff09..c9054d013 100644 --- a/libretroshare/src/ft/ftcontroller.h +++ b/libretroshare/src/ft/ftcontroller.h @@ -70,7 +70,8 @@ class ftFileControl COMPLETED = 1, ERROR_COMPLETION = 2, QUEUED = 3, - PAUSED = 4 + PAUSED = 4, + CHECKING_HASH = 5 }; ftFileControl(); @@ -150,7 +151,7 @@ class ftController: public CacheTransfer, public RsThread, public pqiMonitor, pu void setFreeDiskSpaceLimit(uint32_t size_in_mb) ; bool FileCancel(std::string hash); - bool FileControl(std::string hash, uint32_t flags); + bool FileControl(const std::string& hash, uint32_t flags); bool FileClearCompleted(); bool FlagFileComplete(std::string hash); bool getFileDownloadChunksDetails(const std::string& hash,FileChunksInfo& info); diff --git a/libretroshare/src/ft/ftfilecreator.cc b/libretroshare/src/ft/ftfilecreator.cc index 3ce60451d..7927c6d30 100644 --- a/libretroshare/src/ft/ftfilecreator.cc +++ b/libretroshare/src/ft/ftfilecreator.cc @@ -466,8 +466,12 @@ bool ftFileCreator::finished() bool ftFileCreator::hashReceivedData(std::string& hash) { - RsStackMutex stack(ftcMutex) ; - + // csoler: No mutex here please ! + // + // This is a bit dangerous, but otherwise we might stuck the GUI for a + // long time. Therefore, we must pay attention not to call this function + // at a time file_name nor hash can be modified, which is easy. + // return RsDirUtil::hashFile(file_name,hash) ; } diff --git a/libretroshare/src/ft/ftfilecreator.h b/libretroshare/src/ft/ftfilecreator.h index a5a60affe..1fef63a54 100644 --- a/libretroshare/src/ft/ftfilecreator.h +++ b/libretroshare/src/ft/ftfilecreator.h @@ -58,7 +58,10 @@ class ftFileCreator: public ftFileProvider FileChunksInfo::ChunkStrategy getChunkStrategy() ; // Computes a sha1sum of the partial file, to check that the data is overall consistent. - // + // This function is not mutexed. This is a bit dangerous, but otherwise we might stuck the GUI for a + // long time. Therefore, we must pay attention not to call this function + // at a time file_name nor hash can be modified, which is quite easy. + bool hashReceivedData(std::string& hash) ; // Computes a CRC32 map of all chunks, for comparison with reference, and re-starting invalid chunks. diff --git a/libretroshare/src/ft/fttransfermodule.cc b/libretroshare/src/ft/fttransfermodule.cc index 35c5da9f0..a497da822 100644 --- a/libretroshare/src/ft/fttransfermodule.cc +++ b/libretroshare/src/ft/fttransfermodule.cc @@ -27,6 +27,7 @@ * #define FT_DEBUG 1 *****/ +#define FT_DEBUG 1 #include "fttransfermodule.h" /************************************************************************* @@ -58,9 +59,11 @@ const int32_t FT_TM_FAST_RTT = 1.0; const int32_t FT_TM_STD_RTT = 5.0; const int32_t FT_TM_SLOW_RTT = 9.0; -#define FT_TM_FLAG_DOWNLOADING 0 -#define FT_TM_FLAG_CHECKING 3 -#define FT_TM_FLAG_CHECKING 3 +#define FT_TM_FLAG_DOWNLOADING 0 +#define FT_TM_FLAG_CANCELED 1 +#define FT_TM_FLAG_COMPLETE 2 +#define FT_TM_FLAG_CHECKING 3 +#define FT_TM_FLAG_CHUNK_CRC 4 ftTransferModule::ftTransferModule(ftFileCreator *fc, ftDataMultiplex *dm, ftController *c) :mFileCreator(fc), mMultiplexor(dm), mFtController(c), mFlag(FT_TM_FLAG_DOWNLOADING) @@ -69,7 +72,9 @@ ftTransferModule::ftTransferModule(ftFileCreator *fc, ftDataMultiplex *dm, ftCon mHash = mFileCreator->getHash(); mSize = mFileCreator->getFileSize(); - mFileStatus.hash = mHash; + mFileStatus.hash = mHash; + + _hash_thread = NULL ; // Dummy for Testing (should be handled independantly for // each peer. @@ -380,34 +385,36 @@ bool ftTransferModule::queryInactive() { /* NB: Not sure about this lock... might cause deadlock. */ - RsStackMutex stack(tfMtx); /******* STACK LOCKED ******/ + { + RsStackMutex stack(tfMtx); /******* STACK LOCKED ******/ #ifdef FT_DEBUG - std::cerr << "ftTransferModule::queryInactive()" << std::endl; + std::cerr << "ftTransferModule::queryInactive()" << std::endl; #endif - if (mFileStatus.stat == ftFileStatus::PQIFILE_INIT) - mFileStatus.stat = ftFileStatus::PQIFILE_DOWNLOADING; + if (mFileStatus.stat == ftFileStatus::PQIFILE_INIT) + mFileStatus.stat = ftFileStatus::PQIFILE_DOWNLOADING; - if (mFileStatus.stat == ftFileStatus::PQIFILE_CHECKING) - return false ; + if (mFileStatus.stat == ftFileStatus::PQIFILE_CHECKING) + return false ; - if (mFileStatus.stat != ftFileStatus::PQIFILE_DOWNLOADING) - { - if (mFileStatus.stat == ftFileStatus::PQIFILE_FAIL_CANCEL) - mFlag = 2; //file canceled by user - return false; - } + if (mFileStatus.stat != ftFileStatus::PQIFILE_DOWNLOADING) + { + if (mFileStatus.stat == ftFileStatus::PQIFILE_FAIL_CANCEL) + mFlag = FT_TM_FLAG_COMPLETE; //file canceled by user + return false; + } - std::map::iterator mit; - for(mit = mFileSources.begin(); mit != mFileSources.end(); mit++) - { - locked_tickPeerTransfer(mit->second); - } - if(mFileCreator->finished()) // transfer is complete - { - mFileStatus.stat = ftFileStatus::PQIFILE_CHECKING ; - mFlag = 3; + std::map::iterator mit; + for(mit = mFileSources.begin(); mit != mFileSources.end(); mit++) + { + locked_tickPeerTransfer(mit->second); + } + if(mFileCreator->finished()) // transfer is complete + { + mFileStatus.stat = ftFileStatus::PQIFILE_CHECKING ; + mFlag = FT_TM_FLAG_CHECKING; + } } return true; @@ -471,20 +478,18 @@ int ftTransferModule::tick() switch (flags) { - case 0: //file transfer not complete + case FT_TM_FLAG_DOWNLOADING: //file transfer not complete adjustSpeed(); break; - case 1: //file transfer complete + case FT_TM_FLAG_COMPLETE: //file transfer complete completeFileTransfer(); break; - case 2: //file transfer canceled + case FT_TM_FLAG_CANCELED: //file transfer canceled break; - case 3: - // Check if file hash matches the hashed data + case FT_TM_FLAG_CHECKING: // Check if file hash matches the hashed data checkFile() ; break ; - case 4: - // File is waiting for CRC32 map. Check if received, and re-set matched chunks + case FT_TM_FLAG_CHUNK_CRC: // File is waiting for CRC32 map. Check if received, and re-set matched chunks checkCRC() ; break ; default: @@ -497,8 +502,42 @@ int ftTransferModule::tick() bool ftTransferModule::isCheckingHash() { RsStackMutex stack(tfMtx); /******* STACK LOCKED ******/ - return mFlag == 3 ; +#ifdef FT_DEBUG + std::cerr << "isCheckingHash(): mFlag=" << mFlag << std::endl; +#endif + return mFlag == FT_TM_FLAG_CHECKING ; } + +class HashThread: public RsThread +{ + public: + HashThread(ftFileCreator *m) + : _m(m),_finished(false),_hash("") {} + + virtual void run() + { + _m->hashReceivedData(_hash) ; + + RsStackMutex stack(_hashThreadMtx) ; + _finished = true ; + } + std::string hash() + { + RsStackMutex stack(_hashThreadMtx) ; + return _hash ; + } + bool finished() + { + RsStackMutex stack(_hashThreadMtx) ; + return _finished ; + } + private: + RsMutex _hashThreadMtx ; + ftFileCreator *_m ; + bool _finished ; + std::string _hash ; +}; + bool ftTransferModule::checkFile() { { @@ -506,24 +545,42 @@ bool ftTransferModule::checkFile() #ifdef FT_DEBUG std::cerr << "ftTransferModule::checkFile(): checking File " << mHash << std::endl ; #endif - std::string hash_check ; - if(!mFileCreator->hashReceivedData(hash_check)) + // if we don't have a hashing thread, create one. + + if(_hash_thread == NULL) { - std::cerr << "ftTransferModule::checkFile(): Impossible to hash received file " << mHash << " for check. What is happenning?" << std::endl ; + // Note: using new is really important to avoid copy and write errors in the thread. + // + _hash_thread = new HashThread(mFileCreator) ; + _hash_thread->start() ; +#ifdef FT_DEBUG + std::cerr << "ftTransferModule::checkFile(): launched hashing thread for file " << mHash << std::endl ; +#endif return false ; } - if(hash_check == mHash) + if(!_hash_thread->finished()) { - mFlag = 1 ; // Transfer is complete. #ifdef FT_DEBUG - std::cerr << "ftTransferModule::checkFile(): File verification complete ! Setting mFlag to 1" << std::endl ; + std::cerr << "ftTransferModule::checkFile(): file " << mHash << " is being hashed.?" << std::endl ; #endif + return false ; + } + + if(_hash_thread->hash() == mHash) + { + mFlag = FT_TM_FLAG_COMPLETE ; // Transfer is complete. +#ifdef FT_DEBUG + std::cerr << "ftTransferModule::checkFile(): hash finished. File verification complete ! Setting mFlag to 1" << std::endl ; +#endif + delete _hash_thread ; + _hash_thread = NULL ; return true ; } - mFlag = 4 ; // Ask for CRC map. But for now, cancel file transfer. + delete _hash_thread ; + mFlag = FT_TM_FLAG_CHUNK_CRC ; // Ask for CRC map. But for now, cancel file transfer. mFileStatus.stat = ftFileStatus::PQIFILE_FAIL_CANCEL ; } cancelFileTransferUpward() ; @@ -547,7 +604,7 @@ bool ftTransferModule::checkCRC() #endif mFileCreator->crossCheckChunkMap(_crc32map) ; - mFlag = 0 ; + mFlag = FT_TM_FLAG_DOWNLOADING ; #ifdef FT_DEBUG std::cerr << "ftTransferModule::checkCRC(): Done. Restarting download." << std::endl ; diff --git a/libretroshare/src/ft/fttransfermodule.h b/libretroshare/src/ft/fttransfermodule.h index 2d80e290e..d79e77aed 100644 --- a/libretroshare/src/ft/fttransfermodule.h +++ b/libretroshare/src/ft/fttransfermodule.h @@ -51,6 +51,8 @@ const uint32_t PQIPEER_DOWNLOADING = 0x0002; const uint32_t PQIPEER_IDLE = 0x0004; const uint32_t PQIPEER_SUSPEND = 0x0010; +class HashThread ; + class peerInfo { public: @@ -190,6 +192,8 @@ private: CRC32Map _crc32map ; ftFileStatus mFileStatus; //used for pause/resume file transfer + + HashThread *_hash_thread ; }; #endif //FT_TRANSFER_MODULE_HEADER diff --git a/libretroshare/src/rsiface/rsfiles.h b/libretroshare/src/rsiface/rsfiles.h index 09ccc354e..4a78b8051 100644 --- a/libretroshare/src/rsiface/rsfiles.h +++ b/libretroshare/src/rsiface/rsfiles.h @@ -39,8 +39,9 @@ extern RsFiles *rsFiles; class Expression; /* These are used mainly by ftController at the moment */ -const uint32_t RS_FILE_CTRL_PAUSE = 0x00000100; -const uint32_t RS_FILE_CTRL_START = 0x00000200; +const uint32_t RS_FILE_CTRL_PAUSE = 0x00000100; +const uint32_t RS_FILE_CTRL_START = 0x00000200; +const uint32_t RS_FILE_CTRL_FORCE_CHECK = 0x00000400; const uint32_t RS_FILE_RATE_TRICKLE = 0x00000001; const uint32_t RS_FILE_RATE_SLOW = 0x00000002;