~ubuntu-branches/debian/wheezy/libtorrent/wheezy

« back to all changes in this revision

Viewing changes to src/protocol/peer_connection_metadata.cc

  • Committer: Bazaar Package Importer
  • Author(s): Rogério Brito
  • Date: 2011-03-09 20:04:41 UTC
  • mfrom: (1.3.4 upstream) (7.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20110309200441-ffi9aaqdyd72d8xl
Tags: 0.12.7-4
* Steal patch from upstream's bug tracking system to enable IPv6.
* Refresh patches to apply cleanly.
* This should, hopefully, be a good step towards addressing #490277.

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 <cstring>
 
40
#include <sstream>
 
41
 
 
42
#include "data/chunk_list_node.h"
 
43
#include "download/choke_manager.h"
 
44
#include "download/chunk_selector.h"
 
45
#include "download/chunk_statistics.h"
 
46
#include "download/download_main.h"
 
47
#include "torrent/dht_manager.h"
 
48
#include "torrent/download_info.h"
 
49
#include "torrent/peer/connection_list.h"
 
50
#include "torrent/peer/peer_info.h"
 
51
 
 
52
#include "extensions.h"
 
53
#include "peer_connection_metadata.h"
 
54
 
 
55
namespace torrent {
 
56
 
 
57
PeerConnectionMetadata::~PeerConnectionMetadata() {
 
58
}
 
59
 
 
60
void
 
61
PeerConnectionMetadata::initialize_custom() {
 
62
}
 
63
 
 
64
void
 
65
PeerConnectionMetadata::update_interested() {
 
66
}
 
67
 
 
68
bool
 
69
PeerConnectionMetadata::receive_keepalive() {
 
70
  if (cachedTime - m_timeLastRead > rak::timer::from_seconds(240))
 
71
    return false;
 
72
 
 
73
  m_tryRequest = true;
 
74
 
 
75
  // There's no point in adding ourselves to the write poll if the
 
76
  // buffer is full, as that will already have been taken care of.
 
77
  if (m_up->get_state() == ProtocolWrite::IDLE &&
 
78
      m_up->can_write_keepalive()) {
 
79
 
 
80
    write_insert_poll_safe();
 
81
 
 
82
    ProtocolBuffer<512>::iterator old_end = m_up->buffer()->end();
 
83
    m_up->write_keepalive();
 
84
 
 
85
    if (is_encrypted())
 
86
      m_encryption.encrypt(old_end, m_up->buffer()->end() - old_end);
 
87
  }
 
88
 
 
89
  return true;
 
90
}
 
91
 
 
92
// We keep the message in the buffer if it is incomplete instead of
 
93
// keeping the state and remembering the read information. This
 
94
// shouldn't happen very often compared to full reads.
 
95
inline bool
 
96
PeerConnectionMetadata::read_message() {
 
97
  ProtocolBuffer<512>* buf = m_down->buffer();
 
98
 
 
99
  if (buf->remaining() < 4)
 
100
    return false;
 
101
 
 
102
  // Remember the start of the message so we may reset it if we don't
 
103
  // have the whole message.
 
104
  ProtocolBuffer<512>::iterator beginning = buf->position();
 
105
 
 
106
  uint32_t length = buf->read_32();
 
107
 
 
108
  if (length == 0) {
 
109
    // Keepalive message.
 
110
    m_down->set_last_command(ProtocolBase::KEEP_ALIVE);
 
111
 
 
112
    return true;
 
113
 
 
114
  } else if (buf->remaining() < 1) {
 
115
    buf->set_position_itr(beginning);
 
116
    return false;
 
117
 
 
118
  } else if (length > (1 << 20)) {
 
119
    throw communication_error("PeerConnection::read_message() got an invalid message length.");
 
120
  }
 
121
    
 
122
  m_down->set_last_command((ProtocolBase::Protocol)buf->peek_8());
 
123
 
 
124
  // Ignore most messages, they aren't relevant for a metadata download.
 
125
  switch (buf->read_8()) {
 
126
  case ProtocolBase::CHOKE:
 
127
  case ProtocolBase::UNCHOKE:
 
128
  case ProtocolBase::INTERESTED:
 
129
  case ProtocolBase::NOT_INTERESTED:
 
130
    return true;
 
131
 
 
132
  case ProtocolBase::HAVE:
 
133
    if (!m_down->can_read_have_body())
 
134
      break;
 
135
 
 
136
    buf->read_32();
 
137
    return true;
 
138
 
 
139
  case ProtocolBase::REQUEST:
 
140
    if (!m_down->can_read_request_body())
 
141
      break;
 
142
 
 
143
    m_down->read_request();
 
144
    return true;
 
145
 
 
146
  case ProtocolBase::PIECE:
 
147
    throw communication_error("Received a piece but the connection is strictly for meta data.");
 
148
 
 
149
  case ProtocolBase::CANCEL:
 
150
    if (!m_down->can_read_cancel_body())
 
151
      break;
 
152
 
 
153
    m_down->read_request();
 
154
    return true;
 
155
 
 
156
  case ProtocolBase::PORT:
 
157
    if (!m_down->can_read_port_body())
 
158
      break;
 
159
 
 
160
    manager->dht_manager()->add_node(m_peerInfo->socket_address(), m_down->buffer()->read_16());
 
161
    return true;
 
162
 
 
163
  case ProtocolBase::EXTENSION_PROTOCOL:
 
164
    m_download->info()->signal_network_log().emit("PeerConnectionMetadata::read_message() case ProtocolBase::EXTENSION_PROTOCOL:");
 
165
 
 
166
    if (!m_down->can_read_extension_body())
 
167
      break;
 
168
 
 
169
    if (m_extensions->is_default()) {
 
170
      m_extensions = new ProtocolExtension();
 
171
      m_extensions->set_info(m_peerInfo, m_download);
 
172
    }
 
173
 
 
174
    {
 
175
      int extension = m_down->buffer()->read_8();
 
176
      m_extensions->read_start(extension, length - 2, (extension == ProtocolExtension::UT_PEX) && !m_download->want_pex_msg());
 
177
      m_down->set_state(ProtocolRead::READ_EXTENSION);
 
178
    }
 
179
 
 
180
    if (!down_extension())
 
181
      return false;
 
182
 
 
183
    m_download->info()->signal_network_log().emit("PeerConnectionMetadata::read_message() case ProtocolBase::EXTENSION_PROTOCOL: finished");
 
184
 
 
185
    // Drop peer if it disabled the metadata extension.
 
186
    if (!m_extensions->is_remote_supported(ProtocolExtension::UT_METADATA))
 
187
      throw close_connection();
 
188
 
 
189
    m_down->set_state(ProtocolRead::IDLE);
 
190
    m_tryRequest = true;
 
191
    write_insert_poll_safe();
 
192
 
 
193
    return true;
 
194
 
 
195
  case ProtocolBase::BITFIELD:
 
196
    // Discard the bitfield sent by the peer.
 
197
    m_skipLength = length - 1;
 
198
    m_down->set_state(ProtocolRead::READ_SKIP_PIECE);
 
199
    return false;
 
200
 
 
201
  default:
 
202
    throw communication_error("Received unsupported message type.");
 
203
  }
 
204
 
 
205
  // We were unsuccessfull in reading the message, need more data.
 
206
  buf->set_position_itr(beginning);
 
207
  return false;
 
208
}
 
209
 
 
210
void
 
211
PeerConnectionMetadata::event_read() {
 
212
  m_timeLastRead = cachedTime;
 
213
 
 
214
  // Need to make sure ProtocolBuffer::end() is pointing to the end of
 
215
  // the unread data, and that the unread data starts from the
 
216
  // beginning of the buffer. Or do we use position? Propably best,
 
217
  // therefor ProtocolBuffer::position() points to the beginning of
 
218
  // the unused data.
 
219
 
 
220
  try {
 
221
    
 
222
    // Normal read.
 
223
    //
 
224
    // We rarely will read zero bytes as the read of 64 bytes will
 
225
    // almost always either not fill up or it will require additional
 
226
    // reads.
 
227
    //
 
228
    // Only loop when end hits 64.
 
229
 
 
230
    do {
 
231
      switch (m_down->get_state()) {
 
232
      case ProtocolRead::IDLE:
 
233
        if (m_down->buffer()->size_end() < read_size) {
 
234
          unsigned int length = read_stream_throws(m_down->buffer()->end(), read_size - m_down->buffer()->size_end());
 
235
          m_down->throttle()->node_used_unthrottled(length);
 
236
 
 
237
          if (is_encrypted())
 
238
            m_encryption.decrypt(m_down->buffer()->end(), length);
 
239
 
 
240
          m_down->buffer()->move_end(length);
 
241
        }
 
242
 
 
243
        while (read_message());
 
244
        
 
245
        if (m_down->buffer()->size_end() == read_size) {
 
246
          m_down->buffer()->move_unused();
 
247
          break;
 
248
        } else {
 
249
          m_down->buffer()->move_unused();
 
250
          return;
 
251
        }
 
252
 
 
253
      case ProtocolRead::READ_EXTENSION:
 
254
        if (!down_extension())
 
255
          return;
 
256
 
 
257
        // Drop peer if it disabled the metadata extension.
 
258
        if (!m_extensions->is_remote_supported(ProtocolExtension::UT_METADATA))
 
259
          throw close_connection();
 
260
 
 
261
        m_download->info()->signal_network_log().emit("PeerConnectionMetadata::event_read() case ProtocolRead::READ_EXTENSION:");
 
262
 
 
263
        m_down->set_state(ProtocolRead::IDLE);
 
264
        m_tryRequest = true;
 
265
        write_insert_poll_safe();
 
266
        break;
 
267
 
 
268
      // Actually skipping the bitfield.
 
269
      // We never receive normal piece messages anyway.
 
270
      case ProtocolRead::READ_SKIP_PIECE:
 
271
        if (!read_skip_bitfield())
 
272
          return;
 
273
 
 
274
        m_down->set_state(ProtocolRead::IDLE);
 
275
        break;
 
276
 
 
277
      default:
 
278
        throw internal_error("PeerConnection::event_read() wrong state.");
 
279
      }
 
280
 
 
281
      // Figure out how to get rid of the shouldLoop boolean.
 
282
    } while (true);
 
283
 
 
284
  // Exception handlers:
 
285
 
 
286
  } catch (close_connection& e) {
 
287
    m_download->connection_list()->erase(this, 0);
 
288
 
 
289
  } catch (blocked_connection& e) {
 
290
    m_download->info()->signal_network_log().emit("Momentarily blocked read connection.");
 
291
    m_download->connection_list()->erase(this, 0);
 
292
 
 
293
  } catch (network_error& e) {
 
294
    m_download->connection_list()->erase(this, 0);
 
295
 
 
296
  } catch (storage_error& e) {
 
297
    m_download->info()->signal_storage_error().emit(e.what());
 
298
    m_download->connection_list()->erase(this, 0);
 
299
 
 
300
  } catch (base_error& e) {
 
301
    std::stringstream s;
 
302
    s << "Connection read fd(" << get_fd().get_fd() << ',' << m_down->get_state() << ',' << m_down->last_command() << ") \"" << e.what() << '"';
 
303
 
 
304
    throw internal_error(s.str());
 
305
  }
 
306
}
 
307
 
 
308
inline void
 
309
PeerConnectionMetadata::fill_write_buffer() {
 
310
  ProtocolBuffer<512>::iterator old_end = m_up->buffer()->end();
 
311
 
 
312
  if (m_tryRequest)
 
313
    m_tryRequest = try_request_metadata_pieces();
 
314
 
 
315
  if (m_sendPEXMask && m_up->can_write_extension() &&
 
316
      send_pex_message()) {
 
317
    // Don't do anything else if send_pex_message() succeeded.
 
318
 
 
319
  } else if (m_extensions->has_pending_message() && m_up->can_write_extension() &&
 
320
             send_ext_message()) {
 
321
    // Same.
 
322
  }
 
323
 
 
324
  if (is_encrypted())
 
325
    m_encryption.encrypt(old_end, m_up->buffer()->end() - old_end);
 
326
}
 
327
 
 
328
void
 
329
PeerConnectionMetadata::event_write() {
 
330
  try {
 
331
  
 
332
    do {
 
333
 
 
334
      switch (m_up->get_state()) {
 
335
      case ProtocolWrite::IDLE:
 
336
 
 
337
        fill_write_buffer();
 
338
 
 
339
        if (m_up->buffer()->remaining() == 0) {
 
340
          manager->poll()->remove_write(this);
 
341
          return;
 
342
        }
 
343
 
 
344
        m_up->set_state(ProtocolWrite::MSG);
 
345
 
 
346
      case ProtocolWrite::MSG:
 
347
        if (!m_up->buffer()->consume(m_up->throttle()->node_used_unthrottled(write_stream_throws(m_up->buffer()->position(),
 
348
                                                                                                 m_up->buffer()->remaining()))))
 
349
          return;
 
350
 
 
351
        m_up->buffer()->reset();
 
352
 
 
353
        if (m_up->last_command() != ProtocolBase::EXTENSION_PROTOCOL) {
 
354
          m_up->set_state(ProtocolWrite::IDLE);
 
355
          break;
 
356
        }
 
357
 
 
358
        m_up->set_state(ProtocolWrite::WRITE_EXTENSION);
 
359
 
 
360
      case ProtocolWrite::WRITE_EXTENSION:
 
361
        if (!up_extension())
 
362
          return;
 
363
 
 
364
        m_up->set_state(ProtocolWrite::IDLE);
 
365
        break;
 
366
 
 
367
      default:
 
368
        throw internal_error("PeerConnection::event_write() wrong state.");
 
369
      }
 
370
 
 
371
    } while (true);
 
372
 
 
373
  } catch (close_connection& e) {
 
374
    m_download->connection_list()->erase(this, 0);
 
375
 
 
376
  } catch (blocked_connection& e) {
 
377
    m_download->info()->signal_network_log().emit("Momentarily blocked write connection.");
 
378
    m_download->connection_list()->erase(this, 0);
 
379
 
 
380
  } catch (network_error& e) {
 
381
    m_download->connection_list()->erase(this, 0);
 
382
 
 
383
  } catch (storage_error& e) {
 
384
    m_download->info()->signal_storage_error().emit(e.what());
 
385
    m_download->connection_list()->erase(this, 0);
 
386
 
 
387
  } catch (base_error& e) {
 
388
    std::stringstream s;
 
389
    s << "Connection write fd(" << get_fd().get_fd() << ',' << m_up->get_state() << ',' << m_up->last_command() << ") \"" << e.what() << '"';
 
390
 
 
391
    throw internal_error(s.str());
 
392
  }
 
393
}
 
394
 
 
395
bool
 
396
PeerConnectionMetadata::read_skip_bitfield() {
 
397
  if (m_down->buffer()->remaining()) {
 
398
    uint32_t length = std::min(m_skipLength, (uint32_t)m_down->buffer()->remaining());
 
399
    m_down->buffer()->consume(length);
 
400
    m_skipLength -= length;
 
401
  }
 
402
 
 
403
  if (m_skipLength) {
 
404
    uint32_t length = std::min(m_skipLength, (uint32_t)null_buffer_size);
 
405
    length = read_stream_throws(m_nullBuffer, length);
 
406
    if (!length)
 
407
      return false;
 
408
    m_skipLength -= length;
 
409
  }
 
410
 
 
411
  return !m_skipLength;
 
412
}
 
413
 
 
414
// Same as the PCB code, but only one at a time and with the extension protocol.
 
415
bool
 
416
PeerConnectionMetadata::try_request_metadata_pieces() {
 
417
  if (m_download->file_list()->chunk_size() == 1 || !m_extensions->is_remote_supported(ProtocolExtension::UT_METADATA))
 
418
    return false;
 
419
 
 
420
  if (download_queue()->queued_empty())
 
421
    m_downStall = 0;
 
422
 
 
423
  uint32_t pipeSize = download_queue()->calculate_pipe_size(m_peerChunks.download_throttle()->rate()->rate());
 
424
 
 
425
  // Don't start requesting if we can't do it in large enough chunks.
 
426
  if (download_queue()->queued_size() >= (pipeSize + 10) / 2)
 
427
    return false;
 
428
 
 
429
  // DEBUG:
 
430
//   if (!download_queue()->queued_size() < pipeSize || !m_up->can_write_extension() ||
 
431
  if (!m_up->can_write_extension() || m_extensions->has_pending_message())
 
432
    return false;
 
433
 
 
434
  const Piece* p = download_queue()->delegate();
 
435
 
 
436
  if (p == NULL)
 
437
    return false;
 
438
 
 
439
  if (!m_download->file_list()->is_valid_piece(*p) || !m_peerChunks.bitfield()->get(p->index()))
 
440
    throw internal_error("PeerConnectionMetadata::try_request_metadata_pieces() tried to use an invalid piece.");
 
441
 
 
442
//   return m_extensions->request_metadata_piece(p);
 
443
  
 
444
  // DEBUG:
 
445
  if (m_extensions->request_metadata_piece(p)) {
 
446
    m_download->info()->signal_network_log().emit("PeerConnectionMetadata::try_request_metadata_pieces() succeded.");
 
447
    return true;
 
448
  } else {
 
449
    m_download->info()->signal_network_log().emit("PeerConnectionMetadata::try_request_metadata_pieces() failed.");
 
450
    return false;
 
451
  }
 
452
}
 
453
 
 
454
void
 
455
PeerConnectionMetadata::receive_metadata_piece(uint32_t piece, const char* data, uint32_t length) {
 
456
  if (data == NULL) {
 
457
    // Length is not set in a reject message.
 
458
    length = ProtocolExtension::metadata_piece_size;
 
459
 
 
460
    if ((piece << ProtocolExtension::metadata_piece_shift) + ProtocolExtension::metadata_piece_size >= m_download->file_list()->size_bytes())
 
461
      length = m_download->file_list()->chunk_size() % ProtocolExtension::metadata_piece_size;
 
462
 
 
463
    m_tryRequest = false;
 
464
    read_cancel_piece(Piece(0, piece << ProtocolExtension::metadata_piece_shift, length));
 
465
 
 
466
    m_download->info()->signal_network_log().emit("PeerConnectionMetadata::receive_metadata_piece reject.");
 
467
    return;
 
468
  }
 
469
 
 
470
  if (!down_chunk_start(Piece(0, piece << ProtocolExtension::metadata_piece_shift, length))) {
 
471
    m_download->info()->signal_network_log().emit("PeerConnectionMetadata::receive_metadata_piece skip.");
 
472
    down_chunk_skip_process(data, length);
 
473
  } else {
 
474
    m_download->info()->signal_network_log().emit("PeerConnectionMetadata::receive_metadata_piece process.");
 
475
    down_chunk_process(data, length);
 
476
  }
 
477
 
 
478
  if (!m_downloadQueue.transfer()->is_finished())
 
479
    throw internal_error("PeerConnectionMetadata::receive_metadata_piece did not have complete piece.");
 
480
 
 
481
  m_tryRequest = true;
 
482
  down_chunk_finished();
 
483
}
 
484
 
 
485
}