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

📄 tcptime.c

📁 代码在ti的c67系列单片机上实现了完整的TCPIP协议栈
💻 C
字号:
//--------------------------------------------------------------------------
// Ip Stack
//--------------------------------------------------------------------------
// TCPTIME.C
//
// TCP Timer Timeout Functions
//
// Author: Michael A. Denio
// Copyright 1999 by Texas Instruments Inc.
//-------------------------------------------------------------------------
#include <stkmain.h>
#include "tcp.h"

// tcp_backoff - Exponential backoff applied to Timer Ticks
UINT32 tcp_backoff[TCP_MAXBACKOFF+1] =
       { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };

//--------------------------------------------------------------------
// TcpSetPersist
//
// Set persist time used when client advertised window is Zero
//--------------------------------------------------------------------
void TcpSetPersist( TCPPROT *pt )
{
    UINT32 Ticks;

    // Calculate
    Ticks = ( pt->t_srtt + 2 * pt->t_rttvar ) >> TCP_FIXP_SHIFT;
    Ticks *= tcp_backoff[pt->t_rtxindex];

    // Start/restart persistance timer.
    TCPT_RANGESET( pt->dwTicksPersist, Ticks, TCPTV_PERSMIN, TCPTV_PERSMAX);

    // Back off some more next time
    if (pt->t_rtxindex < TCP_MAXBACKOFF)
        pt->t_rtxindex++;
}

//--------------------------------------------------------------------
// TcpTimeoutWait2
//
// Called when the TCP wait timer (TIME_WAIT or FIN_WAIT_2) has fired
//--------------------------------------------------------------------
void TcpTimeoutWait2( TCPPROT *pt )
{
    // If we're in the TIMEWAIT state, close the control block
    // Otherwise, we're in FIN_WAIT_2 - if we've been idle for more
    // than MAX_IDLE (10min), close the control block. Otherwise,
    // time another interval.
    if( pt->t_state != TSTATE_TIMEWAIT && pt->t_tidle <= TCPTV_MAX_IDLE )
        pt->dwTicksWait2 = TCPTV_KEEP_INTVL;
    else
        TcpClose( pt );
}

//--------------------------------------------------------------------
// TcpTimeoutPersist
//
// Called when the TCP retransmit timer has expired
//--------------------------------------------------------------------
void TcpTimeoutPersist( TCPPROT *pt )
{
    DbgPrintf(DBG_INFO,"TCP: Persist Timeout");

    // Bump the timeout stats
    tcps.dwPersistTimeout++;

    // Set the next persist timeout
    TcpSetPersist( pt );

    // Force a segment (check for lost window advertisement)
    pt->t_flags |= TF_PERSIST;
    TcpOutput( pt );
}

//--------------------------------------------------------------------
// TcpTimeoutKeep
//
// Called when the TCP KeepAlive timer has expired
//--------------------------------------------------------------------
void TcpTimeoutKeep( TCPPROT *pt )
{
    INT32  KeepAlive;

    DbgPrintf(DBG_INFO,"TCP: Keep Timeout");

    // Bump the timeout stats
    tcps.dwKeepTimeout++;

    // Check for timeout on a connection request
    if( pt->t_state < TSTATE_ESTAB )
        goto KeepDrop;

    // Get the socket option KEEPALIVE
    KeepAlive = SockGetOptionFlags( pt->hSock ) & SO_KEEPALIVE;

    // Once "closed", KeepAlive no longer applies. Otherwise, when
    // KeepAlive is set, send a probe.
    if( KeepAlive && pt->t_state <= TSTATE_CLOSEWAIT )
    {
        // If we've been idle too long (2 hours + 10 min), drop connection
        if( pt->t_tidle >= TCPTV_KEEP_IDLE + TCPTV_MAX_IDLE )
            goto KeepDrop;

        // Bump the "probe" stats
        tcps.dwKeepProbe++;

        // Send a keepalive packet
        TcpGenPacket( pt, SockGetFIP(pt->hSock), SockGetFPort(pt->hSock),
                      SockGetLIP(pt->hSock), SockGetLPort(pt->hSock),
                      pt->rcv_nxt, pt->snd_una-1, 0 );

        // Set to probe again in in 75 seconds
        pt->dwTicksKeep = TCPTV_KEEP_INTVL;
    }
    else
    {
        // We're not active
        // Set to probe again in in 2 hours seconds
        pt->dwTicksKeep = TCPTV_KEEP_IDLE;
    }
    return;

KeepDrop:
    // Bump the drop stats
    tcps.dwKeepDrops++;

    // Set socket error and drop connection
    TcpDrop( pt, ETIMEDOUT );
}

//--------------------------------------------------------------------
// TcpTimeoutRexmt
//
// Called when the TCP retransmit timer has expired
//--------------------------------------------------------------------
void TcpTimeoutRexmt( TCPPROT *pt )
{
    UINT32 win,Ticks;

    DbgPrintf(DBG_INFO,"TCP: Retransmit Timeout");

    //
    // Message has not been acked within retransmit interval.
    // Back off to a longer retransmit interval and retransmit one segment.
    //
    if( ++pt->t_rtxindex > TCP_MAXBACKOFF )
    {
        //
        // Aleady at max - drop it like a bad habit
        //
        pt->t_rtxindex = TCP_MAXBACKOFF;

        // Bump the drop stats
        tcps.dwTimeoutDrops++;

        // Set socket error and drop connection
        TcpDrop( pt, ETIMEDOUT );
        return;
    }

    // Bump the stats
    tcps.dwRexmtTimeout++;

    // Calculate
    Ticks = ( pt->t_srtt + 4 * pt->t_rttvar ) >> TCP_FIXP_SHIFT;
    Ticks *= tcp_backoff[pt->t_rtxindex];

    // Start/restart retransmit timer.
    TCPT_RANGESET( pt->t_trtx, Ticks, TCPTV_RTXMIN, TCPTV_RTXMAX);
    pt->dwTicksRexmt = pt->t_trtx;

    DbgPrintf(DBG_INFO,"TCP: Retransmit Ticks %ld",pt->t_trtx);

    //
    // If we've retransmitted four or more times, notify the
    // Socket handler. Also, the round trip time is no longer
    // accurate, so we reset it.
    //
    if (pt->t_rtxindex > TCP_MAXBACKOFF / 4)
    {
        // Notify socket its losing data
        SockValidateRoute( pt->hSock );
        // First pre-adjust rttvar so that RTO will be
        // the same if we time out again
        pt->t_rttvar += pt->t_srtt/4;
        // Now clear srtt so that the measured RTT is used
        pt->t_srtt   = TCPTV_SRTTBASE;
    }

    // Retransmit earliest unacked sequence
    pt->snd_nxt = pt->snd_una;

    // Force a segment to be sent.
    pt->t_flags |= TF_ACKNOW;

    // If timing a segment in this window, stop the timer.
    pt->t_trtt = 0;

    //
    // Close the congestion window down to one segment
    // (we'll open it by one segment for each ack we get).
    //
    // This "slow start" keeps us from dumping all that data
    // as back-to-back packets
    //

    // Take one half the LESSER of the advertised window, or the
    // congestion window.
    if( pt->snd_wnd < pt->snd_cwnd )
        win = pt->snd_wnd / 2 / (UINT32)pt->t_mss;
    else
        win = pt->snd_cwnd / 2 / (UINT32)pt->t_mss;
    if (win < 2)
        win = 2;
    pt->snd_cwnd = pt->t_mss;                   // (one segment)
    pt->t_dupacks = 0;                          // Reset fast retransmit

    // Retransmit earliest unacked sequence
    TcpOutput( pt );
}

//--------------------------------------------------------------------
// TcpXmitTimer
//
// Called when reset xmit timer based on new RTT data
//--------------------------------------------------------------------
void TcpXmitTimer( TCPPROT *pt, UINT32 rtt )
{
    INT32       delta;
    UINT32      rto;

    // Keep this stat for the heck of it.
    tcps.dwRttUpdated++;

    rtt = rtt << TCP_FIXP_SHIFT;

    if( !pt->t_srtt )
    {
        // We have no data yet, so just initialize
        //
        // srtt   = rtt
        // rttvar = srtt / 2
        // RTO    = srtt + 2 * rttvar   (same as 2*rtt)
        //
        pt->t_srtt   = rtt;
        pt->t_rttvar = pt->t_srtt / 2;
        rto = ( rtt * 2 ) >> TCP_FIXP_SHIFT;
    }
    else
    {
        //
        // We want to adjust srtt / rttvar by the following formulas:
        //
        //      delta  = ticks - srtt
        //      srtt   = srtt + (1/8)delta
        //      rttvar = rttvar + (1/4)(|delta| - rttvar)
        //      RTO    = srtt + 4 * rttvar
        //
        delta = rtt - (INT32)pt->t_srtt;

        pt->t_srtt += (UINT32)(delta/8);
        if( (INT32)pt->t_srtt <= 0 )
            pt->t_srtt = 1 << TCP_FIXP_SHIFT;

        if( delta < 0 )
            delta = -delta;

        delta -= (INT32)pt->t_rttvar;
        pt->t_rttvar += (UINT32)(delta/4);
        if( (INT32)pt->t_rttvar <= 0 )
            pt->t_rttvar = 1 << (TCP_FIXP_SHIFT-2);

        rto = ( pt->t_srtt + 4 * pt->t_rttvar ) >> TCP_FIXP_SHIFT;
    }

    // Reset RTT timer
    pt->t_trtt     = 0;

    // Reset RTT backoff
    pt->t_rtxindex = 0;

    TCPT_RANGESET( pt->t_trtx, rto, TCPTV_RTXMIN, TCPTV_RTXMAX);
}

⌨️ 快捷键说明

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