📄 sched.c
字号:
/* 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 + -