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;
386 struct popen_data
*pop
;
388 foreach (pop
, copiousoutput_data
) {
393 unlink(pop
->filename
);
394 mem_free(pop
->filename
);
403 free_connection_data(struct connection
*conn
)
405 assertm(conn
->running
, "connection already suspended");
406 /* XXX: Recovery path? Originally, there was none. I think we'll get
407 * at least active_connections underflows along the way. --pasky */
410 active_connections
--;
411 assertm(active_connections
>= 0, "active connections underflow");
412 if_assert_failed active_connections
= 0;
415 if (conn
->socket
->ssl
&& conn
->cached
)
416 mem_free_set(&conn
->cached
->ssl_info
, get_ssl_connection_cipher(conn
->socket
));
422 if (conn
->popen
) close_popen(conn
->socket
->fd
);
423 done_socket(conn
->socket
);
424 done_socket(conn
->data_socket
);
426 shutdown_connection_stream(conn
);
428 mem_free_set(&conn
->info
, NULL
);
430 kill_timer(&conn
->timer
);
432 if (conn
->state
!= S_WAIT
)
433 done_host_connection(conn
);
437 notify_connection_callbacks(struct connection
*conn
)
439 enum connection_state state
= conn
->state
;
440 struct download
*download
, *next
;
442 foreachsafe (download
, next
, conn
->downloads
) {
443 download
->cached
= conn
->cached
;
444 if (download
->callback
)
445 download
->callback(download
, download
->data
);
446 if (is_in_progress_state(state
) && connection_disappeared(conn
))
452 done_connection(struct connection
*conn
)
454 /* When removing the connection callbacks should always be aware of it
455 * so they can unregister themselves. We do this by enforcing that the
456 * connection is in a result state. If it is not already it is an
457 * internal bug. This should never happen but it does. ;) --jonas */
458 if (!is_in_result_state(conn
->state
))
459 set_connection_state(conn
, S_INTERNAL
);
462 notify_connection_callbacks(conn
);
463 if (conn
->referrer
) done_uri(conn
->referrer
);
465 done_uri(conn
->proxied_uri
);
466 mem_free(conn
->socket
);
467 mem_free(conn
->data_socket
);
468 done_progress(conn
->progress
);
474 add_to_queue(struct connection
*conn
)
476 struct connection
*c
;
477 enum connection_priority priority
= get_priority(conn
);
479 foreach (c
, connection_queue
)
480 if (get_priority(c
) > priority
)
483 add_at_pos(c
->prev
, conn
);
487 /* Returns zero if no callback was done and the keepalive connection should be
488 * deleted or non-zero if the keepalive connection should not be deleted. */
490 do_keepalive_connection_callback(struct keepalive_connection
*keep_conn
)
492 struct uri
*proxied_uri
= get_proxied_uri(keep_conn
->uri
);
493 struct uri
*proxy_uri
= get_proxy_uri(keep_conn
->uri
, NULL
);
495 if (proxied_uri
&& proxy_uri
) {
496 struct connection
*conn
;
498 conn
= init_connection(proxy_uri
, proxied_uri
, NULL
, 0,
499 CACHE_MODE_NEVER
, PRI_CANCEL
);
502 void (*done
)(struct connection
*) = keep_conn
->done
;
506 /* Get the keepalive info and let it clean up */
507 if (!has_keepalive_connection(conn
)
508 || !add_host_connection(conn
)) {
509 free_connection_data(conn
);
510 done_connection(conn
);
514 active_connections
++;
521 if (proxied_uri
) done_uri(proxied_uri
);
522 if (proxy_uri
) done_uri(proxy_uri
);
528 done_keepalive_connection(struct keepalive_connection
*keep_conn
)
530 if (keep_conn
->done
&& do_keepalive_connection_callback(keep_conn
))
533 del_from_list(keep_conn
);
534 if (keep_conn
->socket
!= -1) close(keep_conn
->socket
);
535 done_uri(keep_conn
->uri
);
539 static struct keepalive_connection
*
540 init_keepalive_connection(struct connection
*conn
, long timeout_in_seconds
,
541 void (*done
)(struct connection
*))
543 struct keepalive_connection
*keep_conn
;
544 struct uri
*uri
= conn
->uri
;
547 if_assert_failed
return NULL
;
549 keep_conn
= mem_calloc(1, sizeof(*keep_conn
));
550 if (!keep_conn
) return NULL
;
552 keep_conn
->uri
= get_uri_reference(uri
);
553 keep_conn
->done
= done
;
554 keep_conn
->protocol_family
= conn
->socket
->protocol_family
;
555 keep_conn
->socket
= conn
->socket
->fd
;
556 timeval_from_seconds(&keep_conn
->timeout
, timeout_in_seconds
);
557 timeval_now(&keep_conn
->creation_time
);
562 static struct keepalive_connection
*
563 get_keepalive_connection(struct connection
*conn
)
565 struct keepalive_connection
*keep_conn
;
567 if (!conn
->uri
->host
) return NULL
;
569 foreach (keep_conn
, keepalive_connections
)
570 if (compare_uri(keep_conn
->uri
, conn
->uri
, URI_KEEPALIVE
))
577 has_keepalive_connection(struct connection
*conn
)
579 struct keepalive_connection
*keep_conn
= get_keepalive_connection(conn
);
581 if (!keep_conn
) return 0;
583 conn
->socket
->fd
= keep_conn
->socket
;
584 conn
->socket
->protocol_family
= keep_conn
->protocol_family
;
586 /* Mark that the socket should not be closed and the callback should be
588 keep_conn
->socket
= -1;
589 keep_conn
->done
= NULL
;
590 done_keepalive_connection(keep_conn
);
596 add_keepalive_connection(struct connection
*conn
, long timeout_in_seconds
,
597 void (*done
)(struct connection
*))
599 struct keepalive_connection
*keep_conn
;
601 assertm(conn
->socket
->fd
!= -1, "keepalive connection not connected");
602 if_assert_failed
goto done
;
604 keep_conn
= init_keepalive_connection(conn
, timeout_in_seconds
, done
);
606 /* Make sure that the socket descriptor will not periodically be
607 * checked or closed by free_connection_data(). */
608 clear_handlers(conn
->socket
->fd
);
609 conn
->socket
->fd
= -1;
610 add_to_list(keepalive_connections
, keep_conn
);
613 /* It will take just a little more time */
619 free_connection_data(conn
);
620 done_connection(conn
);
621 register_check_queue();
624 /* Timer callback for @keepalive_timeout. As explained in @install_timer,
625 * this function must erase the expired timer ID from all variables. */
627 keepalive_timer(void *x
)
629 keepalive_timeout
= TIMER_ID_UNDEF
;
630 /* The expired timer ID has now been erased. */
631 check_keepalive_connections();
635 check_keepalive_connections(void)
637 struct keepalive_connection
*keep_conn
, *next
;
643 kill_timer(&keepalive_timeout
);
645 foreachsafe (keep_conn
, next
, keepalive_connections
) {
648 if (can_read(keep_conn
->socket
)) {
649 done_keepalive_connection(keep_conn
);
653 timeval_sub(&age
, &keep_conn
->creation_time
, &now
);
654 if (timeval_cmp(&age
, &keep_conn
->timeout
) > 0) {
655 done_keepalive_connection(keep_conn
);
662 for (; p
> MAX_KEEPALIVE_CONNECTIONS
; p
--) {
663 assertm(!list_empty(keepalive_connections
), "keepalive list empty");
664 if_assert_failed
return;
665 done_keepalive_connection(keepalive_connections
.prev
);
668 if (!list_empty(keepalive_connections
))
669 install_timer(&keepalive_timeout
, KEEPALIVE_CHECK_TIME
,
670 keepalive_timer
, NULL
);
674 abort_all_keepalive_connections(void)
676 while (!list_empty(keepalive_connections
))
677 done_keepalive_connection(keepalive_connections
.next
);
679 check_keepalive_connections();
687 struct connection
*conn
;
690 foreach (conn
, connection_queue
) {
691 if (!list_has_next(connection_queue
, conn
)) break;
693 if (get_priority(conn
->next
) < get_priority(conn
)) {
694 struct connection
*c
= conn
->next
;
707 interrupt_connection(struct connection
*conn
)
709 free_connection_data(conn
);
713 suspend_connection(struct connection
*conn
)
715 interrupt_connection(conn
);
716 set_connection_state(conn
, S_WAIT
);
720 run_connection(struct connection
*conn
)
722 protocol_handler_T
*func
= get_protocol_handler(conn
->uri
->protocol
);
726 assertm(!conn
->running
, "connection already running");
727 if_assert_failed
return;
729 if (!add_host_connection(conn
)) {
730 set_connection_state(conn
, S_OUT_OF_MEM
);
731 done_connection(conn
);
735 active_connections
++;
741 /* Set certain state on a connection and then abort the connection. */
743 abort_connection(struct connection
*conn
, enum connection_state state
)
745 assertm(is_in_result_state(state
),
746 "connection didn't end in result state (%d)", state
);
748 if (state
== S_OK
&& conn
->cached
)
749 normalize_cache_entry(conn
->cached
, conn
->from
);
751 set_connection_state(conn
, state
);
753 if (conn
->running
) interrupt_connection(conn
);
754 done_connection(conn
);
755 register_check_queue();
758 /* Set certain state on a connection and then retry the connection. */
760 retry_connection(struct connection
*conn
, enum connection_state state
)
762 int max_tries
= get_opt_int("connection.retries");
764 assertm(is_in_result_state(state
),
765 "connection didn't end in result state (%d)", state
);
767 set_connection_state(conn
, state
);
769 interrupt_connection(conn
);
770 if (conn
->uri
->post
|| !max_tries
|| ++conn
->tries
>= max_tries
) {
771 done_connection(conn
);
772 register_check_queue();
774 conn
->prev_error
= conn
->state
;
775 run_connection(conn
);
780 try_to_suspend_connection(struct connection
*conn
, struct uri
*uri
)
782 enum connection_priority priority
= get_priority(conn
);
783 struct connection
*c
;
785 foreachback (c
, connection_queue
) {
786 if (get_priority(c
) <= priority
) return -1;
787 if (c
->state
== S_WAIT
) continue;
788 if (c
->uri
->post
&& get_priority(c
) < PRI_CANCEL
) continue;
789 if (uri
&& !compare_uri(uri
, c
->uri
, URI_HOST
)) continue;
790 suspend_connection(c
);
798 try_connection(struct connection
*conn
, int max_conns_to_host
, int max_conns
)
800 struct host_connection
*host_conn
= get_host_connection(conn
);
802 if (host_conn
&& get_object_refcount(host_conn
) >= max_conns_to_host
)
803 return try_to_suspend_connection(conn
, host_conn
->uri
) ? 0 : -1;
805 if (active_connections
>= max_conns
)
806 return try_to_suspend_connection(conn
, NULL
) ? 0 : -1;
808 run_connection(conn
);
815 struct connection
*conn
;
816 int max_conns_to_host
= get_opt_int("connection.max_connections_to_host");
817 int max_conns
= get_opt_int("connection.max_connections");
820 conn
= connection_queue
.next
;
822 check_keepalive_connections();
824 while (conn
!= (struct connection
*) &connection_queue
) {
825 struct connection
*c
;
826 enum connection_priority pri
= get_priority(conn
);
828 for (c
= conn
; c
!= (struct connection
*) &connection_queue
&& get_priority(c
) == pri
;) {
829 struct connection
*cc
= c
;
832 if (cc
->state
== S_WAIT
&& get_keepalive_connection(cc
)
833 && try_connection(cc
, max_conns_to_host
, max_conns
))
837 for (c
= conn
; c
!= (struct connection
*) &connection_queue
&& get_priority(c
) == pri
;) {
838 struct connection
*cc
= c
;
841 if (cc
->state
== S_WAIT
842 && try_connection(cc
, max_conns_to_host
, max_conns
))
849 foreachback (conn
, connection_queue
) {
850 if (get_priority(conn
) < PRI_CANCEL
) break;
851 if (conn
->state
== S_WAIT
) {
852 set_connection_state(conn
, S_INTERRUPTED
);
853 done_connection(conn
);
862 register_check_queue(void)
864 return register_bottom_half(check_queue
, NULL
);
868 load_uri(struct uri
*uri
, struct uri
*referrer
, struct download
*download
,
869 enum connection_priority pri
, enum cache_mode cache_mode
, off_t start
)
871 struct cache_entry
*cached
;
872 struct connection
*conn
;
873 struct uri
*proxy_uri
, *proxied_uri
;
874 enum connection_state connection_state
= S_OK
;
877 download
->conn
= NULL
;
878 download
->cached
= NULL
;
880 download
->state
= S_OUT_OF_MEM
;
881 download
->prev_error
= 0;
885 foreach (conn
, connection_queue
) {
886 struct download
*assigned
;
888 foreach (assigned
, conn
->downloads
) {
889 assertm(assigned
!= download
, "Download assigned to '%s'", struri(conn
->uri
));
891 download
->state
= S_INTERNAL
;
892 if (download
->callback
)
893 download
->callback(download
, download
->data
);
896 /* No recovery path should be necessary. */
901 cached
= get_validated_cache_entry(uri
, cache_mode
);
904 download
->cached
= cached
;
905 download
->state
= S_OK
;
907 * This doesn't work since sometimes |download->progress|
908 * is undefined and contains random memory locations.
909 * It's not supposed to point on anything here since
910 * |download| has no connection attached.
911 * Downloads resuming will probably break in some
912 * cases without this, though.
913 * FIXME: Needs more investigation. --pasky */
914 /* if (download->progress) download->progress->start = start; */
915 if (download
->callback
)
916 download
->callback(download
, download
->data
);
921 proxied_uri
= get_proxied_uri(uri
);
922 proxy_uri
= get_proxy_uri(uri
, &connection_state
);
926 || (get_protocol_need_slash_after_host(proxy_uri
->protocol
)
927 && !proxy_uri
->hostlen
)) {
930 if (connection_state
== S_OK
) {
931 connection_state
= proxy_uri
&& proxied_uri
932 ? S_BAD_URL
: S_OUT_OF_MEM
;
935 download
->state
= connection_state
;
936 download
->callback(download
, download
->data
);
938 if (proxy_uri
) done_uri(proxy_uri
);
939 if (proxied_uri
) done_uri(proxied_uri
);
943 foreach (conn
, connection_queue
) {
945 || !compare_uri(conn
->uri
, proxy_uri
, 0))
949 done_uri(proxied_uri
);
951 if (get_priority(conn
) > pri
) {
955 register_check_queue();
961 download
->progress
= conn
->progress
;
962 download
->conn
= conn
;
963 download
->cached
= conn
->cached
;
964 add_to_list(conn
->downloads
, download
);
965 /* This is likely to call download->callback() now! */
966 set_connection_state(conn
, conn
->state
);
972 conn
= init_connection(proxy_uri
, proxied_uri
, referrer
, start
, cache_mode
, pri
);
975 download
->state
= S_OUT_OF_MEM
;
976 download
->callback(download
, download
->data
);
978 if (proxy_uri
) done_uri(proxy_uri
);
979 if (proxied_uri
) done_uri(proxied_uri
);
983 if (cache_mode
< CACHE_MODE_FORCE_RELOAD
&& cached
&& !list_empty(cached
->frag
)
984 && !((struct fragment
*) cached
->frag
.next
)->offset
)
985 conn
->from
= ((struct fragment
*) cached
->frag
.next
)->length
;
988 download
->progress
= conn
->progress
;
989 download
->conn
= conn
;
990 download
->cached
= NULL
;
991 download
->state
= S_OK
;
992 add_to_list(conn
->downloads
, download
);
996 set_connection_state(conn
, S_WAIT
);
1000 register_check_queue();
1005 /* FIXME: one object in more connections */
1007 cancel_download(struct download
*download
, int interrupt
)
1009 struct connection
*conn
;
1012 if_assert_failed
return;
1014 /* Did the connection already end? */
1015 if (is_in_result_state(download
->state
))
1018 assertm(download
->conn
!= NULL
, "last state is %d", download
->state
);
1022 download
->state
= S_INTERRUPTED
;
1023 del_from_list(download
);
1025 conn
= download
->conn
;
1027 conn
->pri
[download
->pri
]--;
1028 assertm(conn
->pri
[download
->pri
] >= 0, "priority counter underflow");
1029 if_assert_failed conn
->pri
[download
->pri
] = 0;
1031 if (list_empty(conn
->downloads
)) {
1032 /* Necessary because of assertion in get_priority(). */
1033 conn
->pri
[PRI_CANCEL
]++;
1035 if (conn
->detached
|| interrupt
)
1036 abort_connection(conn
, S_INTERRUPTED
);
1042 register_check_queue();
1046 move_download(struct download
*old
, struct download
*new,
1047 enum connection_priority newpri
)
1049 struct connection
*conn
;
1053 /* The download doesn't necessarily have a connection attached, for
1054 * example the file protocol loads it's object immediately. This is
1055 * catched by the result state check below. */
1060 new->cached
= old
->cached
;
1061 new->prev_error
= old
->prev_error
;
1062 new->progress
= old
->progress
;
1063 new->state
= old
->state
;
1066 if (is_in_result_state(old
->state
)) {
1067 /* Ensure that new->conn is always "valid", that is NULL if the
1068 * connection has been detached and non-NULL otherwise. */
1069 if (new->callback
) {
1071 new->progress
= NULL
;
1072 new->callback(new, new->data
);
1077 assertm(old
->conn
!= NULL
, "last state is %d", old
->state
);
1079 conn
->pri
[new->pri
]++;
1080 add_to_list(conn
->downloads
, new);
1082 cancel_download(old
, 0);
1086 /* This will remove 'pos' bytes from the start of the cache for the specified
1087 * connection, if the cached object is already too big. */
1089 detach_connection(struct download
*download
, off_t pos
)
1091 struct connection
*conn
= download
->conn
;
1093 if (is_in_result_state(download
->state
)) return;
1095 if (!conn
->detached
) {
1097 off_t i
, total_pri
= 0;
1102 total_len
= (conn
->est_length
== -1) ? conn
->from
1105 if (total_len
< (get_opt_long("document.cache.memory.size")
1106 * MAX_CACHED_OBJECT_PERCENT
/ 100)) {
1107 /* This whole thing will fit to the memory anyway, so
1108 * there's no problem in detaching the connection. */
1112 for (i
= 0; i
< PRI_CANCEL
; i
++)
1113 total_pri
+= conn
->pri
[i
];
1114 assertm(total_pri
, "detaching free connection");
1115 /* No recovery path should be necessary...? */
1117 /* Pre-clean cache. */
1118 shrink_format_cache(0);
1120 if (total_pri
!= 1 || is_object_used(conn
->cached
)) {
1121 /* We're too important, or someone uses our cache
1126 /* DBG("detached"); */
1128 /* We aren't valid cache entry anymore. */
1129 conn
->cached
->valid
= 0;
1133 /* Strip the entry. */
1134 free_entry_to(conn
->cached
, pos
);
1137 /* Timer callback for @conn->timer. As explained in @install_timer,
1138 * this function must erase the expired timer ID from all variables. */
1140 connection_timeout(struct connection
*conn
)
1142 conn
->timer
= TIMER_ID_UNDEF
;
1143 /* The expired timer ID has now been erased. */
1144 timeout_socket(conn
->socket
);
1147 /* Timer callback for @conn->timer. As explained in @install_timer,
1148 * this function must erase the expired timer ID from all variables.
1150 * Huh, using two timers? Is this to account for changes of c->unrestartable
1151 * or can it be reduced? --jonas */
1153 connection_timeout_1(struct connection
*conn
)
1155 install_timer(&conn
->timer
, (milliseconds_T
)
1156 ((conn
->unrestartable
1157 ? get_opt_int("connection.unrestartable_receive_timeout")
1158 : get_opt_int("connection.receive_timeout"))
1159 * 500), (void (*)(void *)) connection_timeout
, conn
);
1160 /* The expired timer ID has now been erased. */
1164 set_connection_timeout(struct connection
*conn
)
1166 kill_timer(&conn
->timer
);
1168 install_timer(&conn
->timer
, (milliseconds_T
)
1169 ((conn
->unrestartable
1170 ? get_opt_int("connection.unrestartable_receive_timeout")
1171 : get_opt_int("connection.receive_timeout"))
1172 * 500), (void (*)(void *)) connection_timeout_1
, conn
);
1177 abort_all_connections(void)
1179 while (!list_empty(connection_queue
)) {
1180 abort_connection(connection_queue
.next
, S_INTERRUPTED
);
1183 abort_all_keepalive_connections();
1187 abort_background_connections(void)
1189 struct connection
*conn
, *next
;
1191 foreachsafe (conn
, next
, connection_queue
) {
1192 if (get_priority(conn
) >= PRI_CANCEL
)
1193 abort_connection(conn
, S_INTERRUPTED
);
1198 is_entry_used(struct cache_entry
*cached
)
1200 struct connection
*conn
;
1202 foreach (conn
, connection_queue
)
1203 if (conn
->cached
== cached
)