File indexing completed on 2025-01-05 04:37:21

0001 /*
0002     SPDX-FileCopyrightText: 2012 Joris Guisson <joris.guisson@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "connectionlimit.h"
0008 #include <util/functions.h>
0009 
0010 namespace bt
0011 {
0012 static bt::Uint32 SystemConnectionLimit()
0013 {
0014 #ifndef Q_WS_WIN
0015     return bt::MaxOpenFiles() - 50; // leave about 50 free for regular files
0016 #else
0017     return 9999; // there isn't a real limit on windows
0018 #endif
0019 }
0020 
0021 ConnectionLimit::ConnectionLimit()
0022     : global_limit(SystemConnectionLimit())
0023     , global_total(0)
0024     , torrent_limit(0)
0025 {
0026 }
0027 
0028 ConnectionLimit::~ConnectionLimit()
0029 {
0030 }
0031 
0032 void ConnectionLimit::setLimits(Uint32 global_limit, Uint32 torrent_limit)
0033 {
0034     this->global_limit = global_limit;
0035     this->torrent_limit = torrent_limit;
0036     if (this->global_limit > SystemConnectionLimit())
0037         this->global_limit = SystemConnectionLimit();
0038 }
0039 
0040 ConnectionLimit::Token::Ptr ConnectionLimit::acquire(const SHA1Hash &hash)
0041 {
0042     if (global_limit != 0 && global_total >= global_limit)
0043         return Token::Ptr();
0044 
0045     QMap<SHA1Hash, bt::Uint32>::iterator i = torrent_totals.find(hash);
0046     if (i == torrent_totals.end()) {
0047         torrent_totals[hash] = 1;
0048         global_total++;
0049         return Token::Ptr(new Token(*this, hash));
0050     } else if (torrent_limit == 0 || i.value() < torrent_limit) {
0051         i.value()++;
0052         global_total++;
0053         return Token::Ptr(new Token(*this, hash));
0054     }
0055 
0056     return Token::Ptr();
0057 }
0058 
0059 void ConnectionLimit::release(const ConnectionLimit::Token &token)
0060 {
0061     QMap<SHA1Hash, bt::Uint32>::iterator i = torrent_totals.find(token.infoHash());
0062     if (i != torrent_totals.end()) {
0063         if (i.value() > 0)
0064             i.value()--;
0065 
0066         // erase when torrent has no tokens left
0067         if (i.value() == 0)
0068             torrent_totals.erase(i);
0069 
0070         if (global_total > 0)
0071             global_total--;
0072     }
0073 }
0074 
0075 ConnectionLimit::Token::Token(ConnectionLimit &limit, const SHA1Hash &hash)
0076     : limit(limit)
0077     , hash(hash)
0078 {
0079 }
0080 
0081 ConnectionLimit::Token::~Token()
0082 {
0083     limit.release(*this);
0084 }
0085 
0086 }