From 8a86b9ed7dc99dffa75ee16f51b4f89b473bee70 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 8 May 2017 22:00:51 +0200 Subject: [PATCH] added a per-friend upload slots limit in FT. Default is 0=unlimited --- libretroshare/src/ft/ftcontroller.cc | 30 ++++++- libretroshare/src/ft/ftcontroller.h | 6 +- libretroshare/src/ft/ftserver.cc | 88 ++++++++++++++++++- libretroshare/src/ft/ftserver.h | 4 + libretroshare/src/retroshare/rsfiles.h | 2 + .../src/gui/settings/TransferPage.cpp | 7 ++ .../src/gui/settings/TransferPage.h | 1 + .../src/gui/settings/TransferPage.ui | 10 +++ 8 files changed, 143 insertions(+), 5 deletions(-) diff --git a/libretroshare/src/ft/ftcontroller.cc b/libretroshare/src/ft/ftcontroller.cc index fad8642fa..86be40793 100644 --- a/libretroshare/src/ft/ftcontroller.cc +++ b/libretroshare/src/ft/ftcontroller.cc @@ -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 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_SLOW_RATE = 100 * 1024; @@ -113,6 +114,7 @@ ftController::ftController(ftDataMultiplex *dm, p3ServiceControl *sc, uint32_t f { _max_active_downloads = 5 ; // default queue size mDefaultEncryptionPolicy = RS_FILE_CTRL_ENCRYPTION_POLICY_PERMISSIVE; + _max_uploads_per_friend = FT_FILECONTROL_MAX_UPLOAD_SLOTS_DEFAULT ; /* TODO */ cnt = 0 ; } @@ -239,8 +241,8 @@ void ftController::data_tick() { RsStackMutex stack(ctrlMutex); /******* LOCKED ********/ - for(std::map::iterator it(mDownloads.begin());it!=mDownloads.end();++it) - it->second->mCreator->removeInactiveChunks() ; + for(std::map::iterator it(mDownloads.begin());it!=mDownloads.end();++it) + it->second->mCreator->removeInactiveChunks() ; last_clean_time = now ; } @@ -1723,6 +1725,7 @@ void ftController::statusChange(const std::list &plist) const std::string active_downloads_size_ss("MAX_ACTIVE_DOWNLOADS"); const std::string download_dir_ss("DOWN_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 free_space_limit_ss("FREE_SPACE_LIMIT"); const std::string default_encryption_policy_ss("DEFAULT_ENCRYPTION_POLICY"); @@ -1771,6 +1774,9 @@ bool ftController::saveList(bool &cleanup, std::list& saveData) 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" ; rs_sprintf(s, "%lu", RsDiscSpace::freeSpaceLimit()); @@ -2057,9 +2063,29 @@ bool ftController::loadConfigMap(std::map &configMap) 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; } +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) { RsStackMutex stack(ctrlMutex); /******* LOCKED ********/ diff --git a/libretroshare/src/ft/ftcontroller.h b/libretroshare/src/ft/ftcontroller.h index edeb8d82f..fd9acd3cd 100644 --- a/libretroshare/src/ft/ftcontroller.h +++ b/libretroshare/src/ft/ftcontroller.h @@ -146,6 +146,9 @@ class ftController: public RsTickingThread, public pqiServiceMonitor, public p3C void setFreeDiskSpaceLimit(uint32_t size_in_mb) ; uint32_t defaultEncryptionPolicy(); + void setMaxUploadsPerFriend(uint32_t m) ; + uint32_t getMaxUploadsPerFriend() ; + bool FileCancel(const RsFileHash& hash); bool FileControl(const RsFileHash& hash, uint32_t flags); bool FileClearCompleted(); @@ -261,7 +264,8 @@ class ftController: public RsTickingThread, public pqiServiceMonitor, public p3C 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 diff --git a/libretroshare/src/ft/ftserver.cc b/libretroshare/src/ft/ftserver.cc index 15a44f34f..a10d1ce02 100644 --- a/libretroshare/src/ft/ftserver.cc +++ b/libretroshare/src/ft/ftserver.cc @@ -60,7 +60,8 @@ const int ftserverzone = 29539; #define FTSERVER_DEBUG() std::cerr << time(NULL) << " : FILE_SERVER : " << __FUNCTION__ << " : " #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 */ ftServer::ftServer(p3PeerMgr *pm, p3ServiceControl *sc) @@ -318,6 +319,16 @@ uint32_t ftServer::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) { mFtController->setDefaultEncryptionPolicy(s) ; @@ -1518,6 +1529,78 @@ int ftServer::tick() 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& tmap(mUploadLimitMap[pid]) ; + std::map::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() { // now File Input. @@ -1534,7 +1617,8 @@ int ftServer::handleIncoming() case RS_PKT_SUBTYPE_FT_DATA_REQUEST: { RsFileTransferDataRequestItem *f = dynamic_cast(item) ; - if (f) + + if (f && checkUploadLimit(f->PeerId(),f->file.hash)) { #ifdef SERVER_DEBUG FTSERVER_DEBUG() << "ftServer::handleIncoming: received data request for hash " << f->file.hash << ", offset=" << f->fileoffset << ", chunk size=" << f->chunksize << std::endl; diff --git a/libretroshare/src/ft/ftserver.h b/libretroshare/src/ft/ftserver.h index 5ad4824b5..e55c30858 100644 --- a/libretroshare/src/ft/ftserver.h +++ b/libretroshare/src/ft/ftserver.h @@ -138,6 +138,8 @@ public: virtual void setFreeDiskSpaceLimit(uint32_t size_in_mb) ; virtual void setDefaultEncryptionPolicy(uint32_t policy) ; // RS_FILE_CTRL_ENCRYPTION_POLICY_STRICT/PERMISSIVE virtual uint32_t defaultEncryptionPolicy() ; + virtual void setMaxUploadSlotsPerFriend(uint32_t n) ; + virtual uint32_t getMaxUploadSlotsPerFriend() ; /*** * Control of Downloads Priority. @@ -266,6 +268,7 @@ protected: bool findEncryptedHash(const RsPeerId& virtual_peer_id, RsFileHash& encrypted_hash); bool encryptHash(const RsFileHash& hash, RsFileHash& hash_of_hash); + bool checkUploadLimit(const RsPeerId& pid,const RsFileHash& hash); private: /**** INTERNAL FUNCTIONS ***/ @@ -293,6 +296,7 @@ private: std::map mEncryptedHashes ; // This map is such that sha1(it->second) = it->first std::map mEncryptedPeerIds ; // This map holds the hash to be used with each peer id + std::map > mUploadLimitMap ; }; diff --git a/libretroshare/src/retroshare/rsfiles.h b/libretroshare/src/retroshare/rsfiles.h index ba24552e5..29515e1a5 100644 --- a/libretroshare/src/retroshare/rsfiles.h +++ b/libretroshare/src/retroshare/rsfiles.h @@ -167,6 +167,8 @@ class RsFiles virtual bool FileClearCompleted() = 0; virtual void setDefaultEncryptionPolicy(uint32_t policy)=0 ; // RS_FILE_CTRL_ENCRYPTION_POLICY_STRICT/PERMISSIVE virtual uint32_t defaultEncryptionPolicy()=0 ; + virtual void setMaxUploadSlotsPerFriend(uint32_t n)=0 ; + virtual uint32_t getMaxUploadSlotsPerFriend()=0 ; /*** * Control of Downloads Priority. diff --git a/retroshare-gui/src/gui/settings/TransferPage.cpp b/retroshare-gui/src/gui/settings/TransferPage.cpp index 76a01632d..75669b96f 100644 --- a/retroshare-gui/src/gui/settings/TransferPage.cpp +++ b/retroshare-gui/src/gui/settings/TransferPage.cpp @@ -38,6 +38,7 @@ TransferPage::TransferPage(QWidget * parent, Qt::WindowFlags flags) ui.setupUi(this); 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._e2e_encryption_CB,SIGNAL(activated(int)),this,SLOT(updateEncryptionPolicy(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) ; } +void TransferPage::updateMaxUploadSlots(int b) +{ + rsFiles->setMaxUploadSlotsPerFriend(b) ; +} + void TransferPage::updateEncryptionPolicy(int b) { switch(b) @@ -100,6 +106,7 @@ void TransferPage::load() whileBlocking(ui._diskSpaceLimit_SB)->setValue(rsFiles->freeDiskSpaceLimit()) ; whileBlocking(ui._max_tr_up_per_sec_SB)->setValue(rsTurtle->getMaxTRForwardRate()) ; + whileBlocking(ui._max_up_SB)->setValue(rsFiles->getMaxUploadSlotsPerFriend()) ; } void TransferPage::updateDefaultStrategy(int i) diff --git a/retroshare-gui/src/gui/settings/TransferPage.h b/retroshare-gui/src/gui/settings/TransferPage.h index d7f7c4da7..e8ed42ca6 100644 --- a/retroshare-gui/src/gui/settings/TransferPage.h +++ b/retroshare-gui/src/gui/settings/TransferPage.h @@ -48,6 +48,7 @@ class TransferPage: public ConfigPage void updateDiskSizeLimit(int) ; void updateMaxTRUpRate(int); void updateEncryptionPolicy(int); + void updateMaxUploadSlots(int); void editDirectories() ; void setIncomingDirectory(); diff --git a/retroshare-gui/src/gui/settings/TransferPage.ui b/retroshare-gui/src/gui/settings/TransferPage.ui index 474e6f3b5..ee48788be 100644 --- a/retroshare-gui/src/gui/settings/TransferPage.ui +++ b/retroshare-gui/src/gui/settings/TransferPage.ui @@ -203,6 +203,13 @@ + + + + Maximum uploads per friend (0 = no limit) + + + @@ -251,6 +258,9 @@ + + +