// // Created by epagris on 2023.01.16.. // #include #include #include "tcp_window.h" #include "../../../dynmem.h" #define MIN(a,b) (((a) < (b)) ? (a) : (b)) TcpWindow *tcpw_create(uint32_t size) { uint32_t allocSize = sizeof(TcpWindow) + size; // calculate full allocation size TcpWindow * tcpw = (TcpWindow *) dynmem_alloc(allocSize); // allocate data block at the end memset(tcpw, 0, sizeof(TcpWindow)); tcpw->size = size; return tcpw; } void tcpw_destroy(TcpWindow * tcpw) { dynmem_free(tcpw); } void tcpw_set_seqnum_offset(TcpWindow * tcpw, uint32_t offset) { tcpw->firstByteOffset = offset; tcpw->nextWritten = offset; tcpw->firstUnACK = offset; } static inline uint32_t tcpw_get_occupied_size(TcpWindow * tcpw) { return tcpw->nextWritten - tcpw->firstUnACK; } uint32_t tcpw_get_max_window_size(TcpWindow * tcpw) { return tcpw->size - tcpw_get_occupied_size(tcpw); } uint32_t tcpw_store(TcpWindow * tcpw, const uint8_t * data, uint32_t size, uint32_t seqNum) { // check that seqNum is the continuation of the previous content if (seqNum != (tcpw->nextWritten)) { // if not, then cannot store return 0; } // calculate copy size, limit if required uint32_t freeArea = tcpw_get_max_window_size(tcpw); uint32_t copySize = MIN(size, freeArea); // determine first block size uint32_t nextWriteIndex = (tcpw->nextWritten - tcpw->firstByteOffset); // determinte next write index uint32_t spaceToBufEnd = tcpw->size - nextWriteIndex; // space to buffer end uint32_t firstBlockSize = MIN(spaceToBufEnd, copySize); // first block size uint32_t secondBlockSize = (firstBlockSize < copySize) ? copySize - firstBlockSize : 0; // second block size memcpy(tcpw->data + nextWriteIndex, data, firstBlockSize); // copy first block if (secondBlockSize > 0) { // copy second block if needed memcpy(tcpw->data, data + firstBlockSize, secondBlockSize); } // adjust indices tcpw->nextWritten += copySize; // advance next written if ((tcpw->nextWritten - tcpw->firstByteOffset) >= tcpw->size) { // advance first byte offset tcpw->firstByteOffset -= tcpw->size; } return copySize; } bool tcpw_acknowledge(TcpWindow * tcpw, uint32_t ackNum) { bool invalid = tcpw_get_occupied_size(tcpw) == 0 || // storage is empty ackNum > (tcpw->firstUnACK + tcpw_get_occupied_size(tcpw)); // acknowledgement sequence number exceeds what we have stored if (invalid) { return false; } tcpw->firstUnACK = ackNum; return true; }