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

📄 tcp_recv.c

📁 minix3的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
TIME-WAIT:	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*/		rcv_hi= tcp_conn->tc_RCV_HI;		if (tcp_hdr_flags & THF_URG)			rcv_hi++;		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))			{				DBLOCK(0x20,					printf("segment is not acceptable\n");					printf("\t");					tcp_print_pack(ip_hdr, tcp_hdr);					printf("\n\t");					tcp_print_conn(tcp_conn);					printf("\n"));				tcp_conn->tc_flags |= TCF_SEND_ACK;				tcp_conn_write(tcp_conn, 1);				/* Sometimes, a retransmission sets the PSH				 * flag (Solaris 2.4)				 */				if (tcp_conn->tc_rcvd_data != NULL &&					(tcp_hdr_flags & THF_PSH))				{					tcp_conn->tc_flags |= TCF_RCV_PUSH;					if (tcp_conn->tc_fd &&						(tcp_conn->tc_fd->tf_flags &						TFF_READ_IP))					{						tcp_fd_read(tcp_conn, 1);					}					if (tcp_conn->tc_fd &&						(tcp_conn->tc_fd->tf_flags &						TFF_SEL_READ))					{						tcp_rsel_read(tcp_conn);					}				}			}			break;		}/*	RST ?		state == CLOSING || state == LAST-ACK ||			state == TIME-WAIT ?			state= CLOSED			exit		:			state= CLOSED			error "connection reset"			exit*/		if (tcp_hdr_flags & THF_RST)		{			if ((tcp_conn->tc_flags &				(TCF_FIN_SENT|TCF_FIN_RECV)) ==				(TCF_FIN_SENT|TCF_FIN_RECV) &&				tcp_conn->tc_send_data == NULL)			{				/* Clean shutdown, but the other side				 * doesn't want to ACK our FIN.				 */				tcp_close_connection (tcp_conn, 0);			}			else				tcp_close_connection(tcp_conn, ECONNRESET);			break;		}/*	SYN in window ?		state= CLOSED		error "connection reset"		exit*/		if ((tcp_hdr_flags & THF_SYN) && tcp_GEmod4G(seg_seq,			tcp_conn->tc_RCV_NXT))		{			tcp_close_connection(tcp_conn, ECONNRESET);			break;		}/*	!ACK ?		discard packet		exit*/		if (!(tcp_hdr_flags & THF_ACK))			break;/*	SND.UNA < SEG.ACK <= SND.NXT ?		SND.UNA= SEG.ACK		reply "send ok"		SND.WL1 < SEG.SEQ || (SND.WL1 == SEG.SEQ &&			SND.WL2 <= SEG.ACK ?			SND.WND= SEG.WND			SND.Wl1= SEG.SEQ			SND.WL2= SEG.ACK	SEG.ACK <= SND.UNA ?		ignore ACK	SEG.ACK > SND.NXT ?		<SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>		discard packet		exit*/		/* Always reset the send timer after a valid ack is		 * received. The assumption is that either the ack really		 * acknowledges some data (normal case), contains a zero		 * window, or the remote host has another reason not		 * to accept any data. In all cases, the remote host is		 * alive, so the connection should stay alive too.		 * Do not reset stt if the state is CLOSING, i.e. if		 * the user closed the connection and we still have		 * some data to deliver. We don't want a zero window		 * to keep us from closing the connection.		 */		if (tcp_conn->tc_state != TCS_CLOSING)			tcp_conn->tc_stt= 0;		snd_una= tcp_conn->tc_SND_UNA;		snd_nxt= tcp_conn->tc_SND_NXT;		if (seg_ack == snd_una)		{						if (tcp_Gmod4G(snd_nxt, snd_una))			{				/* Duplicate ACK */				if (++tcp_conn->tc_snd_dack ==					TCP_DACK_RETRANS)				{					tcp_fast_retrans(tcp_conn);				}			}			/* This ACK doesn't acknowledge any new data, this			 * is a likely situation if we are only receiving			 * data. We only update the window if we are			 * actually sending or if we currently have a			 * zero window.			 */			if (tcp_conn->tc_snd_cwnd == snd_una &&				seg_wnd != 0)			{				DBLOCK(2, printf("zero window opened\n"));				/* The other side opened up its receive				 * window. */				mss= tcp_conn->tc_mtu-IP_TCP_MIN_HDR_SIZE;				if (seg_wnd > 2*mss)					seg_wnd= 2*mss;				tcp_conn->tc_snd_cwnd= snd_una+seg_wnd;				tcp_conn_write(tcp_conn, 1);			}			if (seg_wnd == 0)			{				tcp_conn->tc_snd_cwnd= tcp_conn->tc_SND_TRM=					snd_una;			}		}		else if (tcp_Lmod4G(snd_una, seg_ack) &&			tcp_LEmod4G(seg_ack, snd_nxt))		{			tcp_release_retrans(tcp_conn, seg_ack, seg_wnd);			if (tcp_conn->tc_state == TCS_CLOSED)				break;		}		else if (tcp_Gmod4G(seg_ack,			snd_nxt))		{			tcp_conn->tc_flags |= TCF_SEND_ACK;			tcp_conn_write(tcp_conn, 1);			DBLOCK(1, printf(			"got an ack of something I haven't send\n");				printf( "seg_ack= %lu, SND_NXT= %lu\n",				seg_ack, snd_nxt));			break;		}/*	process data...*/		tcp_extract_ipopt(tcp_conn, ip_hdr);		tcp_extract_tcpopt(tcp_conn, tcp_hdr, &mss);		if (data_len)		{			if (tcp_LEmod4G(seg_seq, tcp_conn->tc_RCV_NXT))			{				process_data (tcp_conn, tcp_hdr,					tcp_data, data_len);			}			else			{				process_advanced_data (tcp_conn,					tcp_hdr, tcp_data, data_len);			}			tcp_conn->tc_flags |= TCF_SEND_ACK;			tcp_conn_write(tcp_conn, 1);			/* Don't process a FIN if we got new data */			break;		}/*	FIN ?		reply pending receives		advace RCV.NXT over the FIN		<SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>		state == ESTABLISHED ?			state= CLOSE-WAIT		state == FIN-WAIT-1 ?			state= CLOSING		state == FIN-WAIT-2 ?			state= TIME-WAIT		state == TIME-WAIT ?			restart the TIME-WAIT timer	exit*/		if ((tcp_hdr_flags & THF_FIN) && tcp_LEmod4G(seg_seq,			tcp_conn->tc_RCV_NXT))		{			if (!(tcp_conn->tc_flags & TCF_FIN_RECV) &&				tcp_Lmod4G(tcp_conn->tc_RCV_NXT,				tcp_conn->tc_RCV_HI))			{				tcp_conn->tc_RCV_NXT++;				tcp_conn->tc_flags |= TCF_FIN_RECV;			}			tcp_conn->tc_flags |= TCF_SEND_ACK;			tcp_conn_write(tcp_conn, 1);			if (tcp_conn->tc_fd &&				(tcp_conn->tc_fd->tf_flags & TFF_READ_IP))			{				tcp_fd_read(tcp_conn, 1);			}			if (tcp_conn->tc_fd &&				(tcp_conn->tc_fd->tf_flags & TFF_SEL_READ))			{				tcp_rsel_read(tcp_conn);			}		}		break;	default:		printf("tcp_frag2conn: unknown state ");		tcp_print_state(tcp_conn);		break;	}	if (tcp_data != NULL)		bf_afree(tcp_data);}PRIVATE voidprocess_data(tcp_conn, tcp_hdr, tcp_data, data_len)tcp_conn_t *tcp_conn;tcp_hdr_t *tcp_hdr;acc_t *tcp_data;int data_len;{	u32_t lo_seq, hi_seq, urg_seq, seq_nr, adv_seq, nxt;	u32_t urgptr;	int tcp_hdr_flags;	unsigned int offset;	acc_t *tmp_data, *rcvd_data, *adv_data;	int len_diff;	assert(tcp_conn->tc_busy);	/* Note, tcp_data will be freed by the caller. */	assert (!(tcp_hdr->th_flags & THF_SYN));	seq_nr= ntohl(tcp_hdr->th_seq_nr);	urgptr= ntohs(tcp_hdr->th_urgptr);	tcp_data->acc_linkC++;	lo_seq= seq_nr;	tcp_hdr_flags= tcp_hdr->th_flags & TH_FLAGS_MASK;	if (tcp_Lmod4G(lo_seq, tcp_conn->tc_RCV_NXT))	{		DBLOCK(0x10,			printf("segment is a retransmission\n"));		offset= tcp_conn->tc_RCV_NXT-lo_seq;		tcp_data= bf_delhead(tcp_data, offset);		lo_seq += offset;		data_len -= offset;		if (tcp_hdr_flags & THF_URG)		{			printf("process_data: updating urgent pointer\n");			if (urgptr >= offset)				urgptr -= offset;			else				tcp_hdr_flags &= ~THF_URG;		}	}	assert (lo_seq == tcp_conn->tc_RCV_NXT);	if (tcp_hdr_flags & THF_URG)	{		if (!(tcp_conn->tc_flags & TCF_BSD_URG))		{			/* Update urgent pointer to point past the urgent			 * data			 */			urgptr++;		}		if (urgptr == 0)			tcp_hdr_flags &= ~THF_URG;	}	if (tcp_hdr_flags & THF_URG)	{		if (urgptr > data_len)			urgptr= data_len;		urg_seq= lo_seq+urgptr;		if (tcp_GEmod4G(urg_seq, tcp_conn->tc_RCV_HI))			urg_seq= tcp_conn->tc_RCV_HI;		if (tcp_conn->tc_flags & TCF_BSD_URG)		{			if (tcp_Gmod4G(tcp_conn->tc_RCV_NXT,				tcp_conn->tc_RCV_LO))			{				DBLOCK(1, printf(					"ignoring urgent data\n"));				bf_afree(tcp_data);				/* Should set advertised window to				 * zero */				/* Flush */				tcp_conn->tc_flags |= TCF_RCV_PUSH;				if (tcp_conn->tc_fd &&					(tcp_conn->tc_fd->tf_flags &					TFF_READ_IP))				{					tcp_fd_read(tcp_conn, 1);				}				if (tcp_conn->tc_fd &&					(tcp_conn->tc_fd->tf_flags &					TFF_SEL_READ))				{					tcp_rsel_read(tcp_conn);				}				return;			}		}		if (tcp_Gmod4G(urg_seq, tcp_conn->tc_RCV_UP))			tcp_conn->tc_RCV_UP= urg_seq;#if 0		if (urgptr < data_len)		{			data_len= urgptr;			tmp_data= bf_cut(tcp_data, 0, data_len);			bf_afree(tcp_data);			tcp_data= tmp_data;			tcp_hdr_flags &= ~THF_FIN;		}#endif		tcp_conn->tc_flags |= TCF_RCV_PUSH;	}	else	{		/* Normal data. */	}	if (tcp_hdr_flags & THF_PSH)	{		tcp_conn->tc_flags |= TCF_RCV_PUSH;	}	hi_seq= lo_seq+data_len;	if (tcp_Gmod4G(hi_seq, tcp_conn->tc_RCV_HI))	{		data_len= tcp_conn->tc_RCV_HI-lo_seq;		tmp_data= bf_cut(tcp_data, 0, data_len);		bf_afree(tcp_data);		tcp_data= tmp_data;		hi_seq= lo_seq+data_len;		tcp_hdr_flags &= ~THF_FIN;	}	assert (tcp_LEmod4G (hi_seq, tcp_conn->tc_RCV_HI));	rcvd_data= tcp_conn->tc_rcvd_data;	tcp_conn->tc_rcvd_data= 0;	tmp_data= bf_append(rcvd_data, tcp_data);	tcp_conn->tc_rcvd_data= tmp_data;	tcp_conn->tc_RCV_NXT= hi_seq;	if ((tcp_hdr_flags & THF_FIN) && 		tcp_Lmod4G(tcp_conn->tc_RCV_NXT, tcp_conn->tc_RCV_HI) &&		!(tcp_conn->tc_flags & TCF_FIN_RECV))	{		tcp_conn->tc_RCV_NXT++;		tcp_conn->tc_flags |= TCF_FIN_RECV;	}	if (tcp_conn->tc_fd && (tcp_conn->tc_fd->tf_flags & TFF_READ_IP))		tcp_fd_read(tcp_conn, 1);	if (tcp_conn->tc_fd && (tcp_conn->tc_fd->tf_flags & TFF_SEL_READ))		tcp_rsel_read(tcp_conn);	DIFBLOCK(2, (tcp_conn->tc_RCV_NXT == tcp_conn->tc_RCV_HI),		printf("conn[[%d] full receive buffer\n", 		tcp_conn-tcp_conn_table));	if (tcp_conn->tc_adv_data == NULL)		return;	if (tcp_hdr_flags & THF_FIN)	{		printf("conn[%d]: advanced data after FIN\n",			tcp_conn-tcp_conn_table);		tcp_data= tcp_conn->tc_adv_data;		tcp_conn->tc_adv_data= NULL;		bf_afree(tcp_data);		return;	}	lo_seq= tcp_conn->tc_adv_seq;	if (tcp_Gmod4G(lo_seq, tcp_conn->tc_RCV_NXT))		return;		/* Not yet */	tcp_data= tcp_conn->tc_adv_data;	tcp_conn->tc_adv_data= NULL;	data_len= bf_bufsize(tcp_data);	if (tcp_Lmod4G(lo_seq, tcp_conn->tc_RCV_NXT))	{		offset= tcp_conn->tc_RCV_NXT-lo_seq;		if (offset >= data_len)		{			bf_afree(tcp_data);			return;		}		tcp_data= bf_delhead(tcp_data, offset);		lo_seq += offset;		data_len -= offset;	}	assert (lo_seq == tcp_conn->tc_RCV_NXT);	hi_seq= lo_seq+data_len;	assert (tcp_LEmod4G (hi_seq, tcp_conn->tc_RCV_HI));	rcvd_data= tcp_conn->tc_rcvd_data;	tcp_conn->tc_rcvd_data= 0;	tmp_data= bf_append(rcvd_data, tcp_data);

⌨️ 快捷键说明

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