- 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:
csoler 2010-07-06 05:04:11 +00:00
parent 225781aa51
commit 458a8faf70
10 changed files with 329 additions and 117 deletions

View file

@ -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;

View file

@ -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 ;
}

View file

@ -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
*/

View file

@ -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()
{

View file

@ -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
};