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

📄 tcp_output.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 2 页
字号:
		tcp_setpersist(tp);	}	/*	 * No reason to send a segment, just return.	 */	return (0);send:	/*	 * Grab a header mbuf, attaching a copy of data to	 * be transmitted, and initialize the header from	 * the template for sends on this connection.	 */	MGET(m, M_DONTWAIT, MT_DATA);	if (m == NULL)		return (ENOBUFS);	m->m_off = MMAXOFF - sizeof (struct tcpiphdr);	m->m_len = sizeof (struct tcpiphdr);	if (len) {		if (tp->t_force && len == 1) {			TCPSTAT(tcps_sndprobe++);		}		else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) {			TCPSTAT(tcps_sndrexmitpack++);			TCPSTAT(tcps_sndrexmitbyte += len);		} else {			TCPSTAT(tcps_sndpack++);			TCPSTAT(tcps_sndbyte += len);		}		m->m_next = m_copy(so->so_snd.sb_mb, off, len);		if (m->m_next == 0)			len = 0;	} else if (tp->t_flags & TF_ACKNOW) {		TCPSTAT(tcps_sndacks++);	}	else if (flags & (TH_SYN|TH_FIN|TH_RST)) {		TCPSTAT(tcps_sndctrl++);		if (flags & TH_RST) {			TCPSTAT(tcps_sndrst++);		}	}	else if (SEQ_GT(tp->snd_up, tp->snd_una)) {		TCPSTAT(tcps_sndurg++);	}	else {		TCPSTAT(tcps_sndwinup++);	}	ti = mtod(m, struct tcpiphdr *);	if (tp->t_template == 0)		panic("tcp_output");	bcopy((caddr_t)tp->t_template, (caddr_t)ti, sizeof (struct tcpiphdr));	/*	 * Fill in fields, remembering maximum advertised	 * window for use in delaying messages about window sizes.	 * If resending a FIN, be sure not to use a new sequence number.	 */	if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && 	    tp->snd_nxt == tp->snd_max)		    tp->snd_nxt--;	ti->ti_seq = htonl(tp->snd_nxt);	ti->ti_ack = htonl(tp->rcv_nxt);	/*	 * Before ESTABLISHED, force sending of initial options	 * unless TCP set to not do any options.	 */	opt = NULL;	if (flags & TH_SYN && (tp->t_flags & TF_NOOPT) == 0) {		u_short mss;		mss = MIN(so->so_rcv.sb_hiwat / 2, tcp_mss(tp));		if (mss > IP_MSS - sizeof(struct tcpiphdr)) {			opt = tcp_initopt;			optlen = sizeof (tcp_initopt);			*(u_short *)(opt + 2) = htons(mss);		}	}	if (opt) {		m0 = m->m_next;		m->m_next = m_get(M_DONTWAIT, MT_DATA);		if (m->m_next == 0) {			(void) m_free(m);			m_freem(m0);			return (ENOBUFS);		}		m->m_next->m_next = m0;		m0 = m->m_next;		m0->m_len = optlen;		bcopy((caddr_t)opt, mtod(m0, caddr_t), optlen);		opt = (u_char *)(mtod(m0, caddr_t) + optlen);		while (m0->m_len & 0x3) {			*opt++ = TCPOPT_EOL;			m0->m_len++;		}		optlen = m0->m_len;		ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2;	}	ti->ti_flags = flags;	/*	 * Calculate receive window. Don't shrink window,	 * but avoid silly window syndrome.	 */	if (win < so->so_rcv.sb_hiwat / 4 && win < tp->t_maxseg)			win = 0;	if (win < (int)(tp->rcv_adv - tp->rcv_nxt))		win = (int)(tp->rcv_adv - tp->rcv_nxt);		ti->ti_win = htons((u_short)win);	if (SEQ_GT(tp->snd_up, tp->snd_nxt)) {		ti->ti_urp = htons((u_short)(tp->snd_up - tp->snd_nxt));		ti->ti_flags |= TH_URG;	} else		/*		 * If no urgent pointer to send, then we pull		 * the urgent pointer to the left edge of the send window		 * so that it doesn't drift into the send window on sequence		 * number wraparound.		 */		tp->snd_up = tp->snd_una;		/* drag it along */	/*	 * If anything to send and we can send it all, set PUSH.	 * (This will keep happy those implementations which only	 * give data to the user when a buffer fills or a PUSH comes in.)	 */	if (len && off+len == so->so_snd.sb_cc)		ti->ti_flags |= TH_PUSH;	/*	 * Put TCP length in extended header, and then	 * checksum extended header and data.	 */	if (len + optlen)		ti->ti_len = htons((u_short)(sizeof(struct tcphdr) + 			optlen + len));#ifdef TCPLOOPBACK	/* Don't checksum if we are staying on this machine */	if (!loopback)#endif TCPLOOPBACK		ti->ti_sum = in_cksum(m, sizeof (struct tcpiphdr) + (int)optlen + len);	/*	 * In transmit state, time the transmission and arrange for	 * the retransmit.  In persist state, just set snd_max.	 */	if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) {		tcp_seq startseq = tp->snd_nxt;		/*		 * Advance snd_nxt over sequence space of this segment.		 */		if (flags & TH_SYN)			tp->snd_nxt++;		if (flags & TH_FIN) {			tp->snd_nxt++;			tp->t_flags |= TF_SENTFIN;		}		tp->snd_nxt += len;		if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {			tp->snd_max = tp->snd_nxt;			/*			 * Time this transmission if not a retransmission and			 * not currently timing anything.			 */			if (tp->t_rtt == 0) {				tp->t_rtt = 1;				tp->t_rtseq = startseq;				TCPSTAT(tcps_segstimed++);			}		}		/*		 * Set retransmit timer if not currently set,		 * and not doing an ack or a keep-alive probe.		 * Initial value for retransmit timer is smoothed		 * round-trip time + 2 * round-trip time variance.		 * Initialize shift counter which is used for backoff		 * of retransmit time.		 */		if (tp->t_timer[TCPT_REXMT] == 0 &&		    tp->snd_nxt != tp->snd_una) {			tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;			if (tp->t_timer[TCPT_PERSIST]) {			tp->t_timer[TCPT_PERSIST] = 0;				tp->t_rxtshift = 0;		}		}	} else		if (SEQ_GT(tp->snd_nxt + len, tp->snd_max))			tp->snd_max = tp->snd_nxt + len;	/*	 * Trace.	 */	if (so->so_options & SO_DEBUG)		tcp_trace(TA_OUTPUT, tp->t_state, tp, ti, 0);#ifdef TCPLOOPBACK	if (loopback) {		/* Fake IP transit and get to TCP layer fast */		((struct ip *)ti)->ip_hl = sizeof (struct ip) >> 2;		((struct ip *)ti)->ip_len = sizeof (struct tcphdr) + optlen + len;		/*		 * Data (will be) sent.		 * If this advertises a larger window than any other segment,		 * then remember the size of the advertised window.		 * Drop send for purpose of ACK requirements.		 */		if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv))			tp->rcv_adv = tp->rcv_nxt + win;		tp->t_flags &= ~(TF_ACKNOW|TF_DELACK);		/*		 * SMP:		 * Tcp_input() can be called from the interrupt handler so		 * it needs to be able to lock.  Since we are calling down		 * from the user level, unlock here, call tcp_input and let		 * tcp_input pretend that data was from the network.		 * Note that we are at splnet coming into tcp_output		 * and we are not changing ipl here.		 * The so->head check here comes from the fact that on a soclose,		 * we can get here with both so and so->head locked.  We need to		 * release both locks because the first thing tcp_input does is		 * assert the lk_tcb which will cause a lock position panic if		 * any sockets are locked.		 */		{		int owner = 0;		if ( (so->so_head) && (so != so->so_head) && smp_owner(&so->so_head->lk_socket) ){			smp_unlock(&so->so_head->lk_socket);			owner = 1;		}		smp_unlock(&so->lk_socket);		tcp_input(m);		s = splnet();		if ( (so->so_head) && (so != so->so_head) && owner ){			SO_LOCK(so->so_head);			owner = 0;		}		SO_LOCK(so);		}	} else {#endif TCPLOOPBACK		/*	 	 * Fill in IP length and desired time to live and	 	 * send to IP level.	 	 */		((struct ip *)ti)->ip_len = sizeof (struct tcpiphdr) + optlen + len;		((struct ip *)ti)->ip_ttl = TCP_TTL;	error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route,	    so->so_options & SO_DONTROUTE, so);		if (error)			return (error);	TCPSTAT(tcps_sndtotal++);		/*	 	 * Data sent (as far as we can tell).	 	 * If this advertises a larger window than any other segment,	 	 * then remember the size of the advertised window.	 * Any pending ACK has now been sent.	 	 */		if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv))			tp->rcv_adv = tp->rcv_nxt + win;		tp->t_flags &= ~(TF_ACKNOW|TF_DELACK);#ifdef TCPLOOPBACK	}#endif	if (sendalot)		goto again;	return (0);}tcp_setpersist(tp)	register struct tcpcb *tp;{	register int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1;	if (tp->t_timer[TCPT_REXMT])		panic("tcp_output REXMT");	/*	 * Start/restart persistance timer.	 */	TCPT_RANGESET(tp->t_timer[TCPT_PERSIST],	    t * tcp_backoff[tp->t_rxtshift],	    TCPTV_PERSMIN, TCPTV_PERSMAX);	if (tp->t_rxtshift < TCP_MAXRXTSHIFT)	tp->t_rxtshift++;}

⌨️ 快捷键说明

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