iconv: Bail out of the loop when an illegal sequence of bytes occurs.
[elinks/elinks-j605.git] / src / protocol / bittorrent / connection.c
blob08cec1e23a5633c35322ac7e28f1577fd936a207
1 /* Internal "bittorrent" protocol implementation */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <stdlib.h>
8 #include <string.h>
10 #include "elinks.h"
12 #include "cache/cache.h"
13 #include "config/options.h"
14 #include "main/timer.h"
15 #include "network/connection.h"
16 #include "network/progress.h"
17 #include "network/socket.h"
18 #include "protocol/bittorrent/bencoding.h"
19 #include "protocol/bittorrent/bittorrent.h"
20 #include "protocol/bittorrent/common.h"
21 #include "protocol/bittorrent/connection.h"
22 #include "protocol/bittorrent/tracker.h"
23 #include "protocol/bittorrent/peerconnect.h"
24 #include "protocol/bittorrent/peerwire.h"
25 #include "protocol/bittorrent/piececache.h"
26 #include "protocol/protocol.h"
27 #include "protocol/uri.h"
28 #include "session/download.h"
29 #include "util/bitfield.h"
30 #include "util/conv.h"
31 #include "util/memory.h"
32 #include "util/string.h"
33 #include "util/time.h"
36 /* ************************************************************************** */
37 /* Peer selection and connection scheduling: */
38 /* ************************************************************************** */
40 /* Reschedule updating of the connection state. */
41 static void
42 set_bittorrent_connection_timer(struct connection *conn)
44 struct bittorrent_connection *bittorrent = conn->info;
45 milliseconds_T interval = sec_to_ms(get_opt_int("protocol.bittorrent.choke_interval", NULL));
47 install_timer(&bittorrent->timer, interval,
48 (void (*)(void *)) update_bittorrent_connection_state,
49 conn);
52 /* Sort the peers based on the stats rate, bubbaly style! */
53 static void
54 sort_bittorrent_peer_connections(struct bittorrent_connection *bittorrent)
56 struct bittorrent_peer_connection *peer, *prev;
58 while (1) {
59 struct bittorrent_peer_connection *next;
60 int resort = 0;
62 prev = NULL;
64 foreachsafe (peer, next, bittorrent->peers) {
65 if (prev && prev->stats.download_rate < peer->stats.download_rate) {
66 resort = 1;
67 del_from_list(prev);
68 add_at_pos(peer, prev);
71 prev = peer;
74 if (!resort) break;
77 #ifdef CONFIG_DEBUG
78 prev = NULL;
79 foreach (peer, bittorrent->peers) {
80 assert(!prev || prev->stats.download_rate >= peer->stats.download_rate);
81 prev = peer;
83 #endif
86 /* Timer callback for @bittorrent->timer. As explained in @install_timer,
87 * this function must erase the expired timer ID from all variables.
89 * This is basically the choke period handler. */
90 void
91 update_bittorrent_connection_state(struct connection *conn)
93 struct bittorrent_connection *bittorrent = conn->info;
94 struct bittorrent_peer_connection *peer, *next_peer;
95 int peer_conns, max_peer_conns;
96 int min_uploads = get_opt_int("protocol.bittorrent.min_uploads", NULL);
97 int max_uploads = get_opt_int("protocol.bittorrent.max_uploads", NULL);
99 set_bittorrent_connection_timer(conn);
100 /* The expired timer ID has now been erased. */
101 set_connection_timeout(conn);
103 peer_conns = list_size(&bittorrent->peers);
104 max_peer_conns = get_opt_int("protocol.bittorrent.peerwire.connections", NULL);
106 /* First ``age'' the peer rates _before_ the sorting. */
107 foreach (peer, bittorrent->peers)
108 update_bittorrent_peer_connection_stats(peer, 0, 0, 0);
110 /* Sort the peers so that the best peers are at the list start. */
111 sort_bittorrent_peer_connections(bittorrent);
113 /* Unchoke all the optimal peers. In good spirit, also unchoke all
114 * uninterested peers until the maximum number of interested peers have
115 * been unchoked. The rest is choked. */
116 foreachsafe (peer, next_peer, bittorrent->peers) {
117 if (!peer->remote.handshake)
118 continue;
120 if (min_uploads < max_uploads) {
121 unchoke_bittorrent_peer(peer);
123 /* Uninterested peers are not counted as uploads. */
124 if (peer->remote.interested)
125 max_uploads--;
127 } else {
128 choke_bittorrent_peer(peer);
131 /* Can remove the peer so we use foreachsafe(). */
132 update_bittorrent_peer_connection_state(peer);
135 /* FIXME: Find peer(s) to optimistically unchoke. */
137 update_bittorrent_piece_cache_state(bittorrent);
139 /* Close or open peers connections. */
140 if (peer_conns > max_peer_conns) {
141 struct bittorrent_peer_connection *prev;
143 foreachsafe (peer, prev, bittorrent->peers) {
144 done_bittorrent_peer_connection(peer);
145 if (--peer_conns <= max_peer_conns)
146 break;
149 } else if (peer_conns < max_peer_conns) {
150 struct bittorrent_peer *peer_info, *next_peer_info;
152 foreachsafe (peer_info, next_peer_info, bittorrent->peer_pool) {
153 enum bittorrent_state state;
155 state = make_bittorrent_peer_connection(bittorrent, peer_info);
156 if (state != BITTORRENT_STATE_OK)
157 break;
159 del_from_list(peer_info);
160 mem_free(peer_info);
161 if (++peer_conns >= max_peer_conns)
162 break;
166 assert(peer_conns <= max_peer_conns);
168 /* Shrink the peer pool. */
169 if (!list_empty(bittorrent->peers)) {
170 struct bittorrent_peer *peer_info, *next_peer_info;
171 int pool_size = get_opt_int("protocol.bittorrent.peerwire.pool_size", NULL);
172 int pool_peers = 0;
174 foreachsafe (peer_info, next_peer_info, bittorrent->peer_pool) {
175 /* Unlimited. */
176 if (!pool_size) break;
178 if (pool_peers < pool_size) {
179 pool_peers++;
180 continue;
183 del_from_list(peer_info);
184 mem_free(peer_info);
189 /* Progress timer callback for @bittorrent->upload_progress. */
190 static void
191 update_bittorrent_connection_upload(void *data)
193 struct bittorrent_connection *bittorrent = data;
195 update_progress(&bittorrent->upload_progress,
196 bittorrent->uploaded,
197 bittorrent->downloaded,
198 bittorrent->uploaded);
201 void
202 update_bittorrent_connection_stats(struct bittorrent_connection *bittorrent,
203 off_t downloaded, off_t uploaded,
204 off_t received)
206 struct bittorrent_meta *meta = &bittorrent->meta;
208 if (bittorrent->conn->est_length == -1) {
209 off_t length = (off_t) (meta->pieces - 1) * meta->piece_length
210 + meta->last_piece_length;
212 bittorrent->conn->est_length = length;
213 bittorrent->left = length;
214 start_update_progress(&bittorrent->upload_progress,
215 update_bittorrent_connection_upload,
216 bittorrent);
219 if (bittorrent->upload_progress.timer == TIMER_ID_UNDEF
220 && bittorrent->uploaded)
221 update_bittorrent_connection_upload(bittorrent);
223 bittorrent->conn->received += received;
224 bittorrent->conn->from += downloaded;
225 if (downloaded > 0)
226 bittorrent->downloaded += downloaded;
227 bittorrent->uploaded += uploaded;
228 bittorrent->left -= downloaded;
230 if (!bittorrent->downloaded) return;
232 bittorrent->sharing_rate = (double) bittorrent->uploaded
233 / bittorrent->downloaded;
237 /* ************************************************************************** */
238 /* The ``main'' BitTorrent connection setup: */
239 /* ************************************************************************** */
241 /* Callback which is attached to the ELinks connection and invoked when the
242 * connection is shutdown. */
243 static void
244 done_bittorrent_connection(struct connection *conn)
246 struct bittorrent_connection *bittorrent = conn->info;
247 struct bittorrent_peer_connection *peer, *next;
249 assert(bittorrent);
250 assert(conn->done == done_bittorrent_connection);
252 /* We don't want the tracker to see the fetch. */
253 if (bittorrent->fetch)
254 done_bittorrent_fetch(&bittorrent->fetch);
256 foreachsafe (peer, next, bittorrent->peers)
257 done_bittorrent_peer_connection(peer);
259 done_bittorrent_tracker_connection(conn);
260 done_bittorrent_listening_socket(conn);
261 if (bittorrent->cache)
262 done_bittorrent_piece_cache(bittorrent);
263 done_bittorrent_meta(&bittorrent->meta);
265 kill_timer(&bittorrent->timer);
266 kill_timer(&bittorrent->upload_progress.timer);
268 free_list(bittorrent->peer_pool);
270 mem_free_set(&conn->info, NULL);
271 conn->done = NULL;
274 static struct bittorrent_connection *
275 init_bittorrent_connection(struct connection *conn)
277 struct bittorrent_connection *bittorrent;
279 assert(conn->info == NULL);
280 assert(conn->done == NULL);
281 if_assert_failed return NULL;
283 bittorrent = mem_calloc(1, sizeof(*bittorrent));
284 if (!bittorrent) return NULL;
286 init_list(bittorrent->peers);
287 init_list(bittorrent->peer_pool);
289 /* conn->info and conn->done were asserted as NULL above. */
290 conn->info = bittorrent;
291 conn->done = done_bittorrent_connection;
293 init_bittorrent_peer_id(bittorrent->peer_id);
295 bittorrent->conn = conn;
296 bittorrent->tracker.timer = TIMER_ID_UNDEF;
298 /* Initialize here so that error handling can safely call
299 * free_list on it. */
300 init_list(bittorrent->meta.files);
302 return bittorrent;
305 void
306 bittorrent_resume_callback(struct bittorrent_connection *bittorrent)
308 struct connection_state state;
310 /* Failing to create the listening socket is fatal. */
311 state = init_bittorrent_listening_socket(bittorrent->conn);
312 if (!is_in_state(state, S_OK)) {
313 retry_connection(bittorrent->conn, state);
314 return;
317 set_connection_state(bittorrent->conn, connection_state(S_CONN_TRACKER));
318 send_bittorrent_tracker_request(bittorrent->conn);
321 /* Metainfo file download callback */
322 static void
323 bittorrent_metainfo_callback(void *data, struct connection_state state,
324 struct bittorrent_const_string *response)
326 struct connection *conn = data;
327 struct bittorrent_connection *bittorrent = conn->info;
329 bittorrent->fetch = NULL;
331 if (!is_in_state(state, S_OK)) {
332 abort_connection(conn, state);
333 return;
336 switch (parse_bittorrent_metafile(&bittorrent->meta, response)) {
337 case BITTORRENT_STATE_OK:
339 size_t size = list_size(&bittorrent->meta.files);
340 int *selection;
342 assert(bittorrent->tracker.event == BITTORRENT_EVENT_STARTED);
344 selection = get_bittorrent_selection(conn->uri, size);
345 if (selection) {
346 struct bittorrent_file *file;
347 int index = 0;
349 foreach (file, bittorrent->meta.files)
350 file->selected = selection[index++];
352 mem_free(selection);
355 switch (init_bittorrent_piece_cache(bittorrent, response)) {
356 case BITTORRENT_STATE_OK:
357 bittorrent_resume_callback(bittorrent);
358 return;
360 case BITTORRENT_STATE_CACHE_RESUME:
361 set_connection_state(bittorrent->conn,
362 connection_state(S_RESUME));
363 return;
365 case BITTORRENT_STATE_OUT_OF_MEM:
366 state = connection_state(S_OUT_OF_MEM);
367 break;
369 default:
370 state = connection_state(S_BITTORRENT_ERROR);
373 break;
375 case BITTORRENT_STATE_OUT_OF_MEM:
376 state = connection_state(S_OUT_OF_MEM);
377 break;
379 case BITTORRENT_STATE_ERROR:
380 default:
381 /* XXX: This can also happen when passing bittorrent:<uri> and
382 * <uri> gives an HTTP 404 response. It might be worth fixing by
383 * looking at the protocol header, however, direct usage of the
384 * internal bittorrent: is at your own risk ... at least for
385 * now. --jonas */
386 state = connection_state(S_BITTORRENT_METAINFO);
389 abort_connection(conn, state);
392 /* The entry point for BitTorrent downloads. */
393 void
394 bittorrent_protocol_handler(struct connection *conn)
396 struct uri *uri = NULL;
397 struct bittorrent_connection *bittorrent;
399 bittorrent = init_bittorrent_connection(conn);
400 if (!bittorrent) {
401 abort_connection(conn, connection_state(S_OUT_OF_MEM));
402 return;
405 if (conn->uri->datalen)
406 uri = get_uri(conn->uri->data, 0);
408 if (!uri) {
409 abort_connection(conn, connection_state(S_BITTORRENT_BAD_URL));
410 return;
413 set_connection_state(conn, connection_state(S_CONN));
414 set_connection_timeout(conn);
415 conn->from = 0;
417 init_bittorrent_fetch(&bittorrent->fetch, uri,
418 bittorrent_metainfo_callback, conn, 0);
419 done_uri(uri);
422 void
423 bittorrent_peer_protocol_handler(struct connection *conn)
425 abort_connection(conn, connection_state(S_BITTORRENT_PEER_URL));