iconv: Bail out of the loop when an illegal sequence of bytes occurs.
[elinks/elinks-j605.git] / src / protocol / bittorrent / peerconnect.c
blob7dab4f934cf7f9de8ab10a1fa4047696a1be2540
1 /* BitTorrent peer-wire connection management */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <errno.h>
8 #include <stdio.h>
9 #include <sys/types.h>
10 #ifdef HAVE_SYS_SOCKET_H
11 #include <sys/socket.h> /* OS/2 needs this after sys/types.h */
12 #endif
13 #ifdef HAVE_NETINET_IN_H
14 #include <netinet/in.h>
15 #endif
16 #ifdef HAVE_ARPA_INET_H
17 #include <arpa/inet.h>
18 #endif
20 #include "elinks.h"
22 #include "config/options.h"
23 #include "main/select.h"
24 #include "main/timer.h"
25 #include "network/connection.h"
26 #include "network/socket.h"
27 #include "network/state.h"
28 #include "osdep/osdep.h"
29 #include "protocol/bittorrent/common.h"
30 #include "protocol/bittorrent/peerwire.h"
31 #include "protocol/bittorrent/peerconnect.h"
32 #include "protocol/bittorrent/piececache.h"
33 #include "protocol/protocol.h"
34 #include "protocol/uri.h"
35 #include "util/bitfield.h"
36 #include "util/memory.h"
37 #include "util/string.h"
38 #include "util/time.h"
41 /* Only one port is opened and shared between all running BitTorrent
42 * connections. This holds the descripter of the listening socket. */
43 static int bittorrent_socket = -1;
45 /* The active BitTorrent connections sharing the above listening port. */
46 static INIT_LIST_OF(struct bittorrent_connection, bittorrent_connections);
48 /* The incoming (and pending anonymous) peer connections which has not yet been
49 * assigned to a BitTorrent connection because the info hash has not been read
50 * from the handshake. */
51 static INIT_LIST_OF(struct bittorrent_peer_connection, bittorrent_peer_connections);
54 /* Loop the bittorrent connection list and return matching connection
55 * or NULL. */
56 struct bittorrent_connection *
57 find_bittorrent_connection(bittorrent_id_T info_hash)
59 struct bittorrent_connection *bittorrent;
61 foreach (bittorrent, bittorrent_connections)
62 if (!memcmp(bittorrent->meta.info_hash, info_hash, sizeof(info_hash)))
63 return bittorrent;
65 return NULL;
68 static void
69 check_bittorrent_peer_blacklisting(struct bittorrent_peer_connection *peer,
70 struct connection_state state)
72 enum bittorrent_blacklist_flags flags = BITTORRENT_BLACKLIST_NONE;
74 if (bittorrent_id_is_empty(peer->id)
75 || !get_opt_bool("protocol.http.bugs.allow_blacklist", NULL))
76 return;
78 if (is_system_error(state)) {
79 switch (state.syserr) {
80 case ECONNREFUSED:
81 case ENETUNREACH:
82 flags |= BITTORRENT_BLACKLIST_PEER_POOL;
83 break;
85 } else {
86 switch (state.basic) {
87 case S_CANT_WRITE:
88 case S_CANT_READ:
89 if (!peer->local.handshake
90 || !peer->remote.handshake)
91 flags |= BITTORRENT_BLACKLIST_PEER_POOL;
92 break;
94 default:
95 break;
99 if (flags != BITTORRENT_BLACKLIST_NONE) {
100 add_bittorrent_blacklist_flags(peer->id, flags);
105 /* ************************************************************************** */
106 /* Timeout scheduling: */
107 /* ************************************************************************** */
109 /* Timer callback for @peer->timer. As explained in @install_timer,
110 * this function must erase the expired timer ID from all variables. */
111 static void
112 bittorrent_peer_connection_timeout(struct bittorrent_peer_connection *peer)
114 /* Unset the timer so it won't get stopped when removing the peer
115 * connection. */
116 peer->timer = TIMER_ID_UNDEF;
117 /* The expired timer ID has now been erased. */
119 done_bittorrent_peer_connection(peer);
122 /* The timeout mechanism is used for both inactive incoming peer connections
123 * and peer connections attached to a BitTorrent (master) connection. */
124 void
125 set_bittorrent_peer_connection_timeout(struct bittorrent_peer_connection *peer)
127 milliseconds_T timeout = sec_to_ms(get_opt_int("protocol.bittorrent.peerwire.timeout", NULL));
129 kill_timer(&peer->timer);
130 install_timer(&peer->timer, timeout,
131 (void (*)(void *)) bittorrent_peer_connection_timeout,
132 peer);
136 /* ************************************************************************** */
137 /* Socket callback implementation: */
138 /* ************************************************************************** */
140 /* Called when the connection changes state. Usually state starts out being
141 * S_DMS (while looking up the host) then moves to S_CONN (while connecting),
142 * and should hopefully become S_TRANS (while transfering). Note, state can hold
143 * both internally defined connection states as described above and errno
144 * values, such as ECONNREFUSED. */
145 static void
146 set_bittorrent_socket_state(struct socket *socket, struct connection_state state)
148 struct bittorrent_peer_connection *peer = socket->conn;
150 if (is_in_state(state, S_TRANS) && peer->bittorrent)
151 set_connection_state(peer->bittorrent->conn,
152 connection_state(S_TRANS));
155 /* Called when progress is made such as when the select() loop detects and
156 * schedules reads and writes. The state variable must be ignored. */
157 static void
158 set_bittorrent_socket_timeout(struct socket *socket, struct connection_state state)
160 assert(is_in_state(state, 0));
161 set_bittorrent_peer_connection_timeout(socket->conn);
164 /* Called when a non-fatal error condition has appeared, i.e. the condition is
165 * caused by some internal or local system error or simply a timeout. */
166 static void
167 retry_bittorrent_socket(struct socket *socket, struct connection_state state)
169 struct bittorrent_peer_connection *peer = socket->conn;
171 check_bittorrent_peer_blacklisting(peer, state);
173 /* FIXME: Maybe we should try to reconnect (or simply add connect info
174 * to the peer info list) , but only if we initiated the connection,
175 * i.e. if peer->local.initiater == 1, since it could be just the
176 * tracker probing us. */
178 done_bittorrent_peer_connection(peer);
181 /* Called when a fatal and unrecoverable error condition has appeared, such as a
182 * DNS query failed. */
183 static void
184 done_bittorrent_socket(struct socket *socket, struct connection_state state)
186 struct bittorrent_peer_connection *peer = socket->conn;
188 check_bittorrent_peer_blacklisting(peer, state);
190 done_bittorrent_peer_connection(peer);
193 /* All the above socket handlers are attached to the socket via this table. */
194 static struct socket_operations bittorrent_socket_operations = {
195 set_bittorrent_socket_state,
196 set_bittorrent_socket_timeout,
197 retry_bittorrent_socket,
198 done_bittorrent_socket,
202 /* ************************************************************************** */
203 /* Peer connection management: */
204 /* ************************************************************************** */
206 /* Allocate and initialize a basic peer connection either for incoming or
207 * outgoing connection. */
208 static struct bittorrent_peer_connection *
209 init_bittorrent_peer_connection(int socket)
211 struct bittorrent_peer_connection *peer;
213 peer = mem_calloc(1, sizeof(*peer));
214 if (!peer) return NULL;
216 peer->socket = init_socket(peer, &bittorrent_socket_operations);
217 if (!peer->socket) {
218 mem_free(peer);
219 return NULL;
222 /* We want simultaneous reads and writes. */
223 peer->socket->duplex = 1;
224 peer->socket->fd = socket;
226 init_list(peer->local.requests);
227 init_list(peer->remote.requests);
228 init_list(peer->queue);
230 /* Peers start out being choked and not being interested. */
231 peer->local.choked = 1;
232 peer->remote.choked = 1;
234 return peer;
237 /* Shutdown an remove a peer connection from what ever context it
238 * is currently attached, be it the. */
239 void
240 done_bittorrent_peer_connection(struct bittorrent_peer_connection *peer)
242 del_from_list(peer);
244 /* The peer might not have been associated with a BitTorrent connection,
245 * yet. */
246 if (peer->bittorrent) {
247 add_requests_to_bittorrent_piece_cache(peer, &peer->local);
249 if (peer->bitfield) {
250 remove_bittorrent_peer_from_piece_cache(peer);
251 mem_free(peer->bitfield);
255 free_list(peer->remote.requests);
256 free_list(peer->queue);
258 kill_timer(&peer->timer);
260 /* Unregister the socket from the select() loop mechanism. */
261 done_socket(peer->socket);
262 mem_free(peer->socket);
264 mem_free(peer);
268 /* Establish connection to a peer. As a backend, it uses the internal and more
269 * generic connection creater which takes care of DNS querying etc. */
270 enum bittorrent_state
271 make_bittorrent_peer_connection(struct bittorrent_connection *bittorrent,
272 struct bittorrent_peer *peer_info)
274 enum bittorrent_state result = BITTORRENT_STATE_OUT_OF_MEM;
275 struct uri *uri = NULL;
276 struct string uri_string = NULL_STRING;
277 struct bittorrent_peer_connection *peer;
279 peer = init_bittorrent_peer_connection(-1);
280 if (!peer) goto out;
282 peer->local.initiater = 1;
284 add_to_list(bittorrent->peers, peer);
285 peer->bittorrent = bittorrent;
287 peer->bitfield = init_bitfield(bittorrent->meta.pieces);
288 if (!peer->bitfield) goto out;
290 memcpy(peer->id, peer_info->id, sizeof(peer->id));
292 /* XXX: Very hacky; construct a fake URI from which make_connection()
293 * can extract the IP address and port number. */
294 /* FIXME: Rather change the make_connection() interface. This is an ugly
295 * hack. */
296 if (!init_string(&uri_string)) goto out;
297 if (!add_format_to_string(&uri_string,
298 #ifdef CONFIG_IPV6
299 strchr(peer_info->ip, ':') ?
300 "bittorrent-peer://[%s]:%u/" :
301 #endif
302 "bittorrent-peer://%s:%u/",
303 peer_info->ip, (unsigned) peer_info->port))
304 goto out;
305 uri = get_uri(uri_string.source, 0);
306 if (!uri) goto out;
308 make_connection(peer->socket, uri, send_bittorrent_peer_handshake, 1);
309 result = BITTORRENT_STATE_OK;
311 out:
312 if (uri)
313 done_uri(uri);
314 done_string(&uri_string);
315 if (peer && result != BITTORRENT_STATE_OK)
316 done_bittorrent_peer_connection(peer);
317 return result;
321 /* ************************************************************************** */
322 /* Listening socket management: */
323 /* ************************************************************************** */
325 /* Number of connections to keep in the listening backlog before dropping new
326 * ones. */
327 #define LISTEN_BACKLOG \
328 get_opt_int("protocol.bittorrent.peerwire.connections", NULL)
330 /* Called when we receive a connection on the listening socket. */
331 static void
332 accept_bittorrent_peer_connection(void *____)
334 struct sockaddr_in addr;
335 int peer_sock;
336 int addrlen = sizeof(addr);
337 struct bittorrent_peer_connection *peer;
338 struct read_buffer *buffer;
340 peer_sock = accept(bittorrent_socket, (struct sockaddr *) &addr, &addrlen);
341 if (peer_sock < 0) return;
343 if (set_nonblocking_fd(peer_sock) < 0) {
344 close(peer_sock);
345 return;
348 peer = init_bittorrent_peer_connection(peer_sock);
349 if (!peer) {
350 close(peer_sock);
351 return;
354 peer->remote.initiater = 1;
356 /* Just return. Failure is handled by alloc_read_buffer(). */
357 buffer = alloc_read_buffer(peer->socket);
358 if (!buffer) return;
360 read_from_socket(peer->socket, buffer, connection_state(S_TRANS),
361 read_bittorrent_peer_handshake);
363 add_to_list(bittorrent_peer_connections, peer);
366 /* Based on network/socket.c:get_pasv_socket() but modified to try and bind to a
367 * port range instead of any port. */
368 struct connection_state
369 init_bittorrent_listening_socket(struct connection *conn)
371 struct bittorrent_connection *bittorrent = conn->info;
372 struct sockaddr_in addr, addr2;
373 uint16_t port, max_port;
374 int len;
376 /* XXX: Always add the connection to the list even if we fail so we can
377 * safely assume it is in done_bittorrent_listening_socket(). */
378 add_to_list(bittorrent_connections, bittorrent);
380 /* Has the socket already been initialized? */
381 if (!list_is_singleton(bittorrent_connections))
382 return connection_state(S_OK);
384 /* We could have bailed out from an earlier attempt. */
385 if (bittorrent_socket != -1)
386 close(bittorrent_socket);
388 bittorrent_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
389 if (bittorrent_socket < 0)
390 return connection_state_for_errno(errno);
392 /* Set it non-blocking */
394 if (set_nonblocking_fd(bittorrent_socket) < 0)
395 return connection_state_for_errno(errno);
397 /* Bind it to some port */
399 port = get_opt_int("protocol.bittorrent.ports.min", NULL);
400 max_port = get_opt_int("protocol.bittorrent.ports.max", NULL);
402 memset(&addr, 0, sizeof(addr));
403 addr.sin_port = htons(port);
405 /* Repeatedly try the configured port range. */
406 while (bind(bittorrent_socket, (struct sockaddr *) &addr, sizeof(addr))) {
407 if (errno != EADDRINUSE)
408 return connection_state_for_errno(errno);
410 /* If all ports was in use fail with EADDRINUSE. */
411 if (++port > max_port)
412 return connection_state_for_errno(errno);
414 memset(&addr, 0, sizeof(addr));
415 addr.sin_port = htons(port);
418 /* Get the endpoint info about the new socket and save it */
420 memset(&addr2, 0, sizeof(addr2));
421 len = sizeof(addr2);
422 if (getsockname(bittorrent_socket, (struct sockaddr *) &addr2, &len))
423 return connection_state_for_errno(errno);
425 bittorrent->port = ntohs(addr2.sin_port);
427 /* Go listen */
429 if (listen(bittorrent_socket, LISTEN_BACKLOG))
430 return connection_state_for_errno(errno);
432 set_ip_tos_throughput(bittorrent_socket);
433 set_handlers(bittorrent_socket, accept_bittorrent_peer_connection,
434 NULL, NULL, NULL);
436 return connection_state(S_OK);
439 void
440 done_bittorrent_listening_socket(struct connection *conn)
442 struct bittorrent_connection *connection, *bittorrent = conn->info;
444 /* The bittorrent connection might not even have been added if the
445 * request for the metainfo file failed so carefully look it up. */
446 foreach (connection, bittorrent_connections)
447 if (connection == bittorrent) {
448 del_from_list(bittorrent);
449 break;
452 /* If there are no more connections left remove all pending peer
453 * connections. */
454 if (list_empty(bittorrent_connections)) {
455 struct bittorrent_peer_connection *peer, *next;
457 foreachsafe (peer, next, bittorrent_peer_connections)
458 done_bittorrent_peer_connection(peer);
461 /* Close the listening socket. */
462 if (bittorrent_socket != -1) {
463 /* Unregister the socket from the select() loop mechanism. */
464 clear_handlers(bittorrent_socket);
466 close(bittorrent_socket);
467 bittorrent_socket = -1;