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

📄 tcpout.c

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

//#define TCP_DEBUG

//
// TCP Flags Based on State
//
static UINT8 tcp_outflags[] = {
        TCP_RST | TCP_ACK,      // CLOSED
        0,                      // LISTEN
        TCP_SYN,                // SYNSENT
        TCP_SYN | TCP_ACK,      // SYNRCVD
        TCP_ACK,                // ESTAB
        TCP_ACK,                // CLOSEWAIT
        TCP_FIN|TCP_ACK,        // FINWAIT1
        TCP_FIN|TCP_ACK,        // CLOSING
        TCP_FIN|TCP_ACK,        // LASTACK
        TCP_ACK,                // FINWAIT2
        TCP_ACK };              // TIMEWAIT

//--------------------------------------------------------------------
// TcpOutput()
//
// Called when a TCP may need to be sent
//--------------------------------------------------------------------
int TcpOutput( TCPPROT *pt )
{
    int         sendmore, error = 0;
    INT32       mss,off,win,len,optlen,tmp,TxbTotal;
    UINT32      dwTmp;
    UINT8       flags;
    UINT8       opt[TCP_MAX_OPTIONS];
    HANDLE      hPkt,hFrag;
    uint        Offset,IPHdrLen;
    UINT8       *pb,*pPayload;
    TCPHDR      *pTcpHdr;

sendagain:
    sendmore = 0;

    // Get the total bytes left to send
    // We'll use this value several times
    TxbTotal = SBGetTotal( pt->hSBTx );

    // Get the mss
    // We compare the uint mss to UINT32 values quite a bit
    mss = (INT32)pt->t_mss;

    // Determine length of data to be transmitted
    // If there are some critical flags set, send

    // If we've been idle for longer than the current retransmit time,
    // go back to "slow start" by resetting the congestion window
    if( pt->snd_una==pt->snd_max && pt->t_tidle > pt->t_trtx )
        pt->snd_cwnd = mss;

    //
    // off = Offset from beginning of send buffer to the first byte to send
    // win = Min of adverstised or congestion window
    //
    off = pt->snd_nxt - pt->snd_una;
    win = (pt->snd_wnd < pt->snd_cwnd) ? pt->snd_wnd : pt->snd_cwnd;

    // Get default TCP flags based on the current state
    flags = tcp_outflags[ pt->t_state ];

    // Check for persist condition
    if( pt->t_flags & TF_PERSIST )
    {
        // If the window is still closed, open it window 1 byte
        // else reset the persist state.
        if( !win )
        {
            win = 1;

            // If there is more data to send, make sure FIN is not set
            if( off < TxbTotal )
                flags &= ~TCP_FIN;
        }
        else
        {
            // Clear Persist
            pt->t_flags &= ~TF_PERSIST;
            pt->dwTicksPersist = 0;
            pt->t_rtxindex     = 0;

            // Set NEEDOUTPUT to use what window is available
            // Otherwise we may decide not to send again!
            pt->t_flags |= TF_NEEDOUTPUT;
        }
    }

    //
    // Set len = the max number of bytes we can send this time
    // This is bound by the current send window, or the number of bytes
    // we have left to send.
    //
    if( win < TxbTotal )
        len = win - off;
    else
        len = TxbTotal - off;

    // Check for a problem (len < 0) - we sent too much
    if( len < 0 )
    {
        len = 0;

        // We are either in a normal FIN wait state:
        //         (win > off > TxbTotal) ,
        // or our send window shrank. If the window shrank to zero,
        // back up to last ACK'd data and turn off Rexmt. This will
        // cause us to drop into PERSIST if we don't send.
        if( !win )
        {
            pt->snd_nxt = pt->snd_una;
            pt->dwTicksRexmt = 0;
        }
    }

    // See if we have to bust up our send into multiple segments this pass
    if( len > mss )
    {
        len = mss;
        sendmore = 1;
    }

    // Clear any pending FIN flag if this isn't the last data to go
    if( SEQ_LT( pt->snd_nxt + len, pt->snd_una + TxbTotal ) )
        flags &= ~TCP_FIN;

    // Setup the window size we wish to advertise
    // This is the space we have left in the RX buffer
    // NOTE: "win" is now the ADVERTISED WINDOW SIZE
    win = SBGetSpace( pt->hSBRx );
    if( win < 0 )
        win = 0;
    if( win > TCP_MAXWIN )
        win = TCP_MAXWIN;

    //
    // Check for various send conditions
    //
    if( len )
    {
        // Send if we have a full segment
        if( len == mss )
            goto send;

        // If we're emptying out the send buffer and NOPUSH is not set, send
        if( !(pt->t_flags & TF_NOPUSH) && len+off >= TxbTotal )
            goto send;

        // If forced output (from persist or ENOBUFS), goto send
        if( pt->t_flags & (TF_PERSIST|TF_NEEDOUTPUT) )
            goto send;

        // If receiver's window is at least half open, send
        if( len >= (INT32)(pt->max_sndwnd/2) )
            goto send;

        // Send on a retransmit (here snd_nxt was set back to snd_una)
        if( SEQ_LT( pt->snd_nxt, pt->snd_max ) )
            goto send;
    }

    // Send if we must ACK
    if( pt->t_flags & TF_ACKNOW )
        goto send;

    // Send if we are sending the SYN or RST flag
    if( flags & (TCP_SYN | TCP_RST) )
        goto send;

    // Send if we have urgent data
    if( SEQ_GT( pt->snd_up, pt->snd_una ) )
        goto send;

    //
    // Check for Window Update Conditions
    //

    if( win > 0 )
    {
        // Get the number of bytes that our receive window has opened
        tmp = win - (pt->rcv_adv - pt->rcv_nxt);

        // If the window had opened by 2 segments, advertise new window
        if( tmp >= 2 * mss )
            goto send;

        // If the new window is at least half our receive buffer, advertise
        if( tmp >= SBGetMax(pt->hSBRx)/2 )
            goto send;
    }

    // Lastly, we'll send if FIN is set and we haven't sent it yet, or
    // if we're here because of a re-transmit
    if( (flags & TCP_FIN) &&
            ( !(pt->t_flags & TF_SENTFIN) || (pt->snd_nxt == pt->snd_una) ) )
        goto send;

    // If we get here, we were unable to send, or decided not to
    // send. We also know that we are not in the PERSIST state.
    // If there is data to send and there is no retransmit in progress,
    // then we'll go into PERSIST mode now to wait for a larger window.
    if( TxbTotal && !pt->dwTicksRexmt )
    {
        pt->t_rtxindex = 0;     // Reset backoff for initial persist
        TcpSetPersist( pt );    // Initialize Persist
    }

    return(0);

send:
    //
    // If we get here, we're going to send something
    //

    optlen = 0;

    // If SYN is being sent we'll also include MAXSEG
    if( flags & TCP_SYN )
    {
        // Reset sending sequence number to our assigned ISS
        pt->snd_nxt = pt->iss;

        // Validate the route and the route metrics for this socket.
        // This will return the MSS we advertise, but not the one
        // we actually restrict ourselves to.
        tmp = TcpValidateMetrics( pt, 0 );

        // Add in options if not disabled
        if( !(pt->t_flags & TF_NOOPT) )
        {
            // Send our max seg size
            opt[0] = TCPOPT_MAXSEG;     // TCPOPT_MAXSEG
            opt[1] = TCPOLEN_MAXSEG;    // MAXSEG Size
            opt[2] = (UINT8)(tmp >> 8);
            opt[3] = (UINT8)(tmp);
            optlen += 4;
        }
    }

    // Adjust send length to make room for options
    if( len > mss - optlen )
    {
        len = mss - optlen;
        sendmore = 1;
    }

    //
    // Create the packet
    // Payload = len
    // Reserve = TCPHDR_SIZE + optlen
    //
    if( !(hPkt = SockCreatePacket( pt->hSock, (uint)len,
                                   TCPHDR_SIZE+(uint)optlen )) )
    {
        //
        // Out of buffers condition
        //
        pt->t_flags |= TF_NEEDOUTPUT;
        tcps.dwSndNoBufs++;
        if( pt->t_state != TSTATE_ESTAB )
            return( ENOBUFS );
        else
            return( 0 );
    }

    // Get the frag
    hFrag = PktGetFrag( hPkt );

    // Get the buffer parameters
    pb = FragGetBufParams( hFrag, 0, 0, &Offset );

    // Get the IP header len
    IPHdrLen = PktGetSizeNet( hPkt );

    // Assign a UDP header pointer
    pTcpHdr = (TCPHDR *)(pb + Offset + IPHdrLen);

    // Get pointer to payload
    pPayload  = pb + Offset + IPHdrLen + TCPHDR_SIZE + optlen;

    //
    // Build the TCP Packet
    //
    if( len )
    {
        //
        // We're Sending Data
        //

        // Update the send type stats
        if( pt->t_flags & TF_PERSIST )
            tcps.dwSndProbe++;          // Window probes sent
        else if( SEQ_LT(pt->snd_nxt,pt->snd_max) )
        {
            tcps.dwSndRexmitPack++;     // Retransmit packets

⌨️ 快捷键说明

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