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