| 1 |
Apt-DHT's Distributed Hash Table is very similar to BitTorrent's. |
Apt-DHT's Distributed Hash Table is very similar to BitTorrent's. |
| 2 |
BitTorrent uses a "distributed sloppy hash table" (DHT) for storing peer |
BitTorrent uses a "distributed sloppy hash table" (DHT) for storing peer |
| 3 |
contact information for "trackerless" torrents. In effect, each peer |
contact information for "trackerless" torrents. In effect, each peer |
| 4 |
becomes a tracker. The protocol is based on [Kademila][10] and is |
becomes a tracker. The protocol is based on [Kademlia][10] and is |
| 5 |
implemented over UDP. |
implemented over UDP. |
| 6 |
|
|
| 7 |
[10]: http://www.cs.rice.edu/Conferences/IPTPS02/109.pdf |
[10]: http://www.cs.rice.edu/Conferences/IPTPS02/109.pdf |
| 129 |
character value describing the type of message. The value of the "y" key |
character value describing the type of message. The value of the "y" key |
| 130 |
is one of "q" for query, "r" for response, or "e" for error. |
is one of "q" for query, "r" for response, or "e" for error. |
| 131 |
|
|
| 132 |
#### Queries |
### Queries |
| 133 |
|
|
| 134 |
Queries, or KRPC message dictionaries with a "y" value of "q", contain |
Queries, or KRPC message dictionaries with a "y" value of "q", contain |
| 135 |
two additional keys; "q" and "a". Key "q" has a string value containing |
two additional keys; "q" and "a". Key "q" has a string value containing |
| 136 |
the method name of the query. Key "a" has a dictionary value containing |
the method name of the query. Key "a" has a dictionary value containing |
| 137 |
named arguments to the query. |
named arguments to the query. |
| 138 |
|
|
| 139 |
#### Responses |
### Responses |
| 140 |
|
|
| 141 |
Responses, or KRPC message dictionaries with a "y" value of "r", contain |
Responses, or KRPC message dictionaries with a "y" value of "r", contain |
| 142 |
one additional key "r". The value of "r" is a dictionary containing |
one additional key "r". The value of "r" is a dictionary containing |
| 143 |
named return values. Response messages are sent upon successful |
named return values. Response messages are sent upon successful |
| 144 |
completion of a query. |
completion of a query. |
| 145 |
|
|
| 146 |
#### Errors |
### Errors |
| 147 |
|
|
| 148 |
Errors, or KRPC message dictionaries with a "y" value of "e", contain |
Errors, or KRPC message dictionaries with a "y" value of "e", contain |
| 149 |
one additional key "e". The value of "e" is a list. The first element is |
one additional key "e". The value of "e" is a list. The first element is |
| 152 |
fulfilled. The following table describes the possible error codes: |
fulfilled. The following table describes the possible error codes: |
| 153 |
|
|
| 154 |
<table> |
<table> |
| 155 |
<th><td>Code</td><td>Description</td></th> |
<th align="left"><td>Code</td><td>Description</td></th> |
| 156 |
<tr><td>201</td><td>Generic Error</td></tr> |
<tr><td>201</td><td>Generic Error</td></tr> |
| 157 |
<tr><td>202</td><td>Server Error</td></tr> |
<tr><td>202</td><td>Server Error</td></tr> |
| 158 |
<tr><td>203</td><td>Protocol Error, such as a malformed packet, invalid arguments, or bad token</td></tr> |
<tr><td>203</td><td>Protocol Error, such as a malformed packet, invalid arguments, or bad token</td></tr> |
| 159 |
<tr><td>204</td><td>Method Unknown</td></tr> |
<tr><td>204</td><td>Method Unknown</td></tr> |
| 160 |
</table> |
</table> |
| 161 |
|
|
| 162 |
###### Example Error Packets |
#### Example Error Packets |
| 163 |
|
|
| 164 |
generic error = {"t":"12345678901234567890", "y":"e", "e":[201, "A Generic Error Ocurred"]} |
generic error = {"t":"12345678901234567890", "y":"e", "e":[201, "A Generic Error Ocurred"]} |
| 165 |
bencoded = d1:eli201e23:A Generic Error Ocurrede1:t20:123456789012345678901:y1:ee |
bencoded = d1:eli201e23:A Generic Error Ocurrede1:t20:123456789012345678901:y1:ee |
| 166 |
|
|
| 167 |
#### Contact Encoding |
### Contact Encoding |
| 168 |
|
|
| 169 |
Contact information for peers is encoded as a 6-byte string. Also known |
Contact information for peers is encoded as a 6-byte string. Also known |
| 170 |
as "Compact IP-address/port info" the 4-byte IP address is in network |
as "Compact IP-address/port info" the 4-byte IP address is in network |
| 181 |
querying node. All responses have an "id" key and value containing the |
querying node. All responses have an "id" key and value containing the |
| 182 |
node ID of the responding node. |
node ID of the responding node. |
| 183 |
|
|
| 184 |
#### ping |
### ping |
| 185 |
|
|
| 186 |
The most basic query is a ping. "q" = "ping" A ping query has a single |
The most basic query is a ping. "q" = "ping" A ping query has a single |
| 187 |
argument, "id" the value is a 20-byte string containing the senders node |
argument, "id" the value is a 20-byte string containing the senders node |
| 188 |
ID in network byte order. The appropriate response to a ping has a |
ID in network byte order. The appropriate response to a ping has a |
| 189 |
single key "id" containing the node ID of the responding node. |
single key "id" containing the node ID of the responding node. |
| 190 |
|
|
| 191 |
arguments: {"id" : "<querying nodes id>"} |
arguments: {"id": "<querying nodes id>"} |
| 192 |
response: {"id" : "<queried nodes id>"} |
response: {"id": "<queried nodes id>"} |
| 193 |
|
|
| 194 |
###### Example Packets |
#### Example Packets |
| 195 |
|
|
| 196 |
ping Query = {"t":"12345678901234567890", "y":"q", "q":"ping", "a":{"id":"abcdefghij0123456789"}} |
ping Query = {"t":"12345678901234567890", "y":"q", "q":"ping", "a":{"id":"abcdefghij0123456789"}} |
| 197 |
bencoded = d1:ad2:id20:abcdefghij0123456789e1:q4:ping1:t20:123456789012345678901:y1:qe |
bencoded = d1:ad2:id20:abcdefghij0123456789e1:q4:ping1:t20:123456789012345678901:y1:qe |
| 199 |
Response = {"t":"12345678901234567890", "y":"r", "r": {"id":"mnopqrstuvwxyz123456"}} |
Response = {"t":"12345678901234567890", "y":"r", "r": {"id":"mnopqrstuvwxyz123456"}} |
| 200 |
bencoded = d1:rd2:id20:mnopqrstuvwxyz123456e1:t20:123456789012345678901:y1:re |
bencoded = d1:rd2:id20:mnopqrstuvwxyz123456e1:t20:123456789012345678901:y1:re |
| 201 |
|
|
| 202 |
#### join |
### join |
| 203 |
|
|
| 204 |
join is identical to ping, except in the response provided. It is |
join is identical to ping, except in the response provided. It is |
| 205 |
intended to be sent only to bootstrap nodes during the process of a new |
intended to be sent only to bootstrap nodes during the process of a new |
| 209 |
value is the port number that the bootstrap node received the request |
value is the port number that the bootstrap node received the request |
| 210 |
from. |
from. |
| 211 |
|
|
| 212 |
arguments: {"id" : "<querying nodes id>"} |
arguments: {"id": "<querying nodes id>"} |
| 213 |
response: {"id" : "<queried nodes id>", "ip_addr" : "<querying nodes IP>", "port" : "<querying nodes port>"} |
response: {"id": "<queried nodes id>", "ip_addr": "<querying nodes IP>", "port": "<querying nodes port>"} |
| 214 |
|
|
| 215 |
###### Example Packets |
#### Example Packets |
| 216 |
|
|
| 217 |
join Query = {"t":"12345678901234567890", "y":"q", "q":"join", "a":{"id":"abcdefghij0123456789"}} |
join Query = {"t":"12345678901234567890", "y":"q", "q":"join", "a":{"id":"abcdefghij0123456789"}} |
| 218 |
bencoded = d1:ad2:id20:abcdefghij0123456789e1:q4:join1:t20:123456789012345678901:y1:qe |
bencoded = d1:ad2:id20:abcdefghij0123456789e1:q4:join1:t20:123456789012345678901:y1:qe |
| 220 |
Response = {"t":"12345678901234567890", "y":"r", "r": {"id":"mnopqrstuvwxyz123456", "ip_addr":"123.123.123.123", "port":12345}} |
Response = {"t":"12345678901234567890", "y":"r", "r": {"id":"mnopqrstuvwxyz123456", "ip_addr":"123.123.123.123", "port":12345}} |
| 221 |
bencoded = d1:rd2:id20:mnopqrstuvwxyz1234567:ip_addr15:123.123.123.1234:porti12345ee1:t20:123456789012345678901:y1:re |
bencoded = d1:rd2:id20:mnopqrstuvwxyz1234567:ip_addr15:123.123.123.1234:porti12345ee1:t20:123456789012345678901:y1:re |
| 222 |
|
|
| 223 |
#### find_node |
### find_node |
| 224 |
|
|
| 225 |
Find node is used to find the contact information for a node given its |
Find node is used to find the contact information for a node given its |
| 226 |
ID. "q" == "find_node" A find_node query has two arguments, "id" |
ID. "q" == "find_node" A find_node query has two arguments, "id" |
| 230 |
containing the compact node info for the target node or the K (8) |
containing the compact node info for the target node or the K (8) |
| 231 |
closest good nodes in its own routing table. |
closest good nodes in its own routing table. |
| 232 |
|
|
| 233 |
arguments: {"id" : "<querying nodes id>", "target" : "<id of target node>"} |
arguments: {"id": "<querying nodes id>", "target": "<id of target node>"} |
| 234 |
response: {"id" : "<queried nodes id>", "nodes" : "<compact node info>"} |
response: {"id": "<queried nodes id>", "nodes": "<compact node info>"} |
| 235 |
|
|
| 236 |
###### Example Packets |
#### Example Packets |
| 237 |
|
|
| 238 |
find_node Query = {"t":"12345678901234567890", "y":"q", "q":"find_node", "a": {"id":"abcdefghij0123456789", "target":"mnopqrstuvwxyz123456"}} |
find_node Query = {"t":"12345678901234567890", "y":"q", "q":"find_node", "a": {"id":"abcdefghij0123456789", "target":"mnopqrstuvwxyz123456"}} |
| 239 |
bencoded = d1:ad2:id20:abcdefghij01234567896:target20:mnopqrstuvwxyz123456e1:q9:find_node1:t20:123456789012345678901:y1:qe |
bencoded = d1:ad2:id20:abcdefghij01234567896:target20:mnopqrstuvwxyz123456e1:q9:find_node1:t20:123456789012345678901:y1:qe |
| 241 |
Response = {"t":"12345678901234567890", "y":"r", "r": {"id":"0123456789abcdefghij", "nodes": "def456..."}} |
Response = {"t":"12345678901234567890", "y":"r", "r": {"id":"0123456789abcdefghij", "nodes": "def456..."}} |
| 242 |
bencoded = d1:rd2:id20:0123456789abcdefghij5:nodes9:def456...e1:t20:123456789012345678901:y1:re |
bencoded = d1:rd2:id20:0123456789abcdefghij5:nodes9:def456...e1:t20:123456789012345678901:y1:re |
| 243 |
|
|
| 244 |
#### get_value |
### get_value |
| 245 |
|
|
| 246 |
Get peers associated with a file hash. "q" = "get_value" A get_value |
Get peers associated with a file hash. "q" = "get_value" A get_value |
| 247 |
query has two arguments, "id" containing the node ID of the querying |
query has two arguments, "id" containing the node ID of the querying |
| 252 |
"nodes" is returned containing the K nodes in the queried nodes routing |
"nodes" is returned containing the K nodes in the queried nodes routing |
| 253 |
table closest to the hash supplied in the query. |
table closest to the hash supplied in the query. |
| 254 |
|
|
| 255 |
arguments: {"id" : "<querying nodes id>", "key" : "<20-byte hash of target file>"} |
arguments: {"id": "<querying nodes id>", "key": "<20-byte hash of target file>"} |
| 256 |
response: {"id" : "<queried nodes id>", "values" : ["<peer 1 info string>", "<peer 2 info string>"]} |
response: {"id": "<queried nodes id>", "values": ["<peer 1 info string>", "<peer 2 info string>"]} |
| 257 |
or: {"id" : "<queried nodes id>", "nodes" : "<compact node info>"} |
or: {"id": "<queried nodes id>", "nodes": "<compact node info>"} |
| 258 |
|
|
| 259 |
###### Example Packets |
#### Example Packets |
| 260 |
|
|
| 261 |
get_value Query = {"t":"12345678901234567890", "y":"q", "q":"get_value", "a": {"id":"abcdefghij0123456789", "key":"mnopqrstuvwxyz123456"}} |
get_value Query = {"t":"12345678901234567890", "y":"q", "q":"get_value", "a": {"id":"abcdefghij0123456789", "key":"mnopqrstuvwxyz123456"}} |
| 262 |
bencoded = d1:ad2:id20:abcdefghij01234567893:key20:mnopqrstuvwxyz123456e1:q9:get_value1:t20:123456789012345678901:y1:qe |
bencoded = d1:ad2:id20:abcdefghij01234567893:key20:mnopqrstuvwxyz123456e1:q9:get_value1:t20:123456789012345678901:y1:qe |
| 264 |
Response with peers = {"t":"12345678901234567890", "y":"r", "r": {"id":"abcdefghij0123456789", "values": ["axje.u", "idhtnm"]}} |
Response with peers = {"t":"12345678901234567890", "y":"r", "r": {"id":"abcdefghij0123456789", "values": ["axje.u", "idhtnm"]}} |
| 265 |
bencoded = d1:rd2:id20:abcdefghij01234567896:valuesl6:axje.u6:idhtnmee1:t20:123456789012345678901:y1:re |
bencoded = d1:rd2:id20:abcdefghij01234567896:valuesl6:axje.u6:idhtnmee1:t20:123456789012345678901:y1:re |
| 266 |
|
|
| 267 |
Response with closest nodes = {"t":"12345678901234567890", "y":"r", "r": {"id":"abcdefghij0123456789", "nodes": "def456..."}} |
Response with nodes = {"t":"12345678901234567890", "y":"r", "r": {"id":"abcdefghij0123456789", "nodes": "def456..."}} |
| 268 |
bencoded = d1:rd2:id20:abcdefghij01234567895:nodes9:def456...e1:t20:123456789012345678901:y1:re |
bencoded = d1:rd2:id20:abcdefghij01234567895:nodes9:def456...e1:t20:123456789012345678901:y1:re |
| 269 |
|
|
| 270 |
#### store_value |
### store_value |
| 271 |
|
|
| 272 |
Announce that the peer, controlling the querying node, has the file |
Announce that the peer, controlling the querying node, has the file |
| 273 |
available for download. store_value has two arguments: "id" containing |
available for download. store_value has two arguments: "id" containing |
| 279 |
arguments: {"id" : "<querying nodes id>", "key" : "<20-byte hash of target file>"} |
arguments: {"id" : "<querying nodes id>", "key" : "<20-byte hash of target file>"} |
| 280 |
response: {"id" : "<queried nodes id>"} |
response: {"id" : "<queried nodes id>"} |
| 281 |
|
|
| 282 |
###### Example Packets |
#### Example Packets |
| 283 |
|
|
| 284 |
store_value Query = {"t":"12345678901234567890", "y":"q", "q":"store_value", "a": {"id":"abcdefghij0123456789", "key":"mnopqrstuvwxyz123456"}} |
store_value Query = {"t":"12345678901234567890", "y":"q", "q":"store_value", "a": {"id":"abcdefghij0123456789", "key":"mnopqrstuvwxyz123456"}} |
| 285 |
bencoded = d1:ad2:id20:abcdefghij01234567893:key20:mnopqrstuvwxyz123456e1:q13:store_value1:t20:123456789012345678901:y1:qe |
bencoded = d1:ad2:id20:abcdefghij01234567893:key20:mnopqrstuvwxyz123456e1:q13:store_value1:t20:123456789012345678901:y1:qe |