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
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
Generated on Tue Jul 12 2022 18:53:40 by 1.7.2