| 1 | <?xml version="1.0" encoding="utf-8" ?> |
|---|
| 2 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
|---|
| 3 | <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> |
|---|
| 4 | <head> |
|---|
| 5 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
|---|
| 6 | <meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" /> |
|---|
| 7 | <title></title> |
|---|
| 8 | <link rel="stylesheet" href="../css/bep.css" type="text/css" /> |
|---|
| 9 | </head> |
|---|
| 10 | <body> |
|---|
| 11 | <div class="document"> |
|---|
| 12 | |
|---|
| 13 | <div id="upper" class="clear"> |
|---|
| 14 | <div id="wrap"> |
|---|
| 15 | <div id="header"> |
|---|
| 16 | <h1><a href="../index.html">BitTorrent<span>.org</span></a></h1> |
|---|
| 17 | </div> |
|---|
| 18 | <div id="nav"> |
|---|
| 19 | <ul> |
|---|
| 20 | <li><a href="../index.html">Home</a></li> |
|---|
| 21 | <li><a href="../introduction.html">For Users</a></li> |
|---|
| 22 | <li><span>For Developers</span></li> |
|---|
| 23 | <!-- <li><a href="./blog">Blog</a></li> --> |
|---|
| 24 | <li><a href="../donate.html">Donate!</a></li> |
|---|
| 25 | </ul> |
|---|
| 26 | </div> <!-- nav --> |
|---|
| 27 | <!-- ### Begin Content ### --> |
|---|
| 28 | <div id="second"> |
|---|
| 29 | |
|---|
| 30 | |
|---|
| 31 | |
|---|
| 32 | <table class="rfc2822 docutils field-list" frame="void" rules="none"> |
|---|
| 33 | <col class="field-name" /> |
|---|
| 34 | <col class="field-body" /> |
|---|
| 35 | <tbody valign="top"> |
|---|
| 36 | <tr class="field"><th class="field-name">BEP:</th><td class="field-body">6</td> |
|---|
| 37 | </tr> |
|---|
| 38 | <tr class="field"><th class="field-name">Title:</th><td class="field-body">Fast Extension</td> |
|---|
| 39 | </tr> |
|---|
| 40 | <tr class="field"><th class="field-name">Version:</th><td class="field-body">10528</td> |
|---|
| 41 | </tr> |
|---|
| 42 | <tr class="field"><th class="field-name">Last-Modified:</th><td class="field-body"><a class="reference external" href="https://svn.bittorrent.com/trac.cgi/browser/dotorg/trunk/html/beps/bep_0006.rst">2008-02-04 16:10:30 -0800 (Mon, 04 Feb 2008)</a></td> |
|---|
| 43 | </tr> |
|---|
| 44 | <tr class="field"><th class="field-name">Author:</th><td class="field-body">David Harrison <dave at bittorrent.com>, Bram Cohen <bram at bittorrent.com></td> |
|---|
| 45 | </tr> |
|---|
| 46 | <tr class="field"><th class="field-name">Status:</th><td class="field-body">Draft</td> |
|---|
| 47 | </tr> |
|---|
| 48 | <tr class="field"><th class="field-name">Type:</th><td class="field-body">Standards Track</td> |
|---|
| 49 | </tr> |
|---|
| 50 | <tr class="field"><th class="field-name">Created:</th><td class="field-body">01-Feb-2008</td> |
|---|
| 51 | </tr> |
|---|
| 52 | <tr class="field"><th class="field-name">Post-History:</th><td class="field-body"></td> |
|---|
| 53 | </tr> |
|---|
| 54 | </tbody> |
|---|
| 55 | </table> |
|---|
| 56 | <hr /> |
|---|
| 57 | <div class="contents topic" id="contents"> |
|---|
| 58 | <p class="topic-title first">Contents</p> |
|---|
| 59 | <ul class="simple"> |
|---|
| 60 | <li><a class="reference internal" href="#modifications-to-semantics-of-existing-messages" id="id6">Modifications to Semantics of Existing Messages</a></li> |
|---|
| 61 | <li><a class="reference internal" href="#have-all-have-none" id="id7">Have All/Have None</a></li> |
|---|
| 62 | <li><a class="reference internal" href="#suggest-piece" id="id8">Suggest Piece</a></li> |
|---|
| 63 | <li><a class="reference internal" href="#reject-request" id="id9">Reject Request</a></li> |
|---|
| 64 | <li><a class="reference internal" href="#allowed-fast" id="id10">Allowed Fast</a></li> |
|---|
| 65 | <li><a class="reference internal" href="#allowed-fast-set-generation" id="id11">Allowed Fast Set Generation</a></li> |
|---|
| 66 | <li><a class="reference internal" href="#example-implementation" id="id12">Example Implementation</a></li> |
|---|
| 67 | <li><a class="reference internal" href="#id1" id="id13">References</a></li> |
|---|
| 68 | </ul> |
|---|
| 69 | </div> |
|---|
| 70 | <p>The Fast Extension packages several extensions: <em>Have None/Have All</em>, |
|---|
| 71 | <em>Reject Requests</em>, <em>Suggestions</em> and <em>Allowed Fast.</em> |
|---|
| 72 | These are enabled by setting the third least significant bit of the |
|---|
| 73 | last reserved byte in the BitTorrent handshake:</p> |
|---|
| 74 | <pre class="literal-block"> |
|---|
| 75 | reserved[7] |= 0x04 |
|---|
| 76 | </pre> |
|---|
| 77 | <p>The extension is enabled only if both ends of the connection set this bit.</p> |
|---|
| 78 | <p>The following proposed messages adhere to the syntax of messages found |
|---|
| 79 | in v1.0 of the BitTorrent protocol. All integers are four bytes |
|---|
| 80 | big-endian. All messages start with an integer message length. All |
|---|
| 81 | messages but the Keep-Alive follow the message length with a single |
|---|
| 82 | byte opcode and zero or more opcode-dependant arguments.</p> |
|---|
| 83 | <p>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL |
|---|
| 84 | NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and |
|---|
| 85 | "OPTIONAL" in this document are to be interpreted as described in |
|---|
| 86 | IETF <a class="reference external" href="http://www.ietf.org/rfc/rfc2119.txt">RFC 2119</a> <a class="footnote-reference" href="#id2" id="id3">[1]</a>.</p> |
|---|
| 87 | <div class="section" id="modifications-to-semantics-of-existing-messages"> |
|---|
| 88 | <h1>Modifications to Semantics of Existing Messages</h1> |
|---|
| 89 | <p>The Fast Extension modifies the semantics of the |
|---|
| 90 | <em>Request</em>, <em>Choke</em>, <em>Unchoke</em>, and <em>Cancel</em> |
|---|
| 91 | messages, and adds a <em>Reject Request.</em> Now, every request |
|---|
| 92 | is guaranteed to result in EXACTLY ONE response |
|---|
| 93 | which is either the corresponding reject or corresponding piece |
|---|
| 94 | message. Even when a request is cancelled, the peer receiving |
|---|
| 95 | the cancel should respond with either the corresponding reject or |
|---|
| 96 | the corresponding piece: requests that are being processed are |
|---|
| 97 | allowed to complete.</p> |
|---|
| 98 | <p>Choke no longer implicitly rejects all pending requests, |
|---|
| 99 | thus eliminating some race conditions which could cause pieces |
|---|
| 100 | to be needlessly requested multiple times.</p> |
|---|
| 101 | <p>Additionally, if a peer receives a piece that was never requested, |
|---|
| 102 | the peer MUST close the connection.</p> |
|---|
| 103 | </div> |
|---|
| 104 | <div class="section" id="have-all-have-none"> |
|---|
| 105 | <h1>Have All/Have None</h1> |
|---|
| 106 | <pre class="literal-block"> |
|---|
| 107 | *Have All*: <len=0x0001> <op=0x0E> |
|---|
| 108 | </pre> |
|---|
| 109 | <pre class="literal-block"> |
|---|
| 110 | *Have None*: <len=0x0001><op=0x0F> |
|---|
| 111 | </pre> |
|---|
| 112 | <p><em>Have All</em> and <em>Have None</em> specify that the message sender |
|---|
| 113 | has all or none of the pieces respectively. When present, <em>Have All</em> |
|---|
| 114 | or <em>Have None</em> replace the <em>Have Bitfield.</em> Exactly one of <em>Have All</em>, |
|---|
| 115 | <em>Have None</em>, or <em>Have Bitfield</em> MUST appear and only immediately after |
|---|
| 116 | the handshake. The reason for these messages is to save bandwidth. Also |
|---|
| 117 | slightly to remove the idiosyncrasy of sending no message when a peer |
|---|
| 118 | has no pieces.</p> |
|---|
| 119 | <p>When the fast extension is disabled, if a peer receives <em>Have All</em> or |
|---|
| 120 | <em>Have None</em> then the peer MUST close the connection.</p> |
|---|
| 121 | </div> |
|---|
| 122 | <div class="section" id="suggest-piece"> |
|---|
| 123 | <h1>Suggest Piece</h1> |
|---|
| 124 | <pre class="literal-block"> |
|---|
| 125 | *Suggest Piece*: <len=0x0005><op=0x0D><index> |
|---|
| 126 | </pre> |
|---|
| 127 | <p><em>Suggest Piece</em> is an advisory message meaning "you might like to |
|---|
| 128 | download this piece." The intended usage is for 'super-seeding' |
|---|
| 129 | without throughput reduction, to avoid redundant downloads, and so that |
|---|
| 130 | a seed which is disk I/O bound can upload continguous or identical |
|---|
| 131 | pieces to avoid excessive disk seeks. In all cases, the seed SHOULD |
|---|
| 132 | operate to maintain a roughly equal number of copies of each piece in |
|---|
| 133 | the network. A peer MAY send more than one <em>suggest piece</em> message at |
|---|
| 134 | any given time. A peer receiving multiple <em>suggest piece</em> messages |
|---|
| 135 | MAY interpret this as meaning that all of the suggested pieces |
|---|
| 136 | are equally appropriate.</p> |
|---|
| 137 | <p>When the fast extension is disabled, if a peer receives a |
|---|
| 138 | <em>Suggest Piece</em> message, the peer MUST close the connection.</p> |
|---|
| 139 | </div> |
|---|
| 140 | <div class="section" id="reject-request"> |
|---|
| 141 | <h1>Reject Request</h1> |
|---|
| 142 | <pre class="literal-block"> |
|---|
| 143 | *Reject Request*: <len=0x000D><op=0x10><index><begin><offset> |
|---|
| 144 | </pre> |
|---|
| 145 | <p><em>Reject Request</em> notifies a requesting peer that its request will not be satisfied.</p> |
|---|
| 146 | <p>If the fast extension is disabled and a peer receives a reject |
|---|
| 147 | request then the peer MUST close the connection.</p> |
|---|
| 148 | <p>When the fast extension is enabled:</p> |
|---|
| 149 | <ul class="simple"> |
|---|
| 150 | <li>If a peer receives a reject for a request that was never sent then |
|---|
| 151 | the peer SHOULD close the connection.</li> |
|---|
| 152 | <li>If a peer sends a choke, it MUST reject all requests from the peer |
|---|
| 153 | to whom the choke was sent except it SHOULD NOT reject requests for |
|---|
| 154 | pieces that are in the <em>allowed fast set.</em> A peer SHOULD choke first |
|---|
| 155 | and then reject requests so that the peer receiving the choke does not |
|---|
| 156 | re-request the pieces.</li> |
|---|
| 157 | <li>If a peer receives a request from a peer its choking, the peer |
|---|
| 158 | receiving the request SHOULD send a reject unless the piece is in the |
|---|
| 159 | <em>allowed fast set.</em></li> |
|---|
| 160 | <li>If a peer receives an excessive number of requests from a peer it is |
|---|
| 161 | choking, the peer receiving the requests MAY close the connection |
|---|
| 162 | rather than reject the request. However, consider that it can take |
|---|
| 163 | several seconds for buffers to drain and messages to propagate once a |
|---|
| 164 | peer is choked.</li> |
|---|
| 165 | </ul> |
|---|
| 166 | </div> |
|---|
| 167 | <div class="section" id="allowed-fast"> |
|---|
| 168 | <h1>Allowed Fast</h1> |
|---|
| 169 | <pre class="literal-block"> |
|---|
| 170 | * Allowed Fast: <len=0x0005><op=0x11><index>* |
|---|
| 171 | </pre> |
|---|
| 172 | <p>With the BitTorrent protocol specified in <a class="reference external" href="http://www.bittorrent.org/beps/bep_0002.html">BEP 0002</a> <a class="footnote-reference" href="#id4" id="id5">[2]</a>, new peers take |
|---|
| 173 | several minutes to ramp up before they can effectively engage in |
|---|
| 174 | BitTorrent's tit-for-tat. The reason is simple: starting peers have |
|---|
| 175 | few pieces to trade.</p> |
|---|
| 176 | <p><em>Allowed Fast</em> is an advisory message which means "if you ask for this |
|---|
| 177 | piece, I'll give it to you even if you're choked." <em>Allowed Fast</em> thus |
|---|
| 178 | shortens the awkward stage during which the peer obtains occasional |
|---|
| 179 | optimistic unchokes but cannot sufficiently reciprocate to remain |
|---|
| 180 | unchoked.</p> |
|---|
| 181 | <p>The pieces that can be downloaded when choked constitute a peer's |
|---|
| 182 | <em>allowed fast set.</em> The set is generated using a canonical algorithm |
|---|
| 183 | that produces piece indices unique to the message receiver so that if |
|---|
| 184 | two peers offer <em>k</em> pieces fast it will be the same <em>k</em>, and if one |
|---|
| 185 | offers <em>k+1</em> it will be the same <em>k</em> plus one more. <em>k</em> should be |
|---|
| 186 | small enough to avoid abuse, but large enough to ramp up |
|---|
| 187 | tit-for-tat. We currently set <em>k</em> to 10, but peers are free to change |
|---|
| 188 | this number, e.g., to suit load.</p> |
|---|
| 189 | <p>The message sender MAY list pieces that the message sender does not |
|---|
| 190 | have. The receiver MUST NOT interpret an Allowed Fast message as |
|---|
| 191 | meaning that the message sender has the piece. This allows peers to |
|---|
| 192 | generate and communicate allowed fast sets at the beginning of a |
|---|
| 193 | connection. However, a peer MAY send Allowed Fast messages at any |
|---|
| 194 | time.</p> |
|---|
| 195 | <p>A peer SHOULD send Allowed Fast messages to any starting peer unless |
|---|
| 196 | the local peer lacks sufficient resources. A peer MAY reject requests |
|---|
| 197 | for already Allowed Fast pieces if the local peer lacks sufficient |
|---|
| 198 | resources, if the requested piece has already been sent to the |
|---|
| 199 | requesting peer, or if the requesting peer is not a starting peer. Our |
|---|
| 200 | current implementation rejects requests for Allowed Fast messages |
|---|
| 201 | whenever the requesting peer has more than * k * pieces.</p> |
|---|
| 202 | <blockquote> |
|---|
| 203 | When the fast extension is disabled, if a peer recieves an Allowed |
|---|
| 204 | Fast message then the peer MUST close the connection.</blockquote> |
|---|
| 205 | </div> |
|---|
| 206 | <div class="section" id="allowed-fast-set-generation"> |
|---|
| 207 | <h1>Allowed Fast Set Generation</h1> |
|---|
| 208 | <p>The canonical algorithm for computing a peer <em>P'*s *allowed fast set</em> |
|---|
| 209 | follows. All integers in this pseudocode are four bytes represented |
|---|
| 210 | in network (big-endian) byte order. <em>[a:b]</em> denotes the sequence of |
|---|
| 211 | consecutive bytes from <em>a</em> to <em>b</em> excluding <em>b</em>, i.e., <em>(a, a+1, |
|---|
| 212 | a+2,..., b-1)</em>. <em>x[a:b]</em> denotes a subsequence of elements in an array |
|---|
| 213 | <em>x</em> starting from index <em>a</em> to but not including index <em>b</em>.</p> |
|---|
| 214 | <p>Let <em>ip</em> denote <em>P'*s IPv4 address. We currently have no |
|---|
| 215 | provisions for IPv6. If a peer is behind a Network Address Translator |
|---|
| 216 | (NAT) then *ip</em> should be the externally facing IP address of the |
|---|
| 217 | NAT. Since the node sending the <em>Allowed Fast</em> messages computes |
|---|
| 218 | the set, the correct <em>ip</em> is usually the <em>ip</em> address on the other |
|---|
| 219 | end of the connection. The host computing the set MAY use the <em>ip</em> |
|---|
| 220 | address on the other end of the connection regardless</p> |
|---|
| 221 | <p>Let <em>sz</em> denote the number of pieces in the torrent.</p> |
|---|
| 222 | <p>Let <em>a</em> denote the allowed fast set.</p> |
|---|
| 223 | <p>Let <em>k</em> denote the final number of pieces in the allowed fast set.</p> |
|---|
| 224 | <pre class="literal-block"> |
|---|
| 225 | x = 0xFFFFFF00 & ip (1) |
|---|
| 226 | x.append(infohash) (2) |
|---|
| 227 | while |a| < k: |
|---|
| 228 | x = SHA1(x) (3) |
|---|
| 229 | for i in [0:5] and |a| < k: (4) |
|---|
| 230 | j = i*4 (5) |
|---|
| 231 | y = x[j:j+4] (6) |
|---|
| 232 | index = y % sz (7) |
|---|
| 233 | if index not in a: (8) |
|---|
| 234 | add index to a (9) |
|---|
| 235 | </pre> |
|---|
| 236 | <p>Step (1) selects the most significant octets in peer <em>P'*s |
|---|
| 237 | ip address. We do this to prevent a user that obtains more than one |
|---|
| 238 | IP address on the same network from obtaining more than one |
|---|
| 239 | *allowed fast set.</em> Use of three bytes is heuristic and |
|---|
| 240 | historical.</p> |
|---|
| 241 | <p>Step (3) generates a 20-byte random number on each call. By |
|---|
| 242 | performing a SHA-1 hash on the previous iteration's hash, we can |
|---|
| 243 | generate an arbitrarily long pseudorandom sequence.</p> |
|---|
| 244 | <p>Steps (4) through (9) partition the 20-byte hash into piece indices |
|---|
| 245 | and add them to the allowed fast set.</p> |
|---|
| 246 | </div> |
|---|
| 247 | <div class="section" id="example-implementation"> |
|---|
| 248 | <h1>Example Implementation</h1> |
|---|
| 249 | <p>The following C++ implementation was provided by CacheLogic:</p> |
|---|
| 250 | <pre class="literal-block"> |
|---|
| 251 | void generate_fast_set( |
|---|
| 252 | uint32 k, // number of pieces in set |
|---|
| 253 | uint32 sz, // number of pieces in torrent |
|---|
| 254 | const char infohash[20], // infohash of torrent |
|---|
| 255 | uint32 ip, // in host byte order, ie localhost is 0x7f000001 |
|---|
| 256 | std:: |
|---|
| 257 | vector<uint32> &a) // generated set of piece indices |
|---|
| 258 | { |
|---|
| 259 | a.clear(); |
|---|
| 260 | std::string x; |
|---|
| 261 | char buf[4]; |
|---|
| 262 | *(uint32*)buf = htonl(ip & 0xffffff00); |
|---|
| 263 | x.assign(buf, 4); |
|---|
| 264 | x.append(infohash, 20); // (3) |
|---|
| 265 | while (a.size()<k) { |
|---|
| 266 | x = SHA1(x); // (4) |
|---|
| 267 | for ( int i=0&nbsp;; i<5 && a.size()<k; i++ ) { // (5) |
|---|
| 268 | int j = i*4; // (6) |
|---|
| 269 | uint32 y = ntohl(*(uint32*)(x.data()+j)); // (7) |
|---|
| 270 | uint32 index = y % sz; // (8) |
|---|
| 271 | if (std::find(a.begin(), a.end(), index)==a.end()) { // (9) |
|---|
| 272 | a.push_back(index); // (10) |
|---|
| 273 | } |
|---|
| 274 | } |
|---|
| 275 | } |
|---|
| 276 | } |
|---|
| 277 | </pre> |
|---|
| 278 | <p>Example results generated by this function:</p> |
|---|
| 279 | <pre class="literal-block"> |
|---|
| 280 | 7 piece allowed fast set for torrent with 1313 pieces and hex infohash |
|---|
| 281 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa for node with IP 80.4.4.200: |
|---|
| 282 | 1059,431,808,1217,287,376,1188 |
|---|
| 283 | 9 piece allowed fast set for torrent with 1313 pieces and hex infohash |
|---|
| 284 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa for node with IP 80.4.4.200: |
|---|
| 285 | 1059,431,808,1217,287,376,1188,353,508 |
|---|
| 286 | </pre> |
|---|
| 287 | <!-- Local Variables: |
|---|
| 288 | mode: indented-text |
|---|
| 289 | indent-tabs-mode: nil |
|---|
| 290 | sentence-end-double-space: t |
|---|
| 291 | fill-column: 70 |
|---|
| 292 | coding: utf-8 |
|---|
| 293 | End: --> |
|---|
| 294 | </div> |
|---|
| 295 | <div class="section" id="id1"> |
|---|
| 296 | <h1>References</h1> |
|---|
| 297 | <table class="docutils footnote" frame="void" id="id2" rules="none"> |
|---|
| 298 | <colgroup><col class="label" /><col /></colgroup> |
|---|
| 299 | <tbody valign="top"> |
|---|
| 300 | <tr><td class="label"><a class="fn-backref" href="#id3">[1]</a></td><td><a class="reference external" href="http://www.ietf.org/rfc/rfc2119.txt">http://www.ietf.org/rfc/rfc2119.txt</a></td></tr> |
|---|
| 301 | </tbody> |
|---|
| 302 | </table> |
|---|
| 303 | <table class="docutils footnote" frame="void" id="id4" rules="none"> |
|---|
| 304 | <colgroup><col class="label" /><col /></colgroup> |
|---|
| 305 | <tbody valign="top"> |
|---|
| 306 | <tr><td class="label"><a class="fn-backref" href="#id5">[2]</a></td><td><a class="reference external" href="http://www.bittorrent.org/beps/bep_0002.html">http://www.bittorrent.org/beps/bep_0002.html</a></td></tr> |
|---|
| 307 | </tbody> |
|---|
| 308 | </table> |
|---|
| 309 | </div> |
|---|
| 310 | |
|---|
| 311 | |
|---|
| 312 | </div> |
|---|
| 313 | <div id="footer"> |
|---|
| 314 | <hr/> |
|---|
| 315 | </div> |
|---|
| 316 | |
|---|
| 317 | </div> |
|---|
| 318 | </body> |
|---|
| 319 | </html> |
|---|