Changeset 1144
- Timestamp:
- 03/15/10 12:42:05 (3 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 56 edited
- 1 moved
-
libtorrent/src/dht/dht_node.cc (modified) (1 diff)
-
libtorrent/src/dht/dht_router.cc (modified) (1 diff)
-
libtorrent/src/dht/dht_server.cc (modified) (1 diff)
-
libtorrent/src/dht/dht_server.h (modified) (1 diff)
-
libtorrent/src/dht/dht_tracker.h (modified) (1 diff)
-
libtorrent/src/download/Makefile.am (modified) (1 diff)
-
libtorrent/src/download/download_constructor.cc (modified) (5 diffs)
-
libtorrent/src/download/download_constructor.h (modified) (2 diffs)
-
libtorrent/src/download/download_main.cc (modified) (9 diffs)
-
libtorrent/src/download/download_main.h (modified) (3 diffs)
-
libtorrent/src/download/download_wrapper.cc (modified) (2 diffs)
-
libtorrent/src/download/download_wrapper.h (modified) (1 diff)
-
libtorrent/src/net/address_list.cc (modified) (1 diff)
-
libtorrent/src/net/address_list.h (modified) (2 diffs)
-
libtorrent/src/net/data_buffer.h (modified) (2 diffs)
-
libtorrent/src/net/socket_base.cc (modified) (1 diff)
-
libtorrent/src/net/socket_base.h (modified) (1 diff)
-
libtorrent/src/protocol/Makefile.am (modified) (1 diff)
-
libtorrent/src/protocol/extensions.cc (modified) (12 diffs)
-
libtorrent/src/protocol/extensions.h (modified) (11 diffs)
-
libtorrent/src/protocol/handshake.cc (modified) (3 diffs)
-
libtorrent/src/protocol/handshake_manager.cc (modified) (1 diff)
-
libtorrent/src/protocol/peer_connection_base.cc (modified) (6 diffs)
-
libtorrent/src/protocol/peer_connection_base.h (modified) (2 diffs)
-
libtorrent/src/protocol/peer_connection_leech.cc (modified) (4 diffs)
-
libtorrent/src/protocol/peer_connection_metadata.cc (added)
-
libtorrent/src/protocol/peer_connection_metadata.h (added)
-
libtorrent/src/protocol/peer_factory.cc (modified) (2 diffs)
-
libtorrent/src/protocol/peer_factory.h (modified) (1 diff)
-
libtorrent/src/torrent/Makefile.am (modified) (2 diffs)
-
libtorrent/src/torrent/data/file_list.cc (modified) (2 diffs)
-
libtorrent/src/torrent/data/file_list.h (modified) (1 diff)
-
libtorrent/src/torrent/download.cc (modified) (7 diffs)
-
libtorrent/src/torrent/download.h (modified) (4 diffs)
-
libtorrent/src/torrent/download_info.h (moved) (moved from trunk/libtorrent/src/download/download_info.h) (10 diffs)
-
libtorrent/src/torrent/object_stream.cc (modified) (1 diff)
-
libtorrent/src/torrent/object_stream.h (modified) (1 diff)
-
libtorrent/src/torrent/peer/connection_list.cc (modified) (5 diffs)
-
libtorrent/src/torrent/resume.cc (modified) (3 diffs)
-
libtorrent/src/torrent/torrent.cc (modified) (1 diff)
-
libtorrent/src/torrent/tracker_list.cc (modified) (1 diff)
-
libtorrent/src/tracker/tracker_dht.cc (modified) (1 diff)
-
libtorrent/src/tracker/tracker_http.cc (modified) (1 diff)
-
libtorrent/src/tracker/tracker_manager.cc (modified) (1 diff)
-
libtorrent/src/tracker/tracker_udp.cc (modified) (1 diff)
-
rtorrent/src/command_download.cc (modified) (4 diffs)
-
rtorrent/src/command_helpers.h (modified) (1 diff)
-
rtorrent/src/core/dht_manager.cc (modified) (1 diff)
-
rtorrent/src/core/download.cc (modified) (1 diff)
-
rtorrent/src/core/download.h (modified) (3 diffs)
-
rtorrent/src/core/download_factory.cc (modified) (4 diffs)
-
rtorrent/src/core/download_factory.h (modified) (1 diff)
-
rtorrent/src/core/download_list.cc (modified) (10 diffs)
-
rtorrent/src/core/download_list.h (modified) (1 diff)
-
rtorrent/src/core/manager.cc (modified) (4 diffs)
-
rtorrent/src/core/manager.h (modified) (1 diff)
-
rtorrent/src/display/utils.cc (modified) (2 diffs)
-
rtorrent/src/main.cc (modified) (3 diffs)
-
rtorrent/src/ui/download.cc (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/libtorrent/src/dht/dht_node.cc
r1040 r1144 41 41 #include "torrent/object.h" 42 42 43 // For SACompact... 44 #include "download/download_info.h" 43 #include "net/address_list.h" // For SA. 45 44 46 45 #include "dht_node.h" -
trunk/libtorrent/src/dht/dht_router.cc
r1138 r1144 42 42 43 43 #include "torrent/dht_manager.h" 44 #include "torrent/download_info.h" 44 45 #include "torrent/exceptions.h" 45 46 #include "utils/sha1.h" -
trunk/libtorrent/src/dht/dht_server.cc
r1140 r1144 43 43 #include "torrent/exceptions.h" 44 44 #include "torrent/connection_manager.h" 45 #include "torrent/download_info.h" 45 46 #include "torrent/object.h" 46 47 #include "torrent/object_stream.h" -
trunk/libtorrent/src/dht/dht_server.h
r1138 r1144 45 45 #include "net/socket_datagram.h" 46 46 #include "net/throttle_node.h" 47 #include "download/download_info.h" // for SocketAddressCompact48 47 #include "torrent/hash_string.h" 49 48 #include "torrent/object_raw_bencode.h" -
trunk/libtorrent/src/dht/dht_tracker.h
r1138 r1144 43 43 #include <rak/socket_address.h> 44 44 45 #include " download/download_info.h" // for SocketAddressCompact45 #include "net/address_list.h" // For SA. 46 46 #include "torrent/object_raw_bencode.h" 47 47 -
trunk/libtorrent/src/download/Makefile.am
r1010 r1144 15 15 download_constructor.cc \ 16 16 download_constructor.h \ 17 download_info.h \18 17 download_main.cc \ 19 18 download_main.h \ -
trunk/libtorrent/src/download/download_constructor.cc
r1138 r1144 82 82 83 83 void 84 DownloadConstructor::initialize(const Object& b) { 84 DownloadConstructor::initialize(Object& b) { 85 if (!b.has_key_map("info") && b.has_key_string("magnet-uri")) 86 parse_magnet_uri(b, b.get_key_string("magnet-uri")); 87 85 88 if (b.has_key_string("encoding")) 86 89 m_defaultEncoding = b.get_key_string("encoding"); 87 90 88 m_download->info()->set_private(b.get_key("info").has_key_value("private") && 89 b.get_key("info").get_key_value("private") == 1); 91 m_download->info()->change_flags(DownloadInfo::flag_private, 92 b.get_key("info").has_key_value("private") && 93 b.get_key("info").get_key_value("private") == 1); 90 94 91 95 parse_name(b.get_key("info")); … … 137 141 throw input_error("Download has unordered info dictionary."); 138 142 139 uint32_t chunkSize = b.get_key_value("piece length"); 140 141 if (chunkSize <= (1 << 10) || chunkSize > (128 << 20)) 142 throw input_error("Torrent has an invalid \"piece length\"."); 143 uint32_t chunkSize; 144 145 if (b.has_key_value("meta_download") && b.get_key_value("meta_download")) 146 m_download->info()->set_flags(DownloadInfo::flag_meta_download); 147 148 if (m_download->info()->is_meta_download()) { 149 if (b.get_key_string("pieces").length() != HashString::size_data) 150 throw input_error("Meta-download has invalid piece data."); 151 152 chunkSize = 1; 153 parse_single_file(b, chunkSize); 154 155 } else { 156 chunkSize = b.get_key_value("piece length"); 157 158 if (chunkSize <= (1 << 10) || chunkSize > (128 << 20)) 159 throw input_error("Torrent has an invalid \"piece length\"."); 160 } 143 161 144 162 if (b.has_key("length")) { … … 149 167 fileList->set_root_dir("./" + m_download->info()->name()); 150 168 151 } else {169 } else if (!m_download->info()->is_meta_download()) { 152 170 throw input_error("Torrent must have either length or files entry."); 153 171 } 154 172 155 if (fileList->size_bytes() == 0 )173 if (fileList->size_bytes() == 0 && !m_download->info()->is_meta_download()) 156 174 throw input_error("Torrent has zero length."); 157 175 … … 240 258 241 259 FileList* fileList = m_download->main()->file_list(); 242 fileList->initialize( b.get_key_value("length"), chunkSize);260 fileList->initialize(chunkSize == 1 ? 1 : b.get_key_value("length"), chunkSize); 243 261 fileList->set_multi_file(false); 244 262 … … 344 362 } 345 363 346 } 364 static const char* 365 parse_base32_sha1(const char* pos, HashString& hash) { 366 HashString::iterator hashItr = hash.begin(); 367 368 static const int base_shift = 8+8-5; 369 int shift = base_shift; 370 uint16_t decoded = 0; 371 372 while (*pos) { 373 char c = *pos++; 374 uint16_t value; 375 376 if (c >= 'A' && c <= 'Z') 377 value = c - 'A'; 378 else if (c >= 'a' && c <= 'z') 379 value = c - 'a'; 380 else if (c >= '2' && c <= '7') 381 value = 26 + c - '2'; 382 else if (c == '&') 383 break; 384 else 385 return NULL; 386 387 decoded |= (value << shift); 388 if (shift <= 8) { 389 // Too many characters for a base32 SHA1. 390 if (hashItr == hash.end()) 391 return NULL; 392 393 *hashItr++ = (decoded >> 8); 394 decoded <<= 8; 395 shift += 3; 396 } else { 397 shift -= 5; 398 } 399 } 400 401 return hashItr != hash.end() || shift != base_shift ? NULL : pos; 402 } 403 404 void 405 DownloadConstructor::parse_magnet_uri(Object& b, const std::string& uri) { 406 if (std::strncmp(uri.c_str(), "magnet:?", 8)) 407 throw input_error("Invalid magnet URI."); 408 409 const char* pos = uri.c_str() + 8; 410 411 Object trackers(Object::create_list()); 412 HashString hash; 413 bool hashValid = false; 414 415 while (*pos) { 416 const char* tagStart = pos; 417 while (*pos != '=') 418 if (!*pos++) 419 break; 420 421 raw_string tag(tagStart, pos - tagStart); 422 pos++; 423 424 // hash may be base32 encoded (optional in BEP 0009 and common practice) 425 if (raw_bencode_equal_c_str(tag, "xt")) { 426 if (strncmp(pos, "urn:btih:", 9)) 427 throw input_error("Invalid magnet URI."); 428 429 pos += 9; 430 431 const char* nextPos = parse_base32_sha1(pos, hash); 432 if (nextPos != NULL) { 433 pos = nextPos; 434 hashValid = true; 435 continue; 436 } 437 } 438 439 // everything else, including sometimes the hash, is url encoded. 440 std::string decoded; 441 while (*pos) { 442 char c = *pos++; 443 if (c == '%') { 444 if (sscanf(pos, "%02hhx", &c) != 1) 445 throw input_error("Invalid magnet URI."); 446 447 pos += 2; 448 449 } else if (c == '&') { 450 break; 451 } 452 453 decoded.push_back(c); 454 } 455 456 if (raw_bencode_equal_c_str(tag, "xt")) { 457 // url-encoded hash as per magnet URN specs 458 if (decoded.length() == hash.size_data) { 459 hash = *HashString::cast_from(decoded); 460 hashValid = true; 461 462 // hex-encoded hash as per BEP 0009 463 } else if (decoded.length() == hash.size_data * 2) { 464 std::string::iterator hexItr = decoded.begin(); 465 for (HashString::iterator itr = hash.begin(), last = hash.end(); itr != last; itr++, hexItr += 2) 466 *itr = (rak::hexchar_to_value(*hexItr) << 4) + rak::hexchar_to_value(*(hexItr + 1)); 467 hashValid = true; 468 469 } else { 470 throw input_error("Invalid magnet URI."); 471 } 472 473 } else if (raw_bencode_equal_c_str(tag, "tr")) { 474 trackers.insert_back(Object::create_list()).insert_back(decoded); 475 } 476 // could also handle "dn" = display name (torrent name), but we can't really use that 477 } 478 479 if (!hashValid) 480 throw input_error("Invalid magnet URI."); 481 482 Object& info = b.insert_key("info", Object::create_map()); 483 info.insert_key("pieces", hash.str()); 484 info.insert_key("name", rak::transform_hex(hash.str()) + ".meta"); 485 info.insert_key("meta_download", (int64_t)1); 486 487 if (!trackers.as_list().empty()) { 488 b.insert_preserve_copy("announce", trackers.as_list().begin()->as_list().begin()->as_string()); 489 b.insert_preserve_type("announce-list", trackers); 490 } 491 } 492 493 } -
trunk/libtorrent/src/download/download_constructor.h
r1013 r1144 56 56 DownloadConstructor() : m_download(NULL), m_encodingList(NULL) {} 57 57 58 void initialize( constObject& b);58 void initialize(Object& b); 59 59 60 60 void set_download(DownloadWrapper* d) { m_download = d; } … … 65 65 void parse_tracker(const Object& b); 66 66 void parse_info(const Object& b); 67 void parse_magnet_uri(Object& b, const std::string& uri); 67 68 68 69 void add_tracker_group(const Object& b); -
trunk/libtorrent/src/download/download_main.cc
r1091 r1144 59 59 #include "chunk_selector.h" 60 60 #include "chunk_statistics.h" 61 #include "download_info.h"62 61 #include "download_main.h" 63 62 #include "download_manager.h" … … 65 64 66 65 namespace torrent { 66 67 DownloadInfo::DownloadInfo() : 68 m_flags(flag_compact | flag_accepting_new_peers | flag_pex_enabled | flag_pex_active), 69 70 m_upRate(60), 71 m_downRate(60), 72 m_skipRate(60), 73 74 m_uploadedBaseline(0), 75 m_completedBaseline(0), 76 m_sizePex(0), 77 m_maxSizePex(8), 78 m_metadataSize(0), 79 80 m_loadDate(rak::timer::current_seconds()) { 81 } 67 82 68 83 DownloadMain::DownloadMain() : … … 155 170 m_chunkStatistics->initialize(file_list()->size_chunks()); 156 171 157 info()->set_ open(true);172 info()->set_flags(DownloadInfo::flag_open); 158 173 } 159 174 … … 166 181 return; 167 182 168 info()-> set_open(false);183 info()->unset_flags(DownloadInfo::flag_open); 169 184 170 185 // Don't close the tracker manager here else it will cause STOPPED … … 191 206 throw internal_error("Tried to start an active download"); 192 207 193 info()->set_ active(true);208 info()->set_flags(DownloadInfo::flag_active); 194 209 m_lastConnectedSize = 0; 195 210 … … 207 222 // Set this early so functions like receive_connect_peers() knows 208 223 // not to eat available peers. 209 info()-> set_active(false);224 info()->unset_flags(DownloadInfo::flag_active); 210 225 211 226 m_slotStopHandshakes(this); … … 355 370 m_connectionList->size() < m_connectionList->min_size() / 2 && 356 371 m_peerList.available_list()->size() < m_peerList.available_list()->max_size() / 4) { 357 m_info->set_ pex_active(true);372 m_info->set_flags(DownloadInfo::flag_pex_active); 358 373 359 374 // Only set PEX_ENABLE if we don't have max_size_pex set to zero. … … 365 380 // m_peerList.available_list()->size() >= m_peerList.available_list()->max_size() / 2) { 366 381 togglePex = PeerConnectionBase::PEX_DISABLE; 367 m_info-> set_pex_active(false);382 m_info->unset_flags(DownloadInfo::flag_pex_active); 368 383 } 369 384 … … 456 471 } 457 472 458 } 473 void 474 DownloadMain::set_metadata_size(size_t size) { 475 if (m_info->is_meta_download()) { 476 if (m_fileList.size_bytes() < 2) 477 file_list()->reset_filesize(size); 478 else if (size != m_fileList.size_bytes()) 479 throw communication_error("Peer-supplied metadata size mismatch."); 480 481 } else if (m_info->metadata_size() && m_info->metadata_size() != size) { 482 throw communication_error("Peer-supplied metadata size mismatch."); 483 } 484 485 m_info->set_metadata_size(size); 486 } 487 488 } -
trunk/libtorrent/src/download/download_main.h
r1091 r1144 44 44 #include "globals.h" 45 45 46 #include "download_info.h"47 46 #include "delegator.h" 48 47 … … 50 49 #include "download/available_list.h" 51 50 #include "net/data_buffer.h" 51 #include "torrent/download_info.h" 52 52 #include "torrent/data/file_list.h" 53 53 #include "torrent/peer/peer_list.h" … … 116 116 117 117 bool want_pex_msg() { return m_info->is_pex_active() && m_peerList.available_list()->want_more(); }; 118 119 void set_metadata_size(size_t s); 118 120 119 121 // Carefull with these. -
trunk/libtorrent/src/download/download_wrapper.cc
r1129 r1144 102 102 info()->mutable_local_id().assign(id.c_str()); 103 103 104 info()->slot_ completed() = rak::make_mem_fun(m_main.file_list(), &FileList::completed_bytes);105 info()->slot_ left() = rak::make_mem_fun(m_main.file_list(), &FileList::left_bytes);104 info()->slot_left() = sigc::mem_fun(m_main.file_list(), &FileList::left_bytes); 105 info()->slot_completed() = sigc::mem_fun(m_main.file_list(), &FileList::completed_bytes); 106 106 107 107 m_main.slot_hash_check_add(rak::make_mem_fun(this, &DownloadWrapper::check_chunk_hash)); … … 277 277 // If PEX was disabled since the last peer exchange, deactivate it now. 278 278 } else if (info()->is_pex_active()) { 279 info()-> set_pex_active(false);279 info()->unset_flags(DownloadInfo::flag_pex_active); 280 280 281 281 for (ConnectionList::iterator itr = m_main.connection_list()->begin(); itr != m_main.connection_list()->end(); ++itr) -
trunk/libtorrent/src/download/download_wrapper.h
r1016 r1144 43 43 44 44 #include "data/chunk_handle.h" 45 #include "download/download_info.h"46 45 47 46 #include "download_main.h" -
trunk/libtorrent/src/net/address_list.cc
r1138 r1144 39 39 #include <algorithm> 40 40 #include <rak/functional.h> 41 42 #include "download/download_info.h" // for SocketAddressCompact43 41 44 42 #include "address_list.h" -
trunk/libtorrent/src/net/address_list.h
r1138 r1144 54 54 55 55 void parse_address_compact(raw_string s); 56 void parse_address_compact(const std::string& s) { 57 return parse_address_compact(raw_string(s.data(), s.size())); 58 } 56 void parse_address_compact(const std::string& s); 59 57 60 58 private: … … 76 74 }; 77 75 76 inline void 77 AddressList::parse_address_compact(const std::string& s) { 78 return parse_address_compact(raw_string(s.data(), s.size())); 79 } 80 81 // Move somewhere else. 82 struct SocketAddressCompact { 83 SocketAddressCompact() {} 84 SocketAddressCompact(uint32_t a, uint16_t p) : addr(a), port(p) {} 85 SocketAddressCompact(const rak::socket_address_inet* sa) : addr(sa->address_n()), port(sa->port_n()) {} 86 87 operator rak::socket_address () const { 88 rak::socket_address sa; 89 sa.sa_inet()->clear(); 90 sa.sa_inet()->set_port_n(port); 91 sa.sa_inet()->set_address_n(addr); 92 93 return sa; 94 } 95 96 uint32_t addr; 97 uint16_t port; 98 99 const char* c_str() const { return reinterpret_cast<const char*>(this); } 100 } __attribute__ ((packed)); 101 78 102 } 79 103 -
trunk/libtorrent/src/net/data_buffer.h
r1062 r1144 49 49 50 50 DataBuffer clone() const { DataBuffer d = *this; d.m_owned = false; return d; } 51 DataBuffer release() { DataBuffer d = *this; set(NULL, NULL, false); return d; } 51 52 52 53 char* data() const { return m_data; } … … 71 72 inline void 72 73 DataBuffer::clear() { 73 if (!empty() )74 if (!empty() && m_owned) 74 75 delete[] m_data; 75 76 -
trunk/libtorrent/src/net/socket_base.cc
r1013 r1144 48 48 namespace torrent { 49 49 50 char* SocketBase::m_nullBuffer = new char[ 1 << 17];50 char* SocketBase::m_nullBuffer = new char[SocketBase::null_buffer_size]; 51 51 52 52 SocketBase::~SocketBase() { -
trunk/libtorrent/src/net/socket_base.h
r1013 r1144 69 69 void operator = (const SocketBase&); 70 70 71 static const size_t null_buffer_size = 1 << 17; 72 71 73 static char* m_nullBuffer; 72 74 }; -
trunk/libtorrent/src/protocol/Makefile.am
r1058 r1144 18 18 peer_connection_leech.cc \ 19 19 peer_connection_leech.h \ 20 peer_connection_metadata.cc \ 21 peer_connection_metadata.h \ 20 22 peer_factory.cc \ 21 23 peer_factory.h \ -
trunk/libtorrent/src/protocol/extensions.cc
r1143 r1144 44 44 #include "download/available_list.h" 45 45 #include "download/download_main.h" 46 #include "download/download_manager.h" 47 #include "download/download_wrapper.h" 46 48 #include "protocol/peer_connection_base.h" 47 49 #include "torrent/connection_manager.h" … … 58 60 const ExtHandshakeMessage::key_list_type ExtHandshakeMessage::keys = { 59 61 { key_e, "e" }, 62 { key_m_utMetadata, "m::ut_metadata" }, 60 63 { key_m_utPex, "m::ut_pex" }, 64 { key_metadataSize, "metadata_size" }, 61 65 { key_p, "p" }, 62 66 { key_reqq, "reqq" }, … … 69 73 }; 70 74 75 // DEBUG: Add type info. 76 template <> 77 const ExtMetadataMessage::key_list_type ExtMetadataMessage::keys = { 78 { key_msgType, "msg_type" }, 79 { key_piece, "piece" }, 80 { key_totalSize, "total_size" }, 81 }; 82 71 83 struct message_type { 72 84 const char* key; … … 76 88 const message_type message_keys[] = { 77 89 { "HANDSHAKE", key_handshake_LAST }, 78 { "ut_pex", key_m_utPex } 90 { "ut_pex", key_m_utPex }, 91 { "metadata_size", key_m_utMetadata } 79 92 }; 80 93 … … 134 147 message[key_reqq] = 2048; // maximum request queue size 135 148 149 if (!m_download->info()->is_meta_download()) 150 message[key_metadataSize] = m_download->info()->metadata_size(); 151 136 152 message[key_m_utPex] = is_local_enabled(UT_PEX) ? UT_PEX : 0; 153 message[key_m_utMetadata] = UT_METADATA; 137 154 138 155 char buffer[1024]; … … 201 218 void 202 219 ProtocolExtension::read_start(int type, uint32_t length, bool skip) { 203 if (is_default() || (type >= FIRST_INVALID) || length > (1 << 1 4))220 if (is_default() || (type >= FIRST_INVALID) || length > (1 << 15)) 204 221 throw communication_error("Received invalid extension message."); 205 222 … … 221 238 } 222 239 223 void 240 bool 224 241 ProtocolExtension::read_done() { 242 bool result = true; 243 225 244 try { 226 245 switch(m_readType) { 227 case SKIP_EXTENSION: 228 delete [] m_read; 229 m_read = NULL; 230 return; 231 232 case HANDSHAKE: 233 parse_handshake(); 234 break; 235 236 case UT_PEX: 237 parse_ut_pex(); 238 break; 239 246 case SKIP_EXTENSION: break; 247 case HANDSHAKE: result = parse_handshake(); break; 248 case UT_PEX: result = parse_ut_pex(); break; 249 case UT_METADATA: result = parse_ut_metadata(); break; 240 250 default: 241 251 throw internal_error("ProtocolExtension::read_done called with invalid extension type."); … … 253 263 m_readType = FIRST_INVALID; 254 264 m_flags |= flag_received_ext; 265 266 return result; 255 267 } 256 268 … … 266 278 } 267 279 268 void 280 bool 269 281 ProtocolExtension::parse_handshake() { 270 282 ExtHandshakeMessage message; … … 304 316 m_maxQueueLength = message[key_reqq].as_value(); 305 317 318 if (message[key_metadataSize].is_value()) 319 m_download->set_metadata_size(message[key_metadataSize].as_value()); 320 306 321 m_flags &= ~flag_initial_handshake; 307 } 308 309 void 322 323 return true; 324 } 325 326 bool 310 327 ProtocolExtension::parse_ut_pex() { 311 328 // Ignore message if we're still in the handshake (no connection … … 317 334 // TODO: Check if pex is enabled? 318 335 if (!message[key_pex_added].is_raw_string()) 319 return ;336 return true; 320 337 321 338 raw_string peers = message[key_pex_added].as_raw_string(); 322 339 323 340 if (peers.empty()) 324 return ;341 return true; 325 342 326 343 // TODO: Sort the list before adding it. … … 331 348 332 349 m_download->peer_list()->insert_available(&l); 333 } 334 335 } 350 351 return true; 352 } 353 354 bool 355 ProtocolExtension::parse_ut_metadata() { 356 ExtMetadataMessage message; 357 358 // Piece data comes after bencoded extension message. 359 const char* dataStart = static_map_read_bencode(m_read, m_readPos, message); 360 361 switch(message[key_msgType].as_value()) { 362 case 0: 363 // Can't process new request while still having data to send. 364 if (has_pending_message()) 365 return false; 366 367 send_metadata_piece(message[key_piece].as_value()); 368 break; 369 370 case 1: 371 if (m_connection == NULL) 372 break; 373 374 m_connection->receive_metadata_piece(message[key_piece].as_value(), dataStart, m_readPos - dataStart); 375 break; 376 377 case 2: 378 if (m_connection == NULL) 379 break; 380 381 m_connection->receive_metadata_piece(message[key_piece].as_value(), NULL, 0); 382 break; 383 }; 384 385 return true; 386 } 387 388 void 389 ProtocolExtension::send_metadata_piece(size_t piece) { 390 // Reject out-of-range piece, or if we don't have the complete metadata yet. 391 size_t metadataSize = m_download->info()->metadata_size(); 392 size_t pieceEnd = (metadataSize + metadata_piece_size - 1) >> metadata_piece_shift; 393 394 if (m_download->info()->is_meta_download() || piece >= pieceEnd) { 395 // reject: { "msg_type" => 2, "piece" => ... } 396 m_pendingType = UT_METADATA; 397 m_pending = build_bencode(40, "d8:msg_typei2e5:piecei%zuee", piece); 398 return; 399 } 400 401 // These messages will be rare, so we'll just build the 402 // metadata here instead of caching it uselessly. 403 char* buffer = new char[metadataSize]; 404 object_buffer_t result = object_write_bencode_c(object_write_to_buffer, NULL, object_buffer_t(buffer, buffer + metadataSize), 405 &(*manager->download_manager()->find(m_download->info()))->bencode()->get_key("info")); 406 407 // data: { "msg_type" => 1, "piece" => ..., "total_size" => ... } followed by piece data (outside of dictionary) 408 size_t length = piece == pieceEnd - 1 ? m_download->info()->metadata_size() % metadata_piece_size : metadata_piece_size; 409 m_pendingType = UT_METADATA; 410 m_pending = build_bencode(length + 128, "d8:msg_typei1e5:piecei%zue10:total_sizei%zuee", piece, metadataSize); 411 412 memcpy(m_pending.end(), buffer + (piece << metadata_piece_shift), length); 413 m_pending.set(m_pending.data(), m_pending.end() + length, m_pending.owned()); 414 delete [] buffer; 415 } 416 417 bool 418 ProtocolExtension::request_metadata_piece(const Piece* p) { 419 if (p->offset() % metadata_piece_size) 420 throw internal_error("ProtocolExtension::request_metadata_piece got misaligned piece offset."); 421 422 if (has_pending_message()) 423 return false; 424 425 m_pendingType = UT_METADATA; 426 m_pending = build_bencode(40, "d8:msg_typei0e5:piecei%uee", (unsigned)(p->offset() >> metadata_piece_shift)); 427 return true; 428 } 429 430 } -
trunk/libtorrent/src/protocol/extensions.h
r1141 r1144 45 45 #include "torrent/object_static_map.h" 46 46 47 #include "download/download_info.h" 47 #include "torrent/download_info.h" 48 #include "net/address_list.h" 48 49 #include "net/data_buffer.h" 49 50 … … 62 63 HANDSHAKE = 0, 63 64 UT_PEX, 65 UT_METADATA, 64 66 65 67 FIRST_INVALID, // first invalid message ID … … 83 85 static const int extension_count = FIRST_INVALID - HANDSHAKE - 1; 84 86 87 // Fixed size of a metadata piece (16 KB). 88 static const size_t metadata_piece_shift = 14; 89 static const size_t metadata_piece_size = 1 << metadata_piece_shift; 90 85 91 ProtocolExtension(); 86 92 ~ProtocolExtension() { delete [] m_read; } … … 93 99 94 100 void set_info(PeerInfo* peerInfo, DownloadMain* download) { m_peerInfo = peerInfo; m_download = download; } 101 void set_connection(PeerConnectionBase* c) { m_connection = c; } 95 102 96 103 DataBuffer generate_handshake_message(); … … 114 121 // Handle reading extension data from peer. 115 122 void read_start(int type, uint32_t length, bool skip); 116 voidread_done();123 bool read_done(); 117 124 118 125 char* read_position() { return m_readPos; } … … 134 141 void reset() { std::memset(&m_idMap, 0, sizeof(m_idMap)); } 135 142 143 bool request_metadata_piece(const Piece* p); 144 145 // To handle cases where the extension protocol needs to send a reply. 146 bool has_pending_message() const { return m_pendingType != HANDSHAKE; } 147 MessageType pending_message_type() const { return m_pendingType; } 148 DataBuffer pending_message_data() { return m_pending.release(); } 149 void clear_pending_message() { if (m_pending.empty()) m_pendingType = HANDSHAKE; } 150 136 151 private: 137 void parse_handshake(); 138 void parse_ut_pex(); 152 bool parse_handshake(); 153 bool parse_ut_pex(); 154 bool parse_ut_metadata(); 139 155 140 156 static DataBuffer build_bencode(size_t maxLength, const char* format, ...) ATTRIBUTE_PRINTF(2); 141 157 142 158 void peer_toggle_remote(int type, bool active); 159 void send_metadata_piece(size_t piece); 143 160 144 161 // Map of IDs peer uses for each extension message type, excluding … … 151 168 PeerInfo* m_peerInfo; 152 169 DownloadMain* m_download; 170 PeerConnectionBase* m_connection; 153 171 154 172 uint8_t m_readType; … … 156 174 char* m_read; 157 175 char* m_readPos; 176 177 MessageType m_pendingType; 178 DataBuffer m_pending; 158 179 }; 159 180 … … 164 185 enum ext_handshake_keys { 165 186 key_e, 187 key_m_utMetadata, 166 188 key_m_utPex, 189 key_metadataSize, 167 190 key_p, 168 191 key_reqq, … … 176 199 }; 177 200 201 enum ext_metadata_keys { 202 key_msgType, 203 key_piece, 204 key_totalSize, 205 key_metadata_LAST 206 }; 207 178 208 typedef static_map_type<ext_handshake_keys, key_handshake_LAST> ExtHandshakeMessage; 179 209 typedef static_map_type<ext_pex_keys, key_pex_LAST> ExtPEXMessage; 210 typedef static_map_type<ext_metadata_keys, key_metadata_LAST> ExtMetadataMessage; 180 211 181 212 // … … 190 221 m_peerInfo(NULL), 191 222 m_download(NULL), 223 m_connection(NULL), 192 224 m_readType(FIRST_INVALID), 193 m_read(NULL) { 225 m_read(NULL), 226 m_pendingType(HANDSHAKE) { 194 227 195 228 reset(); 229 set_local_enabled(UT_METADATA); 196 230 } 197 231 -
trunk/libtorrent/src/protocol/handshake.cc
r1142 r1144 37 37 #include "config.h" 38 38 39 #include "download/download_info.h"40 39 #include "download/download_main.h" 41 40 #include "net/throttle_list.h" 42 41 #include "torrent/dht_manager.h" 42 #include "torrent/download_info.h" 43 43 #include "torrent/exceptions.h" 44 44 #include "torrent/error.h" … … 751 751 case READ_MESSAGE: 752 752 case POST_HANDSHAKE: 753 // For meta-downloads, we aren't interested in the bitfield or 754 // extension messages here, PCMetadata handles all that. The 755 // bitfield only refers to the single-chunk meta-data, so fake that. 756 if (m_download->info()->is_meta_download()) { 757 m_bitfield.set_size_bits(1); 758 m_bitfield.allocate(); 759 m_bitfield.set(0); 760 read_done(); 761 break; 762 } 763 753 764 fill_read_buffer(5); 754 765 … … 1057 1068 m_peerInfo->mutable_id().assign((const char*)m_readBuffer.position()); 1058 1069 m_readBuffer.consume(20); 1070 1071 // For meta downloads, we require support of the extension protocol. 1072 if (m_download->info()->is_meta_download() && !m_peerInfo->supports_extensions()) 1073 throw handshake_error(ConnectionManager::handshake_dropped, e_handshake_unwanted_connection); 1059 1074 } 1060 1075 -
trunk/libtorrent/src/protocol/handshake_manager.cc
r1089 r1144 41 41 #include "torrent/exceptions.h" 42 42 #include "torrent/error.h" 43 #include "download/download_info.h"44 43 #include "download/download_main.h" 45 44 #include "torrent/connection_manager.h" 45 #include "torrent/download_info.h" 46 46 #include "torrent/peer/peer_info.h" 47 47 #include "torrent/peer/client_list.h" -
trunk/libtorrent/src/protocol/peer_connection_base.cc
r1105 r1144 48 48 #include "download/chunk_selector.h" 49 49 #include "download/chunk_statistics.h" 50 #include "download/download_info.h"51 50 #include "download/download_main.h" 52 51 #include "net/socket_base.h" 53 52 #include "torrent/connection_manager.h" 53 #include "torrent/download_info.h" 54 54 #include "torrent/throttle.h" 55 55 #include "torrent/peer/peer_info.h" … … 94 94 delete m_extensions; 95 95 96 if (m_extensionMessage.owned()) 97 m_extensionMessage.clear(); 96 m_extensionMessage.clear(); 98 97 } 99 98 … … 116 115 m_encryption = *encryptionInfo; 117 116 m_extensions = extensions; 117 118 m_extensions->set_connection(this); 118 119 119 120 m_peerChunks.set_peer_info(m_peerInfo); … … 582 583 } 583 584 584 if (m_extensions->is_complete()) 585 m_extensions->read_done(); 585 // If extension can't be processed yet (due to a pending write), 586 // disable reads until the pending message is completely sent. 587 if (m_extensions->is_complete() && !m_extensions->is_invalid() && !m_extensions->read_done()) { 588 manager->poll()->remove_read(this); 589 return false; 590 } 586 591 587 592 return m_extensions->is_complete(); … … 694 699 return false; 695 700 696 // clear() deletes the buffer, only do that if we made a copy, 697 // otherwise the buffer is shared among all connections. 698 if (m_extensionMessage.owned()) 699 m_extensionMessage.clear(); 700 else 701 m_extensionMessage.set(NULL, NULL, false); 701 m_extensionMessage.clear(); 702 703 // If we have an unprocessed message, process it now and enable reads again. 704 if (m_extensions->is_complete() && !m_extensions->is_invalid()) { 705 // DEBUG: What, this should fail when we block, no? 706 if (!m_extensions->read_done()) 707 throw internal_error("PeerConnectionBase::up_extension could not process complete extension message."); 708 709 manager->poll()->insert_read(this); 710 } 702 711 703 712 return true; … … 858 867 } 859 868 860 } 869 // Extension protocol needs to send a reply. 870 bool 871 PeerConnectionBase::send_ext_message() { 872 write_prepare_extension(m_extensions->pending_message_type(), m_extensions->pending_message_data()); 873 m_extensions->clear_pending_message(); 874 return true; 875 } 876 877 void 878 PeerConnectionBase::receive_metadata_piece(uint32_t piece, const char* data, uint32_t length) { 879 } 880 881 } -
trunk/libtorrent/src/protocol/peer_connection_base.h
r1058 r1144 141 141 void write_insert_poll_safe(); 142 142 143 // Communication with the protocol extensions 144 virtual void receive_metadata_piece(uint32_t piece, const char* data, uint32_t length); 145 143 146 protected: 144 147 static const uint32_t extension_must_encrypt = ~uint32_t(); … … 180 183 181 184 bool send_pex_message(); 185 bool send_ext_message(); 182 186 183 187 DownloadMain* m_download; -
trunk/libtorrent/src/protocol/peer_connection_leech.cc
r1143 r1144 45 45 #include "download/chunk_selector.h" 46 46 #include "download/chunk_statistics.h" 47 #include "download/download_info.h"48 47 #include "download/download_main.h" 49 48 #include "torrent/dht_manager.h" 49 #include "torrent/download_info.h" 50 50 #include "torrent/peer/connection_list.h" 51 51 #include "torrent/peer/peer_info.h" … … 334 334 } 335 335 336 if (down_extension()) 337 m_down->set_state(ProtocolRead::IDLE); 338 336 if (!down_extension()) 337 return false; 338 339 if (m_extensions->has_pending_message()) 340 write_insert_poll_safe(); 341 342 m_down->set_state(ProtocolRead::IDLE); 339 343 return true; 340 344 … … 434 438 return; 435 439 440 if (m_extensions->has_pending_message()) 441 write_insert_poll_safe(); 442 436 443 m_down->set_state(ProtocolRead::IDLE); 437 444 break; … … 547 554 send_pex_message()) { 548 555 // Don't do anything else if send_pex_message() succeeded. 556 557 } else if (m_extensions->has_pending_message() && m_up->can_write_extension() && 558 send_ext_message()) { 559 // Same. 549 560 550 561 } else if (!m_upChoke.choked() && -
trunk/libtorrent/src/protocol/peer_factory.cc
r1058 r1144 39 39 #include "peer_factory.h" 40 40 #include "peer_connection_leech.h" 41 #include "peer_connection_metadata.h" 41 42 42 43 namespace torrent { … … 63 64 } 64 65 66 PeerConnectionBase* 67 createPeerConnectionMetadata(bool encrypted) { 68 PeerConnectionBase* pc = new PeerConnectionMetadata; 69 70 return pc; 65 71 } 72 73 } -
trunk/libtorrent/src/protocol/peer_factory.h
r1058 r1144 45 45 PeerConnectionBase* createPeerConnectionSeed(bool encrypted); 46 46 PeerConnectionBase* createPeerConnectionInitialSeed(bool encrypted); 47 PeerConnectionBase* createPeerConnectionMetadata(bool encrypted); 47 48 48 49 } -
trunk/libtorrent/src/torrent/Makefile.am
r1136 r1144 17 17 download.cc \ 18 18 download.h \ 19 download_info.h \ 19 20 error.cc \ 20 21 error.h \ … … 66 67 dht_manager.h \ 67 68 download.h \ 69 download_info.h \ 68 70 error.h \ 69 71 exceptions.h \ -
trunk/libtorrent/src/torrent/data/file_list.cc
r1089 r1144 467 467 m_isOpen = true; 468 468 m_frozenRootDir = m_rootDir; 469 470 // For meta-downloads, if the file exists, we have to assume that 471 // it is either 0 or 1 length or the correct size. If the size 472 // turns out wrong later, a storage_error will be thrown elsewhere 473 // to alert the user in this (unlikely) case. 474 // 475 // DEBUG: Make this depend on a flag... 476 if (size_bytes() < 2) { 477 rak::file_stat stat; 478 479 // This probably recurses into open() once, but that is harmless. 480 if (stat.update((*begin())->frozen_path()) && stat.size() > 1) 481 return reset_filesize(stat.size()); 482 } 469 483 } 470 484 … … 662 676 } 663 677 664 } 678 void 679 FileList::reset_filesize(int64_t size) { 680 close(); 681 m_chunkSize = size; 682 m_torrentSize = size; 683 (*begin())->set_size_bytes(size); 684 (*begin())->set_range(m_chunkSize); 685 open(open_no_create); 686 } 687 688 } -
trunk/libtorrent/src/torrent/data/file_list.h
r1085 r1144 168 168 void update_completed() LIBTORRENT_NO_EXPORT; 169 169 170 // Used for meta downloads; we only know the 171 // size after the first extension handshake. 172 void reset_filesize(int64_t) LIBTORRENT_NO_EXPORT; 173 170 174 private: 171 175 bool open_file(File* node, const Path& lastPath, int flags) LIBTORRENT_NO_EXPORT; -
trunk/libtorrent/src/torrent/download.cc
r1129 r1144 53 53 #include "protocol/peer_connection_base.h" 54 54 #include "protocol/peer_factory.h" 55 #include "download/download_info.h"56 55 #include "peer/peer_info.h" 57 56 #include "tracker/tracker_manager.h" 57 #include "torrent/download_info.h" 58 58 #include "torrent/data/file.h" 59 59 #include "torrent/peer/connection_list.h" … … 67 67 namespace torrent { 68 68 69 const DownloadInfo* 70 Download::info() const { return m_ptr->info(); } 71 69 72 void 70 73 Download::open(int flags) { … … 124 127 if (!(flags & start_keep_baseline)) { 125 128 m_ptr->info()->set_uploaded_baseline(m_ptr->info()->up_rate()->total()); 126 m_ptr->info()->set_completed_baseline(m_ptr-> info()->slot_completed()());129 m_ptr->info()->set_completed_baseline(m_ptr->main()->file_list()->completed_bytes()); 127 130 } 128 131 … … 186 189 } 187 190 188 bool189 Download::is_open() const {190 return m_ptr->info()->is_open();191 }192 193 bool194 Download::is_active() const {195 return m_ptr->info()->is_active();196 }191 // bool 192 // Download::is_open() const { 193 // return m_ptr->info()->is_open(); 194 // } 195 196 // bool 197 // Download::is_active() const { 198 // return m_ptr->info()->is_active(); 199 // } 197 200 198 201 bool … … 206 209 } 207 210 208 bool209 Download::is_private() const {210 return m_ptr->info()->is_private();211 }212 213 bool214 Download::is_pex_active() const {215 return m_ptr->info()->is_pex_active();216 }217 218 bool219 Download::is_pex_enabled() const {220 return m_ptr->info()->is_pex_enabled();221 }211 // bool 212 // Download::is_private() const { 213 // return m_ptr->info()->is_private(); 214 // } 215 216 // bool 217 // Download::is_pex_active() const { 218 // return m_ptr->info()->is_pex_active(); 219 // } 220 221 // bool 222 // Download::is_pex_enabled() const { 223 // return m_ptr->info()->is_pex_enabled(); 224 // } 222 225 223 226 void 224 227 Download::set_pex_enabled(bool enabled) { 225 m_ptr->info()->set_pex_enabled(enabled); 226 } 228 m_ptr->info()->change_flags(DownloadInfo::flag_pex_enabled, enabled); 229 } 230 231 // bool 232 // Download::is_meta_download() const { 233 // return m_ptr->info()->is_meta_download(); 234 // } 227 235 228 236 const std::string& … … 510 518 void 511 519 Download::set_connection_type(ConnectionType t) { 520 if (m_ptr->info()->is_meta_download()) { 521 m_ptr->main()->connection_list()->slot_new_connection(&createPeerConnectionMetadata); 522 return; 523 } 524 512 525 switch (t) { 513 526 case CONNECTION_LEECH: … … 518 531 break; 519 532 case CONNECTION_INITIAL_SEED: 520 if (i s_active() && m_ptr->main()->initial_seeding() == NULL)533 if (info()->is_active() && m_ptr->main()->initial_seeding() == NULL) 521 534 throw input_error("Can't switch to initial seeding: download is active."); 522 535 m_ptr->main()->connection_list()->slot_new_connection(&createPeerConnectionInitialSeed); -
trunk/libtorrent/src/torrent/download.h
r1129 r1144 50 50 51 51 class ConnectionList; 52 class DownloadInfo; 52 53 53 54 // Download is safe to copy and destory as it is just a pointer to an … … 69 70 70 71 Download(DownloadWrapper* d = NULL) : m_ptr(d) {} 72 73 const DownloadInfo* info() const; 71 74 72 75 // Not active atm. Opens and prepares/closes the files. … … 90 93 bool is_valid() const { return m_ptr; } 91 94 92 bool is_open() const;93 bool is_active() const;95 // bool is_open() const; 96 // bool is_active() const; 94 97 95 98 bool is_hash_checked() const; 96 99 bool is_hash_checking() const; 97 100 98 bool is_private() const;99 bool is_pex_active() const;100 bool is_pex_enabled() const;101 // bool is_private() const; 102 // bool is_pex_active() const; 103 // bool is_pex_enabled() const; 101 104 void set_pex_enabled(bool enabled); 105 106 // bool is_meta_download() const; 102 107 103 108 // Returns "" if the object is not valid. … … 186 191 CONNECTION_SEED, 187 192 CONNECTION_INITIAL_SEED, 193 CONNECTION_METADATA, 188 194 } ConnectionType; 189 195 -
trunk/libtorrent/src/torrent/download_info.h
r1129 r1144 41 41 #include <string> 42 42 #include <inttypes.h> 43 #include <rak/functional.h>44 43 #include <rak/socket_address.h> 45 #include <rak/timer.h>46 44 #include <sigc++/signal.h> 47 45 48 #include "torrent/rate.h"49 #include "torrent/hash_string.h"46 #include <torrent/rate.h> 47 #include <torrent/hash_string.h> 50 48 51 49 namespace torrent { … … 53 51 class FileList; 54 52 class DownloadMain; 55 class Rate;56 53 57 54 // This will become a Download 'handle' of kinds. … … 59 56 class DownloadInfo { 60 57 public: 61 typedef rak::const_mem_fun0<FileList, uint64_t> slot_stat_type; 62 58 typedef sigc::slot0<uint64_t> slot_stat_type; 63 59 typedef sigc::signal1<void, const std::string&> signal_string_type; 64 60 typedef sigc::signal1<void, uint32_t> signal_chunk_type; … … 72 68 }; 73 69 74 DownloadInfo() :75 m_isOpen(false),76 m_isActive(false),77 m_isCompact(true),78 m_isAcceptingNewPeers(true),79 m_isPrivate(false),80 m_pexEnabled(true),81 m_pexActive(true),70 static const int flag_open = (1 << 0); 71 static const int flag_active = (1 << 1); 72 static const int flag_compact = (1 << 2); 73 static const int flag_accepting_new_peers = (1 << 3); 74 static const int flag_private = (1 << 4); 75 static const int flag_meta_download = (1 << 5); 76 static const int flag_pex_enabled = (1 << 6); 77 static const int flag_pex_active = (1 << 7); 82 78 83 m_upRate(60), 84 m_downRate(60), 85 m_skipRate(60), 86 87 m_uploadedBaseline(0), 88 m_completedBaseline(0), 89 m_sizePex(0), 90 m_maxSizePex(8), 91 92 m_loadDate(rak::timer::current_seconds()) { 93 } 79 DownloadInfo(); 94 80 95 81 const std::string& name() const { return m_name; } … … 105 91 HashString& mutable_local_id() { return m_localId; } 106 92 107 bool is_open() const { return m_isOpen; } 108 void set_open(bool s) { m_isOpen = s; } 93 bool is_open() const { return m_flags & flag_open; } 94 bool is_active() const { return m_flags & flag_active; } 95 bool is_compact() const { return m_flags & flag_compact; } 96 bool is_accepting_new_peers() const { return m_flags & flag_accepting_new_peers; } 97 bool is_private() const { return m_flags & flag_private; } 98 bool is_meta_download() const { return m_flags & flag_meta_download; } 99 bool is_pex_enabled() const { return m_flags & flag_pex_enabled; } 100 bool is_pex_active() const { return m_flags & flag_pex_active; } 109 101 110 bool is_active() const { return m_isActive; } 111 void set_active(bool s) { m_isActive = s; } 102 void set_flags(int flags) { m_flags |= flags; } 103 void unset_flags(int flags) { m_flags &= ~flags; } 104 void change_flags(int flags, bool state) { if (state) set_flags(flags); else unset_flags(flags); } 112 105 113 bool is_compact() const { return m_isCompact; } 114 void set_compact(bool s) { m_isCompact = s; } 115 116 bool is_accepting_new_peers() const { return m_isAcceptingNewPeers; } 117 void set_accepting_new_peers(bool s) { m_isAcceptingNewPeers = s; } 118 119 bool is_private() const { return m_isPrivate; } 120 void set_private(bool p) { m_isPrivate = p; if (p) m_pexEnabled = false; } 121 122 bool is_pex_enabled() const { return m_pexEnabled; } 123 void set_pex_enabled(bool enabled) { m_pexEnabled = enabled && !m_isPrivate; } 124 125 bool is_pex_active() const { return m_pexActive; } 126 void set_pex_active(bool active) { m_pexActive = active; } 106 void set_private() { set_flags(flag_private); unset_flags(flag_pex_enabled); } 107 void set_pex_enabled() { if (!is_private()) set_flags(flag_pex_enabled); } 127 108 128 109 Rate* up_rate() { return &m_upRate; } … … 137 118 uint64_t completed_adjusted() const { return std::max<int64_t>(m_slotStatCompleted() - completed_baseline(), 0); } 138 119 void set_completed_baseline(uint64_t b) { m_completedBaseline = b; } 120 121 size_t metadata_size() const { return m_metadataSize; } 122 void set_metadata_size(size_t size) { m_metadataSize = size; } 139 123 140 124 uint32_t size_pex() const { return m_sizePex; } … … 152 136 uint32_t udp_tries() const { return 2; } 153 137 138 slot_stat_type& slot_left() { return m_slotStatLeft; } 154 139 slot_stat_type& slot_completed() { return m_slotStatCompleted; } 155 slot_stat_type& slot_left() { return m_slotStatLeft; }156 140 157 141 signal_string_type& signal_network_log() { return m_signalNetworkLog; } … … 165 149 HashString m_localId; 166 150 167 // TODO: Use flags. 168 bool m_isOpen; 169 bool m_isActive; 170 bool m_isCompact; 171 bool m_isAcceptingNewPeers; 172 bool m_isPrivate; 173 bool m_pexEnabled; 174 bool m_pexActive; 151 int m_flags; 175 152 176 153 Rate m_upRate; … … 182 159 uint32_t m_sizePex; 183 160 uint32_t m_maxSizePex; 161 size_t m_metadataSize; 184 162 185 163 uint32_t m_loadDate; 186 164 165 slot_stat_type m_slotStatLeft; 187 166 slot_stat_type m_slotStatCompleted; 188 slot_stat_type m_slotStatLeft;189 167 190 168 signal_string_type m_signalNetworkLog; … … 193 171 }; 194 172 195 // Move somewhere else.196 struct SocketAddressCompact {197 SocketAddressCompact() {}198 SocketAddressCompact(uint32_t a, uint16_t p) : addr(a), port(p) {}199 SocketAddressCompact(const rak::socket_address_inet* sa) : addr(sa->address_n()), port(sa->port_n()) {}200 201 operator rak::socket_address () const {202 rak::socket_address sa;203 sa.sa_inet()->clear();204 sa.sa_inet()->set_port_n(port);205 sa.sa_inet()->set_address_n(addr);206 207 return sa;208 }209 210 uint32_t addr;211 uint16_t port;212 213 const char* c_str() const { return reinterpret_cast<const char*>(this); }214 } __attribute__ ((packed));215 216 173 } 217 174 -
trunk/libtorrent/src/torrent/object_stream.cc
r1143 r1144 624 624 } 625 625 626 object_buffer_t 627 object_write_to_size(void* data, object_buffer_t buffer) { 628 *reinterpret_cast<uint64_t*>(data) += std::distance(buffer.first, buffer.second); 629 630 return buffer; 631 } 632 626 633 // 627 634 // static_map operations: -
trunk/libtorrent/src/torrent/object_stream.h
r1140 r1144 73 73 object_buffer_t object_write_to_sha1(void* data, object_buffer_t buffer) LIBTORRENT_EXPORT; 74 74 object_buffer_t object_write_to_stream(void* data, object_buffer_t buffer) LIBTORRENT_EXPORT; 75 // Measures bencode size, 'data' is uint64_t*. 76 object_buffer_t object_write_to_size(void* data, object_buffer_t buffer) LIBTORRENT_EXPORT; 75 77 76 78 // -
trunk/libtorrent/src/torrent/peer/connection_list.cc
r1035 r1144 41 41 42 42 #include "download/choke_manager.h" 43 #include "download/download_info.h"44 43 #include "download/download_main.h" 45 44 #include "net/address_list.h" 46 45 #include "protocol/peer_connection_base.h" 47 46 #include "torrent/exceptions.h" 47 #include "torrent/download_info.h" 48 48 49 49 #include "connection_list.h" … … 85 85 base_type::push_back(peerConnection); 86 86 87 m_download->info()-> set_accepting_new_peers(size() < m_maxSize);87 m_download->info()->change_flags(DownloadInfo::flag_accepting_new_peers, size() < m_maxSize); 88 88 m_signalConnected(peerConnection); 89 89 … … 104 104 base_type::pop_back(); 105 105 106 m_download->info()->set_accepting_new_peers(size() < m_maxSize); 107 106 m_download->info()->change_flags(DownloadInfo::flag_accepting_new_peers, size() < m_maxSize); 108 107 m_signalDisconnected(peerConnection); 109 108 … … 144 143 erase(--end(), flags); 145 144 146 m_download->info()-> set_accepting_new_peers(size() < m_maxSize);145 m_download->info()->change_flags(DownloadInfo::flag_accepting_new_peers, size() < m_maxSize); 147 146 } 148 147 … … 207 206 208 207 m_maxSize = v; 209 m_download->info()-> set_accepting_new_peers(size() < m_maxSize);208 m_download->info()->change_flags(DownloadInfo::flag_accepting_new_peers, size() < m_maxSize); 210 209 m_download->upload_choke_manager()->balance(); 211 210 } -
trunk/libtorrent/src/torrent/resume.cc
r1129 r1144 40 40 #include <rak/socket_address.h> 41 41 42 // For SocketAddressCompact.43 #include "download/download_info.h"44 42 #include "peer/peer_info.h" 45 43 #include "peer/peer_list.h" … … 48 46 #include "data/file_list.h" 49 47 #include "data/transfer_list.h" 48 #include "net/address_list.h" 50 49 51 50 #include "common.h" 52 51 #include "bitfield.h" 53 52 #include "download.h" 53 #include "download_info.h" 54 54 #include "object.h" 55 55 #include "tracker.h" … … 240 240 filesItr->insert_key("mtime", (int64_t)fs.modified_time()); 241 241 242 } else if (!download.i s_active()) {242 } else if (!download.info()->is_active()) { 243 243 244 244 // When stopped, all chunks should have received sync, thus the -
trunk/libtorrent/src/torrent/torrent.cc
r1113 r1144 321 321 ctor.initialize(*object); 322 322 323 std::string infoHash = object_sha1(&object->get_key("info")); 323 std::string infoHash; 324 if (download->info()->is_meta_download()) 325 infoHash = object->get_key("info").get_key("pieces").as_string(); 326 else 327 infoHash = object_sha1(&object->get_key("info")); 324 328 325 329 if (manager->download_manager()->find(infoHash) != manager->download_manager()->end()) 326 330 throw input_error("Info hash already used by another torrent."); 331 332 if (!download->info()->is_meta_download()) { 333 char buffer[1024]; 334 uint64_t metadata_size = 0; 335 object_write_bencode_c(&object_write_to_size, &metadata_size, object_buffer_t(buffer, buffer + sizeof(buffer)), &object->get_key("info")); 336 download->main()->set_metadata_size(metadata_size); 337 } 327 338 328 339 download->set_hash_queue(manager->hash_queue()); -
trunk/libtorrent/src/torrent/tracker_list.cc
r1032 r1144 39 39 #include <rak/functional.h> 40 40 41 #include " download/download_info.h"41 #include "torrent/download_info.h" 42 42 #include "net/address_list.h" 43 43 #include "tracker/tracker_manager.h" -
trunk/libtorrent/src/tracker/tracker_dht.cc
r1138 r1144 42 42 #include "dht/dht_router.h" 43 43 #include "torrent/connection_manager.h" 44 #include "torrent/download_info.h" 44 45 #include "torrent/dht_manager.h" 45 46 #include "torrent/exceptions.h" -
trunk/libtorrent/src/tracker/tracker_http.cc
r1097 r1144 42 42 #include <rak/string_manip.h> 43 43 44 #include "download/download_info.h"45 44 #include "net/address_list.h" 46 45 #include "torrent/connection_manager.h" 46 #include "torrent/download_info.h" 47 47 #include "torrent/exceptions.h" 48 48 #include "torrent/http.h" -
trunk/libtorrent/src/tracker/tracker_manager.cc
r1062 r1144 37 37 #include "config.h" 38 38 39 #include " download/download_info.h"39 #include "torrent/download_info.h" 40 40 #include "torrent/exceptions.h" 41 41 #include "torrent/tracker.h" -
trunk/libtorrent/src/tracker/tracker_udp.cc
r1128 r1144 43 43 #include <cstdio> 44 44 45 #include "download/download_info.h"46 45 #include "net/address_list.h" 47 46 #include "torrent/exceptions.h" 48 47 #include "torrent/connection_manager.h" 48 #include "torrent/download_info.h" 49 49 #include "torrent/poll.h" 50 50 #include "torrent/tracker_list.h" -
trunk/rtorrent/src/command_download.cc
r1131 r1144 337 337 char host[1024]; 338 338 339 if (download->download()->i s_private())339 if (download->download()->info()->is_private()) 340 340 throw torrent::input_error("Download is private."); 341 341 … … 601 601 ADD_CD_STRING("add_peer", std::ptr_fun(&apply_d_add_peer)); 602 602 603 ADD_CD_VALUE("is_open", rak::on(std::mem_fun(&core::Download:: download), std::mem_fun(&torrent::Download::is_open)));604 ADD_CD_VALUE("is_active", rak::on(std::mem_fun(&core::Download:: download), std::mem_fun(&torrent::Download::is_active)));603 ADD_CD_VALUE("is_open", rak::on(std::mem_fun(&core::Download::info), std::mem_fun(&torrent::DownloadInfo::is_open))); 604 ADD_CD_VALUE("is_active", rak::on(std::mem_fun(&core::Download::info), std::mem_fun(&torrent::DownloadInfo::is_active))); 605 605 ADD_CD_VALUE("is_hash_checked", rak::on(std::mem_fun(&core::Download::download), std::mem_fun(&torrent::Download::is_hash_checked))); 606 606 ADD_CD_VALUE("is_hash_checking", rak::on(std::mem_fun(&core::Download::download), std::mem_fun(&torrent::Download::is_hash_checking))); 607 607 ADD_CD_VALUE("is_multi_file", rak::on(std::mem_fun(&core::Download::file_list), std::mem_fun(&torrent::FileList::is_multi_file))); 608 ADD_CD_VALUE("is_private", rak::on(std::mem_fun(&core::Download:: download), std::mem_fun(&torrent::Download::is_private)));609 ADD_CD_VALUE("is_pex_active", rak::on(std::mem_fun(&core::Download:: download), std::mem_fun(&torrent::Download::is_pex_active)));608 ADD_CD_VALUE("is_private", rak::on(std::mem_fun(&core::Download::info), std::mem_fun(&torrent::DownloadInfo::is_private))); 609 ADD_CD_VALUE("is_pex_active", rak::on(std::mem_fun(&core::Download::info), std::mem_fun(&torrent::DownloadInfo::is_pex_active))); 610 610 611 611 ADD_CD_VARIABLE_STRING_PUBLIC("custom1", "rtorrent", "custom1"); … … 677 677 ADD_CD_VALUE_UNI("peers_accounted", rak::on(std::mem_fun(&core::Download::download), std::mem_fun(&torrent::Download::peers_accounted))); 678 678 679 ADD_CD_VALUE_MEM_BI("peer_exchange", &core::Download::download, &torrent::Download::set_pex_enabled, &torrent::Download::is_pex_enabled);680 681 679 ADD_CD_VALUE_MEM_UNI("up_rate", &torrent::Download::mutable_up_rate, &torrent::Rate::rate); 682 680 ADD_CD_VALUE_MEM_UNI("up_total", &torrent::Download::mutable_up_rate, &torrent::Rate::total); … … 723 721 // NEWISH: 724 722 CMD_D_VOID("d.initialize_logs", &cmd_d_initialize_logs); 725 } 723 724 CMD_D_VOID_SLOT("d.peer_exchange", rak::on(std::mem_fun(&core::Download::info), std::mem_fun(&torrent::DownloadInfo::is_pex_enabled))); 725 CMD_D_VALUE_SLOT("d.peer_exchange.set", rak::on2(std::mem_fun(&core::Download::download), std::mem_fun(&torrent::Download::set_pex_enabled))); 726 } -
trunk/rtorrent/src/command_helpers.h
r1131 r1144 226 226 CMD_D_SLOT(key, call_unknown, rpc::object_fn(slot), "i:", "") 227 227 228 #define CMD_D_VOID_SLOT(key, slot) \ 229 CMD_D_SLOT(key, call_unknown, rpc::object_void_fn<core::Download*>(slot), "i:", "") 230 231 #define CMD_D_VALUE_SLOT(key, slot) \ 232 CMD_D_SLOT(key, call_value, rpc::object_value_fn<core::Download*>(slot), "i:i", "") 233 228 234 #define CMD_FUNC_SINGLE(key, command) \ 229 235 rpc::commands.insert_type(key, new rpc::CommandFunction(command), &rpc::CommandFunction::call, rpc::CommandMap::flag_public_xmlrpc, NULL, NULL); -
trunk/rtorrent/src/core/dht_manager.cc
r1138 r1144 195 195 196 196 for (itr = control->core()->download_list()->begin(), end = control->core()->download_list()->end(); itr != end; ++itr) 197 if ((*itr)-> is_active() && !(*itr)->download()->is_private())197 if ((*itr)->download()->info()->is_active() && !(*itr)->download()->info()->is_private()) 198 198 break; 199 199 -
trunk/rtorrent/src/core/download.cc
r1129 r1144 160 160 void 161 161 Download::set_throttle_name(const std::string& throttleName) { 162 if (m_download.i s_active())162 if (m_download.info()->is_active()) 163 163 throw torrent::input_error("Cannot set throttle on active download."); 164 164 -
trunk/rtorrent/src/core/download.h
r1129 r1144 40 40 #include <sigc++/connection.h> 41 41 #include <torrent/download.h> 42 #include <torrent/download_info.h> 42 43 #include <torrent/hash_string.h> 43 44 #include <torrent/tracker_list.h> … … 71 72 ~Download(); 72 73 73 bool is_open() const { return m_download.is_open(); } 74 bool is_active() const { return m_download.is_active(); } 74 const torrent::DownloadInfo* info() const { return m_download.info(); } 75 76 bool is_open() const { return m_download.info()->is_open(); } 77 bool is_active() const { return m_download.info()->is_active(); } 75 78 bool is_done() const { return m_download.file_list()->is_done(); } 76 79 bool is_downloading() const { return is_active() && !is_done(); } … … 80 83 // return true when the torrent is closed. Remove this redundant 81 84 // test in the next milestone. 82 bool is_hash_checked() const { return m_download.is_open() && m_download.is_hash_checked(); }85 bool is_hash_checked() const { return is_open() && m_download.is_hash_checked(); } 83 86 bool is_hash_checking() const { return m_download.is_hash_checking(); } 84 87 -
trunk/rtorrent/src/core/download_factory.cc
r1140 r1144 88 88 } 89 89 90 bool 91 is_magnet_uri(const std::string& uri) { 92 return 93 std::strncmp(uri.c_str(), "magnet:?", 8) == 0; 94 } 95 90 96 DownloadFactory::DownloadFactory(Manager* m) : 91 97 m_manager(m), … … 154 160 m_variables["tied_to_file"] = (int64_t)false; 155 161 162 } else if (is_magnet_uri(m_uri)) { 163 // DEBUG: Use m_object. 164 m_stream = new std::stringstream(); 165 *m_stream << "d10:magnet-uri" << m_uri.length() << ":" << m_uri << "e"; 166 167 m_variables["tied_to_file"] = (int64_t)false; 168 receive_loaded(); 169 156 170 } else { 157 171 std::fstream stream(rak::path_expand(m_uri).c_str(), std::ios::in | std::ios::binary); … … 204 218 205 219 torrent::Object* root = download->bencode(); 220 221 if (download->download()->info()->is_meta_download()) { 222 torrent::Object& meta = root->insert_key("rtorrent_meta_download", torrent::Object::create_map()); 223 meta.insert_key("start", m_start); 224 meta.insert_key("print_log", m_printLog); 225 226 torrent::Object::list_type& commands = meta.insert_key("commands", torrent::Object::create_list()).as_list(); 227 228 for (command_list_type::iterator itr = m_commands.begin(); itr != m_commands.end(); ++itr) 229 commands.push_back(*itr); 230 } 206 231 207 232 if (m_session) { … … 261 286 262 287 if (!m_session && m_variables["tied_to_file"].as_value()) 263 rpc::call_command("d.set_tied_to_file", m_uri , rpc::make_target(download));264 265 rpc::call_command("d. set_peer_exchange", rpc::call_command_value("get_peer_exchange"), rpc::make_target(download));288 rpc::call_command("d.set_tied_to_file", m_uri.empty() ? m_variables["tied_file"] : m_uri, rpc::make_target(download)); 289 290 rpc::call_command("d.peer_exchange.set", rpc::call_command_value("get_peer_exchange"), rpc::make_target(download)); 266 291 267 292 torrent::resume_load_addresses(*download->download(), resumeObject); -
trunk/rtorrent/src/core/download_factory.h
r1133 r1144 114 114 115 115 bool is_network_uri(const std::string& uri); 116 bool is_magnet_uri(const std::string& uri); 116 117 117 118 } -
trunk/rtorrent/src/core/download_list.cc
r1133 r1144 38 38 39 39 #include <algorithm> 40 #include <fstream> 40 41 #include <iostream> 41 42 #include <sigc++/adaptors/bind.h> 42 43 #include <rak/functional.h> 43 44 #include <rak/string_manip.h> 45 #include <torrent/data/file.h> 44 46 #include <torrent/exceptions.h> 45 47 #include <torrent/download.h> … … 237 239 check_contains(download); 238 240 239 if (download->download()->i s_open())241 if (download->download()->info()->is_open()) 240 242 return; 241 243 … … 262 264 void 263 265 DownloadList::close_directly(Download* download) { 264 if (download->download()->i s_active()) {266 if (download->download()->info()->is_active()) { 265 267 download->download()->stop(torrent::Download::stop_skip_tracker); 266 268 … … 269 271 } 270 272 271 if (download->download()->i s_open())273 if (download->download()->info()->is_open()) 272 274 download->download()->close(); 273 275 } … … 321 323 try { 322 324 323 if (download->download()->i s_active())325 if (download->download()->info()->is_active()) 324 326 return; 325 327 … … 370 372 371 373 // If the DHT server is set to auto, start it now. 372 if (!download->download()->i s_private())374 if (!download->download()->info()->is_private()) 373 375 control->dht_manager()->auto_start(); 374 376 … … 406 408 } 407 409 408 if (!download->download()->i s_active())410 if (!download->download()->info()->is_active()) 409 411 return; 410 412 … … 475 477 int64_t hashing = rpc::call_command_value("d.get_hashing", rpc::make_target(download)); 476 478 rpc::call_command_set_value("d.set_hashing", Download::variable_hashing_stopped, rpc::make_target(download)); 479 480 if (download->is_done() && download->download()->info()->is_meta_download()) 481 return process_meta_download(download); 477 482 478 483 switch (hashing) { … … 567 572 check_contains(download); 568 573 574 if (download->download()->info()->is_meta_download()) 575 return process_meta_download(download); 576 569 577 rpc::call_command("d.set_complete", (int64_t)1, rpc::make_target(download)); 570 578 … … 600 608 } 601 609 602 } 610 void 611 DownloadList::process_meta_download(Download* download) { 612 rpc::call_command("d.stop", torrent::Object(), rpc::make_target(download)); 613 rpc::call_command("d.close", torrent::Object(), rpc::make_target(download)); 614 615 std::string metafile = (*download->file_list()->begin())->frozen_path(); 616 std::fstream file(metafile.c_str(), std::ios::in | std::ios::binary); 617 if (!file.is_open()) { 618 control->core()->push_log("Could not read download metadata."); 619 return; 620 } 621 622 torrent::Object* bencode = new torrent::Object(torrent::Object::create_map()); 623 file >> bencode->insert_key("info", torrent::Object()); 624 if (file.fail()) { 625 delete bencode; 626 control->core()->push_log("Could not create download, the input is not a valid torrent."); 627 return; 628 } 629 file.close(); 630 631 // Steal the keys we still need. The old download has no use for them. 632 bencode->insert_key("rtorrent_meta_download", torrent::Object()).swap(download->bencode()->get_key("rtorrent_meta_download")); 633 if (download->bencode()->has_key("announce")) 634 bencode->insert_key("announce", torrent::Object()).swap(download->bencode()->get_key("announce")); 635 if (download->bencode()->has_key("announce-list")) 636 bencode->insert_key("announce-list", torrent::Object()).swap(download->bencode()->get_key("announce-list")); 637 638 erase_ptr(download); 639 control->core()->try_create_download_from_meta_download(bencode, metafile); 640 } 641 642 } -
trunk/rtorrent/src/core/download_list.h
r1133 r1144 163 163 void received_finished(Download* d); 164 164 void confirm_finished(Download* d); 165 166 void process_meta_download(Download* d); 165 167 }; 166 168 -
trunk/rtorrent/src/core/manager.cc
r1131 r1144 40 40 #include <cstring> 41 41 #include <fstream> 42 #include <sstream> 42 43 #include <unistd.h> 43 44 #include <sys/select.h> … … 53 54 #include <torrent/error.h> 54 55 #include <torrent/exceptions.h> 56 #include <torrent/object_stream.h> 55 57 #include <torrent/resume.h> 56 58 #include <torrent/tracker_list.h> … … 396 398 !(flags & create_raw_data) && 397 399 !is_network_uri(uri) && 400 !is_magnet_uri(uri) && 398 401 !file_status_cache()->insert(uri, 0)) 399 402 return; … … 414 417 f->load(uri); 415 418 419 f->commit(); 420 } 421 422 void 423 Manager::try_create_download_from_meta_download(torrent::Object* bencode, const std::string& metafile) { 424 DownloadFactory* f = new DownloadFactory(this); 425 426 f->variables()["tied_to_file"] = (int64_t)true; 427 f->variables()["tied_file"] = metafile; 428 429 torrent::Object& meta = bencode->get_key("rtorrent_meta_download"); 430 torrent::Object::list_type& commands = meta.get_key_list("commands"); 431 for (torrent::Object::list_type::const_iterator itr = commands.begin(); itr != commands.end(); ++itr) 432 f->commands().insert(f->commands().end(), itr->as_string()); 433 434 f->set_start(meta.get_key_value("start")); 435 f->set_print_log(meta.get_key_value("print_log")); 436 f->slot_finished(sigc::bind(sigc::ptr_fun(&rak::call_delete_func<core::DownloadFactory>), f)); 437 438 // Bit of a waste to create the bencode repesentation here 439 // only to have the DownloadFactory decode it. 440 std::stringstream s; 441 s.imbue(std::locale::classic()); 442 s << *bencode; 443 f->load_raw_data(s.str()); 416 444 f->commit(); 417 445 } -
trunk/rtorrent/src/core/manager.h
r1101 r1144 129 129 void try_create_download(const std::string& uri, int flags, const command_list_type& commands); 130 130 void try_create_download_expand(const std::string& uri, int flags, command_list_type commands = command_list_type()); 131 void try_create_download_from_meta_download(torrent::Object* bencode, const std::string& metafile); 131 132 132 133 private: -
trunk/rtorrent/src/display/utils.cc
r1092 r1144 133 133 char* 134 134 print_download_info(char* first, char* last, core::Download* d) { 135 if (!d->download()->i s_open())135 if (!d->download()->info()->is_open()) 136 136 first = print_buffer(first, last, "[CLOSED] "); 137 else if (!d->download()->i s_active())137 else if (!d->download()->info()->is_active()) 138 138 first = print_buffer(first, last, "[OPEN] "); 139 139 else … … 152 152 (double)d->download()->up_rate()->total() / (1 << 20)); 153 153 154 if (d->download()->i s_active() && !d->is_done()) {154 if (d->download()->info()->is_active() && !d->is_done()) { 155 155 first = print_buffer(first, last, " "); 156 156 first = print_download_percentage_done(first, last, d); -
trunk/rtorrent/src/main.cc
r1139 r1144 87 87 optionParser.insert_flag('h', sigc::ptr_fun(&print_help)); 88 88 optionParser.insert_flag('n', OptionParser::Slot()); 89 optionParser.insert_flag('D', OptionParser::Slot()); 89 90 90 91 optionParser.insert_option('b', sigc::bind<0>(sigc::ptr_fun(&rpc::call_command_set_string), "bind")); … … 303 304 304 305 // Deprecated commands. Don't use these anymore. 306 307 if (!OptionParser::has_flag('D', argc, argv)) { 305 308 306 309 rpc::parse_command_multiple … … 348 351 "method.insert = get_max_memory_usage,redirect|const,pieces.memory.max\n" 349 352 "method.insert = set_max_memory_usage,redirect|const,pieces.memory.max.set\n" 353 354 "method.insert = d.get_peer_exchange,redirect|const,d.peer_exchange\n" 350 355 ); 356 357 } 351 358 352 359 if (OptionParser::has_flag('n', argc, argv)) -
trunk/rtorrent/src/ui/download.cc
r1131 r1144 164 164 element->push_column("Chunks:", te_command("cat=$d.get_completed_chunks=,\" / \",$d.get_size_chunks=,\" * \",$d.get_chunk_size=")); 165 165 element->push_column("Priority:", te_command("d.get_priority=")); 166 element->push_column("Peer exchange:", te_command("cat=$if=$d. get_peer_exchange=\\,enabled\\,disabled,\\ ,"166 element->push_column("Peer exchange:", te_command("cat=$if=$d.peer_exchange=\\,enabled\\,disabled,\\ ," 167 167 "$if=$d.is_pex_active=\\,active\\,$d.is_private=\\,private\\,inactive," 168 168 "\\ (,$d.get_size_pex=,/,$d.get_max_size_pex=,)"));
Note: See TracChangeset
for help on using the changeset viewer.
