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

📄 tcp_recv.c

📁 Minix比较全的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*tcp_recv.cCopyright 1995 Philip Homburg*/#include "inet.h"#include "buf.h"#include "clock.h"#include "event.h"#include "type.h"#include "sr.h"#include "io.h"#include "tcp_int.h"#include "tcp.h"#include "assert.h"THIS_FILEFORWARD void create_RST ARGS(( tcp_conn_t *tcp_conn,	ip_hdr_t *ip_hdr, tcp_hdr_t *tcp_hdr, int data_len ));FORWARD void process_data ARGS(( tcp_conn_t *tcp_conn,	tcp_hdr_t *tcp_hdr, acc_t *tcp_data, int data_len ));FORWARD void process_advanced_data ARGS(( tcp_conn_t *tcp_conn,	tcp_hdr_t *tcp_hdr, acc_t *tcp_data, int data_len ));PUBLIC void tcp_frag2conn(tcp_conn, ip_hdr, tcp_hdr, tcp_data, data_len)tcp_conn_t *tcp_conn;ip_hdr_t *ip_hdr;tcp_hdr_t *tcp_hdr;acc_t *tcp_data;size_t data_len;{	tcp_fd_t *connuser;	int tcp_hdr_flags;	int ip_hdr_len, tcp_hdr_len;	u32_t seg_ack, seg_seq, rcv_hi, snd_una, snd_nxt;	u16_t seg_wnd, mtu;	size_t mss;	int acceptable_ACK, segm_acceptable, send_rst, close_connection;	ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;	tcp_hdr_len= (tcp_hdr->th_data_off & TH_DO_MASK) >> 2;	tcp_hdr_flags= tcp_hdr->th_flags & TH_FLAGS_MASK;	seg_ack= ntohl(tcp_hdr->th_ack_nr);	seg_seq= ntohl(tcp_hdr->th_seq_nr);	seg_wnd= ntohs(tcp_hdr->th_window);#if 0 { where(); tcp_print_conn(tcp_conn); printf("\n");	tcp_print_pack(ip_hdr, tcp_hdr); printf("\n"); }#endif	switch (tcp_conn->tc_state)	{	case TCS_CLOSED:/*CLOSED:	discard all data.	!RST ?		ACK ?			<SEQ=SEG.ACK><CTL=RST>			exit		:			<SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>			exit	:		discard packet		exit*/		if (!(tcp_hdr_flags & THF_RST))		{			create_RST(tcp_conn, ip_hdr, tcp_hdr, data_len);			tcp_conn_write(tcp_conn, 1);		}		break;	case TCS_LISTEN:/*LISTEN:	RST ?		discard packet		exit	ACK ?		<SEQ=SEG.ACK><CTL=RST>		exit	SYN ?		BUG: no security check		RCV.NXT= SEG.SEQ+1		IRS= SEG.SEQ		ISS should already be selected		<SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>		SND.NXT=ISS+1		SND.UNA=ISS		state= SYN-RECEIVED		exit	:		shouldnot occur		discard packet		exit*/		if (tcp_hdr_flags & THF_RST)			break;		if (tcp_hdr_flags & THF_ACK)		{			create_RST (tcp_conn, ip_hdr, tcp_hdr, data_len);			tcp_conn_write(tcp_conn, 1);			break;		}		if (tcp_hdr_flags & THF_SYN)		{			tcp_extract_ipopt(tcp_conn, ip_hdr);			tcp_extract_tcpopt(tcp_conn, tcp_hdr, &mss);			mtu= mss+IP_TCP_MIN_HDR_SIZE;			if (mtu < IP_MIN_MTU)			{				/* No or unrealistic mss, use default MTU */				mtu= IP_DEF_MTU;			}			if (mtu < tcp_conn->tc_max_mtu)			{				tcp_conn->tc_max_mtu= mtu;				tcp_conn->tc_mtu= mtu;				DBLOCK(1, printf(					"tcp[%d]: conn[%d]: mtu = %d\n",					tcp_conn->tc_port-tcp_port_table,					tcp_conn-tcp_conn_table, 					mtu););			}			tcp_conn->tc_RCV_LO= seg_seq+1;			tcp_conn->tc_RCV_NXT= seg_seq+1;			tcp_conn->tc_RCV_HI= tcp_conn->tc_RCV_LO+				tcp_conn->tc_rcv_wnd;			tcp_conn->tc_RCV_UP= seg_seq;			tcp_conn->tc_IRS= seg_seq;			tcp_conn->tc_SND_UNA= tcp_conn->tc_ISS;			tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS;			tcp_conn->tc_SND_NXT= tcp_conn->tc_ISS+1;			tcp_conn->tc_SND_UP= tcp_conn->tc_ISS-1;			tcp_conn->tc_SND_PSH= tcp_conn->tc_ISS-1;			tcp_conn->tc_state= TCS_SYN_RECEIVED;			tcp_conn->tc_stt= 0;			assert (tcp_check_conn(tcp_conn));			tcp_conn->tc_locaddr= ip_hdr->ih_dst;			tcp_conn->tc_locport= tcp_hdr->th_dstport;			tcp_conn->tc_remaddr= ip_hdr->ih_src;			tcp_conn->tc_remport= tcp_hdr->th_srcport;			tcp_conn_write(tcp_conn, 1);			DIFBLOCK(0x10, seg_seq == 0,				printf("warning got 0 IRS from ");				writeIpAddr(tcp_conn->tc_remaddr);				printf("\n"));			/* Start the timer (if necessary) */			tcp_set_send_timer(tcp_conn);			break;		}		/* do nothing */		break;	case TCS_SYN_SENT:/*SYN-SENT:	ACK ?		SEG.ACK <= ISS || SEG.ACK > SND.NXT ?			RST ?				discard packet				exit			:				<SEQ=SEG.ACK><CTL=RST>				exit		SND.UNA <= SEG.ACK && SEG.ACK <= SND.NXT ?			ACK is acceptable		:			ACK is !acceptable	:		ACK is !acceptable	RST ?		ACK acceptable ?			discard segment			state= CLOSED			error "connection refused"			exit		:			discard packet			exit	BUG: no security check	SYN ?		IRS= SEG.SEQ		RCV.NXT= IRS+1		ACK ?			SND.UNA= SEG.ACK		SND.UNA > ISS ?			state= ESTABLISHED			<SEQ=SND.NXT><ACK= RCV.NXT><CTL=ACK>			process ev. URG and text			exit		:			state= SYN-RECEIVED			SND.WND= SEG.WND			SND.WL1= SEG.SEQ			SND.WL2= SEG.ACK			<SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>			exit	:		discard segment		exit*/		if (tcp_hdr_flags & THF_ACK)		{			if (tcp_LEmod4G(seg_ack, tcp_conn->tc_ISS) ||				tcp_Gmod4G(seg_ack, tcp_conn->tc_SND_NXT))				if (tcp_hdr_flags & THF_RST)					break;				else				{					/* HACK: force sending a RST,					 * normally, RSTs are not send					 * if the segment is an ACK.					 */					create_RST (tcp_conn, ip_hdr,						tcp_hdr, data_len+1);					tcp_conn_write(tcp_conn, 1);					break;				}			acceptable_ACK= (tcp_LEmod4G(tcp_conn->tc_SND_UNA,				seg_ack) && tcp_LEmod4G(seg_ack,				tcp_conn->tc_SND_NXT));		}		else			acceptable_ACK= FALSE;		if (tcp_hdr_flags & THF_RST)		{			if (acceptable_ACK)			{				DBLOCK(1, printf(					"calling tcp_close_connection\n"));				tcp_close_connection(tcp_conn,					ECONNREFUSED);			}			break;		}		if (tcp_hdr_flags & THF_SYN)		{			tcp_extract_ipopt(tcp_conn, ip_hdr);			tcp_extract_tcpopt(tcp_conn, tcp_hdr, &mss);			mtu= mss+IP_TCP_MIN_HDR_SIZE;			if (mtu < IP_MIN_MTU)			{				/* No or unrealistic mss, use default MTU */				mtu= IP_DEF_MTU;			}			if (mtu < tcp_conn->tc_max_mtu)			{				tcp_conn->tc_max_mtu= mtu;				tcp_conn->tc_mtu= mtu;				DBLOCK(1, printf(					"tcp[%d]: conn[%d]: mtu = %d\n",					tcp_conn->tc_port-tcp_port_table,					tcp_conn-tcp_conn_table, 					mtu););			}			tcp_conn->tc_RCV_LO= seg_seq+1;			tcp_conn->tc_RCV_NXT= seg_seq+1;			tcp_conn->tc_RCV_HI= tcp_conn->tc_RCV_LO +				tcp_conn->tc_rcv_wnd;			tcp_conn->tc_RCV_UP= seg_seq;			tcp_conn->tc_IRS= seg_seq;			if (tcp_hdr_flags & THF_ACK)				tcp_conn->tc_SND_UNA= seg_ack;			if (tcp_Gmod4G(tcp_conn->tc_SND_UNA,				tcp_conn->tc_ISS))			{				tcp_conn->tc_state= TCS_ESTABLISHED;				tcp_conn->tc_rt_dead= TCP_DEF_RT_DEAD;				assert (tcp_check_conn(tcp_conn));				assert(tcp_conn->tc_connInprogress);				tcp_restart_connect(tcp_conn);				tcp_conn->tc_flags |= TCF_SEND_ACK;				tcp_conn_write(tcp_conn, 1);				if (data_len != 0)				{					tcp_frag2conn(tcp_conn, ip_hdr,						tcp_hdr, tcp_data, data_len);					/* tcp_data is already freed */					return;				}				break;			}			tcp_conn->tc_state= TCS_SYN_RECEIVED;			assert (tcp_check_conn(tcp_conn));			tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS;			tcp_conn_write(tcp_conn, 1);		}		break;	case TCS_SYN_RECEIVED:/*SYN-RECEIVED:	test if segment is acceptable:	Segment	Receive	Test	Length	Window	0	0	SEG.SEQ == RCV.NXT	0	>0	RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND	>0	0	not acceptable	>0	>0	(RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND)			|| (RCV.NXT <= SEG.SEQ+SEG.LEN-1 &&			SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND)	for urgent data: use RCV.WND+1 for RCV.WND	Special: Send RST if SEG.SEQ < IRS or SEG.SEQ > RCV.NXT+64K (and		 the packet is not a RST packet itself).*/		rcv_hi= tcp_conn->tc_RCV_HI;		if (tcp_hdr_flags & THF_URG)			rcv_hi++;		send_rst= tcp_Lmod4G(seg_seq, tcp_conn->tc_IRS) ||			tcp_Gmod4G(seg_seq, tcp_conn->tc_RCV_NXT+0x10000);		close_connection= 0;		if (!data_len)		{			if (rcv_hi == tcp_conn->tc_RCV_NXT)				segm_acceptable= (seg_seq == rcv_hi);			else			{				assert (tcp_Gmod4G(rcv_hi,					tcp_conn->tc_RCV_NXT));				segm_acceptable= (tcp_LEmod4G(tcp_conn->					tc_RCV_NXT, seg_seq) &&					tcp_Lmod4G(seg_seq, rcv_hi));			}		}		else		{			if (tcp_Gmod4G(rcv_hi, tcp_conn->tc_RCV_NXT))			{				segm_acceptable= (tcp_LEmod4G(tcp_conn->					tc_RCV_NXT, seg_seq) &&					tcp_Lmod4G(seg_seq, rcv_hi)) ||					(tcp_LEmod4G(tcp_conn->tc_RCV_NXT,					seg_seq+data_len-1) &&					tcp_Lmod4G(seg_seq+data_len-1,					rcv_hi));			}			else			{				segm_acceptable= FALSE;			}		}/*	!segment acceptable ?		RST ?			discard packet			exit		:			<SEG=SND.NXT><ACK=RCV.NXT><CTL=ACK>			exit*/		if (!segm_acceptable)		{			if (tcp_hdr_flags & THF_RST)				; /* do nothing */			else if (send_rst)			{				create_RST(tcp_conn, ip_hdr, tcp_hdr,					data_len);				tcp_conn_write(tcp_conn, 1);			}			else			{				tcp_conn->tc_flags |= TCF_SEND_ACK;				tcp_conn_write(tcp_conn, 1);			}			break;		}/*	RST ?		initiated by a LISTEN ?			state= LISTEN			exit		:			state= CLOSED			error "connection refused"			exit*/		if (tcp_hdr_flags & THF_RST)			close_connection= 1;/*	SYN in window ?		initiated by a LISTEN ?			state= LISTEN			exit		:			state= CLOSED			error "connection reset"			exit*/		if ((tcp_hdr_flags & THF_SYN) && tcp_GEmod4G(seg_seq,			tcp_conn->tc_RCV_NXT))		{			close_connection= 1;		}		if (close_connection)		{			if (!tcp_conn->tc_orglisten)			{				tcp_close_connection(tcp_conn, ECONNREFUSED);				break;			}			connuser= tcp_conn->tc_fd;			assert(connuser);			if (connuser->tf_flags & TFF_LISTENQ)			{				tcp_close_connection (tcp_conn,					ECONNREFUSED);			}			else			{				tcp_conn->tc_connInprogress= 0;				tcp_conn->tc_fd= NULL;				tcp_close_connection (tcp_conn,					ECONNREFUSED);				/* Pick a new ISS next time */				tcp_conn->tc_ISS= 0;				(void)tcp_su4listen(connuser, tcp_conn,					0 /* !do_listenq */);			}			break;		}/*	!ACK ?		discard packet		exit*/		if (!(tcp_hdr_flags & THF_ACK))			break;/*	SND.UNA < SEG.ACK <= SND.NXT ?		state= ESTABLISHED	:		<SEG=SEG.ACK><CTL=RST>		exit*/		if (tcp_Lmod4G(tcp_conn->tc_SND_UNA, seg_ack) &&			tcp_LEmod4G(seg_ack, tcp_conn->tc_SND_NXT))		{			tcp_conn->tc_state= TCS_ESTABLISHED;			tcp_conn->tc_rt_dead= TCP_DEF_RT_DEAD;			tcp_release_retrans(tcp_conn, seg_ack, seg_wnd);			assert (tcp_check_conn(tcp_conn));			assert(tcp_conn->tc_connInprogress);			tcp_restart_connect(tcp_conn);			tcp_frag2conn(tcp_conn, ip_hdr, tcp_hdr, tcp_data,				data_len);			/* tcp_data is already freed */			return;		}		else		{			create_RST (tcp_conn, ip_hdr, tcp_hdr, data_len);			tcp_conn_write(tcp_conn, 1);			break;		}		break;	case TCS_ESTABLISHED:	case TCS_CLOSING:/*ESTABLISHED:FIN-WAIT-1:FIN-WAIT-2:CLOSE-WAIT:CLOSING:LAST-ACK:

⌨️ 快捷键说明

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