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_GROUP_ENTRY_H
38 #define LIBTORRENT_DOWNLOAD_GROUP_ENTRY_H
39
40 #include <algorithm>
41 #include <vector>
42 #include lt_tr1_functional
43 #include <torrent/common.h>
44 #include <torrent/exceptions.h>
45
46 namespace torrent {
47
48 class choke_queue;
49 class PeerConnectionBase;
50
51 struct weighted_connection {
weighted_connectionweighted_connection52 weighted_connection(PeerConnectionBase* pcb, uint32_t w) : connection(pcb), weight(w) {}
53
54 bool operator == (const PeerConnectionBase* pcb) { return pcb == connection; }
55 bool operator != (const PeerConnectionBase* pcb) { return pcb != connection; }
56
57 PeerConnectionBase* connection;
58 uint32_t weight;
59 };
60
61 // TODO: Rename to choke_entry, create an new class called group entry?
62 class group_entry {
63 public:
64 typedef std::vector<weighted_connection> container_type;
65
66 static const uint32_t unlimited = ~uint32_t();
67
group_entry()68 group_entry() : m_max_slots(unlimited), m_min_slots(0) {}
69
size_connections()70 uint32_t size_connections() const { return m_queued.size() + m_unchoked.size(); }
71
max_slots()72 uint32_t max_slots() const { return m_max_slots; }
min_slots()73 uint32_t min_slots() const { return m_min_slots; }
74
set_max_slots(uint32_t s)75 void set_max_slots(uint32_t s) { m_max_slots = s; }
set_min_slots(uint32_t s)76 void set_min_slots(uint32_t s) { m_min_slots = s; }
77
queued()78 const container_type* queued() { return &m_queued; }
unchoked()79 const container_type* unchoked() { return &m_unchoked; }
80
81 protected:
82 friend class choke_queue;
83 friend class PeerConnectionBase;
84
mutable_queued()85 container_type* mutable_queued() { return &m_queued; }
mutable_unchoked()86 container_type* mutable_unchoked() { return &m_unchoked; }
87
88 void connection_unchoked(PeerConnectionBase* pcb);
89 void connection_choked(PeerConnectionBase* pcb);
90
91 void connection_queued(PeerConnectionBase* pcb);
92 void connection_unqueued(PeerConnectionBase* pcb);
93
94 private:
95 uint32_t m_max_slots;
96 uint32_t m_min_slots;
97
98 // After a cycle the end of the vector should have the
99 // highest-priority connections, and any new connections get put at
100 // the back so they should always good candidates for unchoking.
101 container_type m_queued;
102 container_type m_unchoked;
103 };
104
connection_unchoked(PeerConnectionBase * pcb)105 inline void group_entry::connection_unchoked(PeerConnectionBase* pcb) {
106 container_type::iterator itr = std::find_if(m_unchoked.begin(), m_unchoked.end(),
107 std::bind(&weighted_connection::operator==, std::placeholders::_1, pcb));
108
109 if (itr != m_unchoked.end()) throw internal_error("group_entry::connection_unchoked(pcb) failed.");
110
111 m_unchoked.push_back(weighted_connection(pcb, uint32_t()));
112 }
113
connection_queued(PeerConnectionBase * pcb)114 inline void group_entry::connection_queued(PeerConnectionBase* pcb) {
115 container_type::iterator itr = std::find_if(m_queued.begin(), m_queued.end(),
116 std::bind(&weighted_connection::operator==, std::placeholders::_1, pcb));
117
118 if (itr != m_queued.end()) throw internal_error("group_entry::connection_queued(pcb) failed.");
119
120 m_queued.push_back(weighted_connection(pcb, uint32_t()));
121 }
122
123 inline void
connection_choked(PeerConnectionBase * pcb)124 group_entry::connection_choked(PeerConnectionBase* pcb) {
125 container_type::iterator itr = std::find_if(m_unchoked.begin(), m_unchoked.end(),
126 std::bind(&weighted_connection::operator==, std::placeholders::_1, pcb));
127
128 if (itr == m_unchoked.end()) throw internal_error("group_entry::connection_choked(pcb) failed.");
129
130 std::swap(*itr, m_unchoked.back());
131 m_unchoked.pop_back();
132 }
133
134 inline void
connection_unqueued(PeerConnectionBase * pcb)135 group_entry::connection_unqueued(PeerConnectionBase* pcb) {
136 container_type::iterator itr = std::find_if(m_queued.begin(), m_queued.end(),
137 std::bind(&weighted_connection::operator==, std::placeholders::_1, pcb));
138
139 if (itr == m_queued.end()) throw internal_error("group_entry::connection_unqueued(pcb) failed.");
140
141 std::swap(*itr, m_queued.back());
142 m_queued.pop_back();
143 }
144
145 }
146
147 #endif
148