mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-05-17 13:30:36 -04:00
- implemented post-download hash re-check. For now, if the hash does not match, the download is canceled, but in the near future, per-chunk comparison wil occur
. - corrected a bug that caused file copy error: a closeFile() was missing when the file is complete. Because of delays in fwrite, the file would not be always co mplete, nor exist at all for small files (e.g. cache files), which in the later case caused the copy error. Warning: needs a make clean in libretroshare to recompile. git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@3261 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
parent
225781aa51
commit
458a8faf70
10 changed files with 329 additions and 117 deletions
|
@ -1652,6 +1652,9 @@ bool ftController::FileDetails(std::string hash, FileInfo &info)
|
|||
if(it->second->mState == ftFileControl::PAUSED)
|
||||
info.downloadStatus = FT_STATE_PAUSED ;
|
||||
|
||||
if((!completed) && it->second->mTransfer->isCheckingHash())
|
||||
info.downloadStatus = FT_STATE_CHECKING_HASH ;
|
||||
|
||||
info.tfRate = totalRate;
|
||||
info.size = (it->second)->mSize;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <util/rsdiscspace.h>
|
||||
#include <util/rsdir.h>
|
||||
|
||||
/*******
|
||||
* #define FILE_DEBUG 1
|
||||
|
@ -102,50 +103,62 @@ bool ftFileCreator::addFileData(uint64_t offset, uint32_t chunk_size, void *data
|
|||
if(!RsDiscSpace::checkForDiscSpace(RS_PARTIALS_DIRECTORY))
|
||||
return false ;
|
||||
|
||||
RsStackMutex stack(ftcMutex); /********** STACK LOCKED MTX ******/
|
||||
|
||||
if (fd == NULL)
|
||||
if (!locked_initializeFileAttrs())
|
||||
return false;
|
||||
|
||||
/*
|
||||
* check its at the correct location
|
||||
*/
|
||||
if (offset + chunk_size > mSize)
|
||||
bool complete = false ;
|
||||
{
|
||||
chunk_size = mSize - offset;
|
||||
std::cerr <<"Chunk Size greater than total file size, adjusting chunk " << "size " << chunk_size << std::endl;
|
||||
RsStackMutex stack(ftcMutex); /********** STACK LOCKED MTX ******/
|
||||
|
||||
}
|
||||
if (fd == NULL)
|
||||
if (!locked_initializeFileAttrs())
|
||||
return false;
|
||||
|
||||
/*
|
||||
* go to the offset of the file
|
||||
*/
|
||||
if (0 != fseeko64(this->fd, offset, SEEK_SET))
|
||||
{
|
||||
std::cerr << "ftFileCreator::addFileData() Bad fseek at offset " << offset << ", fd=" << (void*)(this->fd) << ", size=" << mSize << ", errno=" << errno << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (1 != fwrite(data, chunk_size, 1, this->fd))
|
||||
{
|
||||
std::cerr << "ftFileCreator::addFileData() Bad fwrite." << std::endl;
|
||||
std::cerr << "ERRNO: " << errno << std::endl;
|
||||
/*
|
||||
* check its at the correct location
|
||||
*/
|
||||
if (offset + chunk_size > mSize)
|
||||
{
|
||||
chunk_size = mSize - offset;
|
||||
std::cerr <<"Chunk Size greater than total file size, adjusting chunk " << "size " << chunk_size << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* go to the offset of the file
|
||||
*/
|
||||
if (0 != fseeko64(this->fd, offset, SEEK_SET))
|
||||
{
|
||||
std::cerr << "ftFileCreator::addFileData() Bad fseek at offset " << offset << ", fd=" << (void*)(this->fd) << ", size=" << mSize << ", errno=" << errno << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (1 != fwrite(data, chunk_size, 1, this->fd))
|
||||
{
|
||||
std::cerr << "ftFileCreator::addFileData() Bad fwrite." << std::endl;
|
||||
std::cerr << "ERRNO: " << errno << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef FILE_DEBUG
|
||||
std::cerr << "ftFileCreator::addFileData() added Data...";
|
||||
std::cerr << std::endl;
|
||||
std::cerr << " pos: " << offset;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "ftFileCreator::addFileData() added Data...";
|
||||
std::cerr << std::endl;
|
||||
std::cerr << " pos: " << offset;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
/*
|
||||
* Notify ftFileChunker about chunks received
|
||||
*/
|
||||
locked_notifyReceived(offset,chunk_size);
|
||||
/*
|
||||
* Notify ftFileChunker about chunks received
|
||||
*/
|
||||
locked_notifyReceived(offset,chunk_size);
|
||||
|
||||
complete = chunkMap.isComplete();
|
||||
}
|
||||
if(complete)
|
||||
{
|
||||
#ifdef FILE_DEBUG
|
||||
std::cerr << "ftFileCreator::addFileData() File is complete: closing" << std::endl ;
|
||||
#endif
|
||||
closeFile();
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME HANDLE COMPLETION HERE - Any better way?
|
||||
*/
|
||||
|
@ -451,3 +464,17 @@ bool ftFileCreator::finished()
|
|||
return chunkMap.isComplete() ;
|
||||
}
|
||||
|
||||
bool ftFileCreator::hashReceivedData(std::string& hash)
|
||||
{
|
||||
RsStackMutex stack(ftcMutex) ;
|
||||
|
||||
return RsDirUtil::hashFile(file_name,hash) ;
|
||||
}
|
||||
|
||||
#include <stdexcept>
|
||||
bool ftFileCreator::crossCheckChunkMap(const CRC32Map& ref)
|
||||
{
|
||||
// still to be implemented.
|
||||
throw std::runtime_error(std::string("Unimplemented function ") + __PRETTY_FUNCTION__) ;
|
||||
return true ;
|
||||
}
|
||||
|
|
|
@ -57,6 +57,17 @@ class ftFileCreator: public ftFileProvider
|
|||
void setChunkStrategy(FileChunksInfo::ChunkStrategy s) ;
|
||||
FileChunksInfo::ChunkStrategy getChunkStrategy() ;
|
||||
|
||||
// Computes a sha1sum of the partial file, to check that the data is overall consistent.
|
||||
//
|
||||
bool hashReceivedData(std::string& hash) ;
|
||||
|
||||
// Computes a CRC32 map of all chunks, for comparison with reference, and re-starting invalid chunks.
|
||||
//
|
||||
bool CRC32ReceivedData(CRC32Map& crc_map) ;
|
||||
|
||||
// Checks the CRC32 of all chunks against the given CRC32 map. Re-flag the bad chunks as being void.
|
||||
//
|
||||
bool crossCheckChunkMap(const CRC32Map& crc_map) ;
|
||||
/*
|
||||
* creation functions for FileCreator
|
||||
*/
|
||||
|
|
|
@ -58,8 +58,12 @@ 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
|
||||
|
||||
ftTransferModule::ftTransferModule(ftFileCreator *fc, ftDataMultiplex *dm, ftController *c)
|
||||
:mFileCreator(fc), mMultiplexor(dm), mFtController(c), mFlag(0)
|
||||
:mFileCreator(fc), mMultiplexor(dm), mFtController(c), mFlag(FT_TM_FLAG_DOWNLOADING)
|
||||
{
|
||||
RsStackMutex stack(tfMtx); /******* STACK LOCKED ******/
|
||||
|
||||
|
@ -376,31 +380,37 @@ 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)
|
||||
if (mFileStatus.stat == ftFileStatus::PQIFILE_INIT)
|
||||
mFileStatus.stat = ftFileStatus::PQIFILE_DOWNLOADING;
|
||||
|
||||
if (mFileStatus.stat != ftFileStatus::PQIFILE_DOWNLOADING)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
std::map<std::string,peerInfo>::iterator mit;
|
||||
for(mit = mFileSources.begin(); mit != mFileSources.end(); mit++)
|
||||
{
|
||||
std::map<std::string,peerInfo>::iterator mit;
|
||||
for(mit = mFileSources.begin(); mit != mFileSources.end(); mit++)
|
||||
{
|
||||
locked_tickPeerTransfer(mit->second);
|
||||
}
|
||||
if(mFileCreator->finished()) // transfer is complete
|
||||
mFlag = 1;
|
||||
{
|
||||
mFileStatus.stat = ftFileStatus::PQIFILE_CHECKING ;
|
||||
mFlag = 3;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ftTransferModule::cancelTransfer()
|
||||
|
@ -411,6 +421,12 @@ bool ftTransferModule::cancelTransfer()
|
|||
return 1;
|
||||
}
|
||||
|
||||
bool ftTransferModule::cancelFileTransferUpward()
|
||||
{
|
||||
if (mFtController)
|
||||
mFtController->FileCancel(mHash);
|
||||
return true;
|
||||
}
|
||||
bool ftTransferModule::completeFileTransfer()
|
||||
{
|
||||
#ifdef FT_DEBUG
|
||||
|
@ -463,6 +479,14 @@ int ftTransferModule::tick()
|
|||
break;
|
||||
case 2: //file transfer canceled
|
||||
break;
|
||||
case 3:
|
||||
// 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
|
||||
checkCRC() ;
|
||||
break ;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -470,6 +494,67 @@ int ftTransferModule::tick()
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool ftTransferModule::isCheckingHash()
|
||||
{
|
||||
RsStackMutex stack(tfMtx); /******* STACK LOCKED ******/
|
||||
return mFlag == 3 ;
|
||||
}
|
||||
bool ftTransferModule::checkFile()
|
||||
{
|
||||
{
|
||||
RsStackMutex stack(tfMtx); /******* STACK LOCKED ******/
|
||||
#ifdef FT_DEBUG
|
||||
std::cerr << "ftTransferModule::checkFile(): checking File " << mHash << std::endl ;
|
||||
#endif
|
||||
std::string hash_check ;
|
||||
|
||||
if(!mFileCreator->hashReceivedData(hash_check))
|
||||
{
|
||||
std::cerr << "ftTransferModule::checkFile(): Impossible to hash received file " << mHash << " for check. What is happenning?" << std::endl ;
|
||||
return false ;
|
||||
}
|
||||
|
||||
if(hash_check == mHash)
|
||||
{
|
||||
mFlag = 1 ; // Transfer is complete.
|
||||
#ifdef FT_DEBUG
|
||||
std::cerr << "ftTransferModule::checkFile(): File verification complete ! Setting mFlag to 1" << std::endl ;
|
||||
#endif
|
||||
return true ;
|
||||
}
|
||||
|
||||
mFlag = 4 ; // Ask for CRC map. But for now, cancel file transfer.
|
||||
mFileStatus.stat = ftFileStatus::PQIFILE_FAIL_CANCEL ;
|
||||
}
|
||||
cancelFileTransferUpward() ;
|
||||
std::cerr << "(EE) ftTransferModule::checkFile(): File verification failed for hash " << mHash << "! Asking for CRC map. mFlag=4. For now: cancelling file transfer." << std::endl ;
|
||||
//askForCRCMap() ;
|
||||
|
||||
return false ;
|
||||
}
|
||||
|
||||
bool ftTransferModule::checkCRC()
|
||||
{
|
||||
#ifdef FT_DEBUG
|
||||
std::cerr << "ftTransferModule::checkCRC(): looking for CRC32 map." << std::endl ;
|
||||
#endif
|
||||
|
||||
if(_crc32map.empty())
|
||||
return false ;
|
||||
|
||||
#ifdef FT_DEBUG
|
||||
std::cerr << "ftTransferModule::checkCRC(): got a CRC32 map. Matching chunks..." << std::endl ;
|
||||
#endif
|
||||
|
||||
mFileCreator->crossCheckChunkMap(_crc32map) ;
|
||||
mFlag = 0 ;
|
||||
|
||||
#ifdef FT_DEBUG
|
||||
std::cerr << "ftTransferModule::checkCRC(): Done. Restarting download." << std::endl ;
|
||||
#endif
|
||||
return true ;
|
||||
}
|
||||
|
||||
|
||||
void ftTransferModule::adjustSpeed()
|
||||
{
|
||||
|
|
|
@ -106,6 +106,7 @@ public:
|
|||
PQIFILE_NOT_ONLINE,
|
||||
PQIFILE_DOWNLOADING,
|
||||
PQIFILE_COMPLETE,
|
||||
PQIFILE_CHECKING,
|
||||
PQIFILE_FAIL,
|
||||
PQIFILE_FAIL_CANCEL,
|
||||
PQIFILE_FAIL_NOT_AVAIL,
|
||||
|
@ -138,7 +139,9 @@ public:
|
|||
bool getPeerState(std::string peerId,uint32_t &state,uint32_t &tfRate);
|
||||
uint32_t getDataRate(std::string peerId);
|
||||
bool cancelTransfer();
|
||||
bool cancelFileTransferUpward();
|
||||
bool completeFileTransfer();
|
||||
bool isCheckingHash() ;
|
||||
|
||||
//interface to multiplex module
|
||||
bool recvFileData(std::string peerId, uint64_t offset,
|
||||
|
@ -164,6 +167,8 @@ private:
|
|||
bool locked_recvPeerData(peerInfo &info, uint64_t offset,
|
||||
uint32_t chunk_size, void *data);
|
||||
|
||||
bool checkFile() ;
|
||||
bool checkCRC() ;
|
||||
|
||||
/* These have independent Mutexes / are const locally (no Mutex protection)*/
|
||||
ftFileCreator *mFileCreator;
|
||||
|
@ -178,10 +183,12 @@ private:
|
|||
std::list<std::string> mOnlinePeers;
|
||||
std::map<std::string,peerInfo> mFileSources;
|
||||
|
||||
uint16_t mFlag; //2:file canceled, 1:transfer complete, 0: not complete
|
||||
uint16_t mFlag; //2:file canceled, 1:transfer complete, 0: not complete, 3: checking hash, 4: checking chunks
|
||||
double desiredRate;
|
||||
double actualRate;
|
||||
|
||||
CRC32Map _crc32map ;
|
||||
|
||||
ftFileStatus mFileStatus; //used for pause/resume file transfer
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue