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

📄 tcp_input.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 4 页
字号:
		    PRINTXTID(1, ("T_DISCONNECT (#2) \n"));		  }		}#endif XTI		freeondrop = 0;		tp = tcp_drop(tp, ECONNREFUSED);		if (smp && smp_owner(&so->lk_socket) == 0){			dropsocket = 0;			goto drop;		}		goto drop;	case TCPS_ESTABLISHED:	case TCPS_FIN_WAIT_1:	case TCPS_FIN_WAIT_2:	case TCPS_CLOSE_WAIT:#ifdef XTI		/* set T_DISCONNECT bit on in socket struct field		 * so->so_xticb.xti_evtarray when so->so_xticb.xti_epvalid and		 * *->xti_evtenabled are on.		 */				if (so->so_xticb.xti_epvalid) { /* valid xti endpoint */		  if (so->so_xticb.xti_evtenabled) {		    so->so_xticb.xti_evtarray[XTI_EVT_T_DISCONNECT]++; 		    PRINTXTID(1, ("T_DISCONNECT (#3) \n"));		  }		}#endif XTI		freeondrop = 0;		tp = tcp_drop(tp, ECONNRESET);		if (smp && smp_owner(&so->lk_socket) == 0){			dropsocket = 0;			goto drop;		}		goto drop;	case TCPS_CLOSING:	case TCPS_LAST_ACK:	case TCPS_TIME_WAIT:#ifdef XTI		/* set T_DISCONNECT bit on in socket struct field		 * so->so_xticb.xti_evtarray when so->so_xticb.xti_epvalid and		 * *->xti_evtenabled are on.		 */			if (so->so_xticb.xti_epvalid) { /* valid xti endpoint */		  if (so->so_xticb.xti_evtenabled) {		    so->so_xticb.xti_evtarray[XTI_EVT_T_DISCONNECT]++; 		    PRINTXTID(1, ("T_DISCONNECT (#4) \n"));		  }		}#endif XTI		freeondrop = 0;		tp = tcp_close(tp);#ifdef TCPLOOPBACK	case TCPS_CLOSED:#endif		if (smp && smp_owner(&so->lk_socket) == 0){			dropsocket = 0;			goto drop;		}		goto drop;	}	/*	 * If a SYN is in the window, then this is an	 * error and we send an RST and drop the connection.	 */	/* tcp_drop cannot be called before dropwithreset without	 * guaranteeing a good socket and tp.  Duplicate all 	 * dropwithreset here, but change where tcp_drop() is called.	 */	if (tiflags & TH_SYN) {		if ((tiflags & TH_RST) || in_broadcast(ti->ti_dst)){			goto drop;		}		if (tiflags & TH_ACK){			tcp_respond(tp,ti,(tcp_seq)0,ti->ti_ack, TH_RST, so);		}		else {			if (tiflags & TH_SYN)				ti->ti_len++;			tcp_respond(tp, ti, ti->ti_seq+ti->ti_len, (tcp_seq)0,			    TH_RST|TH_ACK, so);		}		tp = tcp_drop(tp, ECONNRESET);		if (om) {			(void) m_free(om);		}		if (dropsocket) {			if (smp && smp_owner(&so->lk_socket) == 1)				(void) soabort(so);			if (smp && smp_owner(&so->lk_socket))				smp_unlock(&so->lk_socket);			if ( !smp )				(void) soabort(so);		} else {			if (smp && smp_owner(&so->lk_socket))				smp_unlock(&so->lk_socket);			}		return;	}	/*	 * If the ACK bit is off we drop the segment and return.	 */	if ((tiflags & TH_ACK) == 0){		goto drop;	}		/*	 * Ack processing.	 */	switch (tp->t_state) {	/*	 * In SYN_RECEIVED state if the ack ACKs our SYN then enter	 * ESTABLISHED state and continue processing, otherwise	 * send an RST.	 */	case TCPS_SYN_RECEIVED:		if (SEQ_GT(tp->snd_una, ti->ti_ack) ||		    SEQ_GT(ti->ti_ack, tp->snd_max)){			goto dropwithreset;		}		TCPSTAT(tcps_connects++);#ifdef XTI		if (!(tp->t_acceptmode))#endif XTI		soisconnected(so);		tp->t_state = TCPS_ESTABLISHED;		tp->t_maxseg = MIN(tp->t_maxseg, tcp_mss(tp));		(void) tcp_reass(tp, (struct tcpiphdr *)0);		tp->snd_wl1 = ti->ti_seq - 1;		/* fall into ... */	/*	 * In ESTABLISHED state: drop duplicate ACKs; ACK out of range	 * ACKs.  If the ack is in the range	 *	tp->snd_una < ti->ti_ack <= tp->snd_max	 * then advance tp->snd_una to ti->ti_ack and drop	 * data from the retransmission queue.  If this ACK reflects	 * more up to date window information we update our window information.	 */	case TCPS_ESTABLISHED:	case TCPS_FIN_WAIT_1:	case TCPS_FIN_WAIT_2:	case TCPS_CLOSE_WAIT:	case TCPS_CLOSING:	case TCPS_LAST_ACK:	case TCPS_TIME_WAIT:		if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {			if (ti->ti_len == 0 && ti->ti_win == tp->snd_wnd) {				TCPSTAT(tcps_rcvdupack++);				/*				 * If we have outstanding data (not a				 * window probe), this is a completely				 * duplicate ack (ie, window info didn't				 * change), the ack is the biggest we've				 * seen and we've seen exactly our rexmt				 * threshhold of them, assume a packet				 * has been dropped and retransmit it.				 * Kludge snd_nxt & the congestion				 * window so we send only this one				 * packet.  If this packet fills the				 * only hole in the receiver's seq.				 * space, the next real ack will fully				 * open our window.  This means we				 * have to do the usual slow-start to				 * not overwhelm an intermediate gateway				 * with a burst of packets.  Leave				 * here with the congestion window set				 * to allow 2 packets on the next real				 * ack and the exp-to-linear thresh				 * set for half the current window				 * size (since we know we're losing at				 * the current window size).				 */				if (tp->t_timer[TCPT_REXMT] == 0 ||				    ti->ti_ack != tp->snd_una)					tp->t_dupacks = 0;				else if (++tp->t_dupacks == tcprexmtthresh) {					tcp_seq onxt = tp->snd_nxt;					u_int win =					    MIN(tp->snd_wnd, tp->snd_cwnd) / 2 /						tp->t_maxseg;					if (win < 2)						win = 2;					tp->snd_ssthresh = win * tp->t_maxseg;					tp->t_timer[TCPT_REXMT] = 0;					tp->t_rtt = 0;					tp->snd_nxt = ti->ti_ack;					tp->snd_cwnd = tp->t_maxseg;					(void) tcp_output(tp);					if (SEQ_GT(onxt, tp->snd_nxt))						tp->snd_nxt = onxt;					goto drop;				}			} else				tp->t_dupacks = 0;			break;		}		tp->t_dupacks = 0;		if (SEQ_GT(ti->ti_ack, tp->snd_max)) {			TCPSTAT(tcps_rcvacktoomuch++);			goto dropafterack;		}		acked = ti->ti_ack - tp->snd_una;		TCPSTAT(tcps_rcvackpack++);		TCPSTAT(tcps_rcvackbyte += acked);		/*		 * If transmit timer is running and timed sequence		 * number was acked, update smoothed round trip time.		 * Since we now have an rtt measurement, cancel the		 * timer backoff (cf., Phil Karn's retransmit alg.).		 * Recompute the initial retransmit timer.		 */		if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) {			TCPSTAT(tcps_rttupdated++);			if (tp->t_srtt != 0) {				register short delta;				/*				 * srtt is stored as fixed point with 3 bits				 * after the binary point (i.e., scaled by 8).				 * The following magic is equivalent				 * to the smoothing algorithm in rfc793				 * with an alpha of .875				 * (srtt = rtt/8 + srtt*7/8 in fixed point).				 * Adjust t_rtt to origin 0.				 */				tp->t_rtt--;				delta = tp->t_rtt - (tp->t_srtt >> 3);				if ((tp->t_srtt += delta) <= 0)					tp->t_srtt = 1;				/*				 * We accumulate a smoothed rtt variance				 * (actually, a smoothed mean difference),				 * then set the retransmit timer to smoothed				 * rtt + 2 times the smoothed variance.				 * rttvar is stored as fixed point				 * with 2 bits after the binary point				 * (scaled by 4).  The following is equivalent				 * to rfc793 smoothing with an alpha of .75				 * (rttvar = rttvar*3/4 + |delta| / 4).				 * This replaces rfc793's wired-in beta.				 */				if (delta < 0)					delta = -delta;				delta -= (tp->t_rttvar >> 2);				if ((tp->t_rttvar += delta) <= 0)					tp->t_rttvar = 1;			} else {				/* 				 * No rtt measurement yet - use the				 * unsmoothed rtt.  Set the variance				 * to half the rtt (so our first				 * retransmit happens at 2*rtt)				 */				tp->t_srtt = tp->t_rtt << 3;				tp->t_rttvar = tp->t_rtt << 1;			}			tp->t_rtt = 0;			tp->t_rxtshift = 0;			TCPT_RANGESET(tp->t_rxtcur, 			    ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1,			    TCPTV_MIN, TCPTV_REXMTMAX);		}		/*		 * If all outstanding data is acked, stop retransmit		 * timer and remember to restart (more output or persist).		 * If there is more data to be acked, restart retransmit		 * timer, using current (possibly backed-off) value.		 */		if (ti->ti_ack == tp->snd_max) {			tp->t_timer[TCPT_REXMT] = 0;			tp->t_rxtshift = 0; /* reset to initial value */			needoutput = 1;		} else if (tp->t_timer[TCPT_PERSIST] == 0)			tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;		/*		 * When new data is acked, open the congestion window.		 * If the window gives us less than ssthresh packets		 * in flight, open exponentially (maxseg per packet).		 * Otherwise open linearly (maxseg per window,		 * or maxseg^2 / cwnd per packet).		 */		{		u_int incr = tp->t_maxseg;		if (tp->snd_cwnd > tp->snd_ssthresh)			incr = MAX(incr * incr / tp->snd_cwnd, 1);		tp->snd_cwnd = MIN(tp->snd_cwnd + incr, 65535); /* XXX */		}		if (acked > so->so_snd.sb_cc) {			tp->snd_wnd -= so->so_snd.sb_cc;			sbdrop(&so->so_snd, (int)so->so_snd.sb_cc);			ourfinisacked = 1;#ifdef XTI			if (so->so_xticb.xti_epvalid) { /* valid xti endpoint */			  if (so->so_xticb.xti_evtenabled) {			    if (so->so_xticb.xti_blocked) { /* flow controlled EWOULDBLOCK */			      so->so_xticb.xti_blocked = 0; /* unblocked */			      so->so_xticb.xti_evtarray[XTI_EVT_T_GODATA]++; 			      so->so_xticb.xti_evtarray[XTI_EVT_T_GOEXDATA]++; 			      PRINTXTID(1, ("T_GODATA (#1)    \n"));			      PRINTXTID(1, ("T_GOEXDATA (#1)    \n"));			    }			  }			}	#endif XTI		} else {			sbdrop(&so->so_snd, acked);			tp->snd_wnd -= acked;			ourfinisacked = 0;#ifdef XTI			if (so->so_xticb.xti_epvalid) { /* valid xti endpoint */			  if (so->so_xticb.xti_evtenabled) {			    if (so->so_xticb.xti_blocked) { /* flow controlled EWOULDBLOCK */			      so->so_xticb.xti_blocked = 0; /* unblocked */			      so->so_xticb.xti_evtarray[XTI_EVT_T_GODATA]++; 			      so->so_xticb.xti_evtarray[XTI_EVT_T_GOEXDATA]++; 			      PRINTXTID(1, ("T_GODATA (#2)    \n"));			      PRINTXTID(1, ("T_GOEXDATA (#2)    \n"));			    }			  }			}	#endif XTI		}		if ((so->so_snd.sb_flags & SB_WAIT) || so->so_snd.sb_sel)			sowwakeup(so);		tp->snd_una = ti->ti_ack;		if (SEQ_LT(tp->snd_nxt, tp->snd_una))			tp->snd_nxt = tp->snd_una;		switch (tp->t_state) {		/*		 * In FIN_WAIT_1 STATE in addition to the processing		 * for the ESTABLISHED state if our FIN is now acknowledged		 * then enter FIN_WAIT_2.		 */		case TCPS_FIN_WAIT_1:			if (ourfinisacked) {				/*				 * If we can't receive any more				 * data, then closing user can proceed.				 * Starting the timer is contrary to the				 * specification, but if we don't get a FIN				 * we'll hang forever.				 */				if (so->so_state & SS_CANTRCVMORE) {					soisdisconnected(so);					tp->t_timer[TCPT_2MSL] = TCPTV_MAXIDLE;				}				tp->t_state = TCPS_FIN_WAIT_2;			}			break;	 	/*		 * In CLOSING STATE in addition to the processing for		 * the ESTABLISHED state if the ACK acknowledges our FIN		 * then enter the TIME-WAIT state, otherwise ignore		 * the segment.		 */		case TCPS_CLOSING:			if (ourfinisacked) {				tp->t_state = TCPS_TIME_WAIT;				tcp_canceltimers(tp);				tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;				soisdisconnected(so);			}			break;		/*		 * In LAST_ACK, we may still be waiting for data to drain		 * and/or to be acked, as well as for the ack of our FIN.		 * If our FIN is now acknowledged, delete the TCB,		 * enter the closed state and return.		 */		case TCPS_LAST_ACK:			if (ourfinisacked) {				freeondrop = 0;				tp = tcp_close(tp);				if ( smp && smp_owner(&so->lk_socket) == 0){				    dropsocket = 0;				    goto drop;				}				goto drop;			}			break;		/*		 * In TIME_WAIT state the only thing that should arrive		 * is a retransmission of the remote FIN.  Acknowledge		 * it and restart the finack timer.		 */		case TCPS_TIME_WAIT:			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;			goto dropafterack;		}	}step6:	/*	 * Update window information.	 * Don't look at window if no ACK: TAC's send garbage on first SYN.	 */	if ((tiflags & TH_ACK) &&            (SEQ_LT(tp->snd_wl1, ti->ti_seq) || tp->snd_wl1 == ti->ti_seq &&	    (SEQ_LT(tp->snd_wl2, ti->ti_ack) ||	     tp->snd_wl2 == ti->ti_ack && ti->ti_win > tp->snd_wnd))) {		/* keep track of pure window updates */		if (ti->ti_len == 0 &&		    tp->snd_wl2 == ti->ti_ack && ti->ti_win > tp->snd_wnd)			TCPSTAT(tcps_rcvwinupd++);		tp->snd_wnd = ti->ti_win;		tp->snd_wl1 = ti->ti_seq;		tp->snd_wl2 = ti->ti_ack;		if (tp->snd_wnd > tp->max_sndwnd)			tp->max_sndwnd = tp->snd_wnd;		needoutput = 1;	}	/*	 * Process segments with URG.	 */	if ((tiflags & TH_URG) && ti->ti_urp &&	    TCPS_HAVERCVDFIN(tp->t_state) == 0) {		/*		 * This is a kludge, but if we receive and accept		 * random urgent pointers, we'll crash in		 * soreceive.  It's hard to imagine someone		 * actually wanting to send this much urgent data.		 */		if (ti->ti_urp + so->so_rcv.sb_cc > SB_MAX) {			ti->ti_urp = 0;			/* XXX */			tiflags &= ~TH_URG;		/* XXX */			goto dodata;			/* XXX */		}		/*		 * If this segment advances the known urgent pointer,		 * then mark the data stream.  This should not happen		 * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since		 * a FIN has been received from the remote side. 		 * In these states we ignore the URG.		 *		 * According to RFC961 (Assigned Protocols),		 * the urgent pointer points to the last octet		 * of urgent data.  We continue, however,		 * to consider it to indicate the first octet		 * of data past the urgent section		 * as the original spec states.		 */		if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) {			tp->rcv_up = ti->ti_seq + ti->ti_urp;			so->so_oobmark = so->so_rcv.sb_cc +			    (tp->rcv_up - tp->rcv_nxt) - 1;			if (so->so_oobmark == 0)				so->so_state |= SS_RCVATMARK;			sohasoutofband(so);			tp->t_oobflags &= ~(TCPOOB_HAVEDATA | TCPOOB_HADDATA);		      }		/*		 * Remove out of band data so doesn't get presented to user.		 * This can happen independent of advancing the URG pointer,		 * but if two URG's are pending at once, some out-of-band		 * data may creep in... ick.		 */		if (ti->ti_urp <= ti->ti_len &&#ifdef XTI		    (so->so_options & SO_OOBINLINE) == 0) {		  PRINTXTID(32, ("Calling tcp_pulloobxti\n"));		  tcp_pulloobxti(so, ti);		} else		  /*		   * Because they don't present oob data to user		   * we must update our event structures.		   */		  {		    /* For now do not touch event info		    sbdrop(&so->so_exrcv, so->so_exrcv.sb_cc);		    so->so_xticb.xti_evtarray[XTI_EVT_T_EXDATA] = 0;		    */		  }#else			(so->so_options & SO_OOBINLINE) == 0)			tcp_pulloutofband(so, ti);#endif XTI	} else		/*		 * If no out of band data is expected,		 * pull receive urgent pointer along		 * with the receive window.		 */		if (SEQ_GT(tp->rcv_nxt, tp->rcv_up))			tp->rcv_up = tp->rcv_nxt;dodata:							/* XXX */	/*	 * Process the segment text, merging it into the TCP sequencing queue,	 * and arranging for acknowledgment of receipt if necessary.	 * This process logically involves adjusting tp->rcv_wnd as data	 * is presented to the user (this happens in tcp_usrreq.c,	 * case PRU_RCVD).  If a FIN has already been received on this	 * connection then we just ignore the text.	 */	if ((ti->ti_len || (tiflags&TH_FIN)) &&	    TCPS_HAVERCVDFIN(tp->t_state) == 0) {		TCP_REASS(tp, ti, m, so, tiflags);		if (tcpnodelack == 0)			tp->t_flags |= TF_DELACK;		else			tp->t_flags |= TF_ACKNOW;		/*		 * Note the amount of data that peer has sent into		 * our window, in order to estimate the sender's		 * buffer size.		 */		len = so->so_rcv.sb_hiwat - (tp->rcv_adv - tp->rcv_nxt);		if (len > tp->max_rcvd)			tp->max_rcvd = len;	} else {		m_freem(m);		tiflags &= ~TH_FIN;	}	/*	 * If FIN is received ACK the FIN and let the user know	 * that the connection is closing.	 */	if ((tiflags & TH_FIN) || 	/* 1/91.us.  According to rfc793, the normal tcp state transitions	 * on close are:	 * (side1) ESTABLISHED -> FIN_WAIT_1 -> FIN_WAIT_2 -> TIME_WAIT

⌨️ 快捷键说明

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