⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 connection.c

📁 一个很有名的浏览器
💻 C
📖 第 1 页 / 共 2 页
字号:
	} else {		close(conn->socket.fd);	}done:	free_connection_data(conn);	done_connection(conn);	register_bottom_half((void (*)(void *)) check_queue, NULL);}static voidkeepalive_timer(void *x){	keepalive_timeout = -1;	check_keepalive_connections();}voidcheck_keepalive_connections(void){	struct keepalive_connection *keep_conn, *next;	ttime ct = get_time();	int p = 0;	if (keepalive_timeout != -1) {		kill_timer(keepalive_timeout);		keepalive_timeout = -1;	}	foreachsafe (keep_conn, next, keepalive_connections) {		if (can_read(keep_conn->socket)		    || ct - keep_conn->add_time > keep_conn->timeout) {			done_keepalive_connection(keep_conn);		} else {			p++;		}	}	for (; p > MAX_KEEPALIVE_CONNECTIONS; p--) {		assertm(!list_empty(keepalive_connections), "keepalive list empty");		if_assert_failed return;		done_keepalive_connection(keepalive_connections.prev);	}	if (!list_empty(keepalive_connections))		keepalive_timeout = install_timer(KEEPALIVE_CHECK_TIME,						  keepalive_timer, NULL);}static inline voidabort_all_keepalive_connections(void){	while (!list_empty(keepalive_connections))		done_keepalive_connection(keepalive_connections.next);	check_keepalive_connections();}static inline voidadd_to_queue(struct connection *conn){	struct connection *c;	enum connection_priority priority = get_priority(conn);	foreach (c, queue)		if (get_priority(c) > priority)			break;	add_at_pos(c->prev, conn);}static voidsort_queue(void){	int swp;	do {		struct connection *conn;		swp = 0;		foreach (conn, queue) {			if (!list_has_next(queue, conn)) break;			if (get_priority(conn->next) < get_priority(conn)) {				struct connection *c = conn->next;				del_from_list(conn);				add_at_pos(c, conn);				swp = 1;			}		}	} while (swp);}static voidinterrupt_connection(struct connection *conn){	close_socket(conn, &conn->socket);	free_connection_data(conn);}static inline voidsuspend_connection(struct connection *conn){	interrupt_connection(conn);	set_connection_state(conn, S_WAIT);}static voidrun_connection(struct connection *conn){	protocol_handler *func = get_protocol_handler(conn->uri->protocol);	assert(func);	assertm(!conn->running, "connection already running");	if_assert_failed return;	if (!add_host_connection(conn)) {		set_connection_state(conn, S_OUT_OF_MEM);		done_connection(conn);		return;	}	active_connections++;	conn->running = 1;	func(conn);}voidretry_connection(struct connection *conn){	int max_tries = get_opt_int("connection.retries");	interrupt_connection(conn);	if (conn->uri->post || !max_tries || ++conn->tries >= max_tries) {		/* notify_connection_callbacks(conn); */		done_connection(conn);		register_bottom_half((void (*)(void *)) check_queue, NULL);	} else {		conn->prev_error = conn->state;		run_connection(conn);	}}voidabort_connection(struct connection *conn){	if (conn->running) interrupt_connection(conn);	/* notify_connection_callbacks(conn); */	done_connection(conn);	register_bottom_half((void (*)(void *)) check_queue, NULL);}/* Set certain state on a connection and then abort the connection. */voidabort_conn_with_state(struct connection *conn, enum connection_state state){	set_connection_state(conn, state);	abort_connection(conn);}/* Set certain state on a connection and then retry the connection. */voidretry_conn_with_state(struct connection *conn, enum connection_state state){	set_connection_state(conn, state);	retry_connection(conn);}static inttry_to_suspend_connection(struct connection *conn, struct uri *uri){	enum connection_priority priority = get_priority(conn);	struct connection *c;	foreachback (c, queue) {		if (get_priority(c) <= priority) return -1;		if (c->state == S_WAIT) continue;		if (c->uri->post && get_priority(c) < PRI_CANCEL) continue;		if (uri && !compare_uri(uri, c->uri, URI_HOST)) continue;		suspend_connection(c);		return 0;	}	return -1;}static inline inttry_connection(struct connection *conn, int max_conns_to_host, int max_conns){	struct host_connection *host_conn = get_host_connection(conn);	if (host_conn && get_object_refcount(host_conn) >= max_conns_to_host)		return try_to_suspend_connection(conn, host_conn->uri) ? 0 : -1;	if (active_connections >= max_conns)		return try_to_suspend_connection(conn, NULL) ? 0 : -1;	run_connection(conn);	return 1;}voidcheck_queue(void){	struct connection *conn;	int max_conns_to_host = get_opt_int("connection.max_connections_to_host");	int max_conns = get_opt_int("connection.max_connections");again:	conn = queue.next;	check_queue_bugs();	check_keepalive_connections();	while (conn != (struct connection *) &queue) {		struct connection *c;		enum connection_priority pri = get_priority(conn);		for (c = conn; c != (struct connection *) &queue && get_priority(c) == pri;) {			struct connection *cc = c;			c = c->next;			if (cc->state == S_WAIT && get_keepalive_connection(cc)			    && try_connection(cc, max_conns_to_host, max_conns))				goto again;		}		for (c = conn; c != (struct connection *) &queue && get_priority(c) == pri;) {			struct connection *cc = c;			c = c->next;			if (cc->state == S_WAIT			    && try_connection(cc, max_conns_to_host, max_conns))				goto again;		}		conn = c;	}again2:	foreachback (conn, queue) {		if (get_priority(conn) < PRI_CANCEL) break;		if (conn->state == S_WAIT) {			set_connection_state(conn, S_INTERRUPTED);			done_connection(conn);			goto again2;		}	}	check_queue_bugs();}intload_uri(struct uri *uri, struct uri *referrer, struct download *download,	 enum connection_priority pri, enum cache_mode cache_mode, int start){	struct cache_entry *cached;	struct connection *conn;	struct uri *proxy_uri, *proxied_uri;	enum connection_state connection_state = S_OK;	if (download) {		download->conn = NULL;		download->cached = NULL;		download->pri = pri;		download->state = S_OUT_OF_MEM;		download->prev_error = 0;	}#ifdef CONFIG_DEBUG	foreach (conn, queue) {		struct download *assigned;		foreach (assigned, conn->downloads) {			assertm(assigned != download, "Download assigned to '%s'", struri(conn->uri));			if_assert_failed {				download->state = S_INTERNAL;				if (download->callback) download->callback(download, download->data);				return 0;			}			/* No recovery path should be necessary. */		}	}#endif	cached = get_validated_cache_entry(uri, cache_mode);	if (cached) {		if (download) {			download->cached = cached;			download->state = S_OK;			/* XXX:			 * This doesn't work since sometimes |download->progress|			 * is undefined and contains random memory locations.			 * It's not supposed to point on anything here since			 * |download| has no connection attached.			 * Downloads resuming will probably break in some			 * cases without this, though.			 * FIXME: Needs more investigation. --pasky */			/* if (download->progress) download->progress->start = start; */			if (download->callback)				download->callback(download, download->data);		}		return 0;	}	proxied_uri = get_proxied_uri(uri);	proxy_uri   = get_proxy_uri(uri, &connection_state);	if (!proxy_uri	    || !proxied_uri	    || (get_protocol_need_slash_after_host(proxy_uri->protocol)		&& !proxy_uri->hostlen)) {		if (download) {			if (connection_state == S_OK) {				connection_state = proxy_uri && proxied_uri						 ? S_BAD_URL : S_OUT_OF_MEM;			}			download->state = connection_state;			download->callback(download, download->data);		}		if (proxy_uri) done_uri(proxy_uri);		if (proxied_uri) done_uri(proxied_uri);		return -1;	}	foreach (conn, queue) {		if (conn->detached		    || !compare_uri(conn->uri, proxy_uri, 0))			continue;		done_uri(proxy_uri);		done_uri(proxied_uri);		if (get_priority(conn) > pri) {			del_from_list(conn);			conn->pri[pri]++;			add_to_queue(conn);			register_bottom_half((void (*)(void *)) check_queue, NULL);		} else {			conn->pri[pri]++;		}		if (download) {			download->progress = &conn->progress;			download->conn = conn;			download->cached = conn->cached;			add_to_list(conn->downloads, download);			/* This is likely to call download->callback() now! */			set_connection_state(conn, conn->state);		}		check_queue_bugs();		return 0;	}	conn = init_connection(proxy_uri, proxied_uri, referrer, start, cache_mode, pri);	if (!conn) {		if (download) {			download->state = S_OUT_OF_MEM;			download->callback(download, download->data);		}		if (proxy_uri) done_uri(proxy_uri);		if (proxied_uri) done_uri(proxied_uri);		return -1;	}	if (cache_mode < CACHE_MODE_FORCE_RELOAD && cached && !list_empty(cached->frag)	    && !((struct fragment *) cached->frag.next)->offset)		conn->from = ((struct fragment *) cached->frag.next)->length;	if (download) {		download->progress = &conn->progress;		download->conn = conn;		download->cached = NULL;		add_to_list(conn->downloads, download);	}	add_to_queue(conn);	set_connection_state(conn, S_WAIT);	check_queue_bugs();	register_bottom_half((void (*)(void *)) check_queue, NULL);	return 0;}/* FIXME: one object in more connections */voidchange_connection(struct download *old, struct download *new,		  int newpri, int interrupt){	struct connection *conn;	assert(old);	if_assert_failed return;	if (is_in_result_state(old->state)) {		if (new) {			new->cached = old->cached;			new->state = old->state;			new->prev_error = old->prev_error;			if (new->callback) new->callback(new, new->data);		}		return;	}	check_queue_bugs();	conn = old->conn;	conn->pri[old->pri]--;	assertm(conn->pri[old->pri] >= 0, "priority counter underflow");	if_assert_failed conn->pri[old->pri] = 0;	conn->pri[newpri]++;	del_from_list(old);	old->state = S_INTERRUPTED;	if (new) {		new->progress = &conn->progress;		add_to_list(conn->downloads, new);		new->state = conn->state;		new->prev_error = conn->prev_error;		new->pri = newpri;		new->conn = conn;		new->cached = conn->cached;	} else if (conn->detached || interrupt) {		abort_conn_with_state(conn, S_INTERRUPTED);	}	sort_queue();	check_queue_bugs();	register_bottom_half((void (*)(void *)) check_queue, NULL);}/* This will remove 'pos' bytes from the start of the cache for the specified * connection, if the cached object is already too big. */voiddetach_connection(struct download *download, int pos){	struct connection *conn = download->conn;	if (is_in_result_state(download->state)) return;	if (!conn->detached) {		int total_len;		int i, total_pri = 0;		if (!conn->cached)			return;		total_len = (conn->est_length == -1) ? conn->from						     : conn->est_length;		if (total_len < (get_opt_long("document.cache.memory.size")				 * MAX_CACHED_OBJECT_PERCENT / 100)) {			/* This whole thing will fit to the memory anyway, so			 * there's no problem in detaching the connection. */			return;		}		for (i = 0; i < PRI_CANCEL; i++)			total_pri += conn->pri[i];		assertm(total_pri, "detaching free connection");		/* No recovery path should be necessary...? */		/* Pre-clean cache. */		shrink_format_cache(0);		if (total_pri != 1 || is_object_used(conn->cached)) {			/* We're too important, or someone uses our cache			 * entry. */			return;		}		/* DBG("detached"); */		/* We aren't valid cache entry anymore. */		conn->cached->valid = 0;		conn->detached = 1;	}	/* Strip the entry. */	free_entry_to(conn->cached, pos);}static voidconnection_timeout(struct connection *conn){	conn->timer = -1;	set_connection_state(conn, S_TIMEOUT);	if (conn->dnsquery) {		abort_connection(conn);	} else if (conn->conn_info) {		dns_found(conn, 0); /* jump to next addr */		if (conn->conn_info) set_connection_timeout(conn);	} else {		retry_connection(conn);	}}/* Huh, using two timers? Is this to account for changes of c->unrestartable * or can it be reduced? --jonas */static voidconnection_timeout_1(struct connection *conn){	conn->timer = install_timer((conn->unrestartable				     ? get_opt_int("connection.unrestartable_receive_timeout")				     : get_opt_int("connection.receive_timeout"))				    * 500, (void (*)(void *)) connection_timeout, conn);}voidset_connection_timeout(struct connection *conn){	if (conn->timer != -1) kill_timer(conn->timer);	conn->timer = install_timer((conn->unrestartable				     ? get_opt_int("connection.unrestartable_receive_timeout")				     : get_opt_int("connection.receive_timeout"))				    * 500, (void (*)(void *)) connection_timeout_1, conn);}voidabort_all_connections(void){	while (!list_empty(queue)) {		abort_conn_with_state(queue.next, S_INTERRUPTED);	}	abort_all_keepalive_connections();}voidabort_background_connections(void){	struct connection *conn;	foreach (conn, queue) {		if (get_priority(conn) >= PRI_CANCEL) {			conn = conn->prev;			abort_conn_with_state(conn->next, S_INTERRUPTED);		}	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -