Andrew Boyson / net

Dependents:   oldheating gps motorhome heating

Committer:
andrewboyson
Date:
Tue Mar 31 10:52:21 2020 +0000
Revision:
164:84b20bcd0941
Parent:
163:f063e374cf2a
Child:
165:29a9e5f2eaef
Corrected a bug whereby a TCP connection which was closed by the client (FIN) without ever being used was not closed (FIN) and so the client would keep it alive until we ran out of TCP connections.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewboyson 74:c3756bfa960e 1 #include <stdint.h>
andrewboyson 74:c3756bfa960e 2 #include <stdbool.h>
andrewboyson 90:955f4c6e18a9 3 #include <stdarg.h>
andrewboyson 74:c3756bfa960e 4
andrewboyson 93:580fc113d9e9 5 #include "log.h"
andrewboyson 93:580fc113d9e9 6 #include "net.h"
andrewboyson 93:580fc113d9e9 7 #include "action.h"
andrewboyson 93:580fc113d9e9 8 #include "tcp.h"
andrewboyson 93:580fc113d9e9 9 #include "tcphdr.h"
andrewboyson 93:580fc113d9e9 10 #include "tcb.h"
andrewboyson 93:580fc113d9e9 11 #include "ip4.h"
andrewboyson 93:580fc113d9e9 12 #include "dhcp.h"
andrewboyson 159:3ebef2d02f7f 13 #include "http.h"
andrewboyson 159:3ebef2d02f7f 14 #include "https.h"
andrewboyson 93:580fc113d9e9 15 #include "led.h"
andrewboyson 74:c3756bfa960e 16 #include "tcpsend.h"
andrewboyson 93:580fc113d9e9 17 #include "mstimer.h"
andrewboyson 74:c3756bfa960e 18
andrewboyson 120:05b6d67a0cec 19 #define TIMEOUT_RETRANSMISSION_MS 700
andrewboyson 120:05b6d67a0cec 20 #define MAX_RETRANSMISSIONS 5
andrewboyson 120:05b6d67a0cec 21 #define TIMEOUT_BROKEN_LINK_MS 600000
andrewboyson 74:c3756bfa960e 22
andrewboyson 164:84b20bcd0941 23
andrewboyson 164:84b20bcd0941 24 static void led(int number)
andrewboyson 164:84b20bcd0941 25 {
andrewboyson 164:84b20bcd0941 26 switch (number)
andrewboyson 164:84b20bcd0941 27 {
andrewboyson 164:84b20bcd0941 28 case 0: Led1Set(0); Led2Set(0); Led3Set(0); break;
andrewboyson 164:84b20bcd0941 29 case 1: Led1Set(1); Led2Set(0); Led3Set(0); break;
andrewboyson 164:84b20bcd0941 30 case 2: Led1Set(0); Led2Set(1); Led3Set(0); break;
andrewboyson 164:84b20bcd0941 31 case 3: Led1Set(1); Led2Set(1); Led3Set(0); break;
andrewboyson 164:84b20bcd0941 32 case 4: Led1Set(0); Led2Set(0); Led3Set(1); break;
andrewboyson 164:84b20bcd0941 33 case 5: Led1Set(1); Led2Set(0); Led3Set(1); break;
andrewboyson 164:84b20bcd0941 34 case 6: Led1Set(0); Led2Set(1); Led3Set(1); break;
andrewboyson 164:84b20bcd0941 35 case 7: Led1Set(1); Led2Set(1); Led3Set(1); break;
andrewboyson 164:84b20bcd0941 36 }
andrewboyson 164:84b20bcd0941 37 }
andrewboyson 164:84b20bcd0941 38
andrewboyson 90:955f4c6e18a9 39 static void log(uint16_t remPort, char* fmt, ...)
andrewboyson 90:955f4c6e18a9 40 {
andrewboyson 90:955f4c6e18a9 41 if (TcpTrace)
andrewboyson 90:955f4c6e18a9 42 {
andrewboyson 90:955f4c6e18a9 43 if (NetTraceNewLine) Log("\r\n");
andrewboyson 90:955f4c6e18a9 44 LogTimeF("TCP port %hu - ", remPort);
andrewboyson 90:955f4c6e18a9 45 va_list argptr;
andrewboyson 90:955f4c6e18a9 46 va_start(argptr, fmt);
andrewboyson 90:955f4c6e18a9 47 LogV(fmt, argptr);
andrewboyson 90:955f4c6e18a9 48 va_end(argptr);
andrewboyson 90:955f4c6e18a9 49 Log("\r\n");
andrewboyson 90:955f4c6e18a9 50 }
andrewboyson 90:955f4c6e18a9 51 }
andrewboyson 90:955f4c6e18a9 52
andrewboyson 88:1ba13e6062a3 53 static bool doTrace(uint16_t port)
andrewboyson 88:1ba13e6062a3 54 {
andrewboyson 88:1ba13e6062a3 55 switch (port)
andrewboyson 88:1ba13e6062a3 56 {
andrewboyson 159:3ebef2d02f7f 57 case 80: return HttpGetTrace();
andrewboyson 159:3ebef2d02f7f 58 case 443: return HttpsGetTrace();
andrewboyson 146:0fc66d610fd6 59 default: return false;
andrewboyson 88:1ba13e6062a3 60 }
andrewboyson 88:1ba13e6062a3 61 }
andrewboyson 147:a6093b52e654 62
andrewboyson 159:3ebef2d02f7f 63 static bool addAppData(int *pDataLength, void* pPacket, int connection, uint16_t port, uint32_t windowPositionInStream, int windowSize, bool clientFinished)
andrewboyson 147:a6093b52e654 64 {
andrewboyson 159:3ebef2d02f7f 65 uint8_t* pWindow = (uint8_t*)pPacket + TcpHdrSizeGet();
andrewboyson 145:206bf0d073c7 66 bool finished = false;
andrewboyson 159:3ebef2d02f7f 67 *pDataLength = windowSize;
andrewboyson 75:603b10404183 68 switch (port)
andrewboyson 74:c3756bfa960e 69 {
andrewboyson 159:3ebef2d02f7f 70 case 80: finished = HttpResponse(connection, clientFinished, pDataLength, (char*)pWindow, windowPositionInStream); break;
andrewboyson 159:3ebef2d02f7f 71 case 443: finished = HttpsResponse(connection, clientFinished, pDataLength, pWindow, windowPositionInStream); break;
andrewboyson 144:6bd5c54efc7d 72 }
andrewboyson 145:206bf0d073c7 73 return finished;
andrewboyson 75:603b10404183 74 }
andrewboyson 89:9b765a67699b 75 static int preparePacket(void* pPacket, struct tcb* pTcb, int dataLength, int* pSize)
andrewboyson 75:603b10404183 76 {
andrewboyson 75:603b10404183 77 //Set the acknowledge flag
andrewboyson 75:603b10404183 78 TcpHdrACK = true;
andrewboyson 74:c3756bfa960e 79
andrewboyson 75:603b10404183 80 //Swap the ports for the reply
andrewboyson 89:9b765a67699b 81 TcpHdrSrcPort = pTcb->locPort;
andrewboyson 89:9b765a67699b 82 TcpHdrDstPort = pTcb->remPort;
andrewboyson 75:603b10404183 83
andrewboyson 75:603b10404183 84 //Specify the receive window size to not throttle
andrewboyson 75:603b10404183 85 TcpHdrWindow = 4000;
andrewboyson 75:603b10404183 86
andrewboyson 75:603b10404183 87 //Write the header
andrewboyson 75:603b10404183 88 TcpHdrWriteToPacket(pPacket);
andrewboyson 75:603b10404183 89
andrewboyson 75:603b10404183 90 //Calculate the size of the reply
andrewboyson 75:603b10404183 91 *pSize = TcpHdrSizeGet() + dataLength;
andrewboyson 75:603b10404183 92
andrewboyson 89:9b765a67699b 93 return ActionMakeFromDestAndTrace(UNICAST, doTrace(pTcb->locPort) && NetTraceStack);
andrewboyson 74:c3756bfa960e 94 }
andrewboyson 75:603b10404183 95 int TcpSend(int* pSize, void* pPacket, struct tcb* pTcb)
andrewboyson 74:c3756bfa960e 96 {
andrewboyson 74:c3756bfa960e 97 int dataLength = 0;
andrewboyson 74:c3756bfa960e 98 TcpHdrMakeEmpty();
andrewboyson 74:c3756bfa960e 99 int locMss = *pSize - TcpHdrSizeGet();
andrewboyson 74:c3756bfa960e 100 switch (pTcb->state)
andrewboyson 74:c3756bfa960e 101 {
andrewboyson 74:c3756bfa960e 102 case TCB_SYN_RECEIVED:
andrewboyson 74:c3756bfa960e 103 if (pTcb->bytesSentToRem == 0)
andrewboyson 74:c3756bfa960e 104 {
andrewboyson 74:c3756bfa960e 105 TcpHdrMssSet(locMss);
andrewboyson 74:c3756bfa960e 106 TcpHdrSYN = true;
andrewboyson 74:c3756bfa960e 107 }
andrewboyson 74:c3756bfa960e 108 break;
andrewboyson 74:c3756bfa960e 109
andrewboyson 74:c3756bfa960e 110 case TCB_ESTABLISHED:
andrewboyson 74:c3756bfa960e 111 if (!pTcb->sentFin)
andrewboyson 74:c3756bfa960e 112 {
andrewboyson 74:c3756bfa960e 113 if (pTcb->bytesSentToRem - pTcb->bytesAckdByRem < pTcb->window)
andrewboyson 74:c3756bfa960e 114 {
andrewboyson 156:be12b8fd5b21 115 bool finished = addAppData(&dataLength, pPacket, TcbGetId(pTcb), pTcb->locPort, pTcb->bytesSentToRem - 1, pTcb->remMss, pTcb->rcvdFin);
andrewboyson 145:206bf0d073c7 116 if (finished)
andrewboyson 74:c3756bfa960e 117 {
andrewboyson 144:6bd5c54efc7d 118 TcpHdrFIN = true;
andrewboyson 144:6bd5c54efc7d 119 pTcb->sentFin = true;
andrewboyson 74:c3756bfa960e 120 }
andrewboyson 74:c3756bfa960e 121 }
andrewboyson 74:c3756bfa960e 122 }
andrewboyson 74:c3756bfa960e 123 break;
andrewboyson 74:c3756bfa960e 124 }
andrewboyson 74:c3756bfa960e 125
andrewboyson 79:f50e02fb5c94 126 //Handle the acknowledgement of received bytes
andrewboyson 74:c3756bfa960e 127 bool rcvdSeqHasAdvanced = pTcb->bytesRcvdFromRem > pTcb->bytesAckdToRem;
andrewboyson 74:c3756bfa960e 128 pTcb->bytesAckdToRem = pTcb->bytesRcvdFromRem;
andrewboyson 79:f50e02fb5c94 129 TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send
andrewboyson 74:c3756bfa960e 130
andrewboyson 79:f50e02fb5c94 131 //Specify the start of the data being sent
andrewboyson 79:f50e02fb5c94 132 uint32_t seqToSend = pTcb->bytesSentToRem;
andrewboyson 79:f50e02fb5c94 133 TcpHdrSeqNum = seqToSend + pTcb->locIsn; //Set up the start of the message before adding the bytes sent
andrewboyson 74:c3756bfa960e 134
andrewboyson 74:c3756bfa960e 135 //Record the number of bytes sent
andrewboyson 74:c3756bfa960e 136 uint32_t bytesToSend = 0;
andrewboyson 74:c3756bfa960e 137 if (TcpHdrSYN) bytesToSend += 1; //Add one to acknowledge the SYN
andrewboyson 74:c3756bfa960e 138 bytesToSend += dataLength; //Add the number of bytes received
andrewboyson 74:c3756bfa960e 139 if (TcpHdrFIN) bytesToSend += 1; //Add one to acknowledge the FIN
andrewboyson 74:c3756bfa960e 140
andrewboyson 74:c3756bfa960e 141 pTcb->bytesSentToRem += bytesToSend;
andrewboyson 74:c3756bfa960e 142
andrewboyson 79:f50e02fb5c94 143 //Only send a packet if have bytes or an acknowledgement to send
andrewboyson 75:603b10404183 144 if (!rcvdSeqHasAdvanced && !bytesToSend) return DO_NOTHING;
andrewboyson 79:f50e02fb5c94 145
andrewboyson 89:9b765a67699b 146 return preparePacket(pPacket, pTcb, dataLength, pSize);
andrewboyson 75:603b10404183 147 }
andrewboyson 75:603b10404183 148 int TcpResendLastUnAcked(int* pSize, void *pPacket, struct tcb* pTcb)
andrewboyson 75:603b10404183 149 {
andrewboyson 75:603b10404183 150 int dataLength = 0;
andrewboyson 75:603b10404183 151 TcpHdrMakeEmpty();
andrewboyson 75:603b10404183 152 int locMss = *pSize - TcpHdrSizeGet();
andrewboyson 79:f50e02fb5c94 153 uint32_t seqNum = pTcb->bytesAckdByRem;
andrewboyson 75:603b10404183 154 switch (pTcb->state)
andrewboyson 74:c3756bfa960e 155 {
andrewboyson 75:603b10404183 156 case TCB_SYN_RECEIVED:
andrewboyson 75:603b10404183 157 TcpHdrMssSet(locMss);
andrewboyson 75:603b10404183 158 TcpHdrSYN = true;
andrewboyson 75:603b10404183 159 break;
andrewboyson 74:c3756bfa960e 160
andrewboyson 75:603b10404183 161 case TCB_ESTABLISHED:
andrewboyson 79:f50e02fb5c94 162 case TCB_CLOSE_FIN_WAIT:
andrewboyson 75:603b10404183 163 {
andrewboyson 156:be12b8fd5b21 164 bool finished = addAppData(&dataLength, pPacket, TcbGetId(pTcb), pTcb->locPort, seqNum - 1, pTcb->remMss, pTcb->rcvdFin);
andrewboyson 145:206bf0d073c7 165 if (finished)
andrewboyson 75:603b10404183 166 {
andrewboyson 75:603b10404183 167 TcpHdrFIN = true;
andrewboyson 75:603b10404183 168 pTcb->sentFin = true;
andrewboyson 75:603b10404183 169 }
andrewboyson 145:206bf0d073c7 170 break;
andrewboyson 75:603b10404183 171 }
andrewboyson 74:c3756bfa960e 172 }
andrewboyson 75:603b10404183 173
andrewboyson 75:603b10404183 174 TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send
andrewboyson 75:603b10404183 175 TcpHdrSeqNum = seqNum + pTcb->locIsn; //Set up the start of the message before adding the bytes sent
andrewboyson 79:f50e02fb5c94 176
andrewboyson 89:9b765a67699b 177 return preparePacket(pPacket, pTcb, dataLength, pSize);
andrewboyson 75:603b10404183 178 }
andrewboyson 75:603b10404183 179 int TcpResendLastAck(int* pSize, void *pPacket, struct tcb* pTcb)
andrewboyson 75:603b10404183 180 {
andrewboyson 75:603b10404183 181 int dataLength = 0;
andrewboyson 75:603b10404183 182 TcpHdrMakeEmpty();
andrewboyson 75:603b10404183 183 TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send
andrewboyson 75:603b10404183 184 TcpHdrSeqNum = pTcb->bytesSentToRem + pTcb->locIsn; //Set up the start of the message before adding the bytes sent
andrewboyson 75:603b10404183 185
andrewboyson 89:9b765a67699b 186 return preparePacket(pPacket, pTcb, dataLength, pSize);
andrewboyson 75:603b10404183 187 }
andrewboyson 75:603b10404183 188 int TcpSendReset(int* pSize, void *pPacket, struct tcb* pTcb)
andrewboyson 75:603b10404183 189 {
andrewboyson 75:603b10404183 190 int dataLength = 0;
andrewboyson 75:603b10404183 191 TcpHdrMakeEmpty();
andrewboyson 75:603b10404183 192 TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send
andrewboyson 75:603b10404183 193 TcpHdrSeqNum = pTcb->bytesSentToRem + pTcb->locIsn; //Set up the start of the message before adding the bytes sent
andrewboyson 75:603b10404183 194
andrewboyson 75:603b10404183 195 TcpHdrRST = true;
andrewboyson 75:603b10404183 196
andrewboyson 89:9b765a67699b 197 return preparePacket(pPacket, pTcb, dataLength, pSize);
andrewboyson 74:c3756bfa960e 198 }
andrewboyson 79:f50e02fb5c94 199 int TcpSendClose(int* pSize, void *pPacket, struct tcb* pTcb)
andrewboyson 79:f50e02fb5c94 200 {
andrewboyson 79:f50e02fb5c94 201 int dataLength = 0;
andrewboyson 79:f50e02fb5c94 202 TcpHdrMakeEmpty();
andrewboyson 79:f50e02fb5c94 203 TcpHdrFIN = true;
andrewboyson 79:f50e02fb5c94 204 pTcb->sentFin = true;
andrewboyson 79:f50e02fb5c94 205 pTcb->bytesSentToRem += 1; //For the FIN
andrewboyson 79:f50e02fb5c94 206 TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send
andrewboyson 79:f50e02fb5c94 207 TcpHdrSeqNum = pTcb->bytesSentToRem + pTcb->locIsn; //Set up the start of the message before adding the bytes sent
andrewboyson 79:f50e02fb5c94 208
andrewboyson 89:9b765a67699b 209 return preparePacket(pPacket, pTcb, dataLength, pSize);
andrewboyson 79:f50e02fb5c94 210 }
andrewboyson 79:f50e02fb5c94 211
andrewboyson 80:4ef1500fca1d 212 int TcpPollForPacketToSend(int* pSize, void* pPacket, int ipType, int* pRemArIndex, int* pLocIpScope)
andrewboyson 74:c3756bfa960e 213 {
andrewboyson 83:08c983006a6e 214 //Loops around the TCBs, moving on if empty but staying if not the right type
andrewboyson 79:f50e02fb5c94 215 static struct tcb* pTcb = NULL; //Passing a pointer containing NULL to TcbGetNext causes it to return the first TCB
andrewboyson 79:f50e02fb5c94 216 static bool stay = false;
andrewboyson 83:08c983006a6e 217 if (!stay) pTcb = TcbGetNext(pTcb);
andrewboyson 79:f50e02fb5c94 218 stay = false;
andrewboyson 78:9d8fc88df405 219 if (!pTcb->state) return DO_NOTHING;
andrewboyson 79:f50e02fb5c94 220 if (pTcb->ipType != ipType)
andrewboyson 79:f50e02fb5c94 221 {
andrewboyson 79:f50e02fb5c94 222 stay = true;
andrewboyson 79:f50e02fb5c94 223 return DO_NOTHING;
andrewboyson 79:f50e02fb5c94 224 }
andrewboyson 79:f50e02fb5c94 225
andrewboyson 163:f063e374cf2a 226 //Return the remote AR index and the local IP scope
andrewboyson 163:f063e374cf2a 227 if (pRemArIndex) *pRemArIndex = pTcb->remArIndex;
andrewboyson 80:4ef1500fca1d 228 if (pLocIpScope) *pLocIpScope = pTcb->locIpScope;
andrewboyson 87:40d46a979cdb 229
andrewboyson 163:f063e374cf2a 230 //Reap broken links
andrewboyson 133:a37eb35a03f1 231 if (MsTimerRelative(pTcb->timeLastRcvd, TIMEOUT_BROKEN_LINK_MS))
andrewboyson 79:f50e02fb5c94 232 {
andrewboyson 90:955f4c6e18a9 233 log(pTcb->remPort, "broken link -> reaping TCB");
andrewboyson 79:f50e02fb5c94 234 pTcb->state = TCB_EMPTY;
andrewboyson 79:f50e02fb5c94 235 return DO_NOTHING;
andrewboyson 79:f50e02fb5c94 236 }
andrewboyson 78:9d8fc88df405 237
andrewboyson 79:f50e02fb5c94 238 //Reset the RTO if all bytes are acknowledged
andrewboyson 79:f50e02fb5c94 239 if (pTcb->bytesSentToRem == pTcb->bytesAckdByRem)
andrewboyson 79:f50e02fb5c94 240 {
andrewboyson 93:580fc113d9e9 241 pTcb->timeSendsBeingAcked = MsTimerCount;
andrewboyson 82:20781198d26d 242 pTcb->countSendsNotAcked = 0;
andrewboyson 79:f50e02fb5c94 243 }
andrewboyson 75:603b10404183 244
andrewboyson 79:f50e02fb5c94 245 //Check if have unacknowledged send bytes after the RTO
andrewboyson 133:a37eb35a03f1 246 if (MsTimerRelative(pTcb->timeSendsBeingAcked, TIMEOUT_RETRANSMISSION_MS))
andrewboyson 75:603b10404183 247 {
andrewboyson 82:20781198d26d 248 pTcb->countSendsNotAcked++;
andrewboyson 82:20781198d26d 249 if (pTcb->countSendsNotAcked > MAX_RETRANSMISSIONS)
andrewboyson 82:20781198d26d 250 {
andrewboyson 164:84b20bcd0941 251 log(pTcb->remPort, "reached maximum retransmissions -> reaping TCB");
andrewboyson 90:955f4c6e18a9 252 pTcb->state = TCB_EMPTY;
andrewboyson 164:84b20bcd0941 253 return DO_NOTHING;
andrewboyson 82:20781198d26d 254 }
andrewboyson 90:955f4c6e18a9 255 else
andrewboyson 79:f50e02fb5c94 256 {
andrewboyson 90:955f4c6e18a9 257 log(pTcb->remPort, "only had ack of %lu while sent %lu -> resending", pTcb->bytesAckdByRem, pTcb->bytesSentToRem);
andrewboyson 93:580fc113d9e9 258 pTcb->timeSendsBeingAcked = MsTimerCount;
andrewboyson 90:955f4c6e18a9 259 return TcpResendLastUnAcked(pSize, pPacket, pTcb);
andrewboyson 79:f50e02fb5c94 260 }
andrewboyson 75:603b10404183 261 }
andrewboyson 90:955f4c6e18a9 262 else
andrewboyson 90:955f4c6e18a9 263 {
andrewboyson 90:955f4c6e18a9 264 //If haven't had to do anything else then do a normal send
andrewboyson 90:955f4c6e18a9 265 return TcpSend(pSize, pPacket, pTcb);
andrewboyson 90:955f4c6e18a9 266 }
andrewboyson 74:c3756bfa960e 267 }
andrewboyson 74:c3756bfa960e 268