Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: oldheating gps motorhome heating
tcp/tcpsend.c
- Committer:
- andrewboyson
- Date:
- 2018-11-17
- Revision:
- 83:08c983006a6e
- Parent:
- 82:20781198d26d
- Child:
- 87:40d46a979cdb
File content as of revision 83:08c983006a6e:
#include <stdint.h> #include <stdbool.h> #include "log.h" #include "net.h" #include "action.h" #include "tcp.h" #include "tcphdr.h" #include "tcb.h" #include "ip4.h" #include "dhcp.h" #include "http.h" #include "led.h" #include "tcpsend.h" #define TIMEOUT_RETRANSMISSION 2 #define MAX_RETRANSMISSIONS 10 #define TIMEOUT_KEEP_ALIVE 60 #define TIMEOUT_BROKEN_LINK 600 static int addApplicationData(void* pPacket, uint16_t port, uint32_t start, int mss, int todo) { int dataLength = 0; char* pData = (char*)pPacket + TcpHdrSizeGet(); switch (port) { case 80: HttpSendReply(&dataLength, pData, start, mss, todo); break; default: break; } return dataLength; } static int preparePacket(void* pPacket, struct tcb* pTcb, int dataLength, int* pSize) { //Set the acknowledge flag TcpHdrACK = true; //Swap the ports for the reply TcpHdrSrcPort = pTcb->locPort; TcpHdrDstPort = pTcb->remPort; //Specify the receive window size to not throttle TcpHdrWindow = 4000; //Write the header TcpHdrWriteToPacket(pPacket); //Calculate the size of the reply *pSize = TcpHdrSizeGet() + dataLength; return ActionMakeFromDestAndTrace(UNICAST, TcpDoTrace && NetTraceStack); } int TcpSend(int* pSize, void* pPacket, struct tcb* pTcb) { int dataLength = 0; TcpHdrMakeEmpty(); int locMss = *pSize - TcpHdrSizeGet(); switch (pTcb->state) { case TCB_SYN_RECEIVED: if (pTcb->bytesSentToRem == 0) { TcpHdrMssSet(locMss); TcpHdrSYN = true; } break; case TCB_ESTABLISHED: if (!pTcb->sentFin) { if (pTcb->bytesSentToRem - pTcb->bytesAckdByRem < pTcb->window) { if (pTcb->todo) { dataLength = addApplicationData(pPacket, pTcb->locPort, pTcb->bytesSentToRem - 1, pTcb->remMss, pTcb->todo); if (dataLength < pTcb->remMss) { TcpHdrFIN = true; pTcb->sentFin = true; } } else { if (pTcb->rcvdFin) { TcpHdrFIN = true; pTcb->sentFin = true; } } } } break; } //Handle the acknowledgement of received bytes bool rcvdSeqHasAdvanced = pTcb->bytesRcvdFromRem > pTcb->bytesAckdToRem; pTcb->bytesAckdToRem = pTcb->bytesRcvdFromRem; TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send //Specify the start of the data being sent uint32_t seqToSend = pTcb->bytesSentToRem; TcpHdrSeqNum = seqToSend + pTcb->locIsn; //Set up the start of the message before adding the bytes sent //Record the number of bytes sent uint32_t bytesToSend = 0; if (TcpHdrSYN) bytesToSend += 1; //Add one to acknowledge the SYN bytesToSend += dataLength; //Add the number of bytes received if (TcpHdrFIN) bytesToSend += 1; //Add one to acknowledge the FIN pTcb->bytesSentToRem += bytesToSend; //Only send a packet if have bytes or an acknowledgement to send if (!rcvdSeqHasAdvanced && !bytesToSend) return DO_NOTHING; return preparePacket(pPacket, pTcb, dataLength, pSize); } int TcpResendLastUnAcked(int* pSize, void *pPacket, struct tcb* pTcb) { int dataLength = 0; TcpHdrMakeEmpty(); int locMss = *pSize - TcpHdrSizeGet(); uint32_t seqNum = pTcb->bytesAckdByRem; switch (pTcb->state) { case TCB_SYN_RECEIVED: TcpHdrMssSet(locMss); TcpHdrSYN = true; break; case TCB_ESTABLISHED: case TCB_CLOSE_FIN_WAIT: if (pTcb->todo) { dataLength = addApplicationData(pPacket, pTcb->locPort, seqNum - 1, pTcb->remMss, pTcb->todo); if (dataLength < pTcb->remMss) { TcpHdrFIN = true; pTcb->sentFin = true; } } break; } TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send TcpHdrSeqNum = seqNum + pTcb->locIsn; //Set up the start of the message before adding the bytes sent return preparePacket(pPacket, pTcb, dataLength, pSize); } int TcpResendLastAck(int* pSize, void *pPacket, struct tcb* pTcb) { int dataLength = 0; TcpHdrMakeEmpty(); TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send TcpHdrSeqNum = pTcb->bytesSentToRem + pTcb->locIsn; //Set up the start of the message before adding the bytes sent return preparePacket(pPacket, pTcb, dataLength, pSize); } int TcpSendReset(int* pSize, void *pPacket, struct tcb* pTcb) { int dataLength = 0; TcpHdrMakeEmpty(); TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send TcpHdrSeqNum = pTcb->bytesSentToRem + pTcb->locIsn; //Set up the start of the message before adding the bytes sent TcpHdrRST = true; return preparePacket(pPacket, pTcb, dataLength, pSize); } int TcpSendClose(int* pSize, void *pPacket, struct tcb* pTcb) { int dataLength = 0; TcpHdrMakeEmpty(); TcpHdrFIN = true; pTcb->sentFin = true; pTcb->bytesSentToRem += 1; //For the FIN TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send TcpHdrSeqNum = pTcb->bytesSentToRem + pTcb->locIsn; //Set up the start of the message before adding the bytes sent return preparePacket(pPacket, pTcb, dataLength, pSize); } int TcpPollForPacketToSend(int* pSize, void* pPacket, int ipType, int* pRemArIndex, int* pLocIpScope) { //Loops around the TCBs, moving on if empty but staying if not the right type static struct tcb* pTcb = NULL; //Passing a pointer containing NULL to TcbGetNext causes it to return the first TCB static bool stay = false; if (!stay) pTcb = TcbGetNext(pTcb); stay = false; if (!pTcb->state) return DO_NOTHING; if (pTcb->ipType != ipType) { stay = true; return DO_NOTHING; } //Check and make available the remote AR index if (pTcb->remArIndex < 0) { if (TcpTrace) LogTimeF("TCP - Reaping TCB port %hu - missing remote AR index\r\n", pTcb->remPort); pTcb->state = TCB_EMPTY; return DO_NOTHING; } *pRemArIndex = pTcb->remArIndex; //Return the local IP scope if (pLocIpScope) *pLocIpScope = pTcb->locIpScope; //Close old ones if (TcbElapsed >= pTcb->timeLastRcvd + TIMEOUT_KEEP_ALIVE) { if (TcpTrace) LogTimeF("TCP - Closing TCB port %hu - after keep alive\r\n", pTcb->remPort); return TcpSendClose(pSize, pPacket, pTcb); } //Reap old ones if (TcbElapsed >= pTcb->timeLastRcvd + TIMEOUT_BROKEN_LINK) { if (TcpTrace) LogTimeF("TCP - Reaping TCB port %hu - broken link\r\n", pTcb->remPort); pTcb->state = TCB_EMPTY; return DO_NOTHING; } //Reset the RTO if all bytes are acknowledged if (pTcb->bytesSentToRem == pTcb->bytesAckdByRem) { pTcb->timeSendsBeingAcked = TcbElapsed; pTcb->countSendsNotAcked = 0; } //Check if have unacknowledged send bytes after the RTO if (TcbElapsed >= pTcb->timeSendsBeingAcked + TIMEOUT_RETRANSMISSION) { pTcb->countSendsNotAcked++; if (pTcb->countSendsNotAcked > MAX_RETRANSMISSIONS) { if (TcpTrace) { if (NetTraceNewLine) Log("\r\n"); LogTimeF("TCP - Resending seq %lu on port %hu reached maximum retransmissions\r\n", pTcb->bytesAckdByRem, pTcb->remPort); pTcb->state = TCB_EMPTY; return TcpSendReset(pSize, pPacket, pTcb); } } if (TcpTrace) { if (NetTraceNewLine) Log("\r\n"); LogTimeF("TCP - Resending seq %lu on port %hu waiting for ack of %lu bytes\r\n", pTcb->bytesAckdByRem, pTcb->remPort, pTcb->bytesSentToRem); } pTcb->timeSendsBeingAcked = TcbElapsed; return TcpResendLastUnAcked(pSize, pPacket, pTcb); } //If haven't had to do anything else then do a normal send return TcpSend(pSize, pPacket, pTcb); }