A stack which works with or without an Mbed os library. Provides IPv4 or IPv6 with a full 1500 byte buffer.

Dependents:   oldheating gps motorhome heating

tcp/tcprecv.c

Committer:
andrewboyson
Date:
2018-10-30
Revision:
75:603b10404183
Parent:
74:c3756bfa960e
Child:
76:17534bde28d3

File content as of revision 75:603b10404183:

#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>

#include     "log.h"
#include     "net.h"
#include  "action.h"
#include     "tcp.h"
#include  "tcphdr.h"
#include "tcpsend.h"
#include     "tcb.h"
#include     "ip4.h"
#include    "dhcp.h"
#include    "http.h"
#include     "led.h"

//Payload variables
static struct tcb* pTcb;

static void logReset(char* message)
{
    if (TcpTrace) { LogTime("TCP sent RST - "); Log(message); Log("\r\n"); }
}

static void logTraceBack(void (*traceback)(void), char* fmt, ...)
{
    if (TcpTrace)
    {
        if (NetTraceNewLine) Log("\r\n");
        va_list argptr;
        va_start(argptr, fmt);
        LogV(fmt, argptr);
        va_end(argptr);
        Log("\r\n");
        if (NetTraceStack) traceback();
    }
}

static void startConnection(void *pPacket, int ipType, int remArIndex, int locMss)
{
    //Get the MSS to use for sends - it is the lower of the MSS advertised by the remote host and our local MSS
    int remMss = TcpHdrMssGet();
    pTcb->remMss = remMss ? remMss : 536; //default MSS for IPv4 [576 - 20(TCP) - 20(IP)];
    if (pTcb->remMss > locMss) pTcb->remMss = locMss;
    
    pTcb->lastSendTime     = TcbElapsed;
    pTcb->remArIndex       = remArIndex;
    pTcb->ipType           = ipType;
    pTcb->remPort          = TcpHdrSrcPort;
    pTcb->locPort          = TcpHdrDstPort;
    pTcb->rcvdFin          = false;
    pTcb->sentFin          = false;
    pTcb->window           = TcpHdrWindow;
    pTcb->todo             = 0;
    pTcb->remIsn           = TcpHdrSeqNum;
    pTcb->locIsn           = TcbGetIsn();
    pTcb->bytesRcvdFromRem = 0;
    pTcb->bytesAckdByRem   = 0;
    pTcb->bytesAckdToRem   = 0;
    pTcb->bytesSentToRem   = 0;
}
static void handleReceivedData(void* pPacket, int dataLength, uint32_t position)
{
    pTcb->window = TcpHdrWindow;
    char* pData = (char*)pPacket + TcpHdrSizeGet();
    switch (pTcb->locPort)
    {
        case 80:
            HttpHandleRequest(dataLength, pData, position, &pTcb->todo);
            break;
        default:
            break;
    }
}

int TcpHandleReceivedPacket(void (*traceback)(void), int sizeRx, void* pPacketRx, int* pSizeTx, void* pPacketTx, int ipType, int remArIndex)
{
    TcpHdrReadFromPacket(pPacketRx);
    
    int dataLength =   sizeRx - TcpHdrSizeGet();
    int locMss     = *pSizeTx - TcpHdrSizeGet();
        
    TcpDoTrace = false;
    
    //Filter out unwanted links
    switch (TcpHdrDstPort)
    {
        case 80:
            if (HttpTrace)
            {
                if (NetTraceNewLine) Log("\r\n");
                LogTime("HTTP server request\r\n");
                TcpDoTrace = true;
            }
            break;
            
        default:
            logTraceBack(traceback, "TCP - unknown port %d\r\n", TcpHdrDstPort);
            return DO_NOTHING; //Ignore unknown ports
    }
    
    //Get the existing Transmission Control Block
    pTcb = TcbGetExisting(TcpHdrSrcPort);
    
    //Handle request to reset
    if (TcpHdrRST)
    {
        if (pTcb)
        {
            logTraceBack(traceback, "TCP - received reset - resetting TCB\r\n");
            pTcb->state = TCB_EMPTY;
        }
        return DO_NOTHING;        //Don't reply
    }
    
    //Handle request to synchronise
    if (TcpHdrSYN)
    {
        if (pTcb)
        {
            logReset("received a SYN when connection open");
            pTcb->state = TCB_EMPTY;
            return TcpSendReset(pSizeTx, pPacketTx, pTcb);
        }
        pTcb = TcbGetEmpty();
        if (!pTcb) //Bomb out if no more tcbs are available
        {
            logTraceBack(traceback, "TCP - no more tcbs are available\r\n");
            return DO_NOTHING;
        }
        startConnection(pPacketRx, ipType, remArIndex, locMss);
    }
    
    //Check window and just resend the last ACK if not good
    uint32_t seqRcvdFromRem = TcpHdrSeqNum - pTcb->remIsn;
    bool resendAck = seqRcvdFromRem != pTcb->bytesAckdToRem;
    if (resendAck) return TcpResendLastAck(pSizeTx, pPacketTx, pTcb);
    
    //Record the number of bytes acked by the remote host
    pTcb->bytesAckdByRem = TcpHdrAckNum - pTcb->locIsn;
    
    //Handle FIN
    if (TcpHdrFIN) pTcb->rcvdFin = true; //When reply is all sent only a passive close is needed
        
    if (TcpDoTrace && NetTraceStack) traceback(); //This will already include the TCP header
    
    //Record the number of bytes received from the remote host
    if (TcpHdrSYN) pTcb->bytesRcvdFromRem += 1;          //Add one to acknowledge the SYN
                   pTcb->bytesRcvdFromRem += dataLength; //Add the number of bytes received
    if (TcpHdrFIN) pTcb->bytesRcvdFromRem += 1;          //Add one to acknowledge the FIN

    switch (pTcb->state)
    {
        case TCB_EMPTY:
            pTcb->state = TCB_SYN_RECEIVED;
            break;
            
        case TCB_SYN_RECEIVED:
            if (dataLength)
            {
                logReset("data received before connection established");
                pTcb->state = TCB_EMPTY;
                return TcpSendReset(pSizeTx, pPacketTx, pTcb);
            }
            pTcb->state = TCB_ESTABLISHED;
            break;
            
        case TCB_ESTABLISHED:
            if (dataLength) handleReceivedData (pPacketRx, dataLength, seqRcvdFromRem - 1);
            if (pTcb->sentFin)
            {
                pTcb->state = pTcb->rcvdFin ? TCB_CLOSE_ACK_WAIT : TCB_CLOSE_FIN_WAIT;
            }
            break;
            
        case TCB_CLOSE_FIN_WAIT: //End of active close
            if (TcpHdrFIN)
            {
                pTcb->state = TCB_EMPTY;//Ignore ACK to our FIN. Wait for FIN then close.
            }
            break;
            
        case TCB_CLOSE_ACK_WAIT: //End of passive close
            pTcb->state = TCB_EMPTY;
            break;
    }
    
    return TcpSend(pSizeTx, pPacketTx, pTcb);
}