1 /* Connections management */
16 #include "cache/cache.h"
17 #include "config/options.h"
18 #include "document/document.h"
19 #include "encoding/encoding.h"
20 #include "intl/gettext/libintl.h"
21 #include "main/object.h"
22 #include "main/select.h"
23 #include "main/timer.h"
24 #include "network/connection.h"
25 #include "network/dns.h"
26 #include "network/progress.h"
27 #include "network/socket.h"
28 #include "network/ssl/ssl.h"
29 #include "protocol/protocol.h"
30 #include "protocol/proxy.h"
31 #include "protocol/uri.h"
32 #include "session/session.h"
33 #include "util/error.h"
34 #include "util/memory.h"
35 #include "util/string.h"
36 #include "util/time.h"
39 struct keepalive_connection
{
40 LIST_HEAD(struct keepalive_connection
);
42 /* XXX: This is just the URI of the connection that registered the
43 * keepalive connection so only rely on the protocol, user, password,
44 * host and port part. */
47 /* Function called when the keepalive has timed out or is deleted */
48 void (*done
)(struct connection
*);
51 timeval_T creation_time
;
53 unsigned int protocol_family
:1; /* see network/socket.h, EL_PF_INET, EL_PF_INET6 */
58 static unsigned int connection_id
= 0;
59 static int active_connections
= 0;
60 static timer_id_T keepalive_timeout
= TIMER_ID_UNDEF
;
62 static INIT_LIST_HEAD(connection_queue
);
63 static INIT_LIST_HEAD(host_connections
);
64 static INIT_LIST_HEAD(keepalive_connections
);
67 static void notify_connection_callbacks(struct connection
*conn
);
68 static void check_keepalive_connections(void);
71 static /* inline */ enum connection_priority
72 get_priority(struct connection
*conn
)
74 enum connection_priority priority
;
76 for (priority
= 0; priority
< PRIORITIES
; priority
++)
77 if (conn
->pri
[priority
])
80 assertm(priority
!= PRIORITIES
, "Connection has no owner");
81 /* Recovery path ;-). (XXX?) */
87 get_connections_count(void)
89 return list_size(&connection_queue
);
93 get_keepalive_connections_count(void)
95 return list_size(&keepalive_connections
);
99 get_connections_connecting_count(void)
101 struct connection
*conn
;
104 foreach (conn
, connection_queue
)
105 i
+= is_in_connecting_state(conn
->state
);
111 get_connections_transfering_count(void)
113 struct connection
*conn
;
116 foreach (conn
, connection_queue
)
117 i
+= is_in_transfering_state(conn
->state
);
123 connection_disappeared(struct connection
*conn
)
125 struct connection
*c
;
127 foreach (c
, connection_queue
)
128 if (conn
== c
&& conn
->id
== c
->id
)
134 /* Host connection management: */
135 /* Used to keep track on the number of connections to any given host. When
136 * trying to setup a new connection the list is searched to see if the maximum
137 * number of connection has been reached. If that is the case we try to suspend
138 * an already established connection. */
139 /* Some connections (like file://) that do not involve hosts are not maintained
142 struct host_connection
{
143 OBJECT_HEAD(struct host_connection
);
145 /* XXX: This is just the URI of the connection that registered the
146 * host connection so only rely on the host part. */
150 static struct host_connection
*
151 get_host_connection(struct connection
*conn
)
153 struct host_connection
*host_conn
;
155 if (!conn
->uri
->host
) return NULL
;
157 foreach (host_conn
, host_connections
)
158 if (compare_uri(host_conn
->uri
, conn
->uri
, URI_HOST
))
164 /* Returns if the connection was successfully added. */
165 /* Don't add hostnameless host connections but they're valid. */
167 add_host_connection(struct connection
*conn
)
169 struct host_connection
*host_conn
= get_host_connection(conn
);
171 if (!host_conn
&& conn
->uri
->host
) {
172 host_conn
= mem_calloc(1, sizeof(*host_conn
));
173 if (!host_conn
) return 0;
175 host_conn
->uri
= get_uri_reference(conn
->uri
);
176 object_nolock(host_conn
, "host_connection");
177 add_to_list(host_connections
, host_conn
);
179 if (host_conn
) object_lock(host_conn
);
184 /* Decrements and free()s the host connection if it is the last 'refcount'. */
186 done_host_connection(struct connection
*conn
)
188 struct host_connection
*host_conn
= get_host_connection(conn
);
190 if (!host_conn
) return;
192 object_unlock(host_conn
);
193 if (is_object_used(host_conn
)) return;
195 del_from_list(host_conn
);
196 done_uri(host_conn
->uri
);
201 static void sort_queue();
205 check_queue_bugs(void)
207 struct connection
*conn
;
208 enum connection_priority prev_priority
= 0;
211 foreach (conn
, connection_queue
) {
212 enum connection_priority priority
= get_priority(conn
);
216 assertm(priority
>= prev_priority
, "queue is not sorted");
217 assertm(is_in_progress_state(conn
->state
),
218 "interrupted connection on queue (conn %s, state %d)",
219 struri(conn
->uri
), conn
->state
);
220 prev_priority
= priority
;
223 assertm(cc
== active_connections
,
224 "bad number of active connections (counted %d, stored %d)",
225 cc
, active_connections
);
228 #define check_queue_bugs()
232 set_connection_socket_state(struct socket
*socket
, enum connection_state state
)
235 set_connection_state(socket
->conn
, state
);
239 set_connection_socket_timeout(struct socket
*socket
, enum connection_state state
)
242 set_connection_timeout(socket
->conn
);
246 retry_connection_socket(struct socket
*socket
, enum connection_state state
)
249 retry_connection(socket
->conn
, state
);
253 done_connection_socket(struct socket
*socket
, enum connection_state state
)
256 abort_connection(socket
->conn
, state
);
259 static struct connection
*
260 init_connection(struct uri
*uri
, struct uri
*proxied_uri
, struct uri
*referrer
,
261 off_t start
, enum cache_mode cache_mode
,
262 enum connection_priority priority
)
264 static struct socket_operations connection_socket_operations
= {
265 set_connection_socket_state
,
266 set_connection_socket_timeout
,
267 retry_connection_socket
,
268 done_connection_socket
,
270 struct connection
*conn
= mem_calloc(1, sizeof(*conn
));
272 if (!conn
) return NULL
;
274 assert(proxied_uri
->protocol
!= PROTOCOL_PROXY
);
276 conn
->socket
= init_socket(conn
, &connection_socket_operations
);
282 conn
->data_socket
= init_socket(conn
, &connection_socket_operations
);
283 if (!conn
->data_socket
) {
284 mem_free(conn
->socket
);
289 conn
->progress
= init_progress(start
);
290 if (!conn
->progress
) {
291 mem_free(conn
->data_socket
);
292 mem_free(conn
->socket
);
297 /* load_uri() gets the URI from get_proxy() which grabs a reference for
300 conn
->proxied_uri
= proxied_uri
;
301 conn
->id
= connection_id
++;
302 conn
->pri
[priority
] = 1;
303 conn
->cache_mode
= cache_mode
;
305 conn
->content_encoding
= ENCODING_NONE
;
306 conn
->stream_pipes
[0] = conn
->stream_pipes
[1] = -1;
307 init_list(conn
->downloads
);
308 conn
->est_length
= -1;
309 conn
->timer
= TIMER_ID_UNDEF
;
312 /* Don't set referrer when it is the file protocol and the URI
313 * being loaded is not. This means CGI scripts will have it
314 * available while preventing information about the local
315 * system from being leaked to external servers. */
316 if (referrer
->protocol
!= PROTOCOL_FILE
317 || uri
->protocol
== PROTOCOL_FILE
)
318 conn
->referrer
= get_uri_reference(referrer
);
325 update_connection_progress(struct connection
*conn
)
327 update_progress(conn
->progress
, conn
->received
, conn
->est_length
, conn
->from
);
330 /* Progress timer callback for @conn->progress. As explained in
331 * @start_update_progress, this function must erase the expired timer
332 * ID from @conn->progress->timer. */
334 stat_timer(struct connection
*conn
)
336 update_connection_progress(conn
);
337 /* The expired timer ID has now been erased. */
338 notify_connection_callbacks(conn
);
342 set_connection_state(struct connection
*conn
, enum connection_state state
)
344 struct download
*download
;
345 struct progress
*progress
= conn
->progress
;
347 if (is_in_result_state(conn
->state
) && is_in_progress_state(state
))
348 conn
->prev_error
= conn
->state
;
351 if (conn
->state
== S_TRANS
) {
352 if (progress
->timer
== TIMER_ID_UNDEF
) {
353 start_update_progress(progress
, (void (*)(void *)) stat_timer
, conn
);
354 update_connection_progress(conn
);
355 if (connection_disappeared(conn
))
360 kill_timer(&progress
->timer
);
363 foreach (download
, conn
->downloads
) {
364 download
->state
= state
;
365 download
->prev_error
= conn
->prev_error
;
368 if (is_in_progress_state(state
)) notify_connection_callbacks(conn
);
372 shutdown_connection_stream(struct connection
*conn
)
375 close_encoded(conn
->stream
);
378 if (conn
->stream_pipes
[1] >= 0)
379 close(conn
->stream_pipes
[1]);
380 conn
->stream_pipes
[0] = conn
->stream_pipes
[1] = -1;
381 conn
->stream_pipes_written
= 0;
387 struct popen_data
*pop
;
389 foreach (pop
, copiousoutput_data
) {
394 unlink(pop
->filename
);
395 mem_free(pop
->filename
);
404 free_connection_data(struct connection
*conn
)
406 assertm(conn
->running
, "connection already suspended");
407 /* XXX: Recovery path? Originally, there was none. I think we'll get
408 * at least active_connections underflows along the way. --pasky */
411 active_connections
--;
412 assertm(active_connections
>= 0, "active connections underflow");
413 if_assert_failed active_connections
= 0;
416 if (conn
->socket
->ssl
&& conn
->cached
)
417 mem_free_set(&conn
->cached
->ssl_info
, get_ssl_connection_cipher(conn
->socket
));
423 if (conn
->popen
) close_popen(conn
->socket
->fd
);
424 done_socket(conn
->socket
);
425 done_socket(conn
->data_socket
);
427 shutdown_connection_stream(conn
);
429 mem_free_set(&conn
->info
, NULL
);
431 kill_timer(&conn
->timer
);
433 if (conn
->state
!= S_WAIT
)
434 done_host_connection(conn
);
438 notify_connection_callbacks(struct connection
*conn
)
440 enum connection_state state
= conn
->state
;
441 struct download
*download
, *next
;
443 foreachsafe (download
, next
, conn
->downloads
) {
444 download
->cached
= conn
->cached
;
445 if (download
->callback
)
446 download
->callback(download
, download
->data
);
447 if (is_in_progress_state(state
) && connection_disappeared(conn
))
453 done_connection(struct connection
*conn
)
455 /* When removing the connection callbacks should always be aware of it
456 * so they can unregister themselves. We do this by enforcing that the
457 * connection is in a result state. If it is not already it is an
458 * internal bug. This should never happen but it does. ;) --jonas */
459 if (!is_in_result_state(conn
->state
))
460 set_connection_state(conn
, S_INTERNAL
);
463 notify_connection_callbacks(conn
);
464 if (conn
->referrer
) done_uri(conn
->referrer
);
466 done_uri(conn
->proxied_uri
);
467 mem_free(conn
->socket
);
468 mem_free(conn
->data_socket
);
469 done_progress(conn
->progress
);
475 add_to_queue(struct connection
*conn
)
477 struct connection
*c
;
478 enum connection_priority priority
= get_priority(conn
);
480 foreach (c
, connection_queue
)
481 if (get_priority(c
) > priority
)
484 add_at_pos(c
->prev
, conn
);
488 /* Returns zero if no callback was done and the keepalive connection should be
489 * deleted or non-zero if the keepalive connection should not be deleted. */
491 do_keepalive_connection_callback(struct keepalive_connection
*keep_conn
)
493 struct uri
*proxied_uri
= get_proxied_uri(keep_conn
->uri
);
494 struct uri
*proxy_uri
= get_proxy_uri(keep_conn
->uri
, NULL
);
496 if (proxied_uri
&& proxy_uri
) {
497 struct connection
*conn
;
499 conn
= init_connection(proxy_uri
, proxied_uri
, NULL
, 0,
500 CACHE_MODE_NEVER
, PRI_CANCEL
);
503 void (*done
)(struct connection
*) = keep_conn
->done
;
507 /* Get the keepalive info and let it clean up */
508 if (!has_keepalive_connection(conn
)
509 || !add_host_connection(conn
)) {
510 free_connection_data(conn
);
511 done_connection(conn
);
515 active_connections
++;
522 if (proxied_uri
) done_uri(proxied_uri
);
523 if (proxy_uri
) done_uri(proxy_uri
);
529 done_keepalive_connection(struct keepalive_connection
*keep_conn
)
531 if (keep_conn
->done
&& do_keepalive_connection_callback(keep_conn
))
534 del_from_list(keep_conn
);
535 if (keep_conn
->socket
!= -1) close(keep_conn
->socket
);
536 done_uri(keep_conn
->uri
);
540 static struct keepalive_connection
*
541 init_keepalive_connection(struct connection
*conn
, long timeout_in_seconds
,
542 void (*done
)(struct connection
*))
544 struct keepalive_connection
*keep_conn
;
545 struct uri
*uri
= conn
->uri
;
548 if_assert_failed
return NULL
;
550 keep_conn
= mem_calloc(1, sizeof(*keep_conn
));
551 if (!keep_conn
) return NULL
;
553 keep_conn
->uri
= get_uri_reference(uri
);
554 keep_conn
->done
= done
;
555 keep_conn
->protocol_family
= conn
->socket
->protocol_family
;
556 keep_conn
->socket
= conn
->socket
->fd
;
557 timeval_from_seconds(&keep_conn
->timeout
, timeout_in_seconds
);
558 timeval_now(&keep_conn
->creation_time
);
563 static struct keepalive_connection
*
564 get_keepalive_connection(struct connection
*conn
)
566 struct keepalive_connection
*keep_conn
;
568 if (!conn
->uri
->host
) return NULL
;
570 foreach (keep_conn
, keepalive_connections
)
571 if (compare_uri(keep_conn
->uri
, conn
->uri
, URI_KEEPALIVE
))
578 has_keepalive_connection(struct connection
*conn
)
580 struct keepalive_connection
*keep_conn
= get_keepalive_connection(conn
);
582 if (!keep_conn
) return 0;
584 conn
->socket
->fd
= keep_conn
->socket
;
585 conn
->socket
->protocol_family
= keep_conn
->protocol_family
;
587 /* Mark that the socket should not be closed and the callback should be
589 keep_conn
->socket
= -1;
590 keep_conn
->done
= NULL
;
591 done_keepalive_connection(keep_conn
);
597 add_keepalive_connection(struct connection
*conn
, long timeout_in_seconds
,
598 void (*done
)(struct connection
*))
600 struct keepalive_connection
*keep_conn
;
602 assertm(conn
->socket
->fd
!= -1, "keepalive connection not connected");
603 if_assert_failed
goto done
;
605 keep_conn
= init_keepalive_connection(conn
, timeout_in_seconds
, done
);
607 /* Make sure that the socket descriptor will not periodically be
608 * checked or closed by free_connection_data(). */
609 clear_handlers(conn
->socket
->fd
);
610 conn
->socket
->fd
= -1;
611 add_to_list(keepalive_connections
, keep_conn
);
614 /* It will take just a little more time */
620 free_connection_data(conn
);
621 done_connection(conn
);
622 register_check_queue();
625 /* Timer callback for @keepalive_timeout. As explained in @install_timer,
626 * this function must erase the expired timer ID from all variables. */
628 keepalive_timer(void *x
)
630 keepalive_timeout
= TIMER_ID_UNDEF
;
631 /* The expired timer ID has now been erased. */
632 check_keepalive_connections();
636 check_keepalive_connections(void)
638 struct keepalive_connection
*keep_conn
, *next
;
644 kill_timer(&keepalive_timeout
);
646 foreachsafe (keep_conn
, next
, keepalive_connections
) {
649 if (can_read(keep_conn
->socket
)) {
650 done_keepalive_connection(keep_conn
);
654 timeval_sub(&age
, &keep_conn
->creation_time
, &now
);
655 if (timeval_cmp(&age
, &keep_conn
->timeout
) > 0) {
656 done_keepalive_connection(keep_conn
);
663 for (; p
> MAX_KEEPALIVE_CONNECTIONS
; p
--) {
664 assertm(!list_empty(keepalive_connections
), "keepalive list empty");
665 if_assert_failed
return;
666 done_keepalive_connection(keepalive_connections
.prev
);
669 if (!list_empty(keepalive_connections
))
670 install_timer(&keepalive_timeout
, KEEPALIVE_CHECK_TIME
,
671 keepalive_timer
, NULL
);
675 abort_all_keepalive_connections(void)
677 while (!list_empty(keepalive_connections
))
678 done_keepalive_connection(keepalive_connections
.next
);
680 check_keepalive_connections();
688 struct connection
*conn
;
691 foreach (conn
, connection_queue
) {
692 if (!list_has_next(connection_queue
, conn
)) break;
694 if (get_priority(conn
->next
) < get_priority(conn
)) {
695 struct connection
*c
= conn
->next
;
708 interrupt_connection(struct connection
*conn
)
710 free_connection_data(conn
);
714 suspend_connection(struct connection
*conn
)
716 interrupt_connection(conn
);
717 set_connection_state(conn
, S_WAIT
);
721 run_connection(struct connection
*conn
)
723 protocol_handler_T
*func
= get_protocol_handler(conn
->uri
->protocol
);
727 assertm(!conn
->running
, "connection already running");
728 if_assert_failed
return;
730 if (!add_host_connection(conn
)) {
731 set_connection_state(conn
, S_OUT_OF_MEM
);
732 done_connection(conn
);
736 active_connections
++;
742 /* Set certain state on a connection and then abort the connection. */
744 abort_connection(struct connection
*conn
, enum connection_state state
)
746 assertm(is_in_result_state(state
),
747 "connection didn't end in result state (%d)", state
);
749 if (state
== S_OK
&& conn
->cached
)
750 normalize_cache_entry(conn
->cached
, conn
->from
);
752 set_connection_state(conn
, state
);
754 if (conn
->running
) interrupt_connection(conn
);
755 done_connection(conn
);
756 register_check_queue();
759 /* Set certain state on a connection and then retry the connection. */
761 retry_connection(struct connection
*conn
, enum connection_state state
)
763 int max_tries
= get_opt_int("connection.retries");
765 assertm(is_in_result_state(state
),
766 "connection didn't end in result state (%d)", state
);
768 set_connection_state(conn
, state
);
770 interrupt_connection(conn
);
771 if (conn
->uri
->post
|| !max_tries
|| ++conn
->tries
>= max_tries
) {
772 done_connection(conn
);
773 register_check_queue();
775 conn
->prev_error
= conn
->state
;
776 run_connection(conn
);
781 try_to_suspend_connection(struct connection
*conn
, struct uri
*uri
)
783 enum connection_priority priority
= get_priority(conn
);
784 struct connection
*c
;
786 foreachback (c
, connection_queue
) {
787 if (get_priority(c
) <= priority
) return -1;
788 if (c
->state
== S_WAIT
) continue;
789 if (c
->uri
->post
&& get_priority(c
) < PRI_CANCEL
) continue;
790 if (uri
&& !compare_uri(uri
, c
->uri
, URI_HOST
)) continue;
791 suspend_connection(c
);
799 try_connection(struct connection
*conn
, int max_conns_to_host
, int max_conns
)
801 struct host_connection
*host_conn
= get_host_connection(conn
);
803 if (host_conn
&& get_object_refcount(host_conn
) >= max_conns_to_host
)
804 return try_to_suspend_connection(conn
, host_conn
->uri
) ? 0 : -1;
806 if (active_connections
>= max_conns
)
807 return try_to_suspend_connection(conn
, NULL
) ? 0 : -1;
809 run_connection(conn
);
816 struct connection
*conn
;
817 int max_conns_to_host
= get_opt_int("connection.max_connections_to_host");
818 int max_conns
= get_opt_int("connection.max_connections");
821 conn
= connection_queue
.next
;
823 check_keepalive_connections();
825 while (conn
!= (struct connection
*) &connection_queue
) {
826 struct connection
*c
;
827 enum connection_priority pri
= get_priority(conn
);
829 for (c
= conn
; c
!= (struct connection
*) &connection_queue
&& get_priority(c
) == pri
;) {
830 struct connection
*cc
= c
;
833 if (cc
->state
== S_WAIT
&& get_keepalive_connection(cc
)
834 && try_connection(cc
, max_conns_to_host
, max_conns
))
838 for (c
= conn
; c
!= (struct connection
*) &connection_queue
&& get_priority(c
) == pri
;) {
839 struct connection
*cc
= c
;
842 if (cc
->state
== S_WAIT
843 && try_connection(cc
, max_conns_to_host
, max_conns
))
850 foreachback (conn
, connection_queue
) {
851 if (get_priority(conn
) < PRI_CANCEL
) break;
852 if (conn
->state
== S_WAIT
) {
853 set_connection_state(conn
, S_INTERRUPTED
);
854 done_connection(conn
);
863 register_check_queue(void)
865 return register_bottom_half(check_queue
, NULL
);
869 load_uri(struct uri
*uri
, struct uri
*referrer
, struct download
*download
,
870 enum connection_priority pri
, enum cache_mode cache_mode
, off_t start
)
872 struct cache_entry
*cached
;
873 struct connection
*conn
;
874 struct uri
*proxy_uri
, *proxied_uri
;
875 enum connection_state connection_state
= S_OK
;
878 download
->conn
= NULL
;
879 download
->cached
= NULL
;
881 download
->state
= S_OUT_OF_MEM
;
882 download
->prev_error
= 0;
886 foreach (conn
, connection_queue
) {
887 struct download
*assigned
;
889 foreach (assigned
, conn
->downloads
) {
890 assertm(assigned
!= download
, "Download assigned to '%s'", struri(conn
->uri
));
892 download
->state
= S_INTERNAL
;
893 if (download
->callback
)
894 download
->callback(download
, download
->data
);
897 /* No recovery path should be necessary. */
902 cached
= get_validated_cache_entry(uri
, cache_mode
);
905 download
->cached
= cached
;
906 download
->state
= S_OK
;
908 * This doesn't work since sometimes |download->progress|
909 * is undefined and contains random memory locations.
910 * It's not supposed to point on anything here since
911 * |download| has no connection attached.
912 * Downloads resuming will probably break in some
913 * cases without this, though.
914 * FIXME: Needs more investigation. --pasky */
915 /* if (download->progress) download->progress->start = start; */
916 if (download
->callback
)
917 download
->callback(download
, download
->data
);
922 proxied_uri
= get_proxied_uri(uri
);
923 proxy_uri
= get_proxy_uri(uri
, &connection_state
);
927 || (get_protocol_need_slash_after_host(proxy_uri
->protocol
)
928 && !proxy_uri
->hostlen
)) {
931 if (connection_state
== S_OK
) {
932 connection_state
= proxy_uri
&& proxied_uri
933 ? S_BAD_URL
: S_OUT_OF_MEM
;
936 download
->state
= connection_state
;
937 download
->callback(download
, download
->data
);
939 if (proxy_uri
) done_uri(proxy_uri
);
940 if (proxied_uri
) done_uri(proxied_uri
);
944 foreach (conn
, connection_queue
) {
946 || !compare_uri(conn
->uri
, proxy_uri
, 0))
950 done_uri(proxied_uri
);
952 if (get_priority(conn
) > pri
) {
956 register_check_queue();
962 download
->progress
= conn
->progress
;
963 download
->conn
= conn
;
964 download
->cached
= conn
->cached
;
965 add_to_list(conn
->downloads
, download
);
966 /* This is likely to call download->callback() now! */
967 set_connection_state(conn
, conn
->state
);
973 conn
= init_connection(proxy_uri
, proxied_uri
, referrer
, start
, cache_mode
, pri
);
976 download
->state
= S_OUT_OF_MEM
;
977 download
->callback(download
, download
->data
);
979 if (proxy_uri
) done_uri(proxy_uri
);
980 if (proxied_uri
) done_uri(proxied_uri
);
984 if (cache_mode
< CACHE_MODE_FORCE_RELOAD
&& cached
&& !list_empty(cached
->frag
)
985 && !((struct fragment
*) cached
->frag
.next
)->offset
)
986 conn
->from
= ((struct fragment
*) cached
->frag
.next
)->length
;
989 download
->progress
= conn
->progress
;
990 download
->conn
= conn
;
991 download
->cached
= NULL
;
992 download
->state
= S_OK
;
993 add_to_list(conn
->downloads
, download
);
997 set_connection_state(conn
, S_WAIT
);
1001 register_check_queue();
1006 /* FIXME: one object in more connections */
1008 cancel_download(struct download
*download
, int interrupt
)
1010 struct connection
*conn
;
1013 if_assert_failed
return;
1015 /* Did the connection already end? */
1016 if (is_in_result_state(download
->state
))
1019 assertm(download
->conn
, "last state is %d", download
->state
);
1023 download
->state
= S_INTERRUPTED
;
1024 del_from_list(download
);
1026 conn
= download
->conn
;
1028 conn
->pri
[download
->pri
]--;
1029 assertm(conn
->pri
[download
->pri
] >= 0, "priority counter underflow");
1030 if_assert_failed conn
->pri
[download
->pri
] = 0;
1032 if (list_empty(conn
->downloads
)) {
1033 /* Necessary because of assertion in get_priority(). */
1034 conn
->pri
[PRI_CANCEL
]++;
1036 if (conn
->detached
|| interrupt
)
1037 abort_connection(conn
, S_INTERRUPTED
);
1043 register_check_queue();
1047 move_download(struct download
*old
, struct download
*new,
1048 enum connection_priority newpri
)
1050 struct connection
*conn
;
1054 /* The download doesn't necessarily have a connection attached, for
1055 * example the file protocol loads it's object immediately. This is
1056 * catched by the result state check below. */
1061 new->cached
= old
->cached
;
1062 new->prev_error
= old
->prev_error
;
1063 new->progress
= old
->progress
;
1064 new->state
= old
->state
;
1067 if (is_in_result_state(old
->state
)) {
1068 /* Ensure that new->conn is always "valid", that is NULL if the
1069 * connection has been detached and non-NULL otherwise. */
1070 if (new->callback
) {
1072 new->progress
= NULL
;
1073 new->callback(new, new->data
);
1078 assertm(old
->conn
, "last state is %d", old
->state
);
1080 conn
->pri
[new->pri
]++;
1081 add_to_list(conn
->downloads
, new);
1083 cancel_download(old
, 0);
1087 /* This will remove 'pos' bytes from the start of the cache for the specified
1088 * connection, if the cached object is already too big. */
1090 detach_connection(struct download
*download
, off_t pos
)
1092 struct connection
*conn
= download
->conn
;
1094 if (is_in_result_state(download
->state
)) return;
1096 if (!conn
->detached
) {
1098 off_t i
, total_pri
= 0;
1103 total_len
= (conn
->est_length
== -1) ? conn
->from
1106 if (total_len
< (get_opt_long("document.cache.memory.size")
1107 * MAX_CACHED_OBJECT_PERCENT
/ 100)) {
1108 /* This whole thing will fit to the memory anyway, so
1109 * there's no problem in detaching the connection. */
1113 for (i
= 0; i
< PRI_CANCEL
; i
++)
1114 total_pri
+= conn
->pri
[i
];
1115 assertm(total_pri
, "detaching free connection");
1116 /* No recovery path should be necessary...? */
1118 /* Pre-clean cache. */
1119 shrink_format_cache(0);
1121 if (total_pri
!= 1 || is_object_used(conn
->cached
)) {
1122 /* We're too important, or someone uses our cache
1127 /* DBG("detached"); */
1129 /* We aren't valid cache entry anymore. */
1130 conn
->cached
->valid
= 0;
1134 /* Strip the entry. */
1135 free_entry_to(conn
->cached
, pos
);
1138 /* Timer callback for @conn->timer. As explained in @install_timer,
1139 * this function must erase the expired timer ID from all variables. */
1141 connection_timeout(struct connection
*conn
)
1143 conn
->timer
= TIMER_ID_UNDEF
;
1144 /* The expired timer ID has now been erased. */
1145 timeout_socket(conn
->socket
);
1148 /* Timer callback for @conn->timer. As explained in @install_timer,
1149 * this function must erase the expired timer ID from all variables.
1151 * Huh, using two timers? Is this to account for changes of c->unrestartable
1152 * or can it be reduced? --jonas */
1154 connection_timeout_1(struct connection
*conn
)
1156 install_timer(&conn
->timer
, (milliseconds_T
)
1157 ((conn
->unrestartable
1158 ? get_opt_int("connection.unrestartable_receive_timeout")
1159 : get_opt_int("connection.receive_timeout"))
1160 * 500), (void (*)(void *)) connection_timeout
, conn
);
1161 /* The expired timer ID has now been erased. */
1165 set_connection_timeout(struct connection
*conn
)
1167 kill_timer(&conn
->timer
);
1169 install_timer(&conn
->timer
, (milliseconds_T
)
1170 ((conn
->unrestartable
1171 ? get_opt_int("connection.unrestartable_receive_timeout")
1172 : get_opt_int("connection.receive_timeout"))
1173 * 500), (void (*)(void *)) connection_timeout_1
, conn
);
1178 abort_all_connections(void)
1180 while (!list_empty(connection_queue
)) {
1181 abort_connection(connection_queue
.next
, S_INTERRUPTED
);
1184 abort_all_keepalive_connections();
1188 abort_background_connections(void)
1190 struct connection
*conn
, *next
;
1192 foreachsafe (conn
, next
, connection_queue
) {
1193 if (get_priority(conn
) >= PRI_CANCEL
)
1194 abort_connection(conn
, S_INTERRUPTED
);
1199 is_entry_used(struct cache_entry
*cached
)
1201 struct connection
*conn
;
1203 foreach (conn
, connection_queue
)
1204 if (conn
->cached
== cached
)