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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers tcpsend.c Source File

tcpsend.c

00001 #include <stdint.h>
00002 #include <stdbool.h>
00003 #include <stdarg.h>
00004 
00005 #include     "log.h"
00006 #include     "net.h"
00007 #include  "action.h"
00008 #include     "tcp.h"
00009 #include  "tcphdr.h"
00010 #include     "tcb.h"
00011 #include     "ip4.h"
00012 #include    "dhcp.h"
00013 #include   "httpv.h"
00014 #include   "https.h"
00015 #include     "led.h"
00016 #include "tcpsend.h"
00017 #include "mstimer.h"
00018 
00019 #define TIMEOUT_RETRANSMISSION_MS  700
00020 #define MAX_RETRANSMISSIONS          5
00021 #define TIMEOUT_BROKEN_LINK_MS  600000
00022 
00023 static void log(uint16_t remPort, char* fmt, ...)
00024 {
00025     if (TcpTrace)
00026     {
00027         if (NetTraceNewLine) Log("\r\n");
00028         LogTimeF("TCP port %hu - ", remPort);
00029         va_list argptr;
00030         va_start(argptr, fmt);
00031         LogV(fmt, argptr);
00032         va_end(argptr);
00033         Log("\r\n");
00034     }
00035 }
00036 
00037 static bool doTrace(uint16_t port)
00038 {
00039     switch (port)
00040     {
00041         case  80: return HttpvGetTrace();
00042         case 443: return HttpsGetTrace();
00043         default:  return false;
00044     }    
00045 }
00046 
00047 static bool addAppData(int *pDataLength, void* pPacket, int connection, uint16_t port, uint32_t windowPositionInStream, int windowSize, bool clientFinished)
00048 {
00049     uint8_t* pWindow = (uint8_t*)pPacket + TcpHdrSizeGet();
00050     bool finished = false;
00051     *pDataLength = windowSize;
00052     switch (port)
00053     {
00054         case  80: finished = HttpvResponse(connection, clientFinished, pDataLength, pWindow, windowPositionInStream); break;
00055         case 443: finished = HttpsResponse(connection, clientFinished, pDataLength, pWindow, windowPositionInStream); break;
00056     }
00057     return finished;
00058 }
00059 static int preparePacket(void* pPacket, struct tcb* pTcb, int dataLength, int* pSize)
00060 {
00061     //Set the acknowledge flag
00062     TcpHdrACK = true;
00063     
00064     //Swap the ports for the reply
00065     TcpHdrSrcPort = pTcb->locPort;
00066     TcpHdrDstPort = pTcb->remPort;
00067     
00068     //Specify the receive window size to not throttle
00069     TcpHdrWindow = 4000;
00070     
00071     //Write the header
00072     TcpHdrWriteToPacket(pPacket);
00073     
00074     //Calculate the size of the reply
00075     *pSize = TcpHdrSizeGet() + dataLength;
00076     
00077     return ActionMakeFromDestAndTrace(UNICAST, doTrace(pTcb->locPort) && NetTraceStack);
00078 }
00079 int TcpSend(int* pSize, void* pPacket, struct tcb* pTcb)
00080 {
00081     int dataLength = 0;
00082     TcpHdrMakeEmpty();
00083     int locMss = *pSize - TcpHdrSizeGet();
00084     switch (pTcb->state)
00085     {
00086         case TCB_SYN_RECEIVED:
00087             if (pTcb->bytesSentToRem == 0)
00088             {
00089                 TcpHdrMssSet(locMss);
00090                 TcpHdrSYN = true;
00091             }
00092             break;
00093             
00094         case TCB_ESTABLISHED:
00095             if (!pTcb->sentFin)
00096             {
00097                 if (pTcb->bytesSentToRem - pTcb->bytesAckdByRem < pTcb->window)
00098                 {
00099                     bool finished = addAppData(&dataLength, pPacket, TcbGetId(pTcb), pTcb->locPort, pTcb->bytesSentToRem - 1, pTcb->remMss, pTcb->rcvdFin);
00100                     if (finished)
00101                     {
00102                         TcpHdrFIN     = true;
00103                         pTcb->sentFin = true;
00104                     }
00105                 }
00106             }
00107             break;
00108     }
00109 
00110     //Handle the acknowledgement of received bytes
00111     bool rcvdSeqHasAdvanced = pTcb->bytesRcvdFromRem > pTcb->bytesAckdToRem;
00112     pTcb->bytesAckdToRem = pTcb->bytesRcvdFromRem;
00113     TcpHdrAckNum  = pTcb->bytesAckdToRem + pTcb->remIsn;  //Set up the acknowledgement field ready to send
00114     
00115     //Specify the start of the data being sent
00116     uint32_t seqToSend = pTcb->bytesSentToRem;
00117     TcpHdrSeqNum  = seqToSend            + pTcb->locIsn;  //Set up the start of the message before adding the bytes sent
00118 
00119     //Record the number of bytes sent
00120     uint32_t bytesToSend = 0;
00121     if (TcpHdrSYN) bytesToSend += 1;            //Add one to acknowledge the SYN
00122                    bytesToSend += dataLength;   //Add the number of bytes received
00123     if (TcpHdrFIN) bytesToSend += 1;            //Add one to acknowledge the FIN
00124 
00125     pTcb->bytesSentToRem += bytesToSend;
00126     
00127     //Only send a packet if have bytes or an acknowledgement to send
00128     if (!rcvdSeqHasAdvanced && !bytesToSend) return DO_NOTHING;
00129         
00130     return preparePacket(pPacket, pTcb, dataLength, pSize);
00131 }
00132 int TcpResendLastUnAcked(int* pSize, void *pPacket, struct tcb* pTcb)
00133 {
00134     int dataLength = 0;
00135     TcpHdrMakeEmpty();
00136     int locMss = *pSize - TcpHdrSizeGet();
00137     uint32_t seqNum = pTcb->bytesAckdByRem;
00138     switch (pTcb->state)
00139     {
00140         case TCB_SYN_RECEIVED:
00141             TcpHdrMssSet(locMss);
00142             TcpHdrSYN = true;
00143             break;
00144             
00145         case TCB_ESTABLISHED:
00146         case TCB_CLOSE_FIN_WAIT:
00147             {
00148                 bool finished = addAppData(&dataLength, pPacket, TcbGetId(pTcb), pTcb->locPort, seqNum - 1, pTcb->remMss, pTcb->rcvdFin);
00149                 if (finished)
00150                 {
00151                     TcpHdrFIN     = true;
00152                     pTcb->sentFin = true;
00153                 }
00154                 break;
00155             }
00156     }
00157 
00158     TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn;  //Set up the acknowledgement field ready to send
00159     TcpHdrSeqNum = seqNum               + pTcb->locIsn;  //Set up the start of the message before adding the bytes sent
00160     
00161     return preparePacket(pPacket, pTcb, dataLength, pSize);
00162 }
00163 int TcpResendLastAck(int* pSize, void *pPacket, struct tcb* pTcb)
00164 {
00165     int dataLength = 0;
00166     TcpHdrMakeEmpty();
00167     TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn;  //Set up the acknowledgement field ready to send
00168     TcpHdrSeqNum = pTcb->bytesSentToRem + pTcb->locIsn;  //Set up the start of the message before adding the bytes sent
00169     
00170     return preparePacket(pPacket, pTcb, dataLength, pSize);
00171 }
00172 int TcpSendReset(int* pSize, void *pPacket, struct tcb* pTcb)
00173 {
00174     int dataLength = 0;
00175     TcpHdrMakeEmpty();
00176     TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn;  //Set up the acknowledgement field ready to send
00177     TcpHdrSeqNum = pTcb->bytesSentToRem + pTcb->locIsn;  //Set up the start of the message before adding the bytes sent
00178     
00179     TcpHdrRST = true;
00180     
00181     return preparePacket(pPacket, pTcb, dataLength, pSize);
00182 }
00183 int TcpSendClose(int* pSize, void *pPacket, struct tcb* pTcb)
00184 {
00185     int dataLength = 0;
00186     TcpHdrMakeEmpty();
00187     TcpHdrFIN     = true;
00188     pTcb->sentFin = true;
00189     pTcb->bytesSentToRem += 1; //For the FIN
00190     TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn;  //Set up the acknowledgement field ready to send
00191     TcpHdrSeqNum = pTcb->bytesSentToRem + pTcb->locIsn;  //Set up the start of the message before adding the bytes sent
00192     
00193     return preparePacket(pPacket, pTcb, dataLength, pSize);
00194 }
00195 
00196 int TcpPollForPacketToSend(int* pSize, void* pPacket, int ipType, int* pRemArIndex, int* pLocIpScope)
00197 {
00198     //Loops around the TCBs, moving on if empty but staying if not the right type
00199     static struct tcb* pTcb = NULL; //Passing a pointer containing NULL to TcbGetNext causes it to return the first TCB
00200     static bool stay = false;
00201     if (!stay) pTcb = TcbGetNext(pTcb);
00202     stay = false;
00203     if (!pTcb->state) return DO_NOTHING;
00204     if (pTcb->ipType != ipType)
00205     {
00206         stay = true;
00207         return DO_NOTHING;
00208     }
00209 
00210     //Return the remote AR index and the local IP scope
00211     if (pRemArIndex) *pRemArIndex = pTcb->remArIndex;
00212     if (pLocIpScope) *pLocIpScope = pTcb->locIpScope;
00213             
00214     //Reap broken links 
00215     if (MsTimerRelative(pTcb->timeLastRcvd, TIMEOUT_BROKEN_LINK_MS))
00216     {
00217         log(pTcb->remPort, "broken link -> reaping TCB");
00218         pTcb->state = TCB_EMPTY;
00219         return DO_NOTHING;
00220     }
00221     
00222     //Reset the RTO if all bytes are acknowledged
00223     if (pTcb->bytesSentToRem == pTcb->bytesAckdByRem)
00224     {
00225         pTcb->timeSendsBeingAcked = MsTimerCount;
00226         pTcb->countSendsNotAcked  = 0;
00227     }
00228     
00229     //Check if have unacknowledged send bytes after the RTO
00230     if (MsTimerRelative(pTcb->timeSendsBeingAcked, TIMEOUT_RETRANSMISSION_MS))
00231     {
00232         pTcb->countSendsNotAcked++;
00233         if (pTcb->countSendsNotAcked > MAX_RETRANSMISSIONS)
00234         {
00235             log(pTcb->remPort, "reached maximum retransmissions -> reaping TCB");
00236             pTcb->state = TCB_EMPTY;
00237             return DO_NOTHING;
00238         }
00239         else
00240         {
00241             log(pTcb->remPort, "only had ack of %lu while sent %lu -> resending", pTcb->bytesAckdByRem, pTcb->bytesSentToRem);
00242             pTcb->timeSendsBeingAcked = MsTimerCount;
00243             return TcpResendLastUnAcked(pSize, pPacket, pTcb);
00244         }
00245     }
00246     else
00247     {
00248         //If haven't had to do anything else then do a normal send
00249         return TcpSend(pSize, pPacket, pTcb);
00250     }
00251 }
00252