From 5ac9f67f23b2ad503dac3b6deddb2f74c573fe82 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sun, 21 Dec 2003 17:28:27 +0000 Subject: [PATCH] *** empty log message *** --- Jamfile | 15 +- docs/index.html | 126 ++++++++++---- docs/index.rst | 2 + examples/client_test.cpp | 7 +- include/libtorrent/peer_id.hpp | 6 + include/libtorrent/session.hpp | 2 +- include/libtorrent/torrent_handle.hpp | 3 + src/policy.cpp | 1 + src/session.cpp | 233 +++++++++++++++++++++++--- src/storage.cpp | 7 + src/torrent.cpp | 20 ++- 11 files changed, 361 insertions(+), 61 deletions(-) diff --git a/Jamfile b/Jamfile index eb569a1b8..a5e1e6162 100755 --- a/Jamfile +++ b/Jamfile @@ -1,5 +1,3 @@ - - SOURCES = entry.cpp peer_connection.cpp @@ -16,15 +14,18 @@ SOURCES = sha1.c ; + lib torrent : src/$(SOURCES) - zlib//zlib - $(BOOST_ROOT)/libs/filesystem/build//boost_filesystem - $(BOOST_ROOT)/libs/thread/build//boost_thread +# zlib/zlib +# zlib//zlib +# boost_filesystem.lib +# boost_date_time.lib +# boost_thread.dll : $(BOOST_ROOT) $(BOOST_ROOT) ./include - ./ + ./zlib multi static : debug release @@ -33,7 +34,7 @@ lib torrent exe client_test : examples/client_test.cpp - torrent + torrent : $(BOOST_ROOT) $(BOOST_ROOT) ./include diff --git a/docs/index.html b/docs/index.html index 7f000ac3d..4b62affeb 100755 --- a/docs/index.html +++ b/docs/index.html @@ -43,23 +43,24 @@
  • http_settings
  • big_number
  • hasher
  • -
  • exceptions
    @@ -88,9 +89,10 @@ The current state includes the following features:

  • queues torrents for file check, instead of checking all of them in parallel.
  • uses separate threads for checking files and for main downloader, with a fool-proof thread-safe library interface. (i.e. There's no way for the user to cause a deadlock).
  • -
  • can limit the upload bandwidth usage
  • +
  • can limit the upload bandwidth usage and the maximum number of unchoked peers
  • piece-wise file allocation
  • -
  • upload rate limit, balanced depending on download speed and upload bandwidth
  • +
  • tries to maintain a 1:1 share ratio between all peers but also shifts free +download to peers as free upload. To maintain a global 1:1 ratio.
  • Functions that are yet to be implemented:

    @@ -115,6 +117,12 @@ boost.filesystem boost.date_time and various other boost libraries and zlib.

  • Linux x86 (debian) GCC 3.0
  • +

    It does not compile on

    +
    +
      +
    • GCC 2.95
    • +
    +

    building

    @@ -158,7 +166,8 @@ the session, it contains the m
     class session: public boost::noncopyable
     {
    -        session(int listen_port, const std::string& fingerprint = std::string());
    +        session(int listen_port, const fingerprint& print);
    +        session(int listen_port);
     
             torrent_handle add_torrent(const torrent_info& t, const std::string& save_path);
             void remove_torrent(const torrent_handle& h);
    @@ -179,9 +188,11 @@ the tracker that we've stopped participating in the swarm.

    If the torrent you are trying to add already exists in the session (is either queued for checking, being checked or downloading) add_torrent() will throw duplicate_torrent which derives from std::exception.

    -

    fingerprint is a short string that will be used in the peer_id to -identify the client. If the string is longer than 7 characters it will -be trimmed down to 7 characters. The default is an empty string.

    +

    The difference between the two constructors is that one of them takes a fingerprint +as argument. If this is ommited, the client will get a default fingerprint stating +the version of libtorrent. The fingerprint is a short string that will be used in +the peer-id to identify the client and the client's version. For more details see the +fingerprint class.

    set_upload_rate_limit() set the maximum number of bytes allowed to be sent to peers per second. This bandwidth is distributed among all the peers. If you don't want to limit upload rate, you can set this to -1 (the default).

    @@ -555,6 +566,8 @@ struct peer_info int upload_limit; int upload_ceiling; + int load_balancing; + int downloading_piece_index; int downloading_block_index; int downloading_progress; @@ -586,6 +599,11 @@ should sum up to the upload limit set by s

    upload_ceiling is the current maximum allowed upload rate given the cownload rate and share ratio. If the global upload rate is inlimited, the upload_limit for every peer will be the same as their upload_ceiling.

    +

    load_balancing is a measurment of the balancing of free download (that we get) +and free upload that we give. Every peer gets a certain amount of free upload, but +this member says how much extra free upload this peer has got. If it is a negative +number it means that this was a peer from which we have got this amount of free +download.

    You can know which piece, and which part of that piece, that is currently being downloaded from a specific peer by looking at the next four members. downloading_piece_index is the index of the piece that is currently being downloaded. @@ -725,12 +743,61 @@ call reset() to reinitialize i

    The sha1-algorithm used was implemented by Steve Reid and released as public domain. For more info, see src/sha1.c.

    +
    +

    fingerprint

    +

    The fingerprint class represents information about a client and its version. It is used +to encode this information into the client's peer id.

    +

    This is the class declaration:

    +
    +struct fingerprint
    +{
    +        fingerprint(const char* id_string, int major, int minor, int revision, int tag);
    +
    +        std::string to_string() const;
    +
    +        char id[2];
    +        char major_version;
    +        char minor_version;
    +        char revision_version;
    +        char tag_version;
    +
    +};
    +
    +

    The constructor takes a const char* that should point to a string constant containing +exactly two characters. These are the characters that should be unique for your client. Make +sure not to clash with anybody else. Here are some taken id's:

    + ++++ + + + + + + + + + + + + + + + + +
    id charsclient
    'AZ'Azureus
    'LT'libtorrent (default)
    'BX'BittorrentX
    +

    The major, minor, revision and tag parameters are used to identify the +version of your client. All these numbers must be within the range [0, 9].

    +

    to_string() will generate the actual string put in the peer-id, and return it.

    +
    -

    exceptions

    +

    exceptions

    There are a number of exceptions that can be thrown from different places in libtorrent, here's a complete list with description.

    -

    invalid_handle

    +

    invalid_handle

    This exception is thrown when querying information from a torrent_handle that hasn't been initialized or that has become invalid.

    @@ -741,7 +808,7 @@ struct invalid_handle: std::exception
     
    -

    duplicate_torrent

    +

    duplicate_torrent

    This is thrown by session::add_torrent() if the torrent already has been added to the session.

    @@ -752,7 +819,7 @@ struct duplicate_torrent: std::exception
     
    -

    invalid_encoding

    +

    invalid_encoding

    This is thrown by bdecode() if the input data is not a valid bencoding.

     struct invalid_encoding: std::exception
    @@ -762,7 +829,7 @@ struct invalid_encoding: std::exception
     
    -

    type_error

    +

    type_error

    This is thrown from the accessors of entry if the data type of the entry doesn't match the type you want to extract from it.

    @@ -773,7 +840,7 @@ struct type_error: std::runtime_error
     
    -

    invalid_torrent_file

    +

    invalid_torrent_file

    This exception is thrown from the constructor of torrent_info if the given bencoded information doesn't meet the requirements on what information has to be present in a torrent file.

    @@ -785,9 +852,9 @@ struct invalid_torrent_file: std::exception
     
    -

    example usage

    +

    example usage

    -

    dump_torrent

    +

    dump_torrent

    This is an example of a program that will take a torrent-file as a parameter and print information about it to std out:

    @@ -851,7 +918,7 @@ int main(int argc, char* argv[])
     
    -

    simple client

    +

    simple client

    This is a simple client. It doesn't have much output to keep it simple:

     #include <iostream>
    @@ -880,7 +947,7 @@ int main(int argc, char* argv[])
     
             try
             {
    -                session s(6881, "E\x1");
    +                session s(6881);
     
                     std::ifstream in(argv[1], std::ios_base::binary);
                     in.unsetf(std::ios_base::skipws);
    @@ -904,14 +971,15 @@ int main(int argc, char* argv[])
     
    -

    Feedback

    +

    Feedback

    There's a mailing list.

    You can usually find me as hydri in #btports @ irc.freenode.net.

    -

    Aknowledgements

    +

    Aknowledgements

    Written by Arvid Norberg and Daniel Wallin. Copyright (c) 2003

    Contributions by Magnus Jonsson

    +

    Thanks to Reimond Retz for bugfixes, suggestions and testing

    Project is hosted by sourceforge.

    sf_logo

    diff --git a/docs/index.rst b/docs/index.rst index c15b71bcc..b9da169f4 100755 --- a/docs/index.rst +++ b/docs/index.rst @@ -832,6 +832,8 @@ sure not to clash with anybody else. Here are some taken id's: +----------+-----------------------+ | 'LT' | libtorrent (default) | +----------+-----------------------+ +| 'BX' | BittorrentX | ++----------+-----------------------+ The ``major``, ``minor``, ``revision`` and ``tag`` parameters are used to identify the version of your client. All these numbers must be within the range [0, 9]. diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 06cad4544..bd24f6209 100755 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -302,8 +302,13 @@ int main(int argc, char* argv[]) if (progress > j) out << "#"; else out << "-"; } - out << "\n"; + out << " "; } + else + { + for (int i = 0; i < 19; ++i) out << " "; + } + out << identify_client(i->id) << "\n"; } out << "___________________________________\n"; diff --git a/include/libtorrent/peer_id.hpp b/include/libtorrent/peer_id.hpp index a13840c0f..207b18309 100755 --- a/include/libtorrent/peer_id.hpp +++ b/include/libtorrent/peer_id.hpp @@ -65,6 +65,12 @@ namespace libtorrent return false; } + unsigned char& operator[](int i) + { assert(i >= 0 && i < number_size); return m_number[i]; } + + unsigned char operator[](int i) const + { assert(i >= 0 && i < number_size); return m_number[i]; } + typedef const unsigned char* const_iterator; typedef unsigned char* iterator; diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index fd348b498..a8683642d 100755 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -182,7 +182,7 @@ namespace libtorrent struct http_settings; - std::string extract_fingerprint(const peer_id& p); + std::string identify_client(const peer_id& p); class session: public boost::noncopyable, detail::eh_initializer { diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index d1e51e43a..67a2aeecf 100755 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -84,6 +84,9 @@ namespace libtorrent // the number of bytes of the file we have std::size_t total_done; + + // TODO: add flag that says if there have + // been any incoming connections }; struct partial_piece_info diff --git a/src/policy.cpp b/src/policy.cpp index 1a705c53b..410300122 100755 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -485,6 +485,7 @@ namespace libtorrent // this means we're already connected // to this peer. don't connect to // it again. + assert(i->connection->associated_torrent() == m_torrent); return; } diff --git a/src/session.cpp b/src/session.cpp index 947d82345..1db426dd5 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -62,6 +62,8 @@ namespace std }; #endif +// TODO: enable floating point exceptions in debug mode! + namespace { @@ -486,6 +488,10 @@ namespace libtorrent { // (*m_logger) << "readable: " << p->first->sender().as_string() << "\n"; p->second->receive_data(); + +#ifndef NDEBUG + assert_invariant(); +#endif } catch(std::exception& e) { @@ -684,7 +690,19 @@ namespace libtorrent i != m_connections.end(); ++i) { - assert(i->second->has_data() == m_selector.is_writability_monitored(i->first)); + if (i->second->has_data() != m_selector.is_writability_monitored(i->first)) + { + std::ofstream error_log("error.log", std::ios_base::app); + boost::shared_ptr p = i->second; + error_log << "session_imple::assert_invariant()\n" + "peer_connection::has_data() != is_writability_monitored()\n"; + error_log << "peer_connection::has_data() " << p->has_data() << "\n"; + error_log << "peer_connection::send_quota_left " << p->send_quota_left() << "\n"; + error_log << "peer_connection::send_quota " << p->send_quota() << "\n"; + error_log << "peer_connection::get_peer_id " << p->get_peer_id() << "\n"; + error_log.flush(); + assert(false); + } if (i->second->associated_torrent()) { assert(i->second->associated_torrent() @@ -849,25 +867,200 @@ namespace libtorrent return m_impl.m_alerts.get(); } - // TODO: document - // TODO: if the first 4 charachters are printable - // maybe they should be considered a fingerprint? - std::string extract_fingerprint(const peer_id& p) + namespace { - std::string ret; - const unsigned char* c = p.begin(); - while (c != p.end() && *c != 0) - { - if (std::isprint(*c)) - ret += *c; - else if (*c <= 9) - ret += '0'+ *c; - else - return std::string(); - ++c; - } - if (c == p.end()) return std::string(); - return ret; - } + // takes a peer id and returns a valid boost::optional + // object if the peer id matched the azureus style encoding + // the returned fingerprint contains information about the + // client's id + boost::optional parse_az_style(const peer_id& id) + { + fingerprint ret("..", 0, 0, 0, 0); + peer_id::const_iterator i = id.begin(); + + if (*i != '-') return boost::optional(); + ++i; + + for (int j = 0; j < 2; ++j) + { + if (!std::isprint(*i)) return boost::optional(); + ret.id[j] = *i; + ++i; + } + + if (!std::isdigit(*i)) return boost::optional(); + ret.major_version = *i - '0'; + ++i; + + if (!std::isdigit(*i)) return boost::optional(); + ret.minor_version = *i - '0'; + ++i; + + if (!std::isdigit(*i)) return boost::optional(); + ret.revision_version = *i - '0'; + ++i; + + if (!std::isdigit(*i)) return boost::optional(); + ret.tag_version = *i - '0'; + ++i; + + if (*i != '-') return boost::optional(); + + return boost::optional(ret); + } + + // checks if a peer id can possibly contain a shadow-style + // identification + boost::optional parse_shadow_style(const peer_id& id) + { + fingerprint ret("..", 0, 0, 0, 0); + peer_id::const_iterator i = id.begin(); + + if (!std::isprint(*i)) return boost::optional(); + ret.id[0] = *i; + ret.id[1] = 0; + ++i; + + if (id[8] == 45) + { + if (!std::isdigit(*i)) return boost::optional(); + ret.major_version = *i - '0'; + ++i; + + if (!std::isdigit(*i)) return boost::optional(); + ret.minor_version = *i - '0'; + ++i; + + if (!std::isdigit(*i)) return boost::optional(); + ret.revision_version = *i - '0'; + } + else if (id[0] == 0) + { + if (*i > 127) return boost::optional(); + ret.major_version = *i; + ++i; + + if (*i > 127) return boost::optional(); + ret.minor_version = *i; + ++i; + + if (*i > 127) return boost::optional(); + ret.revision_version = *i; + } + else + return boost::optional(); + + + ret.tag_version = 0; + return boost::optional(ret); + } + + } // namespace unnamed + + + + // TODO: document + std::string identify_client(const peer_id& p) + { + peer_id::const_iterator PID = p.begin(); + boost::optional f; + + + // look for azureus style id + f = parse_az_style(p); + if (f) + { + std::stringstream identity; + + // azureus + if (std::equal(f->id, f->id+2, "AZ")) + identity << "Azureus "; + + // BittorrentX + else if (std::equal(f->id, f->id+2, "BX")) + identity << "BittorrentX "; + + // libtorrent + else if (std::equal(f->id, f->id+2, "LT")) + identity << "libtorrent "; + + // unknown client + else + identity << std::string(f->id, f->id+2) << " "; + + identity << (int)f->major_version + << "." << (int)f->minor_version + << "." << (int)f->revision_version + << "." << (int)f->tag_version; + + return identity.str(); + } + + + // look for shadow style id + f = parse_shadow_style(p); + if (f) + { + std::stringstream identity; + + // Shadow + if (std::equal(f->id, f->id+1, "S")) + identity << "Shadow "; + + // UPnP + else if (std::equal(f->id, f->id+1, "U")) + identity << "UPnP "; + + // unknown client + else + identity << std::string(f->id, f->id+1) << " "; + + identity << (int)f->major_version + << "." << (int)f->minor_version + << "." << (int)f->revision_version; + + return identity.str(); + } + + // ---------------------- + // non standard encodings + // ---------------------- + + + if (std::equal(PID + 5, PID + 5 + 8, "Azureus")) + { + return "Azureus 2.0.3.2"; + } + + + if (std::equal(PID, PID + 11, "DansClient")) + { + return "XanTorrent"; + } + + if (std::equal(PID, PID + 7, "btfans")) + { + return "BitComet"; + } + + if (std::equal(PID, PID + 8, "turbobt")) + { + return "TurboBT"; + } + + + if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\x97")) + { + return "Experimental 3.2.1b2"; + } + + if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0")) + { + return "Experimental 3.1"; + } + + return "Generic"; + } + } diff --git a/src/storage.cpp b/src/storage.cpp index 42250d735..c90196410 100755 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -466,6 +466,8 @@ namespace libtorrent { m_pimpl->write(buf, piece_index, offset, size); } + // TODO: must handle the case where some hashes are identical + // correctly void piece_manager::impl::check_pieces( boost::mutex& mutex , detail::piece_checker_data& data @@ -612,6 +614,8 @@ namespace libtorrent { int found_piece = -1; + // TODO: there's still potential problems if some + // pieces have the same hash for (int i = current_slot; i < m_info.num_pieces(); ++i) { if (pieces[i] && i != current_slot) continue; @@ -620,7 +624,10 @@ namespace libtorrent { i == m_info.num_pieces() - 1]->get(); if (hash == m_info.hash_for_piece(i)) + { found_piece = i; + if (i == current_slot) break; + } } if (found_piece != -1) diff --git a/src/torrent.cpp b/src/torrent.cpp index beb1dfac4..4aed92a2a 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -73,8 +73,22 @@ namespace int calculate_block_size(const torrent_info& i) { - // TODO: if blocks_per_piece > 128 increase block-size - return 16*1024; + const int default_block_size = 16 * 1024; + + // if pieces are too small, adjust the block size + if (i.piece_length() < default_block_size) + { + return i.piece_length(); + } + + // if pieces are too large, adjust the block size + if (i.piece_length() / default_block_size > 128) + { + return i.piece_length() / 128; + } + + // otherwise, go with the default + return default_block_size; } @@ -199,7 +213,7 @@ namespace libtorrent { std::cout << " " << std::setfill(' ') << std::setw(16) << i->ip << " " << std::setw(5) << std::dec << i->port << " " - << i->id << " " << extract_fingerprint(i->id) << "\n"; + << i->id << " " << identify_client(i->id) << "\n"; } std::cout << std::setfill(' ');