1
// libTorrent - BitTorrent library
2
// Copyright (C) 2005-2007, Jari Sundell
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.
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.
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
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
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.
32
// Contact: Jari Sundell <jaris@ifi.uio.no>
35
// 3185 Skoppum, NORWAY
41
#include "download/choke_manager.h"
42
#include "download/chunk_statistics.h"
44
#include "initial_seed.h"
45
#include "peer_connection_leech.h"
49
PeerInfo* const InitialSeeding::chunk_unsent = (PeerInfo*) 0;
50
PeerInfo* const InitialSeeding::chunk_unknown = (PeerInfo*) 1;
51
PeerInfo* const InitialSeeding::chunk_done = (PeerInfo*) 2;
53
InitialSeeding::InitialSeeding(DownloadMain* download) :
55
m_chunksLeft(download->file_list()->size_chunks()),
57
m_peerChunks(new PeerInfo*[m_chunksLeft]) {
59
memset(m_peerChunks, 0, m_chunksLeft * sizeof(m_peerChunks[0]));
62
InitialSeeding::~InitialSeeding() {
64
delete[] m_peerChunks;
68
InitialSeeding::valid_peer(PeerInfo* peer) {
69
return peer > chunk_done;
73
InitialSeeding::clear_peer(PeerInfo* peer) {
74
if (!valid_peer(peer))
77
peer->unset_flags(PeerInfo::flag_blocked);
79
// If peer is still connected, offer new piece right away.
80
if (peer->connection() != NULL)
81
peer->connection()->write_insert_poll_safe();
85
InitialSeeding::chunk_seen(uint32_t index, PeerConnectionBase* pcb) {
86
// When we have two other seeds, trust that the download will
87
// be sufficiently seeded and switch to normal seeding. This is
88
// mainly for when the user accidentally enables initial seeding.
89
if (m_download->chunk_statistics()->complete() > 1)
92
PeerInfo* peer = pcb->mutable_peer_info();
93
PeerInfo* old = m_peerChunks[index];
95
// We didn't send this chunk. Is someone else initial seeding too?
96
// Or maybe we restarted and the peer got this chunk from someone
97
// we did send it to. Either way, we don't know who it belongs to.
98
// Don't mark it done until we see it from someone else, though.
99
if (old == chunk_unsent) {
100
m_peerChunks[index] = chunk_unknown;
104
if (old == peer || old == chunk_done)
107
// We've seen two peers on the swarm receive this chunk.
108
m_peerChunks[index] = chunk_done;
109
if (--m_chunksLeft == 0)
112
// The peer we sent it to originally may now receive another chunk.
117
InitialSeeding::chunk_complete(uint32_t index, PeerConnectionBase* pcb) {
118
clear_peer(m_peerChunks[index]);
119
m_peerChunks[index] = chunk_unknown;
120
chunk_seen(index, pcb);
124
InitialSeeding::new_peer(PeerConnectionBase* pcb) {
125
PeerInfo* peer = pcb->mutable_peer_info();
126
if (peer->is_blocked())
127
peer->set_flags(PeerInfo::flag_restart);
129
// We don't go through the peer's entire bitfield here. This eliminates
130
// cheating by sending a bogus bitfield if it figures out we are initial
131
// seeding, to drop us out of it. We should see HAVE messages for pieces
132
// it has that we were waiting for anyway. We will check individual chunks
133
// as we are about to offer them, to avoid the overhead of checking each
134
// peer's bitfield as well. If it really was cheating, the pieces it isn't
135
// sharing will be sent during the second round of initial seeding.
137
// If we're on the second round, don't check
138
// it until we're about to offer a chunk.
139
if (m_peerChunks[m_nextChunk] != chunk_unsent)
142
// But during primary initial seeding (some chunks not sent at all),
143
// check that nobody already has the next chunk we were going to send.
144
while (m_peerChunks[m_nextChunk] == chunk_unsent && (*m_download->chunk_statistics())[m_nextChunk]) {
145
// Could set to chunk_done if enough peers have it, but if that was the
146
// last one it could cause initial seeding to end and all connections to
147
// be closed, and now is a bad time for that (still being set up). Plus
148
// this gives us the opportunity to wait for HAVE messages and resend
149
// the chunk if it's not being shared.
150
m_peerChunks[m_nextChunk] = chunk_unknown;
151
find_next(false, pcb);
156
InitialSeeding::chunk_offer(PeerConnectionBase* pcb, uint32_t chunkDone) {
157
PeerInfo* peer = pcb->mutable_peer_info();
159
// If this peer completely downloaded the chunk we offered and we have too
160
// many unused upload slots, give it another chunk to download for free.
161
if (peer->is_blocked() && chunkDone != no_offer && m_peerChunks[chunkDone] == peer &&
162
m_download->upload_choke_manager()->size_total() * 10 < 9 * m_download->upload_choke_manager()->max_unchoked()) {
163
m_peerChunks[chunkDone] = chunk_unknown;
164
peer->unset_flags(PeerInfo::flag_blocked);
166
// Otherwise check if we can offer a chunk normally.
167
} else if (peer->is_blocked()) {
168
if (!peer->is_restart())
171
peer->unset_flags(PeerInfo::flag_restart);
173
// Re-connection of a peer we already sent a chunk.
174
// Offer the same chunk again.
175
PeerInfo** peerChunksEnd = m_peerChunks + m_download->file_list()->size_chunks();
176
PeerInfo** itr = std::find_if(m_peerChunks, peerChunksEnd,
177
std::bind2nd(std::equal_to<PeerInfo*>(), peer));
178
if (itr != peerChunksEnd)
179
return itr - m_peerChunks;
181
// Couldn't find the chunk, we probably sent it to someone
182
// else since the disconnection. So offer a new one.
185
uint32_t index = m_nextChunk;
186
bool secondary = false;
188
// If we already sent this chunk to someone else, we're on the second
189
// (or more) round. We might have already found this chunk elsewhere on
190
// the swarm since then and need to find a different one if so.
191
if (m_peerChunks[index] != chunk_unsent) {
194
// Accounting for peers whose bitfield we didn't check when connecting.
195
// If the chunk stats say there are enough peers who have it, believe that.
196
if (m_peerChunks[index] != chunk_done && (*m_download->chunk_statistics())[index] > 1)
197
chunk_complete(index, pcb);
199
if (m_peerChunks[index] == chunk_done)
200
index = find_next(true, pcb);
203
// When we only have one chunk left and we already offered it
204
// to someone who hasn't shared it yet, offer it to everyone
205
// else. We do not override the peer we sent it to, so they
206
// cannot be unblocked, but when initial seeding completes
207
// everyone is unblocked anyway.
208
if (m_chunksLeft == 1 && valid_peer(m_peerChunks[index])) {
209
peer->set_flags(PeerInfo::flag_blocked);
213
// Make sure we don't accidentally offer a chunk it has
214
// already, or it would never even request it from us.
215
// We'll just offer it to the next peer instead.
216
if (pcb->bitfield()->get(index))
219
m_peerChunks[index] = peer;
220
peer->set_flags(PeerInfo::flag_blocked);
221
find_next(secondary, pcb);
226
InitialSeeding::should_upload(uint32_t index) {
227
return m_peerChunks[index] != chunk_done;
231
InitialSeeding::find_next(bool secondary, PeerConnectionBase* pcb) {
233
// Primary seeding: find next chunk not sent yet.
234
while (++m_nextChunk < m_download->file_list()->size_chunks()) {
235
if (m_peerChunks[m_nextChunk] == chunk_unsent) {
236
if (!(*m_download->chunk_statistics())[m_nextChunk])
239
// Someone has this one already. We don't know if we sent it or not.
240
m_peerChunks[m_nextChunk] = chunk_unknown;
244
// Went through all chunks. Continue with secondary seeding.
248
// Secondary seeding: find next chunk that's not done yet.
250
if (++m_nextChunk == m_download->file_list()->size_chunks())
253
if (m_peerChunks[m_nextChunk] != chunk_done && (*m_download->chunk_statistics())[m_nextChunk] > 1)
254
chunk_complete(m_nextChunk, pcb);
256
} while (m_peerChunks[m_nextChunk] == chunk_done);
262
InitialSeeding::complete(PeerConnectionBase* pcb) {
265
m_nextChunk = no_offer;
267
// We think all chunks should be well seeded now. Check to make sure.
268
for (uint32_t i = 0; i < m_download->file_list()->size_chunks(); i++) {
269
if (m_download->chunk_statistics()->complete() + (*m_download->chunk_statistics())[i] < 2) {
270
// Chunk too rare, send it again before switching to normal seeding.
272
m_peerChunks[i] = chunk_unsent;
273
if (m_nextChunk == no_offer)
281
m_download->initial_seeding_done(pcb);
285
InitialSeeding::unblock_all() {
286
for (PeerList::const_iterator itr = m_download->peer_list()->begin(); itr != m_download->peer_list()->end(); ++itr)
287
itr->second->unset_flags(PeerInfo::flag_blocked);