📄 tcpstate.c
字号:
/*-------------------------------------------------------------------*/ /* Return -1 if segment does not have acknowledgment flag set. */ /*-------------------------------------------------------------------*/ if ((Net.Tcp->flags & TCPF_ACK) == 0) return -1; /*-------------------------------------------------------------------*/ /* Check for absurdly high acknowledgment number. */ /*-------------------------------------------------------------------*/ if (SEQ_GT(Net.Tcp->ack_num, Sock->max_snt)) { if (Sock->state == SS_SYNRCVD) TcpReset(); else TcpJustAck(Sock); return -1; } /*-------------------------------------------------------------------*/ /* Compute number of new octets acknowledged. Return if old ack. */ /*-------------------------------------------------------------------*/ if (SEQ_LT(Net.Tcp->ack_num, Sock->snt_una)) return 0; /*-------------------------------------------------------------------*/ /* Update window if any of three conditions are met. */ /*-------------------------------------------------------------------*/ acked = Net.Tcp->ack_num - Sock->snt_una; if (SEQ_LT(Sock->lw_seq, Net.Tcp->seq_num) || acked || (Sock->snd_window < Net.Tcp->window)) { /*-----------------------------------------------------------------*/ /* Remember increased sequence number and record peer's window. */ /*-----------------------------------------------------------------*/ if (SEQ_LT(Sock->lw_seq, Net.Tcp->seq_num)) Sock->lw_seq = Net.Tcp->seq_num; Sock->snd_window = Net.Tcp->window; win_update = TRUE; /*-----------------------------------------------------------------*/ /* Check if window is open. */ /*-----------------------------------------------------------------*/ if (Sock->snd_window) { /*---------------------------------------------------------------*/ /* If window edge has advanced while in "transmit", try output. */ /*---------------------------------------------------------------*/ if (Sock->out_state == TCPO_XMIT) { tcpseq old_end = Sock->snt_una + Sock->snd_window; tcpseq new_end = Net.Tcp->ack_num + Net.Tcp->window; if (SEQ_GT(new_end, old_end)) Net.TryOut = TRUE; } /*---------------------------------------------------------------*/ /* Else change to "transmit" if window has opened in "persist". */ /*---------------------------------------------------------------*/ else if (Sock->out_state == TCPO_PERSIST) { Sock->out_state = TCPO_XMIT; Sock->flags &= ~SF_TIMING_RTT; Sock->retrans_count = 0; NetTimerStop(&Sock->out_tmr); Net.TryOut = TRUE; } } } /*-------------------------------------------------------------------*/ /* Check if state is "transmit". */ /*-------------------------------------------------------------------*/ if (Sock->out_state == TCPO_XMIT) { /*-----------------------------------------------------------------*/ /* Check if nothing was acknowledged. */ /*-----------------------------------------------------------------*/ if (acked == 0) { /*---------------------------------------------------------------*/ /* Check if ack is not a complete duplicate. */ /*---------------------------------------------------------------*/ if (RxBuf->length || win_update) { Sock->dup_acks = 0; } /*---------------------------------------------------------------*/ /* Else perform fast retransmission after three duplicate acks. */ /*---------------------------------------------------------------*/ else if (++Sock->dup_acks == FAST_RXMIT_THRES) { tcpseq snd_nxt; /*-------------------------------------------------------------*/ /* Set slow start threshold to max(half flight size, two MSS). */ /*-------------------------------------------------------------*/ Sock->ssthresh = max(((Sock->snd_nxt - Sock->snt_una) >> 1), (Sock->snd_mss << 1)); /*-------------------------------------------------------------*/ /* Resend the indicated missing segment. */ /*-------------------------------------------------------------*/ snd_nxt = Sock->snd_nxt; Sock->snd_nxt = Sock->snt_una; TcpSendSeg(Sock, Sock->snd_mss); Sock->snd_nxt = snd_nxt; /*-------------------------------------------------------------*/ /* Cancel round trip timing and restart output timer. */ /*-------------------------------------------------------------*/ Sock->flags &= ~SF_TIMING_RTT; NetTimerStart(&Sock->out_tmr, Sock->retrans_timeo); /*-------------------------------------------------------------*/ /* Set congestion window to slow-start threshold plus segments */ /* which triggered the duplicate acknowledgments. */ /*-------------------------------------------------------------*/ Sock->snd_cwnd = Sock->ssthresh + FAST_RXMIT_THRES * Sock->snd_mss; } /*---------------------------------------------------------------*/ /* Follow with fast recovery until ack of new data arrives. */ /*---------------------------------------------------------------*/ else if (Sock->dup_acks > FAST_RXMIT_THRES) { Sock->snd_cwnd += Sock->snd_mss; Net.TryOut = TRUE; } return 0; } /*-----------------------------------------------------------------*/ /* Data was acknowledged. Stop timer and schedule next output. */ /*-----------------------------------------------------------------*/ NetTimerStop(&Sock->out_tmr); Net.TryOut = TRUE; /*-----------------------------------------------------------------*/ /* Update timeout if acknowledged transmission was measured. */ /*-----------------------------------------------------------------*/ if ((Sock->flags & SF_TIMING_RTT) && SEQ_GT(Net.Tcp->ack_num, Sock->rtt_seq)) { uint rrt; /* raw round trip */ int error; /* deviation from smoothed round trip estimate */ /*---------------------------------------------------------------*/ /* Calculate round trip time. */ /*---------------------------------------------------------------*/ rrt = NetTickCount + Sock->retrans_timeo - Sock->out_tmr.time_due; /*---------------------------------------------------------------*/ /* Initialization after first acknowledgment. */ /*---------------------------------------------------------------*/ if (Sock->srtt == 0) { Sock->srtt = (rrt + TICKS_PER_SEC / 2) << 3; /* scaling by 8 */ Sock->rttvar = Sock->srtt >> 2; /* scaling by 4 */ } /*---------------------------------------------------------------*/ /* "srtt" is scaled by 8, so this is really error = rrt - srtt. */ /*---------------------------------------------------------------*/ error = rrt - (Sock->srtt >> 3); /*---------------------------------------------------------------*/ /* "srtt" is scaled by 8, so this is srtt = srtt + error/8. */ /*---------------------------------------------------------------*/ Sock->srtt += error; /*---------------------------------------------------------------*/ /* Convert error to absolute value. */ /*---------------------------------------------------------------*/ if (error < 0) error = -error; /*---------------------------------------------------------------*/ /* "rttvar" is scaled by 4, so this is really */ /* rttvar = rttvar + (|error| - rttvar)/4 */ /*---------------------------------------------------------------*/ Sock->rttvar += error - (Sock->rttvar >> 2); /*---------------------------------------------------------------*/ /* "srtt" is scaled by 8 and rttvar scaled by 4, so this is */ /* rto = srtt + 4 * rttvar */ /*---------------------------------------------------------------*/ Sock->retrans_timeo = (Sock->srtt >> 3) + Sock->rttvar; /*---------------------------------------------------------------*/ /* Ensure retransmit period not reduced below lower bound. */ /*---------------------------------------------------------------*/ if (Sock->retrans_timeo < MIN_RXT) Sock->retrans_timeo = MIN_RXT; /*---------------------------------------------------------------*/ /* Record that round trip timing is no longer active. */ /*---------------------------------------------------------------*/ Sock->flags &= ~SF_TIMING_RTT; } } /*-------------------------------------------------------------------*/ /* Else processing for other output states. */ /*-------------------------------------------------------------------*/ else { /*-----------------------------------------------------------------*/ /* If state is "persist", any ack resets retransmission count. */ /*-----------------------------------------------------------------*/ if (Sock->out_state == TCPO_PERSIST) Sock->retrans_count = 0; /*-----------------------------------------------------------------*/ /* Finished if no data was acknowledged. */ /*-----------------------------------------------------------------*/ if (acked == 0) return 0; /*-----------------------------------------------------------------*/ /* If state is "retransmit", ack moves state to "transmit". */ /*-----------------------------------------------------------------*/ if (Sock->out_state == TCPO_REXMT) { Sock->out_state = TCPO_XMIT; Sock->flags &= ~SF_TIMING_RTT; Sock->retrans_count = 0; NetTimerStop(&Sock->out_tmr); Net.TryOut = TRUE; } } /*-------------------------------------------------------------------*/ /* Update unacknowledged send start and next sequence number sent. */ /*-------------------------------------------------------------------*/ Sock->snt_una = Net.Tcp->ack_num; if (SEQ_GT(Net.Tcp->ack_num, Sock->snd_nxt)) Sock->snd_nxt = Net.Tcp->ack_num; /*-------------------------------------------------------------------*/ /* Clear send urgent flag if urgent data has been acknowledged. */ /*-------------------------------------------------------------------*/ if ((Sock->flags & SF_SUPOK) && SEQ_GE(Net.Tcp->ack_num, Sock->surg_seq)) Sock->flags &= ~SF_SUPOK; /*-------------------------------------------------------------------*/ /* Clear send SYN flag if SYN has been acknowledged. */ /*-------------------------------------------------------------------*/ if (Sock->flags & TCPF_SYN) { --acked; Sock->flags &= ~TCPF_SYN; } /*-------------------------------------------------------------------*/ /* Clear send FIN flag if FIN has been acknowledged. */ /*-------------------------------------------------------------------*/ if ((Sock->flags & SF_SNDFIN) && SEQ_GT(Net.Tcp->ack_num, Sock->fin_seq)) { --acked; Sock->flags &= ~SF_SNDFIN; } /*-------------------------------------------------------------------*/ /* Check if any data was acknowledged. */ /*-------------------------------------------------------------------*/ if (acked) { /*-----------------------------------------------------------------*/ /* First ack after fast recovery deflates the congestion window. */ /*-----------------------------------------------------------------*/ if (Sock->dup_acks >= FAST_RXMIT_THRES) { Sock->snd_cwnd = Sock->ssthresh; } /*-----------------------------------------------------------------*/ /* Else acknowledgment increases congestion window. */ /*-----------------------------------------------------------------*/ else { int incr; /*---------------------------------------------------------------*/ /* If congestion window <= slow-start threshold, use slow-start. */ /*---------------------------------------------------------------*/ if (Sock->snd_cwnd <= Sock->ssthresh) incr = Sock->snd_mss; /* exponential increase */ /*---------------------------------------------------------------*/ /* Else use congestion avoidance algorithm (additive increase). */ /*---------------------------------------------------------------*/ else { incr = (Sock->snd_mss * Sock->snd_mss) / Sock->snd_cwnd; incr = max(incr, 1); } /*---------------------------------------------------------------*/ /* Increase congestion window until bigger than send buffer. */ /*---------------------------------------------------------------*/ if (Sock->snd_cwnd < Sock->sb_size) Sock->snd_cwnd += incr; } /*-----------------------------------------------------------------*/ /* Any data acknowledgment resets duplicate ack counting. */ /*-----------------------------------------------------------------*/ Sock->dup_acks = 0; /*-----------------------------------------------------------------*/ /* Update send buffer and post event. */ /*-----------------------------------------------------------------*/ Sock->sb_start = (Sock->sb_start + acked) % Sock->sb_size; TcpAssert(Sock->sb_count >= acked); Sock->sb_count -= acked; NetPostEvent(Sock, SE_DATA_ACKED); } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -