~ubuntu-branches/ubuntu/wily/libtorrent/wily-proposed

« back to all changes in this revision

Viewing changes to src/data/hash_torrent.cc

  • Committer: Bazaar Package Importer
  • Author(s): Rogério Brito
  • Date: 2011-03-20 01:06:18 UTC
  • mfrom: (1.1.13 upstream) (4.1.9 sid)
  • Revision ID: james.westby@ubuntu.com-20110320010618-g3wyylccqzqko73c
Tags: 0.12.7-5
* Use Steinar's "real" patch for IPv6. Addresses #490277, #618275,
  and Closes: #617791.
* Adapt libtorrent-0.12.6-ipv6-07.patch. It FTBFS otherwise.
* Add proper attibution to the IPv6 patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// libTorrent - BitTorrent library
 
2
// Copyright (C) 2005-2007, 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
#include "config.h"
 
38
 
 
39
#include "data/chunk_list.h"
 
40
#include "torrent/exceptions.h"
 
41
 
 
42
#include "hash_torrent.h"
 
43
#include "hash_queue.h"
 
44
#include "globals.h"
 
45
 
 
46
namespace torrent {
 
47
 
 
48
HashTorrent::HashTorrent(ChunkList* c) :
 
49
  m_position(0),
 
50
  m_outstanding(-1),
 
51
  m_errno(0),
 
52
 
 
53
  m_chunkList(c) {
 
54
}
 
55
 
 
56
bool
 
57
HashTorrent::start(bool tryQuick) {
 
58
  if (m_position == m_chunkList->size())
 
59
    return true;
 
60
 
 
61
  if (m_position > 0 || m_chunkList->empty())
 
62
    throw internal_error("HashTorrent::start() call failed.");
 
63
 
 
64
  m_outstanding = 0;
 
65
 
 
66
  queue(tryQuick);
 
67
  return m_position == m_chunkList->size();
 
68
}
 
69
 
 
70
void
 
71
HashTorrent::clear() {
 
72
  m_outstanding = -1;
 
73
  m_position = 0;
 
74
  m_errno = 0;
 
75
 
 
76
  // Correct?
 
77
  rak::priority_queue_erase(&taskScheduler, &m_delayChecked);
 
78
}
 
79
 
 
80
bool
 
81
HashTorrent::is_checked() {
 
82
  // When closed the chunk list is empty. Position can be equal to
 
83
  // chunk list for a short while as we have outstanding chunks, so
 
84
  // check the latter.
 
85
  return !m_chunkList->empty() && m_position == m_chunkList->size() && m_outstanding == -1;
 
86
}
 
87
 
 
88
// After all chunks are checked it won't show as is_checked until
 
89
// after this function is called. This allows for the hash done signal
 
90
// to be delayed.
 
91
void
 
92
HashTorrent::confirm_checked() {
 
93
  if (m_outstanding != 0)
 
94
    throw internal_error("HashTorrent::confirm_checked() m_outstanding != 0.");
 
95
 
 
96
  m_outstanding = -1;
 
97
}
 
98
 
 
99
void
 
100
HashTorrent::receive_chunkdone() {
 
101
  if (m_outstanding <= 0)
 
102
    throw internal_error("HashTorrent::receive_chunkdone() m_outstanding <= 0.");
 
103
 
 
104
  // m_signalChunk will always point to
 
105
  // DownloadMain::receive_hash_done, so it will take care of cleanup.
 
106
  //
 
107
  // Make sure we call chunkdone before torrentDone has a chance to
 
108
  // trigger.
 
109
  m_outstanding--;
 
110
 
 
111
  queue(false);
 
112
}
 
113
 
 
114
// Mark unsuccessful checks so that if we have just stopped the
 
115
// hash checker it will ensure those pieces get rechecked upon
 
116
// restart.
 
117
void
 
118
HashTorrent::receive_chunk_cleared(uint32_t index) {
 
119
  if (m_outstanding <= 0)
 
120
    throw internal_error("HashTorrent::receive_chunk_cleared() m_outstanding < 0.");
 
121
  
 
122
  if (m_ranges.has(index))
 
123
    throw internal_error("HashTorrent::receive_chunk_cleared() m_ranges.has(index).");
 
124
 
 
125
  m_outstanding--;
 
126
  m_ranges.insert(index, index + 1);
 
127
}
 
128
 
 
129
void
 
130
HashTorrent::queue(bool quick) {
 
131
  if (!is_checking())
 
132
    throw internal_error("HashTorrent::queue() called but it's not running.");
 
133
 
 
134
  while (m_position < m_chunkList->size()) {
 
135
    if (m_outstanding >= 30)
 
136
      return;
 
137
 
 
138
    // Not very efficient, but this is seldomly done.
 
139
    Ranges::iterator itr = m_ranges.find(m_position);
 
140
 
 
141
    if (itr == m_ranges.end()) {
 
142
      m_position = m_chunkList->size();
 
143
      break;
 
144
    } else if (m_position < itr->first) {
 
145
      m_position = itr->first;
 
146
    }
 
147
 
 
148
    // Need to do increment later if we're going to support resume
 
149
    // hashing a quick hashed torrent.
 
150
    ChunkHandle handle = m_chunkList->get(m_position, false);
 
151
 
 
152
    if (quick) {
 
153
      // We're not actually interested in doing any hashing, so just
 
154
      // skip what we know is not possible to hash.
 
155
      //
 
156
      // If the file does not exist then no valid error number is
 
157
      // returned.
 
158
 
 
159
      if (m_outstanding != 0)
 
160
        throw internal_error("HashTorrent::queue() quick hashing but m_outstanding != 0.");
 
161
 
 
162
      if (handle.is_valid())
 
163
        return m_chunkList->release(&handle);
 
164
      
 
165
      if (handle.error_number().is_valid() && handle.error_number().value() != rak::error_number::e_noent)
 
166
        return;
 
167
 
 
168
      m_position++;
 
169
      continue;
 
170
 
 
171
    } else {
 
172
      // If the error number is not valid, then we've just encountered a
 
173
      // file that hasn't be created/resized. Which means we ignore it
 
174
      // when doing initial hashing.
 
175
      if (handle.error_number().is_valid() && handle.error_number().value() != rak::error_number::e_noent) {
 
176
        if (handle.is_valid())
 
177
          throw internal_error("HashTorrent::queue() error, but handle.is_valid().");
 
178
 
 
179
        // We wait for all the outstanding chunks to be checked before
 
180
        // borking completely, else low-memory devices might not be able
 
181
        // to finish the hash check.
 
182
        if (m_outstanding != 0)
 
183
          return;
 
184
 
 
185
        // The rest of the outstanding chunks get ignored by
 
186
        // DownloadWrapper::receive_hash_done. Obsolete.
 
187
        clear();
 
188
 
 
189
        m_errno = handle.error_number().value();
 
190
 
 
191
//         rak::priority_queue_erase(&taskScheduler, &m_delayChecked);
 
192
        rak::priority_queue_insert(&taskScheduler, &m_delayChecked, cachedTime);
 
193
        return;
 
194
      }
 
195
 
 
196
      m_position++;
 
197
 
 
198
      if (!handle.is_valid() && !handle.error_number().is_valid())
 
199
        throw internal_error("Hash torrent errno == 0.");
 
200
 
 
201
      // Missing file, skip the hash check.
 
202
      if (!handle.is_valid())
 
203
        continue;
 
204
 
 
205
      m_slotCheck(handle);
 
206
      m_outstanding++;
 
207
    }
 
208
  }
 
209
 
 
210
  if (m_outstanding == 0) {
 
211
    // Erase the scheduled item just to make sure that if hashing is
 
212
    // started again during the delay it won't cause an exception.
 
213
    rak::priority_queue_erase(&taskScheduler, &m_delayChecked);
 
214
    rak::priority_queue_insert(&taskScheduler, &m_delayChecked, cachedTime);
 
215
   }
 
216
}
 
217
 
 
218
}