1 /* Library of common BitTorrent code */
12 #include "main/select.h"
13 #include "network/connection.h"
14 #include "protocol/bittorrent/common.h"
15 #include "session/download.h"
16 #include "util/conv.h"
17 #include "util/error.h"
18 #include "util/lists.h"
19 #include "util/memory.h"
20 #include "util/random.h"
21 #include "util/sha1.h"
22 #include "util/string.h"
23 #include "util/snprintf.h"
25 const bittorrent_id_T BITTORRENT_NULL_ID
;
27 /* Debug function which returns printable peer ID. */
29 get_peer_id(bittorrent_id_T peer_id
)
31 static unsigned char hex
[41];
34 if (bittorrent_id_is_empty(peer_id
)) {
35 snprintf(hex
, sizeof(hex
), "unknown id %p", peer_id
);
39 for (i
= 0, j
= 0; i
< sizeof(bittorrent_id_T
); i
++, j
++) {
40 unsigned char value
= peer_id
[i
];
45 hex
[j
++] = hx(value
>> 4 & 0xF);
46 hex
[j
] = hx(value
& 0xF);
56 get_peer_message(enum bittorrent_message_id message_id
)
59 enum bittorrent_message_id message_id
;
62 { BITTORRENT_MESSAGE_INCOMPLETE
, "incomplete" },
63 { BITTORRENT_MESSAGE_KEEP_ALIVE
, "keep-alive" },
64 { BITTORRENT_MESSAGE_CHOKE
, "choke" },
65 { BITTORRENT_MESSAGE_UNCHOKE
, "unchoke" },
66 { BITTORRENT_MESSAGE_INTERESTED
, "interested" },
67 { BITTORRENT_MESSAGE_NOT_INTERESTED
, "not-interested" },
68 { BITTORRENT_MESSAGE_HAVE
, "have" },
69 { BITTORRENT_MESSAGE_BITFIELD
, "bitfield" },
70 { BITTORRENT_MESSAGE_REQUEST
, "request" },
71 { BITTORRENT_MESSAGE_PIECE
, "piece" },
72 { BITTORRENT_MESSAGE_CANCEL
, "cancel" },
78 for (i
= 0; messages
[i
].name
; i
++)
79 if (messages
[i
].message_id
== message_id
)
80 return messages
[i
].name
;
87 get_hexed_bittorrent_id(bittorrent_id_T id
)
89 static unsigned char hex
[SHA_DIGEST_LENGTH
* 2 + 1];
92 for (i
= 0; i
< sizeof(bittorrent_id_T
); i
++) {
95 hex
[j
++] = hx(id
[i
] >> 4 & 0xF);
96 hex
[j
] = hx(id
[i
] & 0xF);
99 hex
[SHA_DIGEST_LENGTH
* 2] = 0;
105 bittorrent_piece_is_valid(struct bittorrent_meta
*meta
,
106 uint32_t piece
, unsigned char *data
, uint32_t datalen
)
108 unsigned char *piece_hash
;
109 bittorrent_id_T data_hash
;
111 assert(piece
< meta
->pieces
);
113 SHA1(data
, datalen
, data_hash
);
114 piece_hash
= &meta
->piece_hash
[piece
* SHA_DIGEST_LENGTH
];
116 return !memcmp(data_hash
, piece_hash
, SHA_DIGEST_LENGTH
);
120 done_bittorrent_meta(struct bittorrent_meta
*meta
)
122 free_uri_list(&meta
->tracker_uris
);
123 mem_free_if(meta
->name
);
124 mem_free_if(meta
->comment
);
125 mem_free_if(meta
->piece_hash
);
126 free_list(meta
->files
);
130 done_bittorrent_message(struct bittorrent_message
*message
)
132 del_from_list(message
);
133 done_uri(message
->uri
);
138 /* ************************************************************************** */
139 /* Peer information management: */
140 /* ************************************************************************** */
142 /* Generate a peer ID with of the form: 'E' <version> '-' <random> */
144 init_bittorrent_peer_id(bittorrent_id_T peer_id
)
146 unsigned char *version
= VERSION
;
155 for (; *version
&& i
< sizeof(bittorrent_id_T
); version
++) {
156 if (isdigit(*version
)) {
157 peer_id
[i
++] = *version
;
159 } else if (*version
== '.' && !dots
) {
167 peer_id
[i
++] = *version
;
170 /* Hmm, sizeof(peer_id) don't work here. */
171 random_nonce(peer_id
+ i
, sizeof(bittorrent_id_T
) - i
);
172 while (i
< sizeof(bittorrent_id_T
)) {
173 peer_id
[i
] = hx(peer_id
[i
] & 0xF);
179 bittorrent_id_is_known(struct bittorrent_connection
*bittorrent
,
182 struct bittorrent_peer_connection
*peer
;
184 /* The peer ID matches the client ID? */
185 if (!memcmp(bittorrent
->peer_id
, id
, sizeof(bittorrent
->peer_id
)))
188 foreach (peer
, bittorrent
->peers
)
189 if (!memcmp(peer
->id
, id
, sizeof(peer
->id
)))
192 if (get_peer_from_bittorrent_pool(bittorrent
, id
))
198 struct bittorrent_peer
*
199 get_peer_from_bittorrent_pool(struct bittorrent_connection
*bittorrent
,
202 struct bittorrent_peer
*peer_info
;
204 foreach (peer_info
, bittorrent
->peer_pool
)
205 if (!memcmp(peer_info
->id
, id
, sizeof(peer_info
->id
)))
211 enum bittorrent_state
212 add_peer_to_bittorrent_pool(struct bittorrent_connection
*bittorrent
,
213 bittorrent_id_T id
, int port
,
214 const unsigned char *ip
, int iplen
)
216 struct bittorrent_peer
*peer
;
218 /* Check sanity. Don't error out here since entries in the tracker
219 * responses can contain garbage and we don't want to bring down the
220 * whole connection for that. */
221 if (iplen
<= 0 || !uri_port_is_valid(port
))
222 return BITTORRENT_STATE_OK
;
224 /* The ID can be NULL for the compact format. */
226 enum bittorrent_blacklist_flags flags
;
228 if (bittorrent_id_is_empty(id
))
229 return BITTORRENT_STATE_ERROR
;
231 /* Check if the peer is already known. */
232 if (bittorrent_id_is_known(bittorrent
, id
))
233 return BITTORRENT_STATE_OK
;
235 flags
= get_bittorrent_blacklist_flags(id
);
236 if (flags
!= BITTORRENT_BLACKLIST_NONE
)
237 return BITTORRENT_STATE_OK
;
240 /* Really add the peer. */
242 peer
= mem_calloc(1, sizeof(*peer
) + iplen
);
243 if (!peer
) return BITTORRENT_STATE_OUT_OF_MEM
;
246 if (iplen
) memcpy(peer
->ip
, ip
, iplen
);
247 if (id
) memcpy(peer
->id
, id
, sizeof(peer
->id
));
249 add_to_list(bittorrent
->peer_pool
, peer
);
251 return BITTORRENT_STATE_OK
;
255 /* ************************************************************************** */
256 /* Peer request management: */
257 /* ************************************************************************** */
259 struct bittorrent_peer_request
*
260 get_bittorrent_peer_request(struct bittorrent_peer_status
*status
,
261 uint32_t piece
, uint32_t offset
, uint32_t length
)
263 struct bittorrent_peer_request
*request
;
265 foreach (request
, status
->requests
) {
266 if (request
->piece
== piece
267 && request
->offset
== offset
268 && request
->length
== length
)
276 add_bittorrent_peer_request(struct bittorrent_peer_status
*status
,
277 uint32_t piece
, uint32_t offset
, uint32_t length
)
279 struct bittorrent_peer_request
*request
;
281 request
= get_bittorrent_peer_request(status
, piece
, offset
, length
);
284 request
= mem_alloc(sizeof(*request
));
285 if (!request
) return;
287 request
->piece
= piece
;
288 request
->offset
= offset
;
289 request
->length
= length
;
291 /* FIXME: Rather insert the request so that we atleast try to get
292 * some sort of sequential access to piece data. */
293 add_to_list_end(status
->requests
, request
);
297 del_bittorrent_peer_request(struct bittorrent_peer_status
*status
,
298 uint32_t piece
, uint32_t offset
, uint32_t length
)
300 struct bittorrent_peer_request
*request
;
302 request
= get_bittorrent_peer_request(status
, piece
, offset
, length
);
303 if (!request
) return;
305 del_from_list(request
);
310 /* ************************************************************************** */
311 /* Generic URI downloader: */
312 /* ************************************************************************** */
314 struct bittorrent_fetcher
{
315 struct bittorrent_fetcher
**ref
;
316 bittorrent_fetch_callback_T callback
;
319 unsigned int delete:1;
320 struct download download
;
323 /* This part of the code is very lowlevel and ELinks specific. The download
324 * callback is called each time there is some progress, such as new data. So
325 * first it basically checks the state and tries to handle it accordingly.
326 * Redirects are also handled here. */
328 bittorrent_fetch_callback(struct download
*download
, void *data
)
330 struct bittorrent_fetcher
*fetcher
= data
;
331 struct fragment
*fragment
;
332 struct bittorrent_const_string response
;
333 struct cache_entry
*cached
= download
->cached
;
335 /* If the callback was removed we should shutdown ASAP. */
336 if (!fetcher
->callback
|| is_in_state(download
->state
, S_INTERRUPTED
)) {
337 if (is_in_state(download
->state
, S_INTERRUPTED
))
342 if (is_in_result_state(download
->state
)
343 && !is_in_state(download
->state
, S_OK
)) {
344 fetcher
->callback(fetcher
->data
, download
->state
, NULL
);
346 *fetcher
->ref
= NULL
;
351 if (!cached
|| is_in_queued_state(download
->state
))
354 if (cached
->redirect
&& fetcher
->redirects
++ < MAX_REDIRECTS
) {
355 cancel_download(download
, 0);
357 download
->state
= connection_state(S_WAIT_REDIR
);
359 load_uri(cached
->redirect
, cached
->uri
, download
,
360 PRI_DOWNLOAD
, CACHE_MODE_NORMAL
,
361 download
->progress
? download
->progress
->start
: 0);
366 if (is_in_progress_state(download
->state
))
369 assert(is_in_state(download
->state
, S_OK
));
371 /* If the entry is chunked defragment it and grab the single, remaining
373 fragment
= get_cache_fragment(cached
);
375 fetcher
->callback(fetcher
->data
, connection_state(S_OUT_OF_MEM
), NULL
);
377 *fetcher
->ref
= NULL
;
382 response
.source
= fragment
->data
;
383 response
.length
= fragment
->length
;
385 fetcher
->callback(fetcher
->data
, connection_state(S_OK
), &response
);
388 delete_cache_entry(cached
);
390 *fetcher
->ref
= NULL
;
394 struct bittorrent_fetcher
*
395 init_bittorrent_fetch(struct bittorrent_fetcher
**fetcher_ref
,
396 struct uri
*uri
, bittorrent_fetch_callback_T callback
,
397 void *data
, int delete)
399 struct bittorrent_fetcher
*fetcher
;
401 fetcher
= mem_calloc(1, sizeof(*fetcher
));
403 callback(data
, connection_state(S_OUT_OF_MEM
), NULL
);
408 *fetcher_ref
= fetcher
;
410 fetcher
->ref
= fetcher_ref
;
411 fetcher
->callback
= callback
;
412 fetcher
->data
= data
;
413 fetcher
->delete = delete;
414 fetcher
->download
.callback
= bittorrent_fetch_callback
;
415 fetcher
->download
.data
= fetcher
;
417 load_uri(uri
, NULL
, &fetcher
->download
, PRI_MAIN
, CACHE_MODE_NORMAL
, -1);
423 end_bittorrent_fetch(void *fetcher_data
)
425 struct bittorrent_fetcher
*fetcher
= fetcher_data
;
427 assert(fetcher
&& !fetcher
->callback
);
429 /* Stop any running connections. */
430 cancel_download(&fetcher
->download
, 0);
436 done_bittorrent_fetch(struct bittorrent_fetcher
**fetcher_ref
)
438 struct bittorrent_fetcher
*fetcher
;
442 fetcher
= *fetcher_ref
;
448 *fetcher
->ref
= NULL
;
450 /* Nuke the callback so nothing gets called */
451 fetcher
->callback
= NULL
;
452 register_bottom_half(end_bittorrent_fetch
, fetcher
);
456 /* ************************************************************************** */
457 /* Blacklist management: */
458 /* ************************************************************************** */
460 struct bittorrent_blacklist_item
{
461 LIST_HEAD(struct bittorrent_blacklist_item
);
463 enum bittorrent_blacklist_flags flags
;
467 static INIT_LIST_OF(struct bittorrent_blacklist_item
, bittorrent_blacklist
);
470 static struct bittorrent_blacklist_item
*
471 get_bittorrent_blacklist_item(bittorrent_id_T peer_id
)
473 struct bittorrent_blacklist_item
*item
;
475 foreach (item
, bittorrent_blacklist
)
476 if (!memcmp(item
->id
, peer_id
, sizeof(bittorrent_id_T
)))
483 add_bittorrent_blacklist_flags(bittorrent_id_T peer_id
,
484 enum bittorrent_blacklist_flags flags
)
486 struct bittorrent_blacklist_item
*item
;
488 item
= get_bittorrent_blacklist_item(peer_id
);
490 item
->flags
|= flags
;
494 item
= mem_calloc(1, sizeof(*item
));
498 memcpy(item
->id
, peer_id
, sizeof(bittorrent_id_T
));
500 add_to_list(bittorrent_blacklist
, item
);
504 del_bittorrent_blacklist_flags(bittorrent_id_T peer_id
,
505 enum bittorrent_blacklist_flags flags
)
507 struct bittorrent_blacklist_item
*item
;
509 item
= get_bittorrent_blacklist_item(peer_id
);
512 item
->flags
&= ~flags
;
513 if (item
->flags
) return;
519 enum bittorrent_blacklist_flags
520 get_bittorrent_blacklist_flags(bittorrent_id_T peer_id
)
522 struct bittorrent_blacklist_item
*item
;
524 item
= get_bittorrent_blacklist_item(peer_id
);
526 return item
? item
->flags
: BITTORRENT_BLACKLIST_NONE
;
530 done_bittorrent_blacklist(void)
532 free_list(bittorrent_blacklist
);