diff --git a/src/UDPC_Deque.c b/src/UDPC_Deque.c index 7675b87..e1cee32 100644 --- a/src/UDPC_Deque.c +++ b/src/UDPC_Deque.c @@ -6,6 +6,10 @@ UDPC_Deque* UDPC_Deque_init(uint32_t alloc_size) { UDPC_Deque *deque = malloc(sizeof(UDPC_Deque)); + if(!deque) + { + return NULL; + } UDPC_Deque_clear(deque); deque->alloc_size = alloc_size; deque->buf = malloc(alloc_size); @@ -163,7 +167,12 @@ int UDPC_Deque_get_back(UDPC_Deque *deque, void **data, uint32_t *size) *data = malloc(*size); - if(deque->tail < *size) + if(deque->tail == 0) + { + memcpy(*data, &deque->buf[deque->alloc_size - *size], *size); + return returnValue; + } + else if(deque->tail < *size) { memcpy(data[*size - deque->tail], deque->buf, deque->tail); memcpy( @@ -172,9 +181,32 @@ int UDPC_Deque_get_back(UDPC_Deque *deque, void **data, uint32_t *size) *size - deque->tail); return returnValue; } + else + { + memcpy(*data, &deque->buf[deque->tail - *size], *size); + return returnValue; + } +} - memcpy(*data, &deque->buf[deque->tail - *size], *size); - return returnValue; +void* UDPC_Deque_get_back_ptr(UDPC_Deque *deque, uint32_t unitSize) +{ + if(deque->size < unitSize) + { + return NULL; + } + + if(deque->tail == 0 && deque->size >= unitSize) + { + return &deque->buf[deque->alloc_size - unitSize]; + } + else if(deque->tail < unitSize) + { + return NULL; + } + else + { + return &deque->buf[deque->tail - unitSize]; + } } int UDPC_Deque_get_front(UDPC_Deque *deque, void **data, uint32_t *size) @@ -203,9 +235,21 @@ int UDPC_Deque_get_front(UDPC_Deque *deque, void **data, uint32_t *size) *size - (deque->alloc_size - deque->head)); return returnValue; } + else + { + memcpy(*data, &deque->buf[deque->head], *size); + return returnValue; + } +} - memcpy(*data, &deque->buf[deque->head], *size); - return returnValue; +void* UDPC_Deque_get_front_ptr(UDPC_Deque *deque, uint32_t unitSize) +{ + if(deque->size < unitSize || deque->head + unitSize > deque->alloc_size) + { + return NULL; + } + + return &deque->buf[deque->head]; } void UDPC_Deque_pop_back(UDPC_Deque *deque, uint32_t size) @@ -294,6 +338,32 @@ int UDPC_Deque_index(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, void return 1; } +void* UDPC_Deque_index_ptr(UDPC_Deque *deque, uint32_t unitSize, uint32_t index) +{ + uint32_t pos = unitSize * index; + uint32_t abspos; + if(pos >= deque->size) + { + return NULL; + } + + if(pos + deque->head >= deque->alloc_size) + { + abspos = pos + deque->head - deque->alloc_size; + } + else + { + abspos = pos + deque->head; + } + + if(abspos + unitSize > deque->alloc_size) + { + return NULL; + } + + return &deque->buf[abspos]; +} + int UDPC_Deque_index_rev(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, void **out) { uint32_t pos = unitSize * (index + 1); @@ -328,6 +398,32 @@ int UDPC_Deque_index_rev(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, v return 1; } +void* UDPC_Deque_index_rev_ptr(UDPC_Deque *deque, uint32_t unitSize, uint32_t index) +{ + uint32_t pos = unitSize * (index + 1); + uint32_t abspos; + if(pos >= deque->size + unitSize) + { + return NULL; + } + + if(pos > deque->tail) + { + abspos = deque->alloc_size - (pos - deque->tail); + } + else + { + abspos = deque->tail - pos; + } + + if(abspos + unitSize > deque->alloc_size) + { + return NULL; + } + + return &deque->buf[abspos]; +} + int UDPC_Deque_remove(UDPC_Deque *deque, uint32_t unitSize, uint32_t index) { uint32_t pos = unitSize * index; diff --git a/src/UDPC_Deque.h b/src/UDPC_Deque.h index 54590a1..567ac78 100644 --- a/src/UDPC_Deque.h +++ b/src/UDPC_Deque.h @@ -60,6 +60,14 @@ uint32_t UDPC_Deque_get_used(UDPC_Deque *deque); */ int UDPC_Deque_get_back(UDPC_Deque *deque, void **data, uint32_t *size); +/*! + * \brief Get data ptr from back of deque + * The returned ptr is part of the Deque's internal buffer and must not be + * manually free'd; it will be free'd when the Deque itself is destroyed. + * \return non-null if tail of deque has contiguous data of size unitSize + */ +void* UDPC_Deque_get_back_ptr(UDPC_Deque *deque, uint32_t unitSize); + /*! * \brief Get data from front of deque * Data must be free'd after use as it was allocated with malloc. @@ -69,6 +77,14 @@ int UDPC_Deque_get_back(UDPC_Deque *deque, void **data, uint32_t *size); */ int UDPC_Deque_get_front(UDPC_Deque *deque, void **data, uint32_t *size); +/*! + * \brief Get data ptr from front of deque + * The returned ptr is part of the Deque's internal buffer and must not be + * manually free'd; it will be free'd when the Deque itself is destroyed. + * \return non-null if head of deque has contiguous data of size unitSize + */ +void* UDPC_Deque_get_front_ptr(UDPC_Deque *deque, uint32_t unitSize); + /*! * \brief "free" data from the back of the deque * If size is greater than data used, then all data will be "free"d. @@ -98,6 +114,15 @@ void UDPC_Deque_pop_front(UDPC_Deque *deque, uint32_t size); */ int UDPC_Deque_index(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, void **out); +/*! + * \brief Get a ptr to the indexed data at position unitSize * index + * The ptr will be indexed relative to the head of the Deque. + * The returned ptr is part of the Deque's internal buffer and will be free'd + * when the Deque is destroyed, so it should not be free'd directly. + * \return non-null if indexed data is a valid contiguous part of the buffer + */ +void* UDPC_Deque_index_ptr(UDPC_Deque *deque, uint32_t unitSize, uint32_t index); + /*! * \brief Get a unitSize sized chunk of data at position relative to tail * The out pointer will be malloc'd with size unitSize and will have a copy of @@ -109,6 +134,15 @@ int UDPC_Deque_index(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, void */ int UDPC_Deque_index_rev(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, void **out); +/*! + * \brief Get a ptr to the indexed data at position unitSize * index + * The ptr will be indexed relative to the tail of the Deque. + * The returned ptr is part of the Deque's internal buffer and will be free'd + * when the Deque is destroyed, so it should not be free'd directly. + * \return non-null if indexed data is a valid contiguous part of the buffer + */ +void* UDPC_Deque_index_rev_ptr(UDPC_Deque *deque, uint32_t unitSize, uint32_t index); + /*! * \brief Replaces the data at index with data at the end (if exists) * Note this will reduce the size of the Deque by unitSize amount. diff --git a/src/UDPConnection.c b/src/UDPConnection.c index a763e45..6f239a1 100644 --- a/src/UDPConnection.c +++ b/src/UDPConnection.c @@ -62,6 +62,8 @@ UDPC_Context* UDPC_init(uint16_t listenPort, int isClient) context->connected = UDPC_Deque_init(sizeof(UDPC_INTERNAL_ConnectionData) * (isClient != 0 ? 1 : UDPC_CD_AMOUNT)); + timespec_get(&context->lastUpdated, TIME_UTC); + return context; } @@ -166,6 +168,70 @@ const char* UDPC_get_error_str(uint32_t error) } } +void UDPC_update(UDPC_Context *ctx) +{ + // get dt + struct timespec ts; + timespec_get(&ts, TIME_UTC); + float dt = UDPC_ts_diff_to_seconds(&ts, &ctx->lastUpdated); + ctx->lastUpdated = ts; + + // check rtt + for(int x = 0; x * sizeof(UDPC_INTERNAL_ConnectionData) < ctx->connected->size; ++x) + { + // TODO after fixing Deque + } +} + +float UDPC_ts_diff_to_seconds(struct timespec *ts0, struct timespec *ts1) +{ + float sec = 0.0f; + if(!ts0 || !ts1) + { + return sec; + } + + if(ts0->tv_sec > ts1->tv_sec) + { + sec = ts0->tv_sec - ts1->tv_sec; + if(ts0->tv_nsec > ts1->tv_nsec) + { + sec += ((float)(ts0->tv_nsec - ts1->tv_nsec)) / 1000000000.0f; + } + else if(ts0->tv_nsec < ts1->tv_nsec) + { + sec -= 1.0f; + sec += ((float)(1000000000 + ts0->tv_nsec - ts1->tv_nsec)) / 1000000000.0f; + } + } + else if(ts0->tv_sec < ts1->tv_sec) + { + sec = ts1->tv_sec - ts0->tv_sec; + if(ts0->tv_nsec < ts1->tv_nsec) + { + sec += ((float)(ts1->tv_nsec - ts0->tv_nsec)) / 1000000000.0f; + } + else if(ts0->tv_nsec > ts1->tv_nsec) + { + sec -= 1.0f; + sec += ((float)(1000000000 + ts1->tv_nsec - ts0->tv_nsec)) / 1000000000.0f; + } + } + else + { + if(ts0->tv_nsec > ts1->tv_nsec) + { + sec += ((float)(ts0->tv_nsec - ts1->tv_nsec)) / 1000000000.0f; + } + else + { + sec += ((float)(ts1->tv_nsec - ts0->tv_nsec)) / 1000000000.0f; + } + } + + return sec; +} + int UDPC_INTERNAL_threadfn(void *context) { UDPC_Context *ctx = (UDPC_Context*)context; diff --git a/src/UDPConnection.h b/src/UDPConnection.h index 27f459e..d1ce977 100644 --- a/src/UDPConnection.h +++ b/src/UDPConnection.h @@ -20,11 +20,13 @@ #include #define CleanupSocket(x) close(x) +#else + #define CleanupSocket(x) ((void)0) #endif #define UDPC_CD_AMOUNT 32 -// This struct should not be used outside of this library +/// This struct should not be used outside of this library typedef struct { uint32_t addr; @@ -39,7 +41,7 @@ typedef struct struct timespec sent; } UDPC_INTERNAL_PacketInfo; -// This struct should not be used outside of this library +/// This struct should not be used outside of this library typedef struct { /* @@ -64,7 +66,7 @@ typedef struct struct timespec rtt; } UDPC_INTERNAL_ConnectionData; -// This struct should not be modified, only passed to functions that require it +/// This struct should not be modified, only passed to functions that require it typedef struct { /* @@ -84,6 +86,7 @@ typedef struct mtx_t tflagsMtx; cnd_t threadCV; UDPC_Deque *connected; + struct timespec lastUpdated; } UDPC_Context; UDPC_Context* UDPC_init(uint16_t listenPort, int isClient); @@ -96,6 +99,11 @@ uint32_t UDPC_get_error(UDPC_Context *ctx); const char* UDPC_get_error_str(uint32_t error); +/// If threaded, this function is called automatically +void UDPC_update(UDPC_Context *ctx); + +float UDPC_ts_diff_to_seconds(struct timespec *ts0, struct timespec *ts1); + int UDPC_INTERNAL_threadfn(void *context); // internal usage only #endif diff --git a/src/test/UDPC_UnitTest.c b/src/test/UDPC_UnitTest.c index 01d5f89..83115ee 100644 --- a/src/test/UDPC_UnitTest.c +++ b/src/test/UDPC_UnitTest.c @@ -36,11 +36,27 @@ int main() // push back success ASSERT_TRUE(UDPC_Deque_push_back(deque, arr, sizeof(int) * 4)); ASSERT_EQ_MEM(arr, deque->buf, sizeof(int) * 4); + ASSERT_EQ_MEM(arr, UDPC_Deque_get_back_ptr(deque, sizeof(int) * 4), sizeof(int) * 4); + ASSERT_EQ_MEM(arr, UDPC_Deque_get_front_ptr(deque, sizeof(int) * 4), sizeof(int) * 4); + for(int x = 0; x < 4; ++x) + { + ASSERT_EQ_MEM(&arr[x], UDPC_Deque_index_ptr(deque, sizeof(int), x), sizeof(int)); + ASSERT_EQ_MEM(&arr[3 - x], UDPC_Deque_index_rev_ptr(deque, sizeof(int), x), sizeof(int)); + } ASSERT_EQ(deque->size, sizeof(int) * 4); // push front success ASSERT_TRUE(UDPC_Deque_push_front(deque, &arr[4], sizeof(int) * 4)); ASSERT_EQ_MEM(&arr[4], &deque->buf[sizeof(int) * 12], sizeof(int) * 4); + ASSERT_EQ_MEM(arr, UDPC_Deque_get_back_ptr(deque, sizeof(int) * 4), sizeof(int) * 4); + ASSERT_EQ_MEM(&arr[4], UDPC_Deque_get_front_ptr(deque, sizeof(int) * 4), sizeof(int) * 4); + for(int x = 0; x < 4; ++x) + { + ASSERT_EQ_MEM(&arr[x + 4], UDPC_Deque_index_ptr(deque, sizeof(int), x), sizeof(int)); + ASSERT_EQ_MEM(&arr[x], UDPC_Deque_index_ptr(deque, sizeof(int), x + 4), sizeof(int)); + ASSERT_EQ_MEM(&arr[3 - x], UDPC_Deque_index_rev_ptr(deque, sizeof(int), x), sizeof(int)); + ASSERT_EQ_MEM(&arr[7 - x], UDPC_Deque_index_rev_ptr(deque, sizeof(int), x + 4), sizeof(int)); + } ASSERT_EQ(deque->size, sizeof(int) * 8); // realloc bigger success