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

📄 tcp_timer.c

📁 GNU Hurd 源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * INET		An implementation of the TCP/IP protocol suite for the LINUX *		operating system.  INET is implemented using the  BSD Socket *		interface as the means of communication with the user level. * *		Implementation of the Transmission Control Protocol(TCP). * * Version:	$Id: tcp_timer.c,v 1.62.2.4 1999/09/23 19:21:39 davem Exp $ * * Authors:	Ross Biro, <bir7@leland.Stanford.Edu> *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> *		Mark Evans, <evansmp@uhura.aston.ac.uk> *		Corey Minyard <wf-rch!minyard@relay.EU.net> *		Florian La Roche, <flla@stud.uni-sb.de> *		Charles Hedrick, <hedrick@klinzhai.rutgers.edu> *		Linus Torvalds, <torvalds@cs.helsinki.fi> *		Alan Cox, <gw4pts@gw4pts.ampr.org> *		Matthew Dillon, <dillon@apollo.west.oic.com> *		Arnt Gulbrandsen, <agulbra@nvg.unit.no> *		Jorge Cwik, <jorge@laser.satlink.net> */#include <net/tcp.h>int sysctl_tcp_syn_retries = TCP_SYN_RETRIES; int sysctl_tcp_keepalive_time = TCP_KEEPALIVE_TIME;int sysctl_tcp_keepalive_probes = TCP_KEEPALIVE_PROBES;int sysctl_tcp_retries1 = TCP_RETR1;int sysctl_tcp_retries2 = TCP_RETR2;static void tcp_sltimer_handler(unsigned long);static void tcp_syn_recv_timer(unsigned long);static void tcp_keepalive(unsigned long data);static void tcp_twkill(unsigned long);struct timer_list	tcp_slow_timer = {	NULL, NULL,	0, 0,	tcp_sltimer_handler,};struct tcp_sl_timer tcp_slt_array[TCP_SLT_MAX] = {	{ATOMIC_INIT(0), TCP_SYNACK_PERIOD, 0, tcp_syn_recv_timer},/* SYNACK	*/	{ATOMIC_INIT(0), TCP_KEEPALIVE_PERIOD, 0, tcp_keepalive},  /* KEEPALIVE	*/	{ATOMIC_INIT(0), TCP_TWKILL_PERIOD, 0, tcp_twkill}         /* TWKILL	*/};const char timer_bug_msg[] = KERN_DEBUG "tcpbug: unknown timer value\n";/* * Using different timers for retransmit, delayed acks and probes * We may wish use just one timer maintaining a list of expire jiffies  * to optimize. */void tcp_init_xmit_timers(struct sock *sk){	init_timer(&sk->tp_pinfo.af_tcp.retransmit_timer);	sk->tp_pinfo.af_tcp.retransmit_timer.function=&tcp_retransmit_timer;	sk->tp_pinfo.af_tcp.retransmit_timer.data = (unsigned long) sk;		init_timer(&sk->tp_pinfo.af_tcp.delack_timer);	sk->tp_pinfo.af_tcp.delack_timer.function=&tcp_delack_timer;	sk->tp_pinfo.af_tcp.delack_timer.data = (unsigned long) sk;	init_timer(&sk->tp_pinfo.af_tcp.probe_timer);	sk->tp_pinfo.af_tcp.probe_timer.function=&tcp_probe_timer;	sk->tp_pinfo.af_tcp.probe_timer.data = (unsigned long) sk;}/* *	Reset the retransmission timer */ void tcp_reset_xmit_timer(struct sock *sk, int what, unsigned long when){	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;	switch (what) {	case TIME_RETRANS:		/* When seting the transmit timer the probe timer 		 * should not be set.		 * The delayed ack timer can be set if we are changing the		 * retransmit timer when removing acked frames.		 */		if(tp->probe_timer.prev)			del_timer(&tp->probe_timer);		mod_timer(&tp->retransmit_timer, jiffies+when);		break;	case TIME_DACK:		mod_timer(&tp->delack_timer, jiffies+when);		break;	case TIME_PROBE0:		mod_timer(&tp->probe_timer, jiffies+when);		break;		case TIME_WRITE:		printk(KERN_DEBUG "bug: tcp_reset_xmit_timer TIME_WRITE\n");		break;	default:		printk(KERN_DEBUG "bug: unknown timer value\n");	};}void tcp_clear_xmit_timers(struct sock *sk){		struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;	if(tp->retransmit_timer.prev)		del_timer(&tp->retransmit_timer);	if(tp->delack_timer.prev)		del_timer(&tp->delack_timer);	if(tp->probe_timer.prev)		del_timer(&tp->probe_timer);}static int tcp_write_err(struct sock *sk, int force){	sk->err = sk->err_soft ? sk->err_soft : ETIMEDOUT;	sk->error_report(sk);		tcp_clear_xmit_timers(sk);		/* Time wait the socket. */	if (!force && ((1<<sk->state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING))) {		tcp_time_wait(sk);	} else {		/* Clean up time. */		tcp_set_state(sk, TCP_CLOSE);		return 0;	}	return 1;}/* A write timeout has occurred. Process the after effects. */static int tcp_write_timeout(struct sock *sk){	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);	/* Look for a 'soft' timeout. */	if ((sk->state == TCP_ESTABLISHED &&	     tp->retransmits && (tp->retransmits % TCP_QUICK_TRIES) == 0) ||	    (sk->state != TCP_ESTABLISHED && tp->retransmits > sysctl_tcp_retries1)) {		dst_negative_advice(&sk->dst_cache);	}		/* Have we tried to SYN too many times (repent repent 8)) */	if(tp->retransmits > sysctl_tcp_syn_retries && sk->state==TCP_SYN_SENT) {		tcp_write_err(sk, 1);		/* Don't FIN, we got nothing back */		return 0;	}	/* Has it gone just too far? */	if (tp->retransmits > sysctl_tcp_retries2) 		return tcp_write_err(sk, 0);	return 1;}void tcp_delack_timer(unsigned long data){	struct sock *sk = (struct sock*)data;	if(!sk->zapped &&	   sk->tp_pinfo.af_tcp.delayed_acks &&	   sk->state != TCP_CLOSE) {		/* If socket is currently locked, defer the ACK. */		if (!atomic_read(&sk->sock_readers))			tcp_send_ack(sk);		else			tcp_send_delayed_ack(&(sk->tp_pinfo.af_tcp), HZ/10);	}}void tcp_probe_timer(unsigned long data){	struct sock *sk = (struct sock*)data;	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;	if(sk->zapped) 		return;		if (atomic_read(&sk->sock_readers)) {		/* Try again later. */		tcp_reset_xmit_timer(sk, TIME_PROBE0, HZ/5);		return;	}	/* *WARNING* RFC 1122 forbids this 	 * It doesn't AFAIK, because we kill the retransmit timer -AK	 * FIXME: We ought not to do it, Solaris 2.5 actually has fixing	 * this behaviour in Solaris down as a bug fix. [AC]	 */	if (tp->probes_out > sysctl_tcp_retries2) {		if(sk->err_soft)			sk->err = sk->err_soft;		else			sk->err = ETIMEDOUT;		sk->error_report(sk);		if ((1<<sk->state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING)) {			/* Time wait the socket. */			tcp_time_wait(sk);		} else {			/* Clean up time. */			tcp_set_state(sk, TCP_CLOSE);		}	} else {		/* Only send another probe if we didn't close things up. */		tcp_send_probe0(sk);	}}static __inline__ int tcp_keepopen_proc(struct sock *sk){	int res = 0;	if ((1<<sk->state) & (TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_FIN_WAIT2)) {		struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;		__u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;		if (elapsed >= sysctl_tcp_keepalive_time) {			if (tp->probes_out > sysctl_tcp_keepalive_probes) {				if(sk->err_soft)					sk->err = sk->err_soft;				else					sk->err = ETIMEDOUT;				tcp_set_state(sk, TCP_CLOSE);				sk->shutdown = SHUTDOWN_MASK;				if (!sk->dead)					sk->state_change(sk);			} else {				tp->probes_out++;				tp->pending = TIME_KEEPOPEN;				tcp_write_wakeup(sk);				res = 1;			}		}	}	return res;}/* Kill off TIME_WAIT sockets once their lifetime has expired. */int tcp_tw_death_row_slot = 0;static struct tcp_tw_bucket *tcp_tw_death_row[TCP_TWKILL_SLOTS] =	{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };extern void tcp_timewait_kill(struct tcp_tw_bucket *tw);static void tcp_twkill(unsigned long data){	struct tcp_tw_bucket *tw;	int killed = 0;	tw = tcp_tw_death_row[tcp_tw_death_row_slot];	tcp_tw_death_row[tcp_tw_death_row_slot] = NULL;	while(tw != NULL) {		struct tcp_tw_bucket *next = tw->next_death;		tcp_timewait_kill(tw);		killed++;		tw = next;	}	if(killed != 0) {		struct tcp_sl_timer *slt = (struct tcp_sl_timer *)data;		atomic_sub(killed, &slt->count);	}	tcp_tw_death_row_slot =	  ((tcp_tw_death_row_slot + 1) & (TCP_TWKILL_SLOTS - 1));}/* These are always called from BH context.  See callers in * tcp_input.c to verify this. */void tcp_tw_schedule(struct tcp_tw_bucket *tw){	int slot = (tcp_tw_death_row_slot - 1) & (TCP_TWKILL_SLOTS - 1);	struct tcp_tw_bucket **tpp = &tcp_tw_death_row[slot];	if((tw->next_death = *tpp) != NULL)		(*tpp)->pprev_death = &tw->next_death;	*tpp = tw;	tw->pprev_death = tpp;	tw->death_slot = slot;	tcp_inc_slow_timer(TCP_SLT_TWKILL);}/* Happens rarely if at all, no care about scalability here. */void tcp_tw_reschedule(struct tcp_tw_bucket *tw){

⌨️ 快捷键说明

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