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

📄 tcp_send.c

📁 minix3的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*tcp_send.cCopyright 1995 Philip Homburg*/#include "inet.h"#include "buf.h"#include "clock.h"#include "event.h"#include "type.h"#include "sr.h"#include "assert.h"#include "io.h"#include "ip.h"#include "tcp.h"#include "tcp_int.h"THIS_FILEFORWARD acc_t *make_pack ARGS(( tcp_conn_t *tcp_conn ));FORWARD void tcp_send_timeout ARGS(( int conn, struct timer *timer ));FORWARD void do_snd_event ARGS(( event_t *ev, ev_arg_t arg ));PUBLIC void tcp_conn_write (tcp_conn, enq)tcp_conn_t *tcp_conn;int enq;				/* Writes need to be enqueued. */{	tcp_port_t *tcp_port;	ev_arg_t snd_arg;	assert (tcp_conn->tc_flags & TCF_INUSE);	tcp_port= tcp_conn->tc_port;	if (tcp_conn->tc_flags & TCF_MORE2WRITE)		return;	/* Do we really have something to send here? */	if (tcp_conn->tc_SND_UNA == tcp_conn->tc_SND_NXT &&		!(tcp_conn->tc_flags & TCF_SEND_ACK) &&		!tcp_conn->tc_frag2send)	{		return;	}	tcp_conn->tc_flags |= TCF_MORE2WRITE;	tcp_conn->tc_send_link= NULL;	if (!tcp_port->tp_snd_head)	{		tcp_port->tp_snd_head= tcp_conn;		tcp_port->tp_snd_tail= tcp_conn;		if (enq)		{			snd_arg.ev_ptr= tcp_port;			if (!ev_in_queue(&tcp_port->tp_snd_event))			{				ev_enqueue(&tcp_port->tp_snd_event,					do_snd_event, snd_arg);			}		}		else			tcp_port_write(tcp_port);	}	else	{		tcp_port->tp_snd_tail->tc_send_link= tcp_conn;		tcp_port->tp_snd_tail= tcp_conn;	}}PRIVATE void do_snd_event(ev, arg)event_t *ev;ev_arg_t arg;{	tcp_port_t *tcp_port;	tcp_port= arg.ev_ptr;	assert(ev == &tcp_port->tp_snd_event);	tcp_port_write(tcp_port);}PUBLIC void tcp_port_write(tcp_port)tcp_port_t *tcp_port;{	tcp_conn_t *tcp_conn;	acc_t *pack2write;	int r;	assert (!(tcp_port->tp_flags & TPF_WRITE_IP));	while(tcp_port->tp_snd_head)	{		tcp_conn= tcp_port->tp_snd_head;		assert(tcp_conn->tc_flags & TCF_MORE2WRITE);		for(;;)		{			if (tcp_conn->tc_frag2send)			{				pack2write= tcp_conn->tc_frag2send;				tcp_conn->tc_frag2send= 0;			}			else			{				tcp_conn->tc_busy++;				pack2write= make_pack(tcp_conn);				tcp_conn->tc_busy--;				if (!pack2write)					break;			}			r= ip_send(tcp_port->tp_ipfd, pack2write,				bf_bufsize(pack2write));			if (r != NW_OK)			{				if (r == NW_WOULDBLOCK)					break;				if (r == EPACKSIZE)				{					tcp_mtu_exceeded(tcp_conn);					continue;				}				if (r == EDSTNOTRCH)				{					tcp_notreach(tcp_conn);					continue;				}				if (r == EBADDEST)					continue;			}			assert(r == NW_OK ||				(printf("ip_send failed, error %d\n", r),0));		}		if (pack2write)		{			tcp_port->tp_flags |= TPF_WRITE_IP;			tcp_port->tp_pack= pack2write;			r= ip_write (tcp_port->tp_ipfd,				bf_bufsize(pack2write));			if (r == NW_SUSPEND)			{				tcp_port->tp_flags |= TPF_WRITE_SP;				return;			}			assert(r == NW_OK);			tcp_port->tp_flags &= ~TPF_WRITE_IP;			assert(!(tcp_port->tp_flags &				(TPF_WRITE_IP|TPF_WRITE_SP)));			continue;		}		tcp_conn->tc_flags &= ~TCF_MORE2WRITE;		tcp_port->tp_snd_head= tcp_conn->tc_send_link;	}}PRIVATE acc_t *make_pack(tcp_conn)tcp_conn_t *tcp_conn;{	acc_t *pack2write, *tmp_pack, *tcp_pack;	tcp_hdr_t *tcp_hdr;	ip_hdr_t *ip_hdr;	int tot_hdr_size, ip_hdr_len, no_push, head, more2write;	u32_t seg_seq, seg_lo_data, queue_lo_data, seg_hi, seg_hi_data;	u16_t seg_up, mss;	u8_t seg_flags;	size_t pack_size;	clock_t curr_time, new_dis;	u8_t *optptr;	mss= tcp_conn->tc_mtu-IP_TCP_MIN_HDR_SIZE;	assert(tcp_conn->tc_busy);	curr_time= get_time();	switch (tcp_conn->tc_state)	{	case TCS_CLOSED:	case TCS_LISTEN:		return NULL;	case TCS_SYN_RECEIVED:	case TCS_SYN_SENT:		if (tcp_conn->tc_SND_TRM == tcp_conn->tc_SND_NXT &&			!(tcp_conn->tc_flags & TCF_SEND_ACK))		{			return 0;		}		tcp_conn->tc_flags &= ~TCF_SEND_ACK;		/* Advertise a mss based on the port mtu. The current mtu may		 * be lower if the other side sends a smaller mss.		 */		mss= tcp_conn->tc_port->tp_mtu-IP_TCP_MIN_HDR_SIZE;		/* Include a max segment size option. */		assert(tcp_conn->tc_tcpopt == NULL);		tcp_conn->tc_tcpopt= bf_memreq(4);		optptr= (u8_t *)ptr2acc_data(tcp_conn->tc_tcpopt);		optptr[0]= TCP_OPT_MSS;		optptr[1]= 4;		optptr[2]= mss >> 8;		optptr[3]= mss & 0xFF;		pack2write= tcp_make_header(tcp_conn, &ip_hdr, &tcp_hdr, 			(acc_t *)0);		bf_afree(tcp_conn->tc_tcpopt);		tcp_conn->tc_tcpopt= NULL;		if (!pack2write)		{			DBLOCK(1, printf("connection closed while inuse\n"));			return 0;		}		tot_hdr_size= bf_bufsize(pack2write);		seg_seq= tcp_conn->tc_SND_TRM;		if (tcp_conn->tc_state == TCS_SYN_SENT)			seg_flags= 0;		else			seg_flags= THF_ACK;	/* except for TCS_SYN_SENT						 * ack is always present */		if (seg_seq == tcp_conn->tc_ISS)		{			assert(tcp_conn->tc_transmit_timer.tim_active ||				(tcp_print_conn(tcp_conn), printf("\n"), 0));			seg_flags |= THF_SYN;			tcp_conn->tc_SND_TRM++;		}		tcp_hdr->th_seq_nr= htonl(seg_seq);		tcp_hdr->th_ack_nr= htonl(tcp_conn->tc_RCV_NXT);		tcp_hdr->th_flags= seg_flags;		tcp_hdr->th_window= htons(mss);			/* Initially we allow one segment */		ip_hdr->ih_length= htons(tot_hdr_size);		pack2write->acc_linkC++;		ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;		tcp_pack= bf_delhead(pack2write, ip_hdr_len);		tcp_hdr->th_chksum= ~tcp_pack_oneCsum(ip_hdr, tcp_pack);		bf_afree(tcp_pack);		new_dis= curr_time + 2*HZ*tcp_conn->tc_ttl;		if (new_dis > tcp_conn->tc_senddis)			tcp_conn->tc_senddis= new_dis;		return pack2write;	case TCS_ESTABLISHED:	case TCS_CLOSING:		seg_seq= tcp_conn->tc_SND_TRM;		seg_flags= 0;		pack2write= 0;		seg_up= 0;		if (tcp_conn->tc_flags & TCF_SEND_ACK)		{			seg_flags= THF_ACK;			tcp_conn->tc_flags &= ~TCF_SEND_ACK;			pack2write= tcp_make_header (tcp_conn, &ip_hdr, 				&tcp_hdr, (acc_t *)0);			if (!pack2write)			{				return NULL;			}		}		if (tcp_conn->tc_SND_UNA != tcp_conn->tc_SND_NXT)		{			assert(tcp_LEmod4G(seg_seq, tcp_conn->tc_SND_NXT));			if (seg_seq == tcp_conn->tc_snd_cwnd)			{				DBLOCK(2,					printf("no data: window is closed\n"));				goto after_data;			}			/* Assert that our SYN has been ACKed. */			assert(tcp_conn->tc_SND_UNA != tcp_conn->tc_ISS);			seg_lo_data= seg_seq;			queue_lo_data= tcp_conn->tc_SND_UNA;			seg_hi= tcp_conn->tc_SND_NXT;			seg_hi_data= seg_hi;			if (tcp_conn->tc_flags & TCF_FIN_SENT)			{				if (seg_seq != seg_hi)					seg_flags |= THF_FIN;				if (queue_lo_data == seg_hi_data)					queue_lo_data--;				if (seg_lo_data == seg_hi_data)					seg_lo_data--;				seg_hi_data--;			}			if (!pack2write)			{				pack2write= tcp_make_header (tcp_conn,					&ip_hdr, &tcp_hdr, (acc_t *)0);				if (!pack2write)				{					return NULL;				}			}			tot_hdr_size= bf_bufsize(pack2write);			no_push= (tcp_LEmod4G(tcp_conn->tc_SND_PSH, seg_seq));			head= (seg_seq == tcp_conn->tc_SND_UNA);			if (no_push)			{				/* Shutdown sets SND_PSH */				seg_flags &= ~THF_FIN;				if (seg_hi_data-seg_lo_data <= 1)				{					/* Allways keep at least one byte					 * for a future push.					 */					DBLOCK(0x20,					    printf("no data: no push\n"));					if (head)					{						DBLOCK(0x1, printf(					"no data: setting TCF_NO_PUSH\n"));						tcp_conn->tc_flags |=							TCF_NO_PUSH;					}					goto after_data;				}				seg_hi_data--;			}			if (tot_hdr_size != IP_TCP_MIN_HDR_SIZE)			{				printf(				"tcp_write`make_pack: tot_hdr_size = %d\n",					tot_hdr_size);				mss= tcp_conn->tc_mtu-tot_hdr_size;			}			if (seg_hi_data - seg_lo_data > mss)			{				/* Truncate to at most one segment */				seg_hi_data= seg_lo_data + mss;				seg_hi= seg_hi_data;				seg_flags &= ~THF_FIN;			}			if (no_push &&				seg_hi_data-seg_lo_data != mss)			{				DBLOCK(0x20, printf(				"no data: no push for partial segment\n"));				more2write= (tcp_conn->tc_fd &&					(tcp_conn->tc_fd->tf_flags &					TFF_WRITE_IP));				DIFBLOCK(2, more2write, 					printf(			"tcp_send`make_pack: more2write -> !TCF_NO_PUSH\n");				);				if (head && !more2write)				{					DBLOCK(0x1, printf(				"partial segment: setting TCF_NO_PUSH\n"));					tcp_conn->tc_flags |= TCF_NO_PUSH;					tcp_print_conn(tcp_conn);					printf("\n");				}				goto after_data;			}			if (tcp_Gmod4G(seg_hi, tcp_conn->tc_snd_cwnd))			{				seg_hi_data= tcp_conn->tc_snd_cwnd;				seg_hi= seg_hi_data;				seg_flags &= ~THF_FIN;			}			if (!head &&				seg_hi_data-seg_lo_data < mss)			{				if (tcp_conn->tc_flags & TCF_PUSH_NOW)				{					DBLOCK(0x20,					printf("push: no Nagle\n"));				}				else				{				DBLOCK(0x20,					printf("no data: partial packet\n"));				seg_flags &= ~THF_FIN;				goto after_data;				}			}			if (seg_hi-seg_seq == 0)			{				DBLOCK(0x20,				printf("no data: no data available\n"));				goto after_data;			}			if (tcp_GEmod4G(tcp_conn->tc_SND_UP, seg_lo_data))			{				extern int killer_inet;				if (tcp_GEmod4G(tcp_conn->tc_SND_UP,					seg_hi_data))				{					seg_up= seg_hi_data-seg_seq;				}				else				{					seg_up= tcp_conn->tc_SND_UP-seg_seq;				}				seg_flags |= THF_URG;				if (!killer_inet &&					(tcp_conn->tc_flags & TCF_BSD_URG) &&					seg_up == 0)				{					/* A zero urgent pointer doesn't mean					 * anything when BSD semantics are					 * used (urgent pointer points to the					 * first no urgent byte). The use of					 * a zero urgent pointer also crashes					 * a Solaris 2.3 kernel. If urgent					 * pointer doesn't have BSD semantics					 * then an urgent pointer of zero					 * simply indicates that there is one					 * urgent byte.					 */					seg_flags &= ~THF_URG;				}			}			else				seg_up= 0;			if (tcp_Gmod4G(tcp_conn->tc_SND_PSH, seg_lo_data) &&				tcp_LEmod4G(tcp_conn->tc_SND_PSH, seg_hi_data))			{				seg_flags |= THF_PSH;			}			tcp_conn->tc_SND_TRM= seg_hi;			assert(tcp_conn->tc_transmit_timer.tim_active ||				(tcp_print_conn(tcp_conn), printf("\n"), 0));			if (tcp_conn->tc_rt_seq == 0 && 				tcp_Gmod4G(seg_seq, tcp_conn->tc_rt_threshold))			{				tcp_conn->tc_rt_time= curr_time;				tcp_conn->tc_rt_seq=					tcp_conn->tc_rt_threshold= seg_seq;			}			if (seg_hi_data-seg_lo_data)			{#if DEBUG & 0				assert(tcp_check_conn(tcp_conn));				assert((seg_hi_data-queue_lo_data <=					bf_bufsize(tcp_conn->tc_send_data) &&					seg_lo_data-queue_lo_data <=					bf_bufsize(tcp_conn->tc_send_data) &&					seg_hi_data>seg_lo_data)||					(tcp_print_conn(tcp_conn),					printf(		" seg_hi_data= 0x%x, seg_lo_data= 0x%x, queue_lo_data= 0x%x\n",					seg_hi_data, seg_lo_data,					queue_lo_data), 0));#endif				tmp_pack= pack2write;				while (tmp_pack->acc_next)					tmp_pack= tmp_pack->acc_next;

⌨️ 快捷键说明

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