Merge pull request #808 from csoler/v0.6-FT

added a per-friend upload slots limit in FT. Default is 0=unlimited
This commit is contained in:
csoler 2017-05-08 22:02:38 +02:00 committed by GitHub
commit 4a2f5f0f82
8 changed files with 143 additions and 5 deletions

View File

@ -75,6 +75,7 @@ static const int32_t INACTIVE_CHUNKS_CHECK_DELAY = 240 ; // time after which an
static const int32_t MAX_TIME_INACTIVE_REQUEUED = 120 ; // time after which an inactive ftFileControl is bt-queued static const int32_t MAX_TIME_INACTIVE_REQUEUED = 120 ; // time after which an inactive ftFileControl is bt-queued
static const int32_t FT_FILECONTROL_QUEUE_ADD_END = 0 ; static const int32_t FT_FILECONTROL_QUEUE_ADD_END = 0 ;
static const int32_t FT_FILECONTROL_MAX_UPLOAD_SLOTS_DEFAULT= 0 ;
const uint32_t FT_CNTRL_STANDARD_RATE = 10 * 1024 * 1024; const uint32_t FT_CNTRL_STANDARD_RATE = 10 * 1024 * 1024;
const uint32_t FT_CNTRL_SLOW_RATE = 100 * 1024; const uint32_t FT_CNTRL_SLOW_RATE = 100 * 1024;
@ -113,6 +114,7 @@ ftController::ftController(ftDataMultiplex *dm, p3ServiceControl *sc, uint32_t f
{ {
_max_active_downloads = 5 ; // default queue size _max_active_downloads = 5 ; // default queue size
mDefaultEncryptionPolicy = RS_FILE_CTRL_ENCRYPTION_POLICY_PERMISSIVE; mDefaultEncryptionPolicy = RS_FILE_CTRL_ENCRYPTION_POLICY_PERMISSIVE;
_max_uploads_per_friend = FT_FILECONTROL_MAX_UPLOAD_SLOTS_DEFAULT ;
/* TODO */ /* TODO */
cnt = 0 ; cnt = 0 ;
} }
@ -239,8 +241,8 @@ void ftController::data_tick()
{ {
RsStackMutex stack(ctrlMutex); /******* LOCKED ********/ RsStackMutex stack(ctrlMutex); /******* LOCKED ********/
for(std::map<RsFileHash,ftFileControl*>::iterator it(mDownloads.begin());it!=mDownloads.end();++it) for(std::map<RsFileHash,ftFileControl*>::iterator it(mDownloads.begin());it!=mDownloads.end();++it)
it->second->mCreator->removeInactiveChunks() ; it->second->mCreator->removeInactiveChunks() ;
last_clean_time = now ; last_clean_time = now ;
} }
@ -1723,6 +1725,7 @@ void ftController::statusChange(const std::list<pqiServicePeer> &plist)
const std::string active_downloads_size_ss("MAX_ACTIVE_DOWNLOADS"); const std::string active_downloads_size_ss("MAX_ACTIVE_DOWNLOADS");
const std::string download_dir_ss("DOWN_DIR"); const std::string download_dir_ss("DOWN_DIR");
const std::string partial_dir_ss("PART_DIR"); const std::string partial_dir_ss("PART_DIR");
const std::string max_uploads_per_friend_ss("MAX_UPLOADS_PER_FRIEND");
const std::string default_chunk_strategy_ss("DEFAULT_CHUNK_STRATEGY"); const std::string default_chunk_strategy_ss("DEFAULT_CHUNK_STRATEGY");
const std::string free_space_limit_ss("FREE_SPACE_LIMIT"); const std::string free_space_limit_ss("FREE_SPACE_LIMIT");
const std::string default_encryption_policy_ss("DEFAULT_ENCRYPTION_POLICY"); const std::string default_encryption_policy_ss("DEFAULT_ENCRYPTION_POLICY");
@ -1771,6 +1774,9 @@ bool ftController::saveList(bool &cleanup, std::list<RsItem *>& saveData)
break ; break ;
} }
rs_sprintf(s,"%lu",_max_uploads_per_friend) ;
configMap[max_uploads_per_friend_ss] = s ;
configMap[default_encryption_policy_ss] = (mDefaultEncryptionPolicy==RS_FILE_CTRL_ENCRYPTION_POLICY_PERMISSIVE)?"PERMISSIVE":"STRICT" ; configMap[default_encryption_policy_ss] = (mDefaultEncryptionPolicy==RS_FILE_CTRL_ENCRYPTION_POLICY_PERMISSIVE)?"PERMISSIVE":"STRICT" ;
rs_sprintf(s, "%lu", RsDiscSpace::freeSpaceLimit()); rs_sprintf(s, "%lu", RsDiscSpace::freeSpaceLimit());
@ -2057,9 +2063,29 @@ bool ftController::loadConfigMap(std::map<std::string, std::string> &configMap)
RsDiscSpace::setFreeSpaceLimit(size) ; RsDiscSpace::setFreeSpaceLimit(size) ;
} }
} }
if(configMap.end() != (mit = configMap.find(max_uploads_per_friend_ss)))
{
uint32_t n ;
if (sscanf(mit->second.c_str(), "%u", &n) == 1) {
std::cerr << "have read a max upload slots limit of " << n << std::endl ;
_max_uploads_per_friend = n ;
}
}
return true; return true;
} }
void ftController::setMaxUploadsPerFriend(uint32_t m)
{
RsStackMutex stack(ctrlMutex); /******* LOCKED ********/
_max_uploads_per_friend = m ;
IndicateConfigChanged();
}
uint32_t ftController::getMaxUploadsPerFriend()
{
RsStackMutex stack(ctrlMutex); /******* LOCKED ********/
return _max_uploads_per_friend ;
}
void ftController::setDefaultEncryptionPolicy(uint32_t p) void ftController::setDefaultEncryptionPolicy(uint32_t p)
{ {
RsStackMutex stack(ctrlMutex); /******* LOCKED ********/ RsStackMutex stack(ctrlMutex); /******* LOCKED ********/

View File

@ -146,6 +146,9 @@ class ftController: public RsTickingThread, public pqiServiceMonitor, public p3C
void setFreeDiskSpaceLimit(uint32_t size_in_mb) ; void setFreeDiskSpaceLimit(uint32_t size_in_mb) ;
uint32_t defaultEncryptionPolicy(); uint32_t defaultEncryptionPolicy();
void setMaxUploadsPerFriend(uint32_t m) ;
uint32_t getMaxUploadsPerFriend() ;
bool FileCancel(const RsFileHash& hash); bool FileCancel(const RsFileHash& hash);
bool FileControl(const RsFileHash& hash, uint32_t flags); bool FileControl(const RsFileHash& hash, uint32_t flags);
bool FileClearCompleted(); bool FileClearCompleted();
@ -261,7 +264,8 @@ class ftController: public RsTickingThread, public pqiServiceMonitor, public p3C
FileChunksInfo::ChunkStrategy mDefaultChunkStrategy ; FileChunksInfo::ChunkStrategy mDefaultChunkStrategy ;
uint32_t _max_active_downloads ; // maximum number of simultaneous downloads uint32_t _max_active_downloads ; // maximum number of simultaneous downloads
uint32_t _max_uploads_per_friend ; // maximum number of uploads per friend. 0 means unlimited.
}; };
#endif #endif

View File

@ -60,7 +60,8 @@ const int ftserverzone = 29539;
#define FTSERVER_DEBUG() std::cerr << time(NULL) << " : FILE_SERVER : " << __FUNCTION__ << " : " #define FTSERVER_DEBUG() std::cerr << time(NULL) << " : FILE_SERVER : " << __FUNCTION__ << " : "
#define FTSERVER_ERROR() std::cerr << "(EE) FILE_SERVER ERROR : " #define FTSERVER_ERROR() std::cerr << "(EE) FILE_SERVER ERROR : "
static const time_t FILE_TRANSFER_LOW_PRIORITY_TASKS_PERIOD = 5 ; // low priority tasks handling every 5 seconds static const time_t FILE_TRANSFER_LOW_PRIORITY_TASKS_PERIOD = 5 ; // low priority tasks handling every 5 seconds
static const time_t FILE_TRANSFER_MAX_DELAY_BEFORE_DROP_USAGE_RECORD = 10 ; // keep usage records for 10 secs at most.
/* Setup */ /* Setup */
ftServer::ftServer(p3PeerMgr *pm, p3ServiceControl *sc) ftServer::ftServer(p3PeerMgr *pm, p3ServiceControl *sc)
@ -318,6 +319,16 @@ uint32_t ftServer::defaultEncryptionPolicy()
{ {
return mFtController->defaultEncryptionPolicy() ; return mFtController->defaultEncryptionPolicy() ;
} }
void ftServer::setMaxUploadSlotsPerFriend(uint32_t n)
{
mFtController->setMaxUploadsPerFriend(n) ;
}
uint32_t ftServer::getMaxUploadSlotsPerFriend()
{
return mFtController->getMaxUploadsPerFriend() ;
}
void ftServer::setDefaultEncryptionPolicy(uint32_t s) void ftServer::setDefaultEncryptionPolicy(uint32_t s)
{ {
mFtController->setDefaultEncryptionPolicy(s) ; mFtController->setDefaultEncryptionPolicy(s) ;
@ -1518,6 +1529,78 @@ int ftServer::tick()
return moreToTick; return moreToTick;
} }
bool ftServer::checkUploadLimit(const RsPeerId& pid,const RsFileHash& hash)
{
// No need for this extra cost if the value means "unlimited"
#ifdef SERVER_DEBUG
std::cerr << "Checking upload limit for friend " << pid << " and hash " << hash << ": " ;
#endif
uint32_t max_ups = mFtController->getMaxUploadsPerFriend() ;
if(max_ups == 0)
{
#ifdef SERVER_DEBUG
std::cerr << " no limit! returning true." << std::endl;
#endif
return true ;
}
#ifdef SERVER_DEBUG
std::cerr << " max=" << max_ups ;
#endif
// Find the latest records for this pid.
std::map<RsFileHash,time_t>& tmap(mUploadLimitMap[pid]) ;
std::map<RsFileHash,time_t>::iterator it ;
time_t now = time(NULL) ;
// If the limit has been decresed, we arbitrarily drop some ongoing slots.
while(tmap.size() > max_ups)
tmap.erase(tmap.begin()) ;
// Look in the upload record map. If it's not full, directly allocate a slot. If full, re-use an existing slot if a file is already cited.
if(tmap.size() < max_ups || (tmap.size()==max_ups && tmap.end() != (it = tmap.find(hash))))
{
#ifdef SERVER_DEBUG
std::cerr << " allocated slot for this hash => true" << std::endl;
#endif
tmap[hash] = now ;
return true ;
}
// There's no room in the used slots, but maybe some of them are not used anymore, in which case we remove them, which freeze a slot.
uint32_t cleaned = 0 ;
for(it = tmap.begin();it!=tmap.end() && cleaned<2;)
if(it->second + FILE_TRANSFER_MAX_DELAY_BEFORE_DROP_USAGE_RECORD < now)
{
tmap.erase(it) ;
++cleaned ;
}
else
++it ;
if(cleaned > 0)
{
#ifdef SERVER_DEBUG
std::cerr << " cleaned up " << cleaned << " old hashes => true" << std::endl;
#endif
tmap[hash] = now ;
return true ;
}
#ifdef SERVER_DEBUG
std::cerr << " no slot for this hash => false" << std::endl;
#endif
return false ;
}
int ftServer::handleIncoming() int ftServer::handleIncoming()
{ {
// now File Input. // now File Input.
@ -1534,7 +1617,8 @@ int ftServer::handleIncoming()
case RS_PKT_SUBTYPE_FT_DATA_REQUEST: case RS_PKT_SUBTYPE_FT_DATA_REQUEST:
{ {
RsFileTransferDataRequestItem *f = dynamic_cast<RsFileTransferDataRequestItem*>(item) ; RsFileTransferDataRequestItem *f = dynamic_cast<RsFileTransferDataRequestItem*>(item) ;
if (f)
if (f && checkUploadLimit(f->PeerId(),f->file.hash))
{ {
#ifdef SERVER_DEBUG #ifdef SERVER_DEBUG
FTSERVER_DEBUG() << "ftServer::handleIncoming: received data request for hash " << f->file.hash << ", offset=" << f->fileoffset << ", chunk size=" << f->chunksize << std::endl; FTSERVER_DEBUG() << "ftServer::handleIncoming: received data request for hash " << f->file.hash << ", offset=" << f->fileoffset << ", chunk size=" << f->chunksize << std::endl;

View File

@ -138,6 +138,8 @@ public:
virtual void setFreeDiskSpaceLimit(uint32_t size_in_mb) ; virtual void setFreeDiskSpaceLimit(uint32_t size_in_mb) ;
virtual void setDefaultEncryptionPolicy(uint32_t policy) ; // RS_FILE_CTRL_ENCRYPTION_POLICY_STRICT/PERMISSIVE virtual void setDefaultEncryptionPolicy(uint32_t policy) ; // RS_FILE_CTRL_ENCRYPTION_POLICY_STRICT/PERMISSIVE
virtual uint32_t defaultEncryptionPolicy() ; virtual uint32_t defaultEncryptionPolicy() ;
virtual void setMaxUploadSlotsPerFriend(uint32_t n) ;
virtual uint32_t getMaxUploadSlotsPerFriend() ;
/*** /***
* Control of Downloads Priority. * Control of Downloads Priority.
@ -266,6 +268,7 @@ protected:
bool findEncryptedHash(const RsPeerId& virtual_peer_id, RsFileHash& encrypted_hash); bool findEncryptedHash(const RsPeerId& virtual_peer_id, RsFileHash& encrypted_hash);
bool encryptHash(const RsFileHash& hash, RsFileHash& hash_of_hash); bool encryptHash(const RsFileHash& hash, RsFileHash& hash_of_hash);
bool checkUploadLimit(const RsPeerId& pid,const RsFileHash& hash);
private: private:
/**** INTERNAL FUNCTIONS ***/ /**** INTERNAL FUNCTIONS ***/
@ -293,6 +296,7 @@ private:
std::map<RsFileHash,RsFileHash> mEncryptedHashes ; // This map is such that sha1(it->second) = it->first std::map<RsFileHash,RsFileHash> mEncryptedHashes ; // This map is such that sha1(it->second) = it->first
std::map<RsPeerId,RsFileHash> mEncryptedPeerIds ; // This map holds the hash to be used with each peer id std::map<RsPeerId,RsFileHash> mEncryptedPeerIds ; // This map holds the hash to be used with each peer id
std::map<RsPeerId,std::map<RsFileHash,time_t> > mUploadLimitMap ;
}; };

View File

@ -167,6 +167,8 @@ class RsFiles
virtual bool FileClearCompleted() = 0; virtual bool FileClearCompleted() = 0;
virtual void setDefaultEncryptionPolicy(uint32_t policy)=0 ; // RS_FILE_CTRL_ENCRYPTION_POLICY_STRICT/PERMISSIVE virtual void setDefaultEncryptionPolicy(uint32_t policy)=0 ; // RS_FILE_CTRL_ENCRYPTION_POLICY_STRICT/PERMISSIVE
virtual uint32_t defaultEncryptionPolicy()=0 ; virtual uint32_t defaultEncryptionPolicy()=0 ;
virtual void setMaxUploadSlotsPerFriend(uint32_t n)=0 ;
virtual uint32_t getMaxUploadSlotsPerFriend()=0 ;
/*** /***
* Control of Downloads Priority. * Control of Downloads Priority.

View File

@ -38,6 +38,7 @@ TransferPage::TransferPage(QWidget * parent, Qt::WindowFlags flags)
ui.setupUi(this); ui.setupUi(this);
QObject::connect(ui._queueSize_SB,SIGNAL(valueChanged(int)),this,SLOT(updateQueueSize(int))) ; QObject::connect(ui._queueSize_SB,SIGNAL(valueChanged(int)),this,SLOT(updateQueueSize(int))) ;
QObject::connect(ui._max_up_SB,SIGNAL(valueChanged(int)),this,SLOT(updateMaxUploadSlots(int))) ;
QObject::connect(ui._defaultStrategy_CB,SIGNAL(activated(int)),this,SLOT(updateDefaultStrategy(int))) ; QObject::connect(ui._defaultStrategy_CB,SIGNAL(activated(int)),this,SLOT(updateDefaultStrategy(int))) ;
QObject::connect(ui._e2e_encryption_CB,SIGNAL(activated(int)),this,SLOT(updateEncryptionPolicy(int))) ; QObject::connect(ui._e2e_encryption_CB,SIGNAL(activated(int)),this,SLOT(updateEncryptionPolicy(int))) ;
QObject::connect(ui._diskSpaceLimit_SB,SIGNAL(valueChanged(int)),this,SLOT(updateDiskSizeLimit(int))) ; QObject::connect(ui._diskSpaceLimit_SB,SIGNAL(valueChanged(int)),this,SLOT(updateDiskSizeLimit(int))) ;
@ -59,6 +60,11 @@ void TransferPage::updateMaxTRUpRate(int b)
rsTurtle->setMaxTRForwardRate(b) ; rsTurtle->setMaxTRForwardRate(b) ;
} }
void TransferPage::updateMaxUploadSlots(int b)
{
rsFiles->setMaxUploadSlotsPerFriend(b) ;
}
void TransferPage::updateEncryptionPolicy(int b) void TransferPage::updateEncryptionPolicy(int b)
{ {
switch(b) switch(b)
@ -100,6 +106,7 @@ void TransferPage::load()
whileBlocking(ui._diskSpaceLimit_SB)->setValue(rsFiles->freeDiskSpaceLimit()) ; whileBlocking(ui._diskSpaceLimit_SB)->setValue(rsFiles->freeDiskSpaceLimit()) ;
whileBlocking(ui._max_tr_up_per_sec_SB)->setValue(rsTurtle->getMaxTRForwardRate()) ; whileBlocking(ui._max_tr_up_per_sec_SB)->setValue(rsTurtle->getMaxTRForwardRate()) ;
whileBlocking(ui._max_up_SB)->setValue(rsFiles->getMaxUploadSlotsPerFriend()) ;
} }
void TransferPage::updateDefaultStrategy(int i) void TransferPage::updateDefaultStrategy(int i)

View File

@ -48,6 +48,7 @@ class TransferPage: public ConfigPage
void updateDiskSizeLimit(int) ; void updateDiskSizeLimit(int) ;
void updateMaxTRUpRate(int); void updateMaxTRUpRate(int);
void updateEncryptionPolicy(int); void updateEncryptionPolicy(int);
void updateMaxUploadSlots(int);
void editDirectories() ; void editDirectories() ;
void setIncomingDirectory(); void setIncomingDirectory();

View File

@ -203,6 +203,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Maximum uploads per friend (0 = no limit)</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="label_3">
<property name="text"> <property name="text">
@ -251,6 +258,9 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QSpinBox" name="_max_up_SB"/>
</item>
<item> <item>
<widget class="QComboBox" name="_defaultStrategy_CB"> <widget class="QComboBox" name="_defaultStrategy_CB">
<property name="enabled"> <property name="enabled">