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

📄 sched.c

📁 ELinks is an advanced and well-established feature-rich text mode web (HTTP/FTP/..) browser. ELinks
💻 C
📖 第 1 页 / 共 2 页
字号:
/* sched.c * Links internal scheduler * (c) 2002 Mikulas Patocka * This file is a part of the Links program, released under GPL. */#include "links.h"tcount connection_count = 0;int active_connections = 0;struct list_head queue = {&queue, &queue};struct h_conn {	struct h_conn *next;	struct h_conn *prev;	unsigned char *host;	int conn;};struct list_head h_conns = {&h_conns, &h_conns};struct list_head keepalive_connections = {&keepalive_connections, &keepalive_connections};/* prototypes */int connection_disappeared(struct connection *, tcount);struct h_conn *is_host_on_list(struct connection *);void stat_timer(struct connection *);struct k_conn *is_host_on_keepalive_list(struct connection *);void check_keepalive_connections(void);void free_connection_data(struct connection *);void del_connection(struct connection *);void del_keepalive_socket(struct k_conn *);void keepalive_timer(void *);void add_to_queue(struct connection *);void sort_queue(void);void interrupt_connection(struct connection *);void suspend_connection(struct connection *);int try_to_suspend_connection(struct connection *, unsigned char *);void connection_timeout_1(struct connection *);void reset_timeout(struct connection *);int try_connection(struct connection *);void no_owner(void){	internal("connection has no owner");}long connect_info(int type){	int i = 0;	struct connection *ce;	struct k_conn *cee;	switch (type) {		case CI_FILES:			foreach(ce, queue) i++;			return i;		case CI_CONNECTING:			foreach(ce, queue) i += ce->state > S_WAIT && ce->state < S_TRANS;			return i;		case CI_TRANSFER:			foreach(ce, queue) i += ce->state == S_TRANS;			return i;		case CI_KEEP:			foreach(cee, keepalive_connections) i++;			return i;		case CI_LIST:			return (long) &queue;		default:			internal("cache_info: bad request");	}	return 0;}int connection_disappeared(struct connection *c, tcount count){	struct connection *d;	foreach(d, queue) if (c == d && count == d->count) return 0;	return 1;}struct h_conn *is_host_on_list(struct connection *c){	unsigned char *ho;	struct h_conn *h;	if (!(ho = get_host_name(c->url))) return NULL;	foreach(h, h_conns) if (!strcmp(h->host, ho)) {		mem_free(ho);		return h;	}	mem_free(ho);	return NULL;}int st_r = 0;void stat_timer(struct connection *c){	struct remaining_info *r = &c->prg;	ttime a = get_time() - r->last_time;	if (getpri(c) == PRI_CANCEL && (c->est_length > memory_cache_size * MAX_CACHED_OBJECT || c->from > memory_cache_size * MAX_CACHED_OBJECT)) register_bottom_half(check_queue, NULL);	if (c->state > S_WAIT) {		r->loaded = c->received;		if ((r->size = c->est_length) < (r->pos = c->from) && r->size != -1)			r->size = c->from;		r->dis_b += a;		while (r->dis_b >= SPD_DISP_TIME * CURRENT_SPD_SEC) {			r->cur_loaded -= r->data_in_secs[0];			memmove(r->data_in_secs, r->data_in_secs + 1, sizeof(int) * (CURRENT_SPD_SEC - 1));			r->data_in_secs[CURRENT_SPD_SEC - 1] = 0;			r->dis_b -= SPD_DISP_TIME;		}		r->data_in_secs[CURRENT_SPD_SEC - 1] += r->loaded - r->last_loaded;		r->cur_loaded += r->loaded - r->last_loaded;		r->last_loaded = r->loaded;		r->elapsed += a;	}	r->last_time += a;	r->timer = install_timer(SPD_DISP_TIME, (void (*)(void *))stat_timer, c);	if (!st_r) send_connection_info(c);}void setcstate(struct connection *c, int state){	struct status *stat;	if (c->state < 0 && state >= 0) c->prev_error = c->state;	if ((c->state = state) == S_TRANS) {		struct remaining_info *r = &c->prg;		if (r->timer == -1) {			tcount count = c->count;			if (!r->valid) {				memset(r, 0, sizeof(struct remaining_info));				r->valid = 1;			}			r->last_time = get_time();			r->last_loaded = r->loaded;			st_r = 1;			stat_timer(c);			st_r = 0;			if (connection_disappeared(c, count)) return;		}	} else {		struct remaining_info *r = &c->prg;		if (r->timer != -1) kill_timer(r->timer), r->timer = -1;	}	foreach(stat, c->statuss) {		stat->state = state;		stat->prev_error = c->prev_error;	}	if (state >= 0) send_connection_info(c);}struct k_conn *is_host_on_keepalive_list(struct connection *c){	unsigned char *ho;	int po;	void (*ph)(struct connection *);	struct k_conn *h;	if ((po = get_port(c->url)) == -1) return NULL;	if (!(ph = get_protocol_handle(c->url))) return NULL;	if (!(ho = get_host_and_pass(c->url))) return NULL;	foreach(h, keepalive_connections)		if (h->protocol == ph && h->port == po && !strcmp(h->host, ho)) {			mem_free(ho);			return h;		}	mem_free(ho);	return NULL;}int get_keepalive_socket(struct connection *c){	struct k_conn *k;	int cc;	if (!(k = is_host_on_keepalive_list(c))) return -1;	cc = k->conn;	del_from_list(k);	mem_free(k->host);	mem_free(k);	c->sock1 = cc;	return 0;}void abort_all_keepalive_connections(void){	struct k_conn *k;	foreach(k, keepalive_connections) mem_free(k->host), close(k->conn);	free_list(keepalive_connections);	check_keepalive_connections();}void free_connection_data(struct connection *c){	struct h_conn *h;	if (c->sock1 != -1) set_handlers(c->sock1, NULL, NULL, NULL, NULL);	if (c->sock2 != -1) set_handlers(c->sock2, NULL, NULL, NULL, NULL);	close_socket(&c->sock2);	if (c->pid) {		kill(c->pid, SIGINT);		kill(c->pid, SIGTERM);		kill(c->pid, SIGKILL);		c->pid = 0;	}	if (!c->running) {		internal("connection already suspended");	}	c->running = 0;	if (c->dnsquery) kill_dns_request(&c->dnsquery);	if (c->buffer) {		mem_free(c->buffer);		c->buffer = NULL;	}	if (c->newconn) {		mem_free(c->newconn);		c->newconn = NULL;	}	if (c->info) {		mem_free(c->info);		c->info = NULL;	}	if (c->timer != -1) kill_timer(c->timer), c->timer = -1;	if (--active_connections < 0) {		internal("active connections underflow");		active_connections = 0;	}	if (c->state != S_WAIT) {		if ((h = is_host_on_list(c))) {			if (!--h->conn) {				del_from_list(h);				mem_free(h->host);				mem_free(h);			}		} else internal("suspending connection that is not on the list (state %d)", c->state);	}}void send_connection_info(struct connection *c){	int st = c->state;	tcount count = c->count;	struct status *stat = c->statuss.next;	while ((void *)stat != &c->statuss) {		stat->ce = c->cache;		stat = stat->next;		if (stat->prev->end) stat->prev->end(stat->prev, stat->prev->data);		if (st >= 0 && connection_disappeared(c, count)) return;	}}void del_connection(struct connection *c){	del_from_list(c);	send_connection_info(c);	mem_free(c->url);	if (c->prev_url) mem_free(c->prev_url);	mem_free(c);}#ifdef DEBUGvoid check_queue_bugs(void);#endifvoid add_keepalive_socket(struct connection *c, ttime timeout){	struct k_conn *k;	free_connection_data(c);	if (c->sock1 == -1) {		internal("keepalive connection not connected");		goto del;	}	k = mem_alloc(sizeof(struct k_conn));	if ((k->port = get_port(c->url)) == -1 || !(k->protocol = get_protocol_handle(c->url)) || !(k->host = get_host_and_pass(c->url))) {		mem_free(k);		del_connection(c);		goto close;	}	k->conn = c->sock1;	k->timeout = timeout;	k->add_time = get_time();	add_to_list(keepalive_connections, k);	del:	del_connection(c);#ifdef DEBUG	check_queue_bugs();#endif	register_bottom_half(check_queue, NULL);	return;	close:	close(c->sock1);#ifdef DEBUG	check_queue_bugs();#endif	register_bottom_half(check_queue, NULL);}void del_keepalive_socket(struct k_conn *kc){	del_from_list(kc);	close(kc->conn);	mem_free(kc->host);	mem_free(kc);}int keepalive_timeout = -1;void keepalive_timer(void *x){	keepalive_timeout = -1;	check_keepalive_connections();}void check_keepalive_connections(void){	struct k_conn *kc;	ttime ct = get_time();	int p = 0;	if (keepalive_timeout != -1) kill_timer(keepalive_timeout), keepalive_timeout = -1;	foreach(kc, keepalive_connections) if (can_read(kc->conn) || ct - kc->add_time > kc->timeout) {		kc = kc->prev;		del_keepalive_socket(kc->next);	} else p++;	for (; p > MAX_KEEPALIVE_CONNECTIONS; p--)		if (!list_empty(keepalive_connections))			del_keepalive_socket(keepalive_connections.prev);		else internal("keepalive list empty");	if (!list_empty(keepalive_connections)) keepalive_timeout = install_timer(KEEPALIVE_CHECK_TIME, keepalive_timer, NULL);}void add_to_queue(struct connection *c){	struct connection *cc;	int pri = getpri(c);	foreach(cc, queue) if (getpri(cc) > pri) break;	add_at_pos(cc->prev, c);}void sort_queue(void){	struct connection *c, *n;	int swp;	do {		swp = 0;		foreach(c, queue) if ((void *)c->next != &queue) {			if (getpri(c->next) < getpri(c)) {				n = c->next;				del_from_list(c);				add_at_pos(n, c);				swp = 1;			}		}	} while (swp);}void interrupt_connection(struct connection *c){#ifdef HAVE_SSL	if (c->ssl == (void *)-1) c->ssl = 0;	if(c->ssl) {		SSL_free(c->ssl);		c->ssl=NULL;	}#endif	close_socket(&c->sock1);	free_connection_data(c);}void suspend_connection(struct connection *c){	interrupt_connection(c);	setcstate(c, S_WAIT);}int try_to_suspend_connection(struct connection *c, unsigned char *ho){	int pri = getpri(c);	struct connection *d;	foreachback(d, queue) {		if (getpri(d) <= pri) return -1;		if (d->state == S_WAIT) continue;		if (d->unrestartable == 2 && getpri(d) < PRI_CANCEL) continue;		if (ho) {			unsigned char *h;			if (!(h = get_host_name(d->url))) continue;			if (strcmp(h, ho)) {				mem_free(h);				continue;			}			mem_free(h);		}		suspend_connection(d);		return 0;	}	return -1;}void run_connection(struct connection *c){	struct h_conn *hc;	void (*func)(struct connection *);	if (c->running) {		internal("connection already running");		return;	}	if (is_url_blocked(c->url)) {		setcstate(c, S_BLOCKED_URL);		del_connection(c);		return;	}	safe_strncpy(c->socks_proxy, proxies.socks_proxy, sizeof c->socks_proxy);	if (proxies.only_proxies && casecmp(c->url, "proxy://", 8) && (!*c->socks_proxy || url_bypasses_socks(c->url))) {		setcstate(c, S_NO_PROXY);		del_connection(c);		return;	}		if (!(func = get_protocol_handle(c->url))) {		setcstate(c, S_BAD_URL);		del_connection(c);		return;	}	if (!(hc = is_host_on_list(c))) {		hc = mem_alloc(sizeof(struct h_conn));		if (!(hc->host = get_host_name(c->url))) {			setcstate(c, S_BAD_URL);			del_connection(c);			mem_free(hc);			return;		}		hc->conn = 0;		add_to_list(h_conns, hc);	}	hc->conn++;	active_connections++;	c->running = 1;	func(c);}int is_connection_restartable(struct connection *c){	return !(c->unrestartable >= 2 || (c->tries + 1 >= (max_tries ? max_tries : 1000)));}void retry_connection(struct connection *c){	interrupt_connection(c);	if (!is_connection_restartable(c)) {		/*send_connection_info(c);*/		del_connection(c);#ifdef DEBUG		check_queue_bugs();#endif		register_bottom_half(check_queue, NULL);	} else {		c->tries++;

⌨️ 快捷键说明

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