1 // libTorrent - BitTorrent library 2 // Copyright (C) 2005-2011, Jari Sundell 3 // 4 // This program is free software; you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation; either version 2 of the License, or 7 // (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program; if not, write to the Free Software 16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 // 18 // In addition, as a special exception, the copyright holders give 19 // permission to link the code of portions of this program with the 20 // OpenSSL library under certain conditions as described in each 21 // individual source file, and distribute linked combinations 22 // including the two. 23 // 24 // You must obey the GNU General Public License in all respects for 25 // all of the code used other than OpenSSL. If you modify file(s) 26 // with this exception, you may extend this exception to your version 27 // of the file(s), but you are not obligated to do so. If you do not 28 // wish to do so, delete this exception statement from your version. 29 // If you delete this exception statement from all source files in the 30 // program, then also delete it here. 31 // 32 // Contact: Jari Sundell <jaris@ifi.uio.no> 33 // 34 // Skomakerveien 33 35 // 3185 Skoppum, NORWAY 36 37 #ifndef LIBTORRENT_DOWNLOAD_CHOKE_QUEUE_H 38 #define LIBTORRENT_DOWNLOAD_CHOKE_QUEUE_H 39 40 #include <torrent/common.h> 41 42 #include <list> 43 #include <vector> 44 #include <inttypes.h> 45 #include lt_tr1_functional 46 #include <torrent/download/group_entry.h> 47 48 namespace torrent { 49 50 class choke_status; 51 class group_entry; 52 53 class ConnectionList; 54 class PeerConnectionBase; 55 class DownloadMain; 56 57 struct group_stats { 58 unsigned int sum_min_needed; 59 unsigned int sum_max_needed; 60 unsigned int sum_max_leftovers; 61 unsigned int changed_choked; 62 unsigned int changed_unchoked; 63 unsigned int now_choked; 64 unsigned int now_unchoked; 65 }; 66 67 class LIBTORRENT_EXPORT choke_queue { 68 public: 69 typedef std::function<void (int)> slot_unchoke; 70 typedef std::function<int ()> slot_can_unchoke; 71 typedef std::function<bool (PeerConnectionBase*, bool)> slot_connection; 72 73 typedef std::vector<weighted_connection> container_type; 74 typedef container_type::value_type value_type; 75 typedef container_type::iterator iterator; 76 77 typedef std::pair<uint32_t, iterator> target_type; 78 79 typedef std::vector<group_entry*> group_container_type; 80 81 typedef void (*slot_weight)(iterator first, iterator last); 82 83 static const int flag_unchoke_all_new = 0x1; 84 85 static const uint32_t order_base = (1 << 30); 86 static const uint32_t order_max_size = 4; 87 static const uint32_t weight_size_bytes = order_max_size * sizeof(uint32_t); 88 89 static const uint32_t unlimited = ~uint32_t(); 90 91 struct heuristics_type { 92 slot_weight slot_choke_weight; 93 slot_weight slot_unchoke_weight; 94 95 uint32_t choke_weight[order_max_size]; 96 uint32_t unchoke_weight[order_max_size]; 97 }; 98 99 enum heuristics_enum { 100 HEURISTICS_UPLOAD_LEECH, 101 HEURISTICS_UPLOAD_SEED, 102 HEURISTICS_UPLOAD_LEECH_EXPERIMENTAL, 103 HEURISTICS_DOWNLOAD_LEECH, 104 HEURISTICS_MAX_SIZE 105 }; 106 107 choke_queue(int flags = 0) : m_flags(flags)108 m_flags(flags), 109 m_heuristics(HEURISTICS_MAX_SIZE), 110 m_maxUnchoked(unlimited), 111 m_currently_queued(0), 112 m_currently_unchoked(0) {} 113 ~choke_queue(); 114 is_full()115 bool is_full() const { return !is_unlimited() && size_unchoked() >= m_maxUnchoked; } is_unlimited()116 bool is_unlimited() const { return m_maxUnchoked == unlimited; } 117 size_unchoked()118 uint32_t size_unchoked() const { return m_currently_unchoked; } size_queued()119 uint32_t size_queued() const { return m_currently_queued; } size_total()120 uint32_t size_total() const { return size_unchoked() + size_queued(); } 121 122 // This must be unsigned. max_unchoked()123 uint32_t max_unchoked() const { return m_maxUnchoked; } max_unchoked_signed()124 int32_t max_unchoked_signed() const { return m_maxUnchoked; } set_max_unchoked(uint32_t v)125 void set_max_unchoked(uint32_t v) { m_maxUnchoked = v; } 126 127 void balance(); 128 void balance_entry(group_entry* entry); 129 int cycle(uint32_t quota); 130 131 // Assume interested state is already updated for the PCB and that 132 // this gets called once every time the status changes. 133 void set_queued(PeerConnectionBase* pc, choke_status* base); 134 void set_not_queued(PeerConnectionBase* pc, choke_status* base); 135 136 void set_snubbed(PeerConnectionBase* pc, choke_status* base); 137 void set_not_snubbed(PeerConnectionBase* pc, choke_status* base); 138 139 void disconnected(PeerConnectionBase* pc, choke_status* base); 140 141 static void move_connections(choke_queue* src, choke_queue* dest, DownloadMain* download, group_entry* base); 142 heuristics()143 heuristics_enum heuristics() const { return m_heuristics; } set_heuristics(heuristics_enum hs)144 void set_heuristics(heuristics_enum hs) { m_heuristics = hs; } 145 set_slot_unchoke(slot_unchoke s)146 void set_slot_unchoke(slot_unchoke s) { m_slotUnchoke = s; } set_slot_can_unchoke(slot_can_unchoke s)147 void set_slot_can_unchoke(slot_can_unchoke s) { m_slotCanUnchoke = s; } set_slot_connection(slot_connection s)148 void set_slot_connection(slot_connection s) { m_slotConnection = s; } 149 150 // TODO: Consider putting this in queue_group. group_container()151 group_container_type& group_container() { return m_group_container; } 152 modify_currently_queued(int value)153 void modify_currently_queued(int value) { m_currently_queued += value; } modify_currently_unchoked(int value)154 void modify_currently_unchoked(int value) { m_currently_unchoked += value; } 155 156 private: 157 group_stats prepare_weights(group_stats gs); 158 group_stats retrieve_connections(group_stats gs, container_type* queued, container_type* unchoked); 159 void rebuild_containers(container_type* queued, container_type* unchoked); 160 161 inline uint32_t max_alternate() const; 162 163 uint32_t adjust_choke_range(iterator first, iterator last, 164 container_type* src_container, container_type* dest_container, 165 uint32_t max, bool is_choke); 166 167 static heuristics_type m_heuristics_list[HEURISTICS_MAX_SIZE]; 168 169 int m_flags; 170 heuristics_enum m_heuristics; 171 172 uint32_t m_maxUnchoked; 173 174 uint32_t m_currently_queued; 175 uint32_t m_currently_unchoked; 176 177 slot_unchoke m_slotUnchoke; 178 slot_can_unchoke m_slotCanUnchoke; 179 slot_connection m_slotConnection; 180 181 group_container_type m_group_container; 182 }; 183 184 } 185 186 #endif 187