diff --git a/src/Deque.c b/src/Deque.c new file mode 100644 index 0000000..622d65a --- /dev/null +++ b/src/Deque.c @@ -0,0 +1,203 @@ +#include "Deque.h" + +#include +#include + +void UDPC_Deque_init(UDPC_Deque *deque, uint32_t alloc_size) +{ + deque->head = 0; + deque->tail = 0; + deque->size = 0; + deque->alloc_size = alloc_size; + deque->buf = malloc(alloc_size); +} + +int UDPC_Deque_push_back(UDPC_Deque *deque, const char *data, uint32_t size) +{ + if(deque->size + size > deque->alloc_size) + { + return 0; + } + else if(deque->tail + size <= deque->alloc_size) + { + memcpy(&deque->buf[deque->tail], data, size); + deque->tail += size; + if(deque->tail == deque->alloc_size) + { + deque->tail = 0; + } + deque->size += size; + + return 1; + } + + uint32_t temp; + + if(deque->tail < deque->alloc_size) + { + memcpy(&deque->buf[deque->tail], data, deque->alloc_size - deque->tail); + temp = deque->alloc_size - deque->tail; + deque->size += temp; + size -= temp; + deque->tail = 0; + } + if(size > 0) + { + memcpy(&deque->buf[deque->tail], &data[temp], size); + deque->tail += size; + deque->size += size; + } + return 1; +} + +int UDPC_Deque_push_front(UDPC_Deque *deque, const char *data, uint32_t size) +{ + if(deque->size + size > deque->alloc_size) + { + return 0; + } + else if(size <= deque->head) + { + memcpy(&deque->buf[deque->head - size], data, size); + deque->head -= size; + deque->size += size; + + return 1; + } + + if(deque->head > 0) + { + memcpy(deque->buf, &data[size - deque->head], deque->head); + deque->size += deque->head; + size -= deque->head; + deque->head = 0; + } + if(size > 0) + { + memcpy(&deque->buf[deque->alloc_size - size], data, size); + deque->head = deque->alloc_size - size; + deque->size += size; + } + return 1; +} + +uint32_t UDPC_Deque_get_available(UDPC_Deque *deque) +{ + return deque->alloc_size - deque->size; +} + +int UDPC_Deque_get_back(UDPC_Deque *deque, char **data, uint32_t *size) +{ + int returnValue = 1; + if(deque->size == 0) + { + *size = 0; + return 0; + } + else if(*size > deque->size) + { + *size = deque->size; + returnValue = 0; + } + + *data = malloc(*size); + + if(deque->tail < *size) + { + memcpy(data[*size - deque->tail], deque->buf, deque->tail); + memcpy( + *data, + &deque->buf[deque->alloc_size - (*size - deque->tail)], + *size - deque->tail); + return returnValue; + } + + memcpy(*data, &deque->buf[deque->tail - *size], *size); + return returnValue; +} + +int UDPC_Deque_get_front(UDPC_Deque *deque, char **data, uint32_t *size) +{ + int returnValue = 1; + if(deque->size == 0) + { + *size = 0; + return 0; + } + else if(*size > deque->size) + { + *size = deque->size; + returnValue = 0; + } + + *data = malloc(*size); + + if(deque->head + *size > deque->alloc_size) + { + memcpy(*data, &deque->buf[deque->head], deque->alloc_size - deque->head); + memcpy( + data[deque->alloc_size - deque->head], + deque->buf, + *size - (deque->alloc_size - deque->head)); + return returnValue; + } + + memcpy(*data, &deque->buf[deque->head], *size); + return returnValue; +} + +void UDPC_Deque_pop_back(UDPC_Deque *deque, uint32_t size) +{ + if(deque->size == 0) + { + return; + } + else if(deque->size <= size) + { + deque->head = 0; + deque->tail = 0; + deque->size = 0; + return; + } + + deque->size -= size; + + if(deque->tail < size) + { + deque->tail = deque->alloc_size - (size - deque->tail); + } + else + { + deque->tail -= size; + } +} + +void UDPC_Deque_pop_front(UDPC_Deque *deque, uint32_t size) +{ + if(deque->size == 0) + { + return; + } + else if(deque->size <= size) + { + deque->head = 0; + deque->tail = 0; + deque->size = 0; + return; + } + + deque->size -= size; + + if(deque->head + size > deque->alloc_size) + { + deque->head = deque->head + size - deque->alloc_size; + } + else + { + deque->head += size; + if(deque->head == deque->alloc_size) + { + deque->head = 0; + } + } +} diff --git a/src/Deque.h b/src/Deque.h new file mode 100644 index 0000000..dccc6f6 --- /dev/null +++ b/src/Deque.h @@ -0,0 +1,67 @@ +#ifndef UDPC_DEQUE_H +#define UDPC_DEQUE_H + +#include + +typedef struct +{ + uint32_t head; + uint32_t tail; + uint32_t size; + uint32_t alloc_size; + char *buf; +} UDPC_Deque; + +void UDPC_Deque_init(UDPC_Deque *deque, uint32_t alloc_size); + +/*! + * If there was not enough space in the Deque, then no data is inserted at all. + * \return non-zero on success (there was enough size to insert data) + */ +int UDPC_Deque_push_back(UDPC_Deque *deque, const char *data, uint32_t size); + +/*! + * If there was not enough space in the Deque, then no data is inserted at all. + * \return non-zero on success (there was enough size to insert data) + */ +int UDPC_Deque_push_front(UDPC_Deque *deque, const char *data, uint32_t size); + +uint32_t UDPC_Deque_get_available(UDPC_Deque *deque); + +/*! + * \brief Get data from back of deque + * Data must be free'd after use as it was allocated with malloc. + * When size is greater than deque size, partial data is allocated, size is + * updated to allocated amount. If deque is empty, no data is allocated. + * \return non-zero if full requested size was returned + */ +int UDPC_Deque_get_back(UDPC_Deque *deque, char **data, uint32_t *size); + +/*! + * \brief Get data from front of deque + * Data must be free'd after use as it was allocated with malloc. + * When size is greater than deque size, partial data is allocated, size is + * updated to allocated amount. If deque is empty, no data is allocated. + * \return non-zero if full requested size was returned + */ +int UDPC_Deque_get_front(UDPC_Deque *deque, char **data, uint32_t *size); + +/*! + * \brief "free" data from the back of the deque + * If size is greater than data used, then all data will be "free"d. + * Note that this doesn't actually deallocate data, but changes internal values + * that keep track of data positions in the internal buffer. The data will only + * actually be removed when it is overwritten or the Deque is free'd. + */ +void UDPC_Deque_pop_back(UDPC_Deque *deque, uint32_t size); + +/*! + * \brief "free" data from the front of the deque + * If size is greater than data used, then all data will be "free"d. + * Note that this doesn't actually deallocate data, but changes internal values + * that keep track of data positions in the internal buffer. The data will only + * actually be removed when it is overwritten or the Deque is free'd. + */ +void UDPC_Deque_pop_front(UDPC_Deque *deque, uint32_t size); + +#endif diff --git a/src/UDPConnection.c b/src/UDPConnection.c index df40274..0b6d33a 100644 --- a/src/UDPConnection.c +++ b/src/UDPConnection.c @@ -1,8 +1,6 @@ #include "UDPConnection.h" -#include - -UDPC_Context UDPC_init(unsigned short listenPort) +UDPC_Context UDPC_init(uint16_t listenPort) { UDPC_Context context; context.error = 0; @@ -45,6 +43,8 @@ UDPC_Context UDPC_init(unsigned short listenPort) DWORD nonblocking = 1; if(ioctlsocket(context.socketHandle, FIONBIO, &nonblocking) != 0) { +#else + { #endif context.error = UDPCON_ERR_SOCKETNONBF; CleanupSocket(context.socketHandle); @@ -56,7 +56,7 @@ UDPC_Context UDPC_init(unsigned short listenPort) return context; } -UDPC_Context UDPC_init_threaded_update(unsigned short listenPort) +UDPC_Context UDPC_init_threaded_update(uint16_t listenPort) { UDPC_Context context = UDPC_init(listenPort); diff --git a/src/UDPConnection.h b/src/UDPConnection.h index 036a4f5..bccf6b0 100644 --- a/src/UDPConnection.h +++ b/src/UDPConnection.h @@ -3,6 +3,8 @@ #include #include +#include +#include #define UDPC_PLATFORM_WINDOWS 1 #define UDPC_PLATFORM_MAC 2 @@ -39,29 +41,69 @@ #define UDPCON_ERR_CVFAIL 5 // failed to create condition variable #define UDPCON_ERR_THREADFAIL 6 // failed to create thread +// This struct should not be used outside of this library +typedef struct +{ + uint32_t addr; + uint32_t id; + /* + * 0x1 - is resending + * 0x2 - is not received checked + * 0x4 - has been re-sent + */ + uint32_t flags; + char *data; + struct timespec sent; +} UDPC_INTERNAL_PacketInfo; + +// This struct should not be used outside of this library +typedef struct +{ + /* + * 0x1 - trigger send + * 0x2 - is good mode + * 0x4 - is good rtt + */ + uint32_t flags; + uint32_t id; + uint32_t lseq; + uint32_t rseq; + uint32_t ack; + float timer; + float toggleT; + float toggleTimer; + float toggledTimer; + uint16_t port; + UDPC_INTERNAL_PacketInfo *sentPkts; + UDPC_INTERNAL_PacketInfo *sendPktQueue; + struct timespec received; + struct timespec sent; + struct timespec rtt; +} UDPC_INTERNAL_ConnectionData; + // This struct should not be modified, only passed to functions that require it typedef struct { - int error; + /* + * 0x1 - is threaded + */ + uint32_t flags; + /* + * 0x1 - thread should stop + */ + uint32_t threadFlags; + uint32_t error; int socketHandle; struct sockaddr_in socketInfo; thrd_t threadHandle; mtx_t tCVMtx; mtx_t tflagsMtx; cnd_t threadCV; - /* - * 0x1 - is threaded - */ - int flags; - /* - * 0x1 - thread should stop - */ - int threadFlags; } UDPC_Context; -UDPC_Context UDPC_init(unsigned short listenPort); +UDPC_Context UDPC_init(uint16_t listenPort); -UDPC_Context UDPC_init_threaded_update(unsigned short listenPort); +UDPC_Context UDPC_init_threaded_update(uint16_t listenPort); void UDPC_destroy(UDPC_Context *ctx);