+++ /dev/null
-build*/
-compile_commands.json
+++ /dev/null
-cmake_minimum_required(VERSION 3.7)
-project(UDPConnection)
-
-set(UDPConnection_VERSION 1.0)
-
-set(UDPConnection_SOURCES
- src/UDPConnection.c
- src/UDPC_Deque.c
- src/UDPC_HashMap.c
-)
-
-set(CMAKE_C_FLAGS "-Wall -Wno-missing-braces")
-set(CMAKE_C_FLAGS_DEBUG "-O0 -g")
-set(CMAKE_C_FLAGS_RELEASE "-O3 -D NDEBUG")
-
-if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
- message(STATUS "Setting build type to 'Debug', none was specified.")
- set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE)
- set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release")
-endif()
-
-add_library(UDPConnection ${UDPConnection_SOURCES})
-
-set_target_properties(UDPConnection PROPERTIES VERSION ${UDPConnection_VERSION})
-
-target_compile_features(UDPConnection PUBLIC c_std_11)
-target_link_libraries(UDPConnection PUBLIC pthread)
-
-if(CMAKE_BUILD_TYPE MATCHES "Debug")
- set(UDPC_UnitTest_SOURCES
- src/test/UDPC_UnitTest.c)
- add_executable(UnitTest ${UDPC_UnitTest_SOURCES})
- target_link_libraries(UnitTest PUBLIC UDPConnection)
- target_include_directories(UnitTest PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
-
- set(UDPC_NetworkTest_SOURCES
- src/test/UDPC_NetworkTest.c)
- add_executable(NetworkTest ${UDPC_NetworkTest_SOURCES})
- target_link_libraries(NetworkTest PUBLIC UDPConnection)
- target_include_directories(NetworkTest PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
-endif()
-
-install(TARGETS UDPConnection DESTINATION lib)
-install(FILES
- ${CMAKE_CURRENT_SOURCE_DIR}/src/UDPConnection.h
- ${CMAKE_CURRENT_SOURCE_DIR}/src/UDPC_Defines.h
- ${CMAKE_CURRENT_SOURCE_DIR}/src/UDPC_Deque.h
- ${CMAKE_CURRENT_SOURCE_DIR}/src/UDPC_HashMap.h
- DESTINATION include)
+++ /dev/null
-#ifndef UDPC_DEFINES_H
-#define UDPC_DEFINES_H
-
-#define UDPC_PLATFORM_WINDOWS 1
-#define UDPC_PLATFORM_MAC 2
-#define UDPC_PLATFORM_LINUX 3
-#define UDPC_PLATFORM_UNKNOWN 0
-
-#if defined _WIN32
- #define UDPC_PLATFORM UDPC_PLATFORM_WINDOWS
-#elif defined __APPLE__
- #define UDPC_PLATFORM UDPC_PLATFORM_MAC
-#elif defined __linux__
- #define UDPC_PLATFORM UDPC_PLATFORM_LINUX
-#else
- #define UDPC_PLATFORM UDPC_PLATFORM_UNKNOWN
-#endif
-
-#define UDPC_SUCCESS 0
-#define UDPC_ERR_SOCKETFAIL 1 // failed to create socket
-#define UDPC_ERR_SOCKETBINDF 2 // failed to bind socket
-#define UDPC_ERR_SOCKETNONBF 3 // failed to set non-blocking on socket
-#define UDPC_ERR_MTXFAIL 4 // failed to create mutex
-#define UDPC_ERR_CVFAIL 5 // failed to create condition variable
-#define UDPC_ERR_THREADFAIL 6 // failed to create thread
-
-// Error strings are defined in UDPConnection.c
-extern const char *UDPC_ERR_SOCKETFAIL_STR;
-extern const char *UDPC_ERR_SOCKETBINDF_STR;
-extern const char *UDPC_ERR_SOCKETNONBF_STR;
-extern const char *UDPC_ERR_MTXFAIL_STR;
-extern const char *UDPC_ERR_CVFAIL_STR;
-extern const char *UDPC_ERR_THREADFAIL_STR;
-
-#define UDPC_CD_AMOUNT 32
-
-#define UDPC_GOOD_MODE_SEND_INTERVAL (1.0f/30.0f)
-#define UDPC_BAD_MODE_SEND_INTERVAL (1.0f/10.0f)
-#define UDPC_TIMEOUT_SECONDS 10.0f
-#define UDPC_HEARTBEAT_PKT_INTERVAL (15.0f/100.0f)
-#define UDPC_INIT_PKT_INTERVAL 5
-#define UDPC_INIT_PKT_INTERVAL_F ((float)UDPC_INIT_PKT_INTERVAL)
-#define UDPC_PKT_DEFAULT_PROTOCOL_ID 1357924680
-
-#define UDPC_ID_CONNECT 0x80000000
-#define UDPC_ID_PING 0x40000000
-#define UDPC_ID_NO_REC_CHK 0x20000000
-#define UDPC_ID_RESENDING 0x10000000
-
-#define UDPC_SENT_PKTS_MAX_SIZE 34
-#define UDPC_SENT_PKTS_ALLOC_SIZE 35
-#define UDPC_SEND_PKTS_ALLOC_SIZE 40
-#define UDPC_RESEND_PKTS_ALLOC_SIZE 40
-
-#define UDPC_PACKET_MAX_SIZE 8192
-
-#define UDPC_PACKET_TIMEOUT_SEC 1.0f
-#define UDPC_GOOD_RTT_LIMIT_SEC 0.25f
-
-#define UDPC_REC_PKTS_ALLOC_SIZE 128
-
-#define UDPC_CONNECTED_EVENT_SIZE 64
-#define UDPC_DISCONNECTED_EVENT_SIZE 64
-
-#endif
+++ /dev/null
-#include "UDPC_Deque.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-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);
- if(deque->buf)
- {
- return deque;
- }
- else
- {
- free(deque);
- return NULL;
- }
-}
-
-void UDPC_Deque_destroy(UDPC_Deque *deque)
-{
- free(deque->buf);
- free(deque);
-}
-
-int UDPC_Deque_realloc(UDPC_Deque *deque, uint32_t new_size)
-{
- if(new_size < deque->size)
- {
- return 0;
- }
- else if(deque->size != 0 && deque->tail <= deque->head)
- {
- char *buf = malloc(new_size);
- memcpy(buf, &deque->buf[deque->head], deque->alloc_size - deque->head);
- if(deque->tail != 0)
- {
- memcpy(&buf[deque->alloc_size - deque->head], deque->buf, deque->tail);
- }
- free(deque->buf);
- deque->buf = buf;
- deque->alloc_size = new_size;
- deque->head = 0;
- deque->tail = deque->size;
- if(deque->tail == deque->alloc_size)
- {
- deque->tail = 0;
- }
- return 1;
- }
- else
- {
- void *buf = realloc(deque->buf, new_size);
- if(buf)
- {
- deque->buf = buf;
- deque->alloc_size = new_size;
- return 1;
- }
- else
- {
- return 0;
- }
- }
-}
-
-int UDPC_Deque_push_back(UDPC_Deque *deque, const void *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], &((const char*)data)[temp], size);
- deque->tail += size;
- deque->size += size;
- }
- return 1;
-}
-
-int UDPC_Deque_push_front(UDPC_Deque *deque, const void *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, &((const char*)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;
-}
-
-int UDPC_Deque_push_back_realloc(UDPC_Deque *deque, const void *data, uint32_t size)
-{
- if(UDPC_Deque_push_back(deque, data, size) == 0)
- {
- if(UDPC_Deque_realloc(deque, deque->alloc_size * 2) != 0)
- {
- return UDPC_Deque_push_back(deque, data, size);
- }
- }
- return 0;
-}
-
-int UDPC_Deque_push_front_realloc(UDPC_Deque *deque, const void *data, uint32_t size)
-{
- if(UDPC_Deque_push_front(deque, data, size) == 0)
- {
- if(UDPC_Deque_realloc(deque, deque->alloc_size * 2) != 0)
- {
- return UDPC_Deque_push_front(deque, data, size);
- }
- }
- return 0;
-}
-
-uint32_t UDPC_Deque_get_available(UDPC_Deque *deque)
-{
- return deque->alloc_size - deque->size;
-}
-
-uint32_t UDPC_Deque_get_used(UDPC_Deque *deque)
-{
- return deque->size;
-}
-
-int UDPC_Deque_get_back(UDPC_Deque *deque, void **data, uint32_t *size)
-{
- int returnValue = 1;
- if(deque->size == 0)
- {
- *size = 0;
- *data = NULL;
- return 0;
- }
- else if(*size > deque->size)
- {
- *size = deque->size;
- returnValue = 0;
- }
-
- *data = malloc(*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(
- *data,
- &deque->buf[deque->alloc_size - (*size - deque->tail)],
- *size - deque->tail);
- return returnValue;
- }
- else
- {
- 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)
-{
- int returnValue = 1;
- if(deque->size == 0)
- {
- *size = 0;
- *data = NULL;
- 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;
- }
- else
- {
- 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)
-{
- if(deque->size == 0)
- {
- return;
- }
- else if(deque->size <= size)
- {
- UDPC_Deque_clear(deque);
- 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)
- {
- UDPC_Deque_clear(deque);
- 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;
- }
- }
-}
-
-int UDPC_Deque_index(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, void **out)
-{
- uint32_t pos = unitSize * index;
- uint32_t abspos;
- if(pos >= deque->size)
- {
- *out = NULL;
- return 0;
- }
-
- *out = malloc(unitSize);
-
- 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)
- {
- memcpy(*out, &deque->buf[abspos], deque->alloc_size - abspos);
- memcpy(*out, deque->buf, unitSize - (deque->alloc_size - abspos));
- }
- else
- {
- memcpy(*out, &deque->buf[abspos], unitSize);
- }
-
- 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);
- uint32_t abspos;
- if(pos >= deque->size + unitSize)
- {
- *out = NULL;
- return 0;
- }
-
- *out = malloc(unitSize);
-
- if(pos > deque->tail)
- {
- abspos = deque->alloc_size - (pos - deque->tail);
- }
- else
- {
- abspos = deque->tail - pos;
- }
-
- if(abspos + unitSize >= deque->alloc_size)
- {
- memcpy(*out, &deque->buf[abspos], deque->alloc_size - abspos);
- memcpy(*out, deque->buf, unitSize - (deque->alloc_size - abspos));
- }
- else
- {
- memcpy(*out, &deque->buf[abspos], unitSize);
- }
-
- 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;
- uint32_t abspos;
- uint32_t lastpos;
- if(deque->size == 0 || pos >= deque->size)
- {
- return 0;
- }
- else if(deque->size <= unitSize)
- {
- UDPC_Deque_clear(deque);
- return 1;
- }
-
- if(pos + deque->head >= deque->alloc_size)
- {
- abspos = pos + deque->head - deque->alloc_size;
- }
- else
- {
- abspos = pos + deque->head;
- }
-
- if(deque->tail == 0)
- {
- lastpos = deque->alloc_size - unitSize;
- }
- else
- {
- lastpos = deque->tail - unitSize;
- }
-
- if(abspos != lastpos)
- {
- if(deque->tail == 0)
- {
- memcpy(&deque->buf[abspos], &deque->buf[deque->alloc_size - unitSize], unitSize);
- deque->tail = deque->alloc_size - unitSize;
- }
- else
- {
- memcpy(&deque->buf[abspos], &deque->buf[deque->tail - unitSize], unitSize);
- deque->tail -= unitSize;
- }
- deque->size -= unitSize;
- }
- else
- {
- UDPC_Deque_pop_back(deque, unitSize);
- }
-
- return 1;
-}
-
-void UDPC_Deque_clear(UDPC_Deque *deque)
-{
- deque->head = 0;
- deque->tail = 0;
- deque->size = 0;
-}
+++ /dev/null
-#ifndef UDPC_DEQUE_H
-#define UDPC_DEQUE_H
-
-#include <stdint.h>
-
-typedef struct {
- uint32_t head;
- uint32_t tail;
- uint32_t size;
- uint32_t alloc_size;
- char *buf;
-} UDPC_Deque;
-
-/*!
- * \return non-null on success
- */
-UDPC_Deque* UDPC_Deque_init(uint32_t alloc_size);
-
-/*!
- * Frees resources used by a UDPC_Deque
- */
-void UDPC_Deque_destroy(UDPC_Deque *deque);
-
-/*!
- * Fails if new_size is smaller than current size of Deque.
- * On failure, deque remains unchanged.
- * \return non-zero on success
- */
-int UDPC_Deque_realloc(UDPC_Deque *deque, uint32_t new_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 void *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 void *data, uint32_t size);
-
-/*!
- * \brief Same as push_back, but realloc if not enough free space
- * Note when realloc occurs, the allocated space is doubled.
- * \return non-zero on data pushed into Deque success
- */
-int UDPC_Deque_push_back_realloc(UDPC_Deque *deque, const void *data, uint32_t size);
-
-/*!
- * \brief Same as push_front, but realloc if not enough free space
- * Note when realloc occurs, the allocated space is doubled.
- * \return non-zero on data pushed into Deque success
- */
-int UDPC_Deque_push_front_realloc(UDPC_Deque *deque, const void *data, uint32_t size);
-
-/*!
- * \return size in bytes of available data
- */
-uint32_t UDPC_Deque_get_available(UDPC_Deque *deque);
-
-/*!
- * \return size in bytes of used data
- */
-uint32_t UDPC_Deque_get_used(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, 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.
- * 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, 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.
- * 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);
-
-/*!
- * \brief Get a unitSize sized chunk of data at position unitSize * index
- * The data will be indexed relative to the head of the Deque.
- * The out pointer will be malloc'd with size unitSize and will have a copy of
- * the data at the specified unitSize * index.
- * Note that the out data must be free'd, but on fail nothing will be malloc'd
- * and *out will be set to NULL.
- * \return non-zero if unitSize * index < 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
- * the data at the specified unitSize * index relative to tail in reverse
- * direction.
- * Note that the out data must be free'd, but on fail nothing will be malloc'd
- * and *out will be set to NULL.
- * \return non-zero if unitSize * index < size
- */
-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.
- * \return non-zero if data was removed
- */
-int UDPC_Deque_remove(UDPC_Deque *deque, uint32_t unitSize, uint32_t index);
-
-void UDPC_Deque_clear(UDPC_Deque *deque);
-
-#endif
+++ /dev/null
-#include "UDPC_HashMap.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-UDPC_HashMap* UDPC_HashMap_init(uint32_t capacity, uint32_t unitSize)
-{
- UDPC_HashMap *m = malloc(sizeof(UDPC_HashMap));
- if(!m)
- {
- return NULL;
- }
-
- int fail = 0;
- m->size = 0;
- m->capacity = (capacity > UDPC_HASHMAP_INIT_CAPACITY ? capacity : UDPC_HASHMAP_INIT_CAPACITY);
- m->unitSize = unitSize;
-
- m->buckets = malloc(sizeof(UDPC_HashMap_Node*) * m->capacity);
- if(!m->buckets)
- {
- free(m);
- return NULL;
- }
-
- for(int x = 0; x < m->capacity; ++x)
- {
- if(fail != 0)
- {
- m->buckets[x] = NULL;
- continue;
- }
- m->buckets[x] = calloc(1, sizeof(UDPC_HashMap_Node));
- if(!m->buckets[x])
- {
- fail = 1;
- }
- }
-
- if(fail != 0)
- {
- for(int x = 0; x < m->capacity; ++x)
- {
- if(m->buckets[x])
- {
- free(m->buckets[x]);
- }
- }
- free(m->buckets);
- free(m);
- return NULL;
- }
-
- return m;
-}
-
-void UDPC_HashMap_destroy(UDPC_HashMap *hashMap)
-{
- UDPC_HashMap_Node *current;
- UDPC_HashMap_Node *next;
- for(int x = 0; x < hashMap->capacity; ++x)
- {
- current = hashMap->buckets[x];
- while(current)
- {
- next = current->next;
- if(current->data) { free(current->data); }
- free(current);
- current = next;
- }
- }
- free(hashMap->buckets);
- free(hashMap);
-}
-
-void* UDPC_HashMap_insert(UDPC_HashMap *hm, uint32_t key, void *data)
-{
- if(hm->capacity <= hm->size)
- {
- if(UDPC_HashMap_realloc(hm, hm->capacity * 2) == 0)
- {
- return NULL;
- }
- }
-
- uint32_t hash = UDPC_HASHMAP_MOD(key, hm->capacity);
-
- UDPC_HashMap_Node *current = hm->buckets[hash];
- while(current->next)
- {
- current = current->next;
- }
- current->next = malloc(sizeof(UDPC_HashMap_Node));
- current->next->key = key;
- if(hm->unitSize != 0)
- {
- current->next->data = malloc(hm->unitSize);
- memcpy(current->next->data, data, hm->unitSize);
- }
- else
- {
- current->next->data = NULL;
- }
- current->next->next = NULL;
- current->next->prev = current;
-
- ++hm->size;
- return current->next->data;
-}
-
-int UDPC_HashMap_remove(UDPC_HashMap *hm, uint32_t key)
-{
- if(hm->size == 0)
- {
- return 0;
- }
-
- uint32_t hash = UDPC_HASHMAP_MOD(key, hm->capacity);
-
- UDPC_HashMap_Node *current = hm->buckets[hash]->next;
- while(current && current->key != key)
- {
- current = current->next;
- }
-
- if(!current) { return 0; }
-
- current->prev->next = current->next;
- if(current->next) { current->next->prev = current->prev; }
-
- if(current->data) { free(current->data); }
- free(current);
-
- --hm->size;
-
- return 1;
-}
-
-void* UDPC_HashMap_get(UDPC_HashMap *hm, uint32_t key)
-{
- if(hm->size == 0)
- {
- return NULL;
- }
-
- uint32_t hash = UDPC_HASHMAP_MOD(key, hm->capacity);
-
- UDPC_HashMap_Node *current = hm->buckets[hash];
- while(current && (current == hm->buckets[hash] || current->key != key))
- {
- current = current->next;
- }
-
- if(!current) { return NULL; }
-
- return current->data;
-}
-
-int UDPC_HashMap_has(UDPC_HashMap *hm, uint32_t key)
-{
- if(hm->size == 0)
- {
- return 0;
- }
-
- uint32_t hash = UDPC_HASHMAP_MOD(key, hm->capacity);
-
- UDPC_HashMap_Node *current = hm->buckets[hash];
- while(current && (current == hm->buckets[hash] || current->key != key))
- {
- current = current->next;
- }
-
- return current != NULL ? 1 : 0;
-}
-
-int UDPC_HashMap_realloc(UDPC_HashMap *hm, uint32_t newCapacity)
-{
- if(hm->size > newCapacity)
- {
- return 0;
- }
-
- // allocate newBuckets
- int fail = 0;
- UDPC_HashMap_Node **newBuckets = malloc(sizeof(UDPC_HashMap_Node*) * newCapacity);
- if(!newBuckets) { return 0; }
- for(int x = 0; x < newCapacity; ++x)
- {
- if(fail != 0) { newBuckets[x] = NULL; continue; }
- newBuckets[x] = calloc(1, sizeof(UDPC_HashMap_Node));
- if(!newBuckets[x]) { fail = 1; }
- }
- if(fail != 0)
- {
- for(int x = 0; x < newCapacity; ++x)
- {
- if(newBuckets[x]) { free(newBuckets[x]); }
- }
- free(newBuckets);
- return 0;
- }
-
- // rehash entries from hm->buckets to newBuckets
- uint32_t hash;
- UDPC_HashMap_Node *current;
- UDPC_HashMap_Node *next;
- UDPC_HashMap_Node *newCurrent;
- for(int x = 0; x < hm->capacity; ++x)
- {
- current = hm->buckets[x]->next;
- while(current)
- {
- next = current->next;
- hash = UDPC_HASHMAP_MOD(current->key, newCapacity);
- newCurrent = newBuckets[hash];
- while(newCurrent->next)
- {
- newCurrent = newCurrent->next;
- }
- newCurrent->next = malloc(sizeof(UDPC_HashMap_Node));
- if(!newCurrent->next)
- {
- fail = 1;
- break;
- }
- newCurrent->next->key = current->key;
- newCurrent->next->data = current->data;
- newCurrent->next->next = NULL;
- newCurrent->next->prev = newCurrent;
- current = next;
- }
- if(fail != 0)
- {
- break;
- }
- }
- if(fail != 0)
- {
- for(int x = 0; x < newCapacity; ++x)
- {
- current = newBuckets[x];
- while(current)
- {
- next = current->next;
- free(current);
- current = next;
- }
- }
- free(newBuckets);
- return 0;
- }
-
- // cleanup hm->buckets to be replaced by newBuckets
- for(int x = 0; x < hm->capacity; ++x)
- {
- current = hm->buckets[x];
- while(current)
- {
- next = current->next;
- // do not free current->data as it is now being pointed to by entries in newBuckets
- free(current);
- current = next;
- }
- }
- free(hm->buckets);
-
- hm->capacity = newCapacity;
- hm->buckets = newBuckets;
-
- return 1;
-}
-
-void UDPC_HashMap_clear(UDPC_HashMap *hm)
-{
- UDPC_HashMap_Node *current;
- UDPC_HashMap_Node *next;
- for(int x = 0; x < hm->capacity; ++x)
- {
- current = hm->buckets[x]->next;
- while(current)
- {
- next = current->next;
- if(current->data) { free(current->data); }
- free(current);
- current = next;
- }
- hm->buckets[x]->next = NULL;
- }
- hm->size = 0;
-}
-
-uint32_t UDPC_HashMap_get_size(UDPC_HashMap *hm)
-{
- return hm->size;
-}
-
-uint32_t UDPC_HashMap_get_capacity(UDPC_HashMap *hm)
-{
- return hm->capacity;
-}
-
-void UDPC_HashMap_itercall(UDPC_HashMap *hm, void (*fn)(void*, uint32_t, char*), void *userData)
-{
- UDPC_HashMap_Node *current;
- for(int x = 0; x < hm->capacity; ++x)
- {
- current = hm->buckets[x]->next;
- while(current)
- {
- fn(userData, current->key, current->data);
- current = current->next;
- }
- }
-}
+++ /dev/null
-#ifndef UDPC_HASHMAP_H
-#define UDPC_HASHMAP_H
-
-#include <stdint.h>
-
-// 5 8 2 7 3 6 1
-// 3 2 5 1 8 7 6
-#define UDPC_HASH32(x) ( \
- ( \
- (((x) & 0xF8000000) >> 5) | \
- (((x) & 0x07F80000) >> 6) | \
- (((x) & 0x00060000) << 10) | \
- (((x) & 0x0001FC00) >> 4) | \
- (((x) & 0x00000380) << 22) | \
- (((x) & 0x0000007E) >> 1) | \
- (((x) & 0x00000001) << 21) \
- ) ^ 0x96969696 \
-)
-
-#define UDPC_HASHMAP_INIT_CAPACITY 13
-
-#define UDPC_HASHMAP_MOD(k, m) ((UDPC_HASH32(k) % (m * 2 + 1)) % m)
-
-struct UDPC_HashMap_Node {
- uint32_t key;
- char *data;
- struct UDPC_HashMap_Node *next;
- struct UDPC_HashMap_Node *prev;
-};
-typedef struct UDPC_HashMap_Node UDPC_HashMap_Node;
-
-typedef struct {
- uint32_t size;
- uint32_t capacity;
- uint32_t unitSize;
- UDPC_HashMap_Node **buckets;
-} UDPC_HashMap;
-
-/*!
- * \brief Creates a HashMap structure
- * Note that UDPC_HashMap_destroy must be called on the returned ptr to free
- * resources to avoid a memory leak.
- * \return non-null if creating the HashMap was successful
- */
-UDPC_HashMap* UDPC_HashMap_init(uint32_t capacity, uint32_t unitSize);
-
-/*!
- * \brief Releases resources used by a HashMap structure
- */
-void UDPC_HashMap_destroy(UDPC_HashMap *hashMap);
-
-/*!
- * \brief Inserts a copy of data pointed to by given pointer
- * Note if size already equals capacity, the hash map's capacity is doubled
- * with UDPC_HashMap_realloc(). realloc requires rehashing of all items which
- * may be costly.
- * Also, if the hash map runs out of space for a specific key to insert, it will
- * also invoke realloc() with double the previous capacity and will attempt to
- * insert again afterwards.
- * It is possible to insert items with duplicate keys. In that case, the first
- * duplicate inserted will be the first returned with get() and first removed
- * with remove().
- * \return Pointer to inserted data, NULL on fail or unitSize = 0
- */
-void* UDPC_HashMap_insert(UDPC_HashMap *hm, uint32_t key, void *data);
-
-/*!
- * \brief Removes data with the given key
- * \return non-zero if data was successfully removed
- */
-int UDPC_HashMap_remove(UDPC_HashMap *hm, uint32_t key);
-
-/*!
- * \brief Returns a pointer to data with the given key
- * Note if unitSize == 0, then the returned pointer will point to a copy of
- * its integer key, which should not be changed manually (otherwise, the hash
- * map would not be able to find it).
- * \return non-NULL if data was found and unitSize != 0
- */
-void* UDPC_HashMap_get(UDPC_HashMap *hm, uint32_t key);
-
-/*!
- * \return non-zero if item with specified key is in the hash map
- */
-int UDPC_HashMap_has(UDPC_HashMap *hm, uint32_t key);
-
-/*!
- * \brief Resizes the maximum capacity of a hash map
- * Note on fail, the hash map is unchanged.
- * If newCapacity is less than the current size of the hash map, this function
- * will fail.
- * \return non-zero if resizing was successful
- */
-int UDPC_HashMap_realloc(UDPC_HashMap *hm, uint32_t newCapacity);
-
-/*!
- * \brief Empties the hash map
- */
-void UDPC_HashMap_clear(UDPC_HashMap *hm);
-
-uint32_t UDPC_HashMap_get_size(UDPC_HashMap *hm);
-
-uint32_t UDPC_HashMap_get_capacity(UDPC_HashMap *hm);
-
-/*!
- * \brief Calls a fn with a ptr to each entry in the hash map
- * The fn is called with userData, entry key, and entry data.
- */
-void UDPC_HashMap_itercall(UDPC_HashMap *hm, void (*fn)(void*, uint32_t, char*), void *userData);
-
-#endif
+++ /dev/null
-#include "UDPC_Defines.h"
-#include "UDPConnection.h"
-
-const char *UDPC_ERR_SOCKETFAIL_STR = "Failed to create socket";
-const char *UDPC_ERR_SOCKETBINDF_STR = "Failed to bind socket";
-const char *UDPC_ERR_SOCKETNONBF_STR = "Failed to set non-blocking on socket";
-const char *UDPC_ERR_MTXFAIL_STR = "Failed to create mutex";
-const char *UDPC_ERR_CVFAIL_STR = "Failed to create condition variable";
-const char *UDPC_ERR_THREADFAIL_STR = "Failed to create thread";
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <errno.h>
-
-UDPC_Context* UDPC_init(uint16_t listenPort, uint32_t listenAddr, int isClient)
-{
- UDPC_Context *context = malloc(sizeof(UDPC_Context));
- context->isThreaded = 0;
- context->protocolID = UDPC_PKT_DEFAULT_PROTOCOL_ID;
- context->error = UDPC_SUCCESS;
- context->flags = 0x4C;
- if(isClient != 0) context->flags |= 0x2;
- context->threadFlags = 0;
- context->conMap = UDPC_HashMap_init(13, sizeof(UDPC_INTERNAL_ConnectionData));
- context->idMap = UDPC_HashMap_init(13, sizeof(UDPC_INTERNAL_ConnectionData*));
- timespec_get(&context->lastUpdated, TIME_UTC);
- context->atostrBuf[UDPC_ATOSTR_BUF_SIZE - 1] = 0;
- context->connectedEvents = UDPC_Deque_init(
- UDPC_CONNECTED_EVENT_SIZE * 4);
- context->disconnectedEvents = UDPC_Deque_init(
- UDPC_DISCONNECTED_EVENT_SIZE * 4);
- context->receivedPackets = UDPC_Deque_init(
- UDPC_REC_PKTS_ALLOC_SIZE * sizeof(UDPC_INTERNAL_PacketInfo));
- context->callbackConnected = NULL;
- context->callbackConnectedUserData = NULL;
- context->callbackDisconnected = NULL;
- context->callbackDisconnectedUserData = NULL;
- context->callbackReceived = NULL;
- context->callbackReceivedUserData = NULL;
-
- // seed rand
- srand(context->lastUpdated.tv_sec);
-
- // create socket
- context->socketHandle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if(context->socketHandle <= 0)
- {
- context->socketHandle = 0;
- context->error = UDPC_ERR_SOCKETFAIL;
- UDPC_INTERNAL_log(context, 0, "Failed to create socket");
- return context;
- }
-
- // bind socket
- context->socketInfo.sin_family = AF_INET;
- context->socketInfo.sin_addr.s_addr =
- (listenAddr == 0 ? INADDR_ANY : listenAddr);
- context->socketInfo.sin_port = htons(listenPort);
- if(bind(
- context->socketHandle,
- (const struct sockaddr*) &context->socketInfo,
- sizeof(struct sockaddr_in)
- ) < 0)
- {
- context->error = UDPC_ERR_SOCKETBINDF;
- CleanupSocket(context->socketHandle);
- context->socketHandle = 0;
- UDPC_INTERNAL_log(context, 0, "Failed to bind socket");
- return context;
- }
-
- // set nonblocking on socket
-#if UDPC_PLATFORM == UDPC_PLATFORM_MAC || UDPC_PLATFORM == UDPC_PLATFORM_LINUX
- int nonblocking = 1;
- if(fcntl(context->socketHandle, F_SETFL, O_NONBLOCK, nonblocking) == -1)
- {
-#elif UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
- DWORD nonblocking = 1;
- if(ioctlsocket(context->socketHandle, FIONBIO, &nonblocking) != 0)
- {
-#else
- {
-#endif
- context->error = UDPC_ERR_SOCKETNONBF;
- CleanupSocket(context->socketHandle);
- context->socketHandle = 0;
- UDPC_INTERNAL_log(context, 0, "Failed to set non-blocking on socket");
-#if UDPC_PLATFORM == UDPC_PLATFORM_UNKNOWN
- UDPC_INTERNAL_log(context, 0, "(Unknown platform)");
-#endif
- return context;
- }
-
- return context;
-}
-
-UDPC_Context* UDPC_init_threaded_update(uint16_t listenPort, uint32_t listenAddr, int isClient)
-{
- UDPC_Context *context = UDPC_init(listenPort, listenAddr, isClient);
-
- context->isThreaded = 1;
-
- context->error = mtx_init(&context->tCVMtx, mtx_timed);
- if(context->error != thrd_success)
- {
- CleanupSocket(context->socketHandle);
- context->socketHandle = 0;
- UDPC_INTERNAL_log(context, 0, "Failed to create mutex");
- context->error = UDPC_ERR_MTXFAIL;
- return context;
- }
- context->error = UDPC_SUCCESS;
-
- context->error = mtx_init(&context->tflagsMtx, mtx_timed);
- if(context->error != thrd_success)
- {
- CleanupSocket(context->socketHandle);
- context->socketHandle = 0;
- mtx_destroy(&context->tCVMtx);
- UDPC_INTERNAL_log(context, 0, "Failed to create mutex");
- context->error = UDPC_ERR_MTXFAIL;
- return context;
- }
- context->error = UDPC_SUCCESS;
-
- context->error = cnd_init(&context->threadCV);
- if(context->error != thrd_success)
- {
- CleanupSocket(context->socketHandle);
- context->socketHandle = 0;
- mtx_destroy(&context->tCVMtx);
- mtx_destroy(&context->tflagsMtx);
- UDPC_INTERNAL_log(context, 0, "Failed to create condition variable");
- context->error = UDPC_ERR_CVFAIL;
- return context;
- }
- context->error = UDPC_SUCCESS;
-
- context->error = thrd_create(
- &context->threadHandle, UDPC_INTERNAL_threadfn, context);
- if(context->error != thrd_success)
- {
- CleanupSocket(context->socketHandle);
- context->socketHandle = 0;
- mtx_destroy(&context->tCVMtx);
- mtx_destroy(&context->tflagsMtx);
- cnd_destroy(&context->threadCV);
- UDPC_INTERNAL_log(context, 0, "Failed to create thread");
- context->error = UDPC_ERR_THREADFAIL;
- return context;
- }
- context->error = UDPC_SUCCESS;
-
- return context;
-}
-
-void UDPC_destroy(UDPC_Context *ctx)
-{
- if(ctx->isThreaded != 0)
- {
- mtx_lock(&ctx->tflagsMtx);
- ctx->threadFlags |= 0x1;
- mtx_unlock(&ctx->tflagsMtx);
- cnd_broadcast(&ctx->threadCV);
-
- thrd_join(ctx->threadHandle, NULL);
-
- mtx_destroy(&ctx->tCVMtx);
- mtx_destroy(&ctx->tflagsMtx);
- cnd_destroy(&ctx->threadCV);
- }
-
- CleanupSocket(ctx->socketHandle);
- UDPC_HashMap_itercall(ctx->conMap, UDPC_INTERNAL_destroy_conMap, NULL);
- UDPC_HashMap_destroy(ctx->conMap);
- UDPC_HashMap_destroy(ctx->idMap);
-
- UDPC_Deque_destroy(ctx->connectedEvents);
- UDPC_Deque_destroy(ctx->disconnectedEvents);
-
- while(ctx->receivedPackets->size != 0)
- {
- UDPC_INTERNAL_PacketInfo *pinfo = UDPC_Deque_get_front_ptr(ctx->receivedPackets, sizeof(UDPC_INTERNAL_PacketInfo));
- if(pinfo->data) { free(pinfo->data); }
- UDPC_Deque_pop_front(ctx->receivedPackets, sizeof(UDPC_INTERNAL_PacketInfo));
- }
- UDPC_Deque_destroy(ctx->receivedPackets);
-
- free(ctx);
-}
-
-void UDPC_INTERNAL_destroy_conMap(void *unused, uint32_t addr, char *data)
-{
- UDPC_INTERNAL_ConnectionData *cd = (UDPC_INTERNAL_ConnectionData*)data;
-
- for(int x = 0; x * sizeof(UDPC_INTERNAL_PacketInfo) < cd->sentPkts->size; ++x)
- {
- UDPC_INTERNAL_PacketInfo *pinfo = UDPC_Deque_index_ptr(
- cd->sentPkts, sizeof(UDPC_INTERNAL_PacketInfo), x);
- if(pinfo->data)
- {
- free(pinfo->data);
- }
- }
- UDPC_Deque_destroy(cd->sentPkts);
-
- for(int x = 0; x * sizeof(UDPC_INTERNAL_PacketInfo) < cd->sendPktQueue->size; ++x)
- {
- UDPC_INTERNAL_PacketInfo *pinfo = UDPC_Deque_index_ptr(
- cd->sendPktQueue, sizeof(UDPC_INTERNAL_PacketInfo), x);
- if(pinfo->data)
- {
- free(pinfo->data);
- }
- }
- UDPC_Deque_destroy(cd->sendPktQueue);
-
- for(int x = 0; x * sizeof(UDPC_INTERNAL_PacketInfo) < cd->priorityPktQueue->size; ++x)
- {
- UDPC_INTERNAL_PacketInfo *pinfo = UDPC_Deque_index_ptr(
- cd->priorityPktQueue, sizeof(UDPC_INTERNAL_PacketInfo), x);
- if(pinfo->data)
- {
- free(pinfo->data);
- }
- }
- UDPC_Deque_destroy(cd->priorityPktQueue);
-}
-
-void UDPC_set_callback_connected(
- UDPC_Context *ctx, UDPC_callback_connected fptr, void *userData)
-{
- if(ctx->isThreaded != 0) { mtx_lock(&ctx->tCVMtx); }
-
- ctx->callbackConnected = fptr;
- ctx->callbackConnectedUserData = userData;
-
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
-}
-
-void UDPC_set_callback_disconnected(
- UDPC_Context *ctx, UDPC_callback_disconnected fptr, void *userData)
-{
- if(ctx->isThreaded != 0) { mtx_lock(&ctx->tCVMtx); }
-
- ctx->callbackDisconnected = fptr;
- ctx->callbackDisconnectedUserData = userData;
-
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
-}
-
-void UDPC_set_callback_received(
- UDPC_Context *ctx, UDPC_callback_received fptr, void *userData)
-{
- if(ctx->isThreaded != 0) { mtx_lock(&ctx->tCVMtx); }
-
- ctx->callbackReceived = fptr;
- ctx->callbackReceivedUserData = userData;
-
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
-}
-
-void UDPC_check_events(UDPC_Context *ctx)
-{
- if(ctx->isThreaded != 0) { mtx_lock(&ctx->tCVMtx); }
-
- if(ctx->callbackConnected)
- {
- for(int x = 0; x * 4 < ctx->connectedEvents->size; ++x)
- {
- ctx->callbackConnected(ctx->callbackConnectedUserData,
- *((uint32_t*)UDPC_Deque_index_ptr(ctx->connectedEvents, 4, x)));
- }
- UDPC_Deque_clear(ctx->connectedEvents);
- }
- else
- {
- UDPC_INTERNAL_log(ctx, 0, "Connected callback not set");
- UDPC_Deque_clear(ctx->connectedEvents);
- }
-
- if(ctx->callbackDisconnected)
- {
- for(int x = 0; x * 4 < ctx->disconnectedEvents->size; ++x)
- {
- ctx->callbackDisconnected(ctx->callbackDisconnectedUserData,
- *((uint32_t*)UDPC_Deque_index_ptr(ctx->disconnectedEvents, 4, x)));
- }
- UDPC_Deque_clear(ctx->disconnectedEvents);
- }
- else
- {
- UDPC_INTERNAL_log(ctx, 0, "Disconnected callback not set");
- UDPC_Deque_clear(ctx->disconnectedEvents);
- }
-
- if(ctx->callbackReceived)
- {
- for(int x = 0; x * sizeof(UDPC_INTERNAL_PacketInfo) < ctx->receivedPackets->size; ++x)
- {
- UDPC_INTERNAL_PacketInfo *pinfo = UDPC_Deque_index_ptr(
- ctx->receivedPackets, sizeof(UDPC_INTERNAL_PacketInfo), x);
- ctx->callbackReceived(
- ctx->callbackReceivedUserData,
- pinfo->addr,
- pinfo->data,
- pinfo->size);
- free(pinfo->data);
- }
- UDPC_Deque_clear(ctx->receivedPackets);
- }
- else
- {
- UDPC_INTERNAL_log(ctx, 0, "Received callback not set");
- for(int x = 0; x * sizeof(UDPC_INTERNAL_PacketInfo) < ctx->receivedPackets->size; ++x)
- {
- UDPC_INTERNAL_PacketInfo *pinfo = UDPC_Deque_index_ptr(
- ctx->receivedPackets, sizeof(UDPC_INTERNAL_PacketInfo), x);
- free(pinfo->data);
- }
- UDPC_Deque_clear(ctx->receivedPackets);
- }
-
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
-}
-
-void UDPC_client_initiate_connection(UDPC_Context *ctx, uint32_t addr, uint16_t port)
-{
- if(ctx->isThreaded != 0) { mtx_lock(&ctx->tCVMtx); }
-
- if((ctx->flags & 0x2) == 0 || UDPC_HashMap_has(ctx->conMap, addr) != 0)
- {
- // must be client or no already-existing connection to same address
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
- return;
- }
-
- UDPC_INTERNAL_ConnectionData cd = {
- 0x9,
- 0,
- 1,
- 0,
- 0xFFFFFFFF,
- 0.0f,
- 30.0f,
- 0.0f,
- 0.0f,
- addr,
- port,
- UDPC_Deque_init(sizeof(UDPC_INTERNAL_PacketInfo) * UDPC_SENT_PKTS_ALLOC_SIZE),
- UDPC_Deque_init(sizeof(UDPC_INTERNAL_PacketInfo) * UDPC_SEND_PKTS_ALLOC_SIZE),
- UDPC_Deque_init(sizeof(UDPC_INTERNAL_PacketInfo) * UDPC_RESEND_PKTS_ALLOC_SIZE),
- {0, 0},
- {0, 0},
- 0.0f
- };
-
- timespec_get(&cd.received, TIME_UTC);
- cd.sent = cd.received;
- cd.sent.tv_sec -= UDPC_INIT_PKT_INTERVAL + 1;
-
- UDPC_HashMap_insert(ctx->conMap, addr, &cd);
-
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
-}
-
-int UDPC_queue_send(UDPC_Context *ctx, uint32_t addr, uint32_t isChecked, void *data, uint32_t size)
-{
- if(ctx->isThreaded != 0) { mtx_lock(&ctx->tCVMtx); }
-
- UDPC_INTERNAL_ConnectionData *cd = UDPC_HashMap_get(ctx->conMap, addr);
- if(cd)
- {
- UDPC_INTERNAL_PacketInfo pinfo = {
- addr,
- 0,
- isChecked != 0 ? 0x2 : 0,
- malloc(size),
- size,
- {0, 0}
- };
- if(pinfo.data)
- {
- memcpy(pinfo.data, data, size);
- if(UDPC_Deque_push_back(cd->sendPktQueue, &pinfo, sizeof(UDPC_INTERNAL_PacketInfo)) == 0)
- {
- UDPC_INTERNAL_log(ctx, 1, "Not enough free space in send "
- "packet queue, failed to queue packet for sending");
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
- return 0;
- }
- else
- {
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
- return 1;
- }
- }
- else
- {
- UDPC_INTERNAL_log(ctx, 0, "Failed to allocate memory to new send-packet queue entry");
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
- return 0;
- }
- }
- else
- {
- UDPC_INTERNAL_log(ctx, 0, "Cannot send to %s when connection has not been esablished",
- UDPC_INTERNAL_atostr(ctx, addr));
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
- return 0;
- }
-}
-
-int UDPC_get_queue_send_available(UDPC_Context *ctx, uint32_t addr)
-{
- if(ctx->isThreaded != 0) { mtx_lock(&ctx->tCVMtx); }
-
- UDPC_INTERNAL_ConnectionData *cd = UDPC_HashMap_get(ctx->conMap, addr);
- if(!cd)
- {
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
- return 0;
- }
-
- int available = UDPC_Deque_get_available(cd->sendPktQueue) / sizeof(UDPC_INTERNAL_PacketInfo);
-
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
-
- return available;
-}
-
-int UDPC_get_accept_new_connections(UDPC_Context *ctx)
-{
- if(ctx->isThreaded != 0) { mtx_lock(&ctx->tCVMtx); }
-
- int result = (ctx->flags & 0x40) != 0 ? 1 : 0;
-
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
-
- return result;
-}
-
-void UDPC_set_accept_new_connections(UDPC_Context *ctx, int isAccepting)
-{
- if(ctx->isThreaded != 0) { mtx_lock(&ctx->tCVMtx); }
-
- if(isAccepting != 0) { ctx->flags |= 0x40; }
- else { ctx->flags &= 0xFFFFFFBF; }
-
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
-}
-
-int UDPC_drop_connection(UDPC_Context *ctx, uint32_t addr)
-{
- int wasDropped = 0;
-
- if(ctx->isThreaded != 0) { mtx_lock(&ctx->tCVMtx); }
-
- UDPC_INTERNAL_ConnectionData *cd = UDPC_HashMap_get(ctx->conMap, addr);
- if(cd)
- {
- if((cd->flags & 0x10) != 0)
- {
- UDPC_HashMap_remove(ctx->idMap, cd->id);
- }
- UDPC_HashMap_remove(ctx->conMap, addr);
- wasDropped = 1;
- }
-
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
-
- return wasDropped;
-}
-
-uint32_t UDPC_get_protocol_id(UDPC_Context *ctx)
-{
- if(ctx->isThreaded != 0) { mtx_lock(&ctx->tCVMtx); }
-
- uint32_t id = ctx->protocolID;
-
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
-
- return id;
-}
-
-void UDPC_set_protocol_id(UDPC_Context *ctx, uint32_t id)
-{
- if(ctx->isThreaded != 0) { mtx_lock(&ctx->tCVMtx); }
-
- ctx->protocolID = id;
-
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
-}
-
-uint32_t UDPC_get_error(UDPC_Context *ctx)
-{
- if(ctx->isThreaded != 0) { mtx_lock(&ctx->tCVMtx); }
-
- uint32_t error = ctx->error;
- ctx->error = 0;
-
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
-
- return error;
-}
-
-const char* UDPC_get_error_str(uint32_t error)
-{
- switch(error)
- {
- case UDPC_SUCCESS: return "No error";
- case UDPC_ERR_SOCKETFAIL: return UDPC_ERR_SOCKETFAIL_STR;
- case UDPC_ERR_SOCKETBINDF: return UDPC_ERR_SOCKETBINDF_STR;
- case UDPC_ERR_SOCKETNONBF: return UDPC_ERR_SOCKETNONBF_STR;
- case UDPC_ERR_MTXFAIL: return UDPC_ERR_MTXFAIL_STR;
- case UDPC_ERR_CVFAIL: return UDPC_ERR_CVFAIL_STR;
- case UDPC_ERR_THREADFAIL: return UDPC_ERR_THREADFAIL_STR;
- default: return "Unknown error";
- }
-}
-
-void UDPC_set_logging_type(UDPC_Context *ctx, uint32_t logType)
-{
- if(ctx->isThreaded != 0) { mtx_lock(&ctx->tCVMtx); }
-
- switch(logType)
- {
- case 0:
- ctx->flags &= 0xFFFFFFC3;
- break;
- case 1:
- ctx->flags &= 0xFFFFFFC7;
- ctx->flags |= 0x4;
- break;
- case 2:
- ctx->flags &= 0xFFFFFFCF;
- ctx->flags |= (0x4 | 0x8);
- break;
- case 3:
- ctx->flags &= 0xFFFFFFDF;
- ctx->flags |= (0x4 | 0x8 | 0x10);
- break;
- default:
- ctx->flags |= (0x4 | 0x8 | 0x10 | 0x20);
- break;
- }
-
- if(ctx->isThreaded != 0) { mtx_unlock(&ctx->tCVMtx); }
-}
-
-void UDPC_update(UDPC_Context *ctx)
-{
- UDPC_INTERNAL_update_struct us = {
- {0, 0},
- 0.0f,
- NULL,
- ctx
- };
- timespec_get(&us.tsNow, TIME_UTC);
- us.dt = UDPC_INTERNAL_ts_diff(&us.tsNow, &ctx->lastUpdated);
- ctx->lastUpdated = us.tsNow;
- us.removedQueue = UDPC_Deque_init(4 * (ctx->conMap->size));
-
- UDPC_HashMap_itercall(ctx->conMap, UDPC_INTERNAL_update_to_rtt_si, &us);
-
- // remove timed out
- for(int x = 0; x * 4 < us.removedQueue->size; ++x)
- {
- uint32_t *key = UDPC_Deque_index_ptr(us.removedQueue, 4, x);
- UDPC_INTERNAL_ConnectionData *cd = UDPC_HashMap_get(ctx->conMap, *key);
-
- while(cd->sentPkts->size != 0)
- {
- UDPC_INTERNAL_PacketInfo *pinfo = UDPC_Deque_get_front_ptr(cd->sentPkts, sizeof(UDPC_INTERNAL_PacketInfo));
- if(pinfo->data) { free(pinfo->data); }
- UDPC_Deque_pop_front(cd->sentPkts, sizeof(UDPC_INTERNAL_PacketInfo));
- }
- UDPC_Deque_destroy(cd->sentPkts);
-
- while(cd->sendPktQueue->size != 0)
- {
- UDPC_INTERNAL_PacketInfo *pinfo = UDPC_Deque_get_front_ptr(cd->sendPktQueue, sizeof(UDPC_INTERNAL_PacketInfo));
- if(pinfo->data) { free(pinfo->data); }
- UDPC_Deque_pop_front(cd->sendPktQueue, sizeof(UDPC_INTERNAL_PacketInfo));
- }
- UDPC_Deque_destroy(cd->sendPktQueue);
-
- while(cd->priorityPktQueue->size != 0)
- {
- UDPC_INTERNAL_PacketInfo *pinfo = UDPC_Deque_get_front_ptr(cd->priorityPktQueue, sizeof(UDPC_INTERNAL_PacketInfo));
- if(pinfo->data) { free(pinfo->data); }
- UDPC_Deque_pop_front(cd->priorityPktQueue, sizeof(UDPC_INTERNAL_PacketInfo));
- }
- UDPC_Deque_destroy(cd->priorityPktQueue);
-
- if((cd->flags & 0x10) != 0)
- {
- UDPC_HashMap_remove(ctx->idMap, cd->id);
- }
- UDPC_HashMap_remove(ctx->conMap, *key);
- }
- UDPC_Deque_destroy(us.removedQueue);
- us.removedQueue = NULL;
-
- // check triggerSend to send packets to connected
- UDPC_HashMap_itercall(ctx->conMap, UDPC_INTERNAL_update_send, &us);
-
- // receive packet
-#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
- typedef int socklen_t;
-#endif
- struct sockaddr_in receivedData;
- socklen_t receivedDataSize = sizeof(receivedData);
- int bytes = recvfrom(
- ctx->socketHandle,
- ctx->recvBuf,
- UDPC_PACKET_MAX_SIZE,
- 0,
- (struct sockaddr*) &receivedData,
- &receivedDataSize);
-
- if(bytes == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
- {
- // expected result for non-blocking socket
- return;
- }
-
- if(bytes < 20)
- {
- UDPC_INTERNAL_log(ctx, 2, "Got invalid packet from %s port %d (too small)",
- UDPC_INTERNAL_atostr(ctx, receivedData.sin_addr.s_addr),
- ntohs(receivedData.sin_port));
- return;
- }
-
- uint32_t temp = ntohl(*((uint32_t*)ctx->recvBuf));
- if(temp != ctx->protocolID)
- {
- UDPC_INTERNAL_log(ctx, 2, "Got invalid packet from %s port %d (invalid protocol id)",
- UDPC_INTERNAL_atostr(ctx, receivedData.sin_addr.s_addr),
- ntohs(receivedData.sin_port));
- return;
- }
-
- uint32_t conID = ntohl(*((uint32_t*)(ctx->recvBuf + 4)));
- uint32_t seqID = ntohl(*((uint32_t*)(ctx->recvBuf + 8)));
- uint32_t rseq = ntohl(*((uint32_t*)(ctx->recvBuf + 12)));
- uint32_t ack = ntohl(*((uint32_t*)(ctx->recvBuf + 16)));
-
- int isConnect = conID & UDPC_ID_CONNECT;
- int isPing = conID & UDPC_ID_PING;
- int isNotRecvCheck = conID & UDPC_ID_NO_REC_CHK;
- int isResent = conID & UDPC_ID_RESENDING;
- conID &= 0x0FFFFFFF;
-
- if(isConnect != 0 && (ctx->flags & 0x40) != 0)
- {
- if((ctx->flags & 0x2) == 0
- && !UDPC_HashMap_get(ctx->conMap, receivedData.sin_addr.s_addr))
- {
- UDPC_INTERNAL_log(ctx, 2, "Establishing connection with %s port %d",
- UDPC_INTERNAL_atostr(ctx, receivedData.sin_addr.s_addr),
- ntohs(receivedData.sin_port));
- UDPC_INTERNAL_ConnectionData newCD = {
- 0x19,
- UDPC_INTERNAL_generate_id(ctx),
- 0,
- 0,
- 0xFFFFFFFF,
- 0.0f,
- 30.0f,
- 0.0f,
- 0.0f,
- receivedData.sin_addr.s_addr,
- ntohs(receivedData.sin_port),
- UDPC_Deque_init(sizeof(UDPC_INTERNAL_PacketInfo) * UDPC_SENT_PKTS_ALLOC_SIZE),
- UDPC_Deque_init(sizeof(UDPC_INTERNAL_PacketInfo) * UDPC_SEND_PKTS_ALLOC_SIZE),
- UDPC_Deque_init(sizeof(UDPC_INTERNAL_PacketInfo) * UDPC_RESEND_PKTS_ALLOC_SIZE),
- us.tsNow,
- us.tsNow,
- 0.0f
- };
- UDPC_HashMap_insert(ctx->conMap, newCD.addr, &newCD);
- UDPC_HashMap_insert(ctx->idMap, newCD.id, UDPC_HashMap_get(ctx->conMap, newCD.addr));
- if(UDPC_Deque_get_available(ctx->connectedEvents) == 0)
- {
- UDPC_Deque_pop_front(ctx->connectedEvents, 4);
- UDPC_Deque_push_back(ctx->connectedEvents, &receivedData.sin_addr.s_addr, 4);
- UDPC_INTERNAL_log(ctx, 1, "Not enough free space in connected "
- "events queue, removing oldest to make room");
- }
- else
- {
- UDPC_Deque_push_back(ctx->connectedEvents, &receivedData.sin_addr.s_addr, 4);
- }
- }
- else if((ctx->flags & 0x2) != 0)
- {
- UDPC_INTERNAL_ConnectionData *cd = UDPC_HashMap_get(ctx->conMap, receivedData.sin_addr.s_addr);
- if(!cd) { return; }
-
- cd->flags &= 0xFFFFFFF7;
- cd->flags |= 0x10;
- cd->id = conID;
- UDPC_INTERNAL_log(ctx, 2, "Got id %u from server %s", conID,
- UDPC_INTERNAL_atostr(ctx, receivedData.sin_addr.s_addr));
- if(UDPC_Deque_get_available(ctx->connectedEvents) == 0)
- {
- UDPC_Deque_pop_front(ctx->connectedEvents, 4);
- UDPC_Deque_push_back(ctx->connectedEvents, &receivedData.sin_addr.s_addr, 4);
- UDPC_INTERNAL_log(ctx, 1, "Not enough free space in connected "
- "events queue, removing oldest to make room");
- }
- else
- {
- UDPC_Deque_push_back(ctx->connectedEvents, &receivedData.sin_addr.s_addr, 4);
- }
- }
- return;
- }
- else if(isPing != 0)
- {
- UDPC_INTERNAL_ConnectionData *cd = UDPC_HashMap_get(ctx->conMap, receivedData.sin_addr.s_addr);
- if(cd)
- {
- cd->flags |= 0x1;
- }
- }
-
- UDPC_INTERNAL_ConnectionData *cd = UDPC_HashMap_get(ctx->conMap, receivedData.sin_addr.s_addr);
- if(!cd)
- {
- // Received packet from unknown, ignoring
- return;
- }
- else if(conID != cd->id)
- {
- // Received packet id and known id does not match, ignoring
- return;
- }
-
- // packet is valid
- UDPC_INTERNAL_log(ctx, 2, "Valid packet %d from %s", seqID,
- UDPC_INTERNAL_atostr(ctx, receivedData.sin_addr.s_addr));
-
- UDPC_INTERNAL_update_rtt(ctx, cd, rseq, &us.tsNow);
- cd->received = us.tsNow;
- UDPC_INTERNAL_check_pkt_timeout(ctx, cd, rseq, ack, &us.tsNow);
-
- int isOutOfOrder = 0;
- uint32_t diff = 0;
- if(seqID > cd->rseq)
- {
- diff = seqID - cd->rseq;
- if(diff <= 0x7FFFFFFF)
- {
- // seqeuence is more recent
- cd->rseq = seqID;
- cd->ack = (cd->ack >> diff) | 0x80000000;
- }
- else
- {
- // sequence is older id, diff requires recalc
- diff = 0xFFFFFFFF - seqID + 1 + cd->rseq;
- if((cd->ack & (0x80000000 >> (diff - 1))) != 0)
- {
- // already received packet
- UDPC_INTERNAL_log(ctx, 2, "Ignoring already received pkt from %s",
- UDPC_INTERNAL_atostr(ctx, cd->addr));
- return;
- }
- cd->ack |= (0x80000000 >> (diff - 1));
-
- isOutOfOrder = 1;
- }
- }
- else if(seqID < cd->rseq)
- {
- diff = cd->rseq - seqID;
- if(diff <= 0x7FFFFFFF)
- {
- // sequence is older
- if((cd->ack & (0x80000000 >> (diff - 1))) != 0)
- {
- // already received packet
- UDPC_INTERNAL_log(ctx, 2, "Ignoring already received pkt from %s",
- UDPC_INTERNAL_atostr(ctx, cd->addr));
- return;
- }
- cd->ack |= (0x80000000 >> (diff - 1));
-
- isOutOfOrder = 1;
- }
- else
- {
- // sequence is more recent, diff requires recalc
- diff = 0xFFFFFFFF - cd->rseq + 1 + seqID;
- cd->rseq = seqID;
- cd->ack = (cd->ack >> diff) | 0x80000000;
- }
- }
- else
- {
- // already received packet
- UDPC_INTERNAL_log(ctx, 2, "Ignoring already received (duplicate) pkt from %s",
- UDPC_INTERNAL_atostr(ctx, cd->addr));
- return;
- }
-
- if(isOutOfOrder != 0)
- {
- UDPC_INTERNAL_log(ctx, 2, "Received valid packet from %s is out of order",
- UDPC_INTERNAL_atostr(ctx, cd->addr));
- }
-
- if(bytes > 20)
- {
- UDPC_INTERNAL_PacketInfo receivedInfo;
- receivedInfo.addr = receivedData.sin_addr.s_addr;
- receivedInfo.id = conID;
- receivedInfo.flags = (isNotRecvCheck != 0 ? 0 : 0x2) | (isResent != 0 ? 0x5 : 0);
- receivedInfo.data = malloc(bytes - 20);
- memcpy(receivedInfo.data, ctx->recvBuf + 20, bytes - 20);
- receivedInfo.size = bytes - 20;
- receivedInfo.sent = us.tsNow;
-
- if(UDPC_Deque_get_available(ctx->receivedPackets) == 0)
- {
- UDPC_INTERNAL_PacketInfo *rpinfo = UDPC_Deque_get_front_ptr(
- ctx->receivedPackets, sizeof(UDPC_INTERNAL_PacketInfo));
- if(rpinfo->data) { free(rpinfo->data); }
- UDPC_Deque_pop_front(ctx->receivedPackets, sizeof(UDPC_INTERNAL_PacketInfo));
- UDPC_Deque_push_back(ctx->receivedPackets, &receivedInfo, sizeof(UDPC_INTERNAL_PacketInfo));
- UDPC_INTERNAL_log(ctx, 1, "Received packet but not enough space in received queue, removing oldest packet to make room");
- }
- else
- {
- UDPC_Deque_push_back(ctx->receivedPackets, &receivedInfo, sizeof(UDPC_INTERNAL_PacketInfo));
- }
- }
- else
- {
- UDPC_INTERNAL_log(ctx, 3, "Packet has no payload, not adding to received queue");
- }
-}
-
-void UDPC_INTERNAL_update_to_rtt_si(void *userData, uint32_t addr, char *data)
-{
- UDPC_INTERNAL_update_struct *us =
- (UDPC_INTERNAL_update_struct*)userData;
- UDPC_INTERNAL_ConnectionData *cd = (UDPC_INTERNAL_ConnectionData*)data;
-
- // check for timed out connection
- if(UDPC_INTERNAL_ts_diff(&us->tsNow, &cd->received) >= UDPC_TIMEOUT_SECONDS)
- {
- UDPC_Deque_push_back(us->removedQueue, &addr, 4);
- UDPC_INTERNAL_log(us->ctx, 2, "Connection timed out with addr %s port %d",
- UDPC_INTERNAL_atostr(us->ctx, addr),
- cd->port);
- if(UDPC_Deque_get_available(us->ctx->disconnectedEvents) == 0)
- {
- UDPC_Deque_pop_front(us->ctx->disconnectedEvents, 4);
- UDPC_Deque_push_back(us->ctx->disconnectedEvents, &addr, 4);
- UDPC_INTERNAL_log(us->ctx, 1, "Not enough free space in "
- "disconnected events queue, removing oldest event to make room");
- }
- else
- {
- UDPC_Deque_push_back(us->ctx->disconnectedEvents, &addr, 4);
- }
- return;
- }
-
- // check good/bad mode
- cd->toggleTimer += us->dt;
- cd->toggledTimer += us->dt;
- if((cd->flags & 0x2) != 0 && (cd->flags & 0x4) == 0)
- {
- // good mode, bad rtt
- UDPC_INTERNAL_log(us->ctx, 2, "Connection with %s switching to bad mode",
- UDPC_INTERNAL_atostr(us->ctx, addr));
-
- cd->flags = cd->flags & 0xFFFFFFFD;
- if(cd->toggledTimer <= 10.0f)
- {
- cd->toggleT *= 2.0f;
- if(cd->toggleT > 60.0f)
- {
- cd->toggleT = 60.0f;
- }
- }
- cd->toggledTimer = 0.0f;
- }
- else if((cd->flags & 0x2) != 0)
- {
- // good mode, good rtt
- if(cd->toggleTimer >= 10.0f)
- {
- cd->toggleTimer = 0.0f;
- cd->toggleT /= 2.0f;
- if(cd->toggleT < 1.0f)
- {
- cd->toggleT = 1.0f;
- }
- }
- }
- else if((cd->flags & 0x2) == 0 && (cd->flags & 0x4) != 0)
- {
- // bad mode, good rtt
- if(cd->toggledTimer >= cd->toggleT)
- {
- cd->toggleTimer = 0.0f;
- cd->toggledTimer = 0.0f;
- UDPC_INTERNAL_log(us->ctx, 2, "Connection with %s switching to good mode",
- UDPC_INTERNAL_atostr(us->ctx, addr));
- cd->flags |= 0x2;
- }
- }
- else
- {
- // bad mode, bad rtt
- cd->toggledTimer = 0.0f;
- }
-
- // check send interval
- cd->timer += us->dt;
- if(cd->timer >= ((cd->flags & 0x2) != 0
- ? UDPC_GOOD_MODE_SEND_INTERVAL : UDPC_BAD_MODE_SEND_INTERVAL))
- {
- cd->timer = 0.0f;
- cd->flags |= 0x1;
- }
-}
-
-void UDPC_INTERNAL_update_send(void *userData, uint32_t addr, char *data)
-{
- UDPC_INTERNAL_update_struct *us =
- (UDPC_INTERNAL_update_struct*)userData;
- UDPC_INTERNAL_ConnectionData *cd = (UDPC_INTERNAL_ConnectionData*)data;
-
- if((cd->flags & 0x1) == 0)
- {
- return;
- }
-
- cd->flags = cd->flags & 0xFFFFFFFE;
-
- if((cd->flags & 0x8) != 0)
- {
- if((us->ctx->flags & 0x2) != 0)
- {
- // initiate connection to server
- if(UDPC_INTERNAL_ts_diff(&us->tsNow, &cd->sent) < UDPC_INIT_PKT_INTERVAL_F)
- {
- return;
- }
- cd->sent = us->tsNow;
-
- char *data = malloc(20);
- UDPC_INTERNAL_prepare_pkt(
- data,
- us->ctx->protocolID,
- 0,
- 0,
- 0xFFFFFFFF,
- NULL,
- 0x8);
-
- struct sockaddr_in destinationInfo;
- destinationInfo.sin_family = AF_INET;
- destinationInfo.sin_addr.s_addr = addr;
- destinationInfo.sin_port = htons(cd->port);
- long int sentBytes = sendto(
- us->ctx->socketHandle,
- data,
- 20,
- 0,
- (struct sockaddr*) &destinationInfo,
- sizeof(struct sockaddr_in));
- if(sentBytes != 20)
- {
- UDPC_INTERNAL_log(us->ctx, 0, "Failed to send init packet to %s "
- "port %d", UDPC_INTERNAL_atostr(us->ctx, addr), cd->port);
- free(data);
- return;
- }
- free(data);
- }
- else
- {
- // initiate connection to client
- cd->flags &= 0xFFFFFFF7;
- cd->sent = us->tsNow;
-
- char *data = malloc(20);
- UDPC_INTERNAL_prepare_pkt(
- data,
- us->ctx->protocolID,
- cd->id,
- cd->rseq,
- cd->ack,
- &cd->lseq,
- 0x8);
-
- struct sockaddr_in destinationInfo;
- destinationInfo.sin_family = AF_INET;
- destinationInfo.sin_addr.s_addr = addr;
- destinationInfo.sin_port = htons(cd->port);
- long int sentBytes = sendto(
- us->ctx->socketHandle,
- data,
- 20,
- 0,
- (struct sockaddr*) &destinationInfo,
- sizeof(struct sockaddr_in));
- if(sentBytes != 20)
- {
- UDPC_INTERNAL_log(us->ctx, 0, "Failed to send init packet to %s "
- "port %d", UDPC_INTERNAL_atostr(us->ctx, addr), cd->port);
- free(data);
- return;
- }
- free(data);
- }
- return;
- }
-
- if(cd->sendPktQueue->size == 0 && cd->priorityPktQueue->size == 0)
- {
- // send and resend packet queue is empty, send heartbeat packet
- if(UDPC_INTERNAL_ts_diff(&us->tsNow, &cd->sent) < UDPC_HEARTBEAT_PKT_INTERVAL)
- {
- return;
- }
-
- char *data = malloc(20);
- UDPC_INTERNAL_prepare_pkt(
- data, us->ctx->protocolID, cd->id, cd->rseq, cd->ack, &cd->lseq, 0);
-
- struct sockaddr_in destinationInfo;
- destinationInfo.sin_family = AF_INET;
- destinationInfo.sin_addr.s_addr = addr;
- destinationInfo.sin_port = htons(cd->port);
- long int sentBytes = sendto(
- us->ctx->socketHandle,
- data,
- 20,
- 0,
- (struct sockaddr*) &destinationInfo,
- sizeof(struct sockaddr_in));
- if(sentBytes != 20)
- {
- UDPC_INTERNAL_log(us->ctx, 0, "Failed to send packet to %s port %d",
- UDPC_INTERNAL_atostr(us->ctx, addr), cd->port);
- free(data);
- return;
- }
-
- UDPC_INTERNAL_PacketInfo sentInfo = {
- addr,
- cd->lseq - 1,
- 0,
- NULL,
- 0,
- us->tsNow
- };
- UDPC_Deque_push_back(
- cd->sentPkts, &sentInfo, sizeof(UDPC_INTERNAL_PacketInfo));
- while(cd->sentPkts->size / sizeof(UDPC_INTERNAL_PacketInfo) > UDPC_SENT_PKTS_MAX_SIZE)
- {
- UDPC_INTERNAL_PacketInfo *pinfo = UDPC_Deque_get_front_ptr(
- cd->sentPkts,
- sizeof(UDPC_INTERNAL_PacketInfo));
- if(pinfo->data && pinfo->size != 0)
- {
- free(pinfo->data);
- }
- UDPC_Deque_pop_front(cd->sentPkts, sizeof(UDPC_INTERNAL_PacketInfo));
- }
- free(data);
- }
- else // sendPktQueue or priorityPktQueue not empty
- {
- UDPC_INTERNAL_PacketInfo *pinfo;
- int isResendingPkt = 0;
-
- if(cd->priorityPktQueue->size != 0)
- {
- pinfo = UDPC_Deque_get_front_ptr(
- cd->priorityPktQueue, sizeof(UDPC_INTERNAL_PacketInfo));
- isResendingPkt = 1;
- }
- else
- {
- pinfo = UDPC_Deque_get_front_ptr(
- cd->sendPktQueue, sizeof(UDPC_INTERNAL_PacketInfo));
- }
- char *data = malloc(20 + pinfo->size);
- UDPC_INTERNAL_prepare_pkt(
- data,
- us->ctx->protocolID,
- cd->id,
- cd->rseq,
- cd->ack,
- &cd->lseq,
- ((pinfo->flags & 0x3) << 1));
- memcpy(&data[20], pinfo->data, pinfo->size);
-
- struct sockaddr_in destinationInfo;
- destinationInfo.sin_family = AF_INET;
- destinationInfo.sin_addr.s_addr = addr;
- destinationInfo.sin_port = htons(cd->port);
- long int sentBytes = sendto(
- us->ctx->socketHandle,
- data,
- 20 + pinfo->size,
- 0,
- (struct sockaddr*) &destinationInfo,
- sizeof(struct sockaddr_in));
- if(sentBytes != 20 + pinfo->size)
- {
- UDPC_INTERNAL_log(us->ctx, 0, "Failed to send packet to %s port %d",
- UDPC_INTERNAL_atostr(us->ctx, addr), cd->port);
- free(data);
- free(pinfo->data);
- if(isResendingPkt != 0)
- {
- UDPC_Deque_pop_front(cd->priorityPktQueue, sizeof(UDPC_INTERNAL_PacketInfo));
- }
- else
- {
- UDPC_Deque_pop_front(cd->sendPktQueue, sizeof(UDPC_INTERNAL_PacketInfo));
- }
- return;
- }
-
- if((pinfo->flags & 0x2) != 0)
- {
- UDPC_INTERNAL_PacketInfo sentInfo = {
- addr,
- cd->lseq - 1,
- 0x2,
- data,
- 20 + pinfo->size,
- us->tsNow
- };
- UDPC_Deque_push_back(
- cd->sentPkts, &sentInfo, sizeof(UDPC_INTERNAL_PacketInfo));
- }
- else
- {
- UDPC_INTERNAL_PacketInfo sentInfo = {
- addr,
- cd->lseq - 1,
- 0,
- NULL,
- 0,
- us->tsNow
- };
- UDPC_Deque_push_back(
- cd->sentPkts, &sentInfo, sizeof(UDPC_INTERNAL_PacketInfo));
- free(data);
- }
-
- while(cd->sentPkts->size / sizeof(UDPC_INTERNAL_PacketInfo) > UDPC_SENT_PKTS_MAX_SIZE)
- {
- UDPC_INTERNAL_PacketInfo *pinfoCached = UDPC_Deque_get_front_ptr(
- cd->sentPkts, sizeof(UDPC_INTERNAL_PacketInfo));
- if(pinfoCached->data && pinfoCached->size != 0)
- {
- free(pinfoCached->data);
- }
- UDPC_Deque_pop_front(cd->sentPkts, sizeof(UDPC_INTERNAL_PacketInfo));
- }
-
- free(pinfo->data);
- if(isResendingPkt != 0)
- {
- UDPC_Deque_pop_front(cd->priorityPktQueue, sizeof(UDPC_INTERNAL_PacketInfo));
- }
- else
- {
- UDPC_Deque_pop_front(cd->sendPktQueue, sizeof(UDPC_INTERNAL_PacketInfo));
- }
- }
-}
-
-void UDPC_INTERNAL_update_rtt(
- UDPC_Context *ctx,
- UDPC_INTERNAL_ConnectionData *cd,
- uint32_t rseq,
- struct timespec *tsNow)
-{
- for(int x = 0; x * sizeof(UDPC_INTERNAL_PacketInfo) < cd->sentPkts->size; ++x)
- {
- UDPC_INTERNAL_PacketInfo *pinfo = UDPC_Deque_index_ptr(cd->sentPkts, sizeof(UDPC_INTERNAL_PacketInfo), x);
- if(pinfo->id == rseq)
- {
- float diff = UDPC_INTERNAL_ts_diff(tsNow, &pinfo->sent);
- if(diff > cd->rtt)
- {
- cd->rtt += (diff - cd->rtt) / 10.0f;
- }
- else
- {
- cd->rtt -= (cd->rtt - diff) / 10.0f;
- }
-
- if(cd->rtt > UDPC_GOOD_RTT_LIMIT_SEC)
- {
- cd->flags &= 0xFFFFFFFB;
- }
- else
- {
- cd->flags |= 0x4;
- }
-
- UDPC_INTERNAL_log(ctx, 2, "%d RTT (%s) %.3fs from %s",
- rseq,
- cd->rtt > UDPC_GOOD_RTT_LIMIT_SEC ? "B" : "G",
- cd->rtt,
- UDPC_INTERNAL_atostr(ctx, cd->addr));
- break;
- }
- }
-}
-
-void UDPC_INTERNAL_check_pkt_timeout(
- UDPC_Context *ctx,
- UDPC_INTERNAL_ConnectionData *cd,
- uint32_t rseq,
- uint32_t ack,
- struct timespec *tsNow)
-{
- --rseq;
- for(; ack != 0; ack = ack << 1)
- {
- if((ack & 0x80000000) != 0) { --rseq; continue; }
-
- // not received by peer yet, check if packet timed out
- for(int x = 0; x * sizeof(UDPC_INTERNAL_PacketInfo) < cd->sentPkts->size; ++x)
- {
- UDPC_INTERNAL_PacketInfo *pinfo = UDPC_Deque_index_rev_ptr(cd->sentPkts, sizeof(UDPC_INTERNAL_PacketInfo), x);
- if(pinfo->id == rseq)
- {
- if((pinfo->flags & 0x2) == 0 || (pinfo->flags & 0x4) != 0)
- {
- // is not received checked or already resent
- break;
- }
- float seconds = UDPC_INTERNAL_ts_diff(tsNow, &pinfo->sent);
- if(seconds >= UDPC_PACKET_TIMEOUT_SEC)
- {
- if(pinfo->size <= 20)
- {
- UDPC_INTERNAL_log(ctx, 0,
- "Timed out sentPkt (%d) to %s has size at most 20",
- rseq,
- UDPC_INTERNAL_atostr(ctx, cd->addr));
- pinfo->flags |= 0x4; // treat as resent to avoid reprinting error
- break;
- }
- // packet timed out, resending
- UDPC_INTERNAL_PacketInfo newPkt = {
- cd->addr,
- 0,
- 0,
- NULL,
- 0,
- {0, 0}
- };
- newPkt.size = pinfo->size - 20;
- newPkt.data = malloc(newPkt.size);
- memcpy(newPkt.data, pinfo->data + 20, newPkt.size);
- free(pinfo->data);
-
- pinfo->flags |= 0x4;
- pinfo->data = NULL;
- pinfo->size = 0;
- UDPC_Deque_push_back(
- cd->priorityPktQueue,
- &newPkt,
- sizeof(UDPC_INTERNAL_PacketInfo));
- }
- break;
- }
- }
-
- --rseq;
- }
-}
-
-float UDPC_INTERNAL_ts_diff(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;
-
- int shouldStop = 0;
- struct timespec ts;
-
- while(shouldStop == 0)
- {
- timespec_get(&ts, TIME_UTC);
- ts.tv_nsec += 16666666;
- while(ts.tv_nsec >= 1000000000)
- {
- ts.tv_nsec -= 1000000000;
- ts.tv_sec += 1;
- }
- mtx_lock(&ctx->tCVMtx);
- cnd_timedwait(&ctx->threadCV, &ctx->tCVMtx, &ts);
- UDPC_update(ctx);
- mtx_unlock(&ctx->tCVMtx);
-
- mtx_lock(&ctx->tflagsMtx);
- shouldStop = ctx->threadFlags & 0x1;
- mtx_unlock(&ctx->tflagsMtx);
- }
-
- return 0;
-}
-
-void UDPC_INTERNAL_prepare_pkt(
- void *data,
- uint32_t protocolID,
- uint32_t conID,
- uint32_t rseq,
- uint32_t ack,
- uint32_t *seqID,
- int flags)
-{
- char *d = data;
- uint32_t temp;
-
- temp = htonl(protocolID);
- memcpy(d, &temp, 4);
-
- temp = htonl(conID
- | ((flags & 0x1) != 0 ? UDPC_ID_PING : 0)
- | ((flags & 0x2) != 0 ? UDPC_ID_RESENDING : 0)
- | ((flags & 0x4) == 0 ? UDPC_ID_NO_REC_CHK : 0)
- | ((flags & 0x8) != 0 ? UDPC_ID_CONNECT : 0));
- memcpy(&d[4], &temp, 4);
-
- if(seqID)
- {
- temp = htonl(*seqID);
- ++(*seqID);
- }
- else
- {
- temp = 0;
- }
-
- memcpy(&d[8], &temp, 4);
- temp = htonl(rseq);
- memcpy(&d[12], &temp, 4);
- temp = htonl(ack);
- memcpy(&d[16], &temp, 4);
-}
-
-void UDPC_INTERNAL_log(UDPC_Context *ctx, uint32_t level, const char *msg, ...)
-{
- va_list args;
- va_start(args, msg);
- switch(level)
- {
- case 0:
- default:
- if((ctx->flags & 0x4) == 0) break;
- fprintf(stderr, "ERR: ");
- break;
- case 1:
- if((ctx->flags & 0x8) == 0) break;
- fprintf(stderr, "WARN: ");
- break;
- case 2:
- if((ctx->flags & 0x10) == 0) break;
- fprintf(stderr, "INFO: ");
- break;
- case 3:
- if((ctx->flags & 0x20) == 0) break;
- fprintf(stderr, "VERBOSE: ");
- break;
- }
- vfprintf(stderr, msg, args);
- fprintf(stderr, "\n");
- va_end(args);
-}
-
-char* UDPC_INTERNAL_atostr(UDPC_Context *ctx, uint32_t addr)
-{
- int index = 0;
- for(int x = 0; x < 4; ++x)
- {
- unsigned char temp = (addr >> (x * 8)) & 0xFF;
-
- if(temp >= 100)
- {
- ctx->atostrBuf[index++] = '0' + temp / 100;
- }
- if(temp >= 10)
- {
- ctx->atostrBuf[index++] = '0' + ((temp / 10) % 10);
- }
- ctx->atostrBuf[index++] = '0' + temp % 10;
-
- if(x < 3)
- {
- ctx->atostrBuf[index++] = '.';
- }
- }
- ctx->atostrBuf[index] = 0;
-
- return ctx->atostrBuf;
-}
-
-uint32_t UDPC_INTERNAL_generate_id(UDPC_Context *ctx)
-{
- uint32_t newID = 0x10000000;
-
- while(newID == 0x10000000)
- {
- newID = rand() % 0x10000000;
- if(UDPC_HashMap_has(ctx->idMap, newID) != 0)
- {
- newID = 0x10000000;
- }
- }
-
- return newID;
-}
-
-uint32_t UDPC_strtoa(const char *addrStr)
-{
- uint32_t addr = 0;
- uint32_t temp = 0;
- uint32_t index = 0;
- while(*addrStr != 0)
- {
- if(*addrStr >= '0' && *addrStr <= '9')
- {
- temp *= 10;
- temp += *addrStr - '0';
- }
- else if(*addrStr == '.' && temp <= 0xFF && index < 3)
- {
- addr |= (temp << (8 * index++));
- temp = 0;
- }
- else
- {
- return 0;
- }
- ++addrStr;
- }
-
- if(index == 3 && temp <= 0xFF)
- {
- addr |= temp << 24;
- return addr;
- }
- else
- {
- return 0;
- }
-}
+++ /dev/null
-#ifndef UDPCONNECTION_H
-#define UDPCONNECTION_H
-
-/*!
- * Any function or struct starting with "UDPC_INTERNAL" should never be used,
- * as they are used internally by this library.
- */
-
-#include <stdio.h>
-#include <threads.h>
-#include <time.h>
-#include <stdint.h>
-
-#include "UDPC_Defines.h"
-#include "UDPC_Deque.h"
-#include "UDPC_HashMap.h"
-
-#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
- #include <winsock2.h>
-
- #define CleanupSocket(x) closesocket(x)
-#elif UDPC_PLATFORM == UDPC_PLATFORM_MAC || UDPC_PLATFORM == UDPC_PLATFORM_LINUX
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <fcntl.h>
- #include <unistd.h>
-
- #define CleanupSocket(x) close(x)
-#else
- #define CleanupSocket(x) ((void)0)
-#endif
-
-#define UDPC_ATOSTR_BUF_SIZE 16
-
-/// (void *userData, uint32_t address)
-/*!
- * Note address is in network byte order (usually big-endian)
- */
-typedef void (*UDPC_callback_connected)(void*, uint32_t);
-
-/// (void *userData, uint32_t address)
-/*!
- * Note address is in network byte order (usually big-endian)
- */
-typedef void (*UDPC_callback_disconnected)(void*, uint32_t);
-
-/// (void *userData, uint32_t address, char *packetData, uint32_t packetSize)
-/*!
- * The data pointed to by the packetData argument is to data internally managed
- * by the UDPC_Context. It will change every time this callback is called so do
- * not depend on it persisting. This means you should copy the data out of it
- * when the callback is invoked and work with the copied data.
- */
-typedef void (*UDPC_callback_received)(void*, uint32_t, char*, uint32_t);
-
-/// This struct should not be used outside of this library
-typedef struct {
- uint32_t addr; // in network order (big-endian)
- uint32_t id;
- /*
- * 0x1 - is resending
- * 0x2 - is check received packet
- * 0x4 - has been re-sent
- * 0x8 - initiate connection packet
- */
- uint32_t flags;
- char *data; // no-header in sendPktQueue and receivedPackets, header in sentPkts
- uint32_t size;
- 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
- * 0x8 - initiating connection to server
- * 0x10 - is id set
- */
- uint32_t flags;
- uint32_t id;
- uint32_t lseq;
- uint32_t rseq;
- uint32_t ack;
- float timer;
- float toggleT;
- float toggleTimer;
- float toggledTimer;
- uint32_t addr; // in network order (big-endian)
- uint16_t port;
- UDPC_Deque *sentPkts;
- UDPC_Deque *sendPktQueue;
- UDPC_Deque *priorityPktQueue;
- struct timespec received;
- struct timespec sent;
- float rtt;
-} UDPC_INTERNAL_ConnectionData;
-
-/// This struct should not be used externally, only passed to functions that require it
-typedef struct {
- int isThreaded;
- /*
- * 0x1 - unused
- * 0x2 - is client
- * 0x4 - log errors
- * 0x8 - log warnings
- * 0x10 - log info
- * 0x20 - log verbose
- * 0x40 - accept new connections
- */
- uint32_t flags;
- /*
- * 0x1 - thread should stop
- */
- uint32_t threadFlags;
- uint32_t protocolID;
- uint32_t error;
- int socketHandle;
- struct sockaddr_in socketInfo;
- thrd_t threadHandle;
- mtx_t tCVMtx;
- mtx_t tflagsMtx;
- cnd_t threadCV;
- UDPC_HashMap *conMap;
- // Clients intentionally do not use idMap at all
- UDPC_HashMap *idMap;
- struct timespec lastUpdated;
- char atostrBuf[UDPC_ATOSTR_BUF_SIZE];
- char recvBuf[UDPC_PACKET_MAX_SIZE];
- UDPC_Deque *connectedEvents;
- UDPC_Deque *disconnectedEvents;
- UDPC_Deque *receivedPackets;
-
- UDPC_callback_connected callbackConnected;
- void *callbackConnectedUserData;
- UDPC_callback_disconnected callbackDisconnected;
- void *callbackDisconnectedUserData;
- UDPC_callback_received callbackReceived;
- void *callbackReceivedUserData;
-} UDPC_Context;
-
-/// This struct should not be used outside of this library
-typedef struct {
- struct timespec tsNow;
- float dt;
- UDPC_Deque *removedQueue;
- UDPC_Context *ctx;
-} UDPC_INTERNAL_update_struct;
-
-/// Creates a new UDPC_Context, for establishing a connection via UDP
-/*!
- * Callbacks must be set to use UDPC effectively, using the following functions:
- * - UDPC_set_callback_connected()
- * - UDPC_set_callback_disconnected()
- * - UDPC_set_callback_received()
- *
- * Clients should also use UDPC_client_initiate_connection() to let UDPC know
- * what server to connect to.
- *
- * UDPC_update() must be called periodically (ideally at 30 updates per second
- * or faster), to send and receive UDP packets, and establish new connections
- * when enabled. An init variant "UDPC_init_threaded_update()" is available
- * which will call update periodically on a separate thread.
- *
- * UDPC_check_events() must also be called to call the set callbacks for
- * connected, disconnected, and received events.
- *
- * When finished using UDPC, UDPC_destroy must be called on the context to free
- * resources.
- */
-UDPC_Context* UDPC_init(uint16_t listenPort, uint32_t listenAddr, int isClient);
-
-/// Creates a new UDPC_Context, where a thread is created to update UDPC on its own
-/*!
- * If using a UDPC_Context created by this init variant, UDPC_update() must not
- * be manually called, as it is called automatically by a separate thread.
- *
- * See the documentation for UDPC_init() for more details.
- */
-UDPC_Context* UDPC_init_threaded_update(uint16_t listenPort, uint32_t listenAddr, int isClient);
-
-/// This fn must be called on a UDPC_Context to free resources
-void UDPC_destroy(UDPC_Context *ctx);
-
-void UDPC_INTERNAL_destroy_conMap(void *unused, uint32_t addr, char *data);
-
-/// Sets the callback for connected events
-void UDPC_set_callback_connected(
- UDPC_Context *ctx, UDPC_callback_connected fptr, void *userData);
-
-/// Sets the callback for disconnected events
-void UDPC_set_callback_disconnected(
- UDPC_Context *ctx, UDPC_callback_disconnected fptr, void *userData);
-
-/// Sets the callback for received packet events
-void UDPC_set_callback_received(
- UDPC_Context *ctx, UDPC_callback_received fptr, void *userData);
-
-/// Invokes callbacks based on events that have ocurred during UDPC_update()
-void UDPC_check_events(UDPC_Context *ctx);
-
-/// Tells UDPC to initiate a connection to a server
-void UDPC_client_initiate_connection(UDPC_Context *ctx, uint32_t addr, uint16_t port);
-
-/*!
- * \brief Queues a packet to send to a connected peer
- * Note addr is expected to be in network-byte-order (big-endian).
- * If isChecked is non-zero, UDPC will attempt to resend the packet if peer has
- * not received it within UDPC_PACKET_TIMEOUT_SEC seconds.
- * \return non-zero on success
- */
-int UDPC_queue_send(
- UDPC_Context *ctx, uint32_t addr, uint32_t isChecked, void *data, uint32_t size);
-
-/*!
- * \brief get the number of packets that can be queued to the addr
- * \return number of queueable packets or 0 if connection has not been established
- */
-int UDPC_get_queue_send_available(UDPC_Context *ctx, uint32_t addr);
-
-/// Returns non-zero if UDPC is accepting new connections
-int UDPC_get_accept_new_connections(UDPC_Context *ctx);
-
-/// Set isAccepting to non-zero to let UDPC accept new connections
-/*!
- * Set isAccepting to zero to prevent UDPC from accepting new connections.
- */
-void UDPC_set_accept_new_connections(UDPC_Context *ctx, int isAccepting);
-
-/// Drops a connection specified by addr
-/*!
- * \return non-zero if the connection existed and was dropped
- */
-int UDPC_drop_connection(UDPC_Context *ctx, uint32_t addr);
-
-/// Gets the currently set protocol id
-uint32_t UDPC_get_protocol_id(UDPC_Context *ctx);
-
-/// Sets the protocol id
-/*!
- * Note that UDPC can only connect to other UDPC instances that use the same
- * protocol id.
- */
-void UDPC_set_protocol_id(UDPC_Context *ctx, uint32_t id);
-
-/*!
- * \brief Get the currently set error code, and clear it internally
- * Error codes and their meanings are defined in UDPC_Defines.h .
- * Use UDPC_get_error_str() to get a string describing the error.
- */
-uint32_t UDPC_get_error(UDPC_Context *ctx);
-
-/// Returns a string describing the error code for UDPC
-const char* UDPC_get_error_str(uint32_t error);
-
-/*!
- * 0 - log nothing
- * 1 - log only errors
- * 2 - log only errors and warnings
- * 3 - log errors, warnings, and info
- * 4+ - log everything
- *
- * By default, erros and warnings are logged.
- */
-void UDPC_set_logging_type(UDPC_Context *ctx, uint32_t logType);
-
-/// If threaded, this function is called automatically
-void UDPC_update(UDPC_Context *ctx);
-
-void UDPC_INTERNAL_update_to_rtt_si(void *userData, uint32_t addr, char *data);
-
-void UDPC_INTERNAL_update_send(void *userData, uint32_t addr, char *data);
-
-void UDPC_INTERNAL_update_rtt(
- UDPC_Context *ctx,
- UDPC_INTERNAL_ConnectionData *cd,
- uint32_t rseq,
- struct timespec *tsNow);
-
-void UDPC_INTERNAL_check_pkt_timeout(
- UDPC_Context *ctx,
- UDPC_INTERNAL_ConnectionData *cd,
- uint32_t rseq,
- uint32_t ack,
- struct timespec *tsNow);
-
-float UDPC_INTERNAL_ts_diff(struct timespec *ts0, struct timespec *ts1);
-
-int UDPC_INTERNAL_threadfn(void *context);
-
-/*
- * 0x1 - is ping
- * 0x2 - is resending
- * 0x4 - is checked received packet
- * 0x8 - is init connection packet
- */
-void UDPC_INTERNAL_prepare_pkt(
- void *data,
- uint32_t protocolID,
- uint32_t conID,
- uint32_t rseq,
- uint32_t ack,
- uint32_t *seqID,
- int flags);
-
-/*!
- * 0 - error
- * 1 - warning
- * 2 - info
- * 3 - verbose
- */
-void UDPC_INTERNAL_log(UDPC_Context *ctx, uint32_t level, const char *msg, ...);
-
-char* UDPC_INTERNAL_atostr(UDPC_Context *ctx, uint32_t addr);
-
-uint32_t UDPC_INTERNAL_generate_id(UDPC_Context *ctx);
-
-/*1
- * \brief Converts a IPV4 string to a 32-bit unsigned integer address in big-endian
- * \return 0 if string is invalid, address in big-endian format otherwise
- */
-uint32_t UDPC_strtoa(const char *addrStr);
-
-#endif
+++ /dev/null
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <threads.h>
-
-#include <UDPConnection.h>
-
-typedef struct
-{
- int isConnected;
- int hasConnectedOnce;
- uint32_t addr;
-} TestContext;
-
-void printUsage()
-{
- printf("Usage: [-c] [-t] -a <addr> -p <target_port> -l <listen_port>"
- " [-d <listen_address>]\n");
-}
-
-void conCallback(void *userdata, uint32_t addr)
-{
- TestContext *ctx = userdata;
- ctx->isConnected = 1;
- ctx->hasConnectedOnce = 1;
- ctx->addr = addr;
- printf("Connected callback called\n");
-}
-
-void discCallback(void *userdata, uint32_t addr)
-{
- TestContext *ctx = userdata;
- ctx->isConnected = 0;
- printf("Disconnected callback called\n");
-}
-
-void recCallback(void *userdata, uint32_t addr, char *data, uint32_t size)
-{
- TestContext *ctx = userdata;
- if(ctx->addr == addr && size == 7 && data[6] == '\0')
- {
- printf("Got %s\n", data);
- }
-}
-
-void updateSendBuffer(uint32_t *index, char *buffer)
-{
- ++(*index);
- if(*index >= 26 * 26 * 26 * 26 * 26 * 26)
- {
- *index = 0;
- }
-
- uint32_t temp = 1;
- for(int x = 0; x < 6; ++x)
- {
- buffer[x] = (*index / temp) % 26 + 'a';
- temp *= 26;
- }
-}
-
-int main(int argc, char** argv)
-{
- int isClient = 0;
- int isThreaded = 0;
- uint32_t targetAddress = 0;
- uint16_t targetPort = 0;
- uint32_t listenAddress = 0;
- uint16_t listenPort = 0;
- TestContext testCtx = {0, 0};
-
- uint32_t sendIndex = 0;
- char sendBuffer[7] = {
- 'a', 'a', 'a',
- 'a', 'a', 'a',
- '\0'
- };
-
- --argc; ++argv;
- while(argc > 0)
- {
- if(strcmp("-c", argv[0]) == 0)
- {
- isClient = 1;
- }
- else if(strcmp("-t", argv[0]) == 0)
- {
- isThreaded = 1;
- }
- else if(strcmp("-a", argv[0]) == 0 && argc > 1)
- {
- targetAddress = UDPC_strtoa(argv[1]);
- --argc; ++argv;
- }
- else if(strcmp("-p", argv[0]) == 0 && argc > 1)
- {
- targetPort = strtoul(argv[1], NULL, 10);
- --argc; ++argv;
- }
- else if(strcmp("-l", argv[0]) == 0 && argc > 1)
- {
- listenPort = strtoul(argv[1], NULL, 10);
- --argc; ++argv;
- }
- else if(strcmp("-d", argv[0]) == 0 && argc > 1)
- {
- listenAddress = UDPC_strtoa(argv[1]);
- --argc; ++argv;
- }
- else if(strcmp("-h", argv[0]) == 0 || strcmp("--help", argv[0]) == 0)
- {
- printUsage();
- return 0;
- }
- --argc; ++argv;
- }
-
- UDPC_Context *ctx;
- if(isThreaded == 0)
- {
- ctx = UDPC_init(listenPort, listenAddress, isClient);
- }
- else
- {
- ctx = UDPC_init_threaded_update(listenPort, listenAddress, isClient);
- }
-
- printf("isClient: %s, targetAddr: %s, targetPort: %u, listenPort: %u\n",
- isClient == 0 ? "false" : "true",
- UDPC_INTERNAL_atostr(ctx, targetAddress),
- targetPort,
- listenPort);
-
- if(UDPC_get_error(ctx) == UDPC_SUCCESS)
- {
- UDPC_set_logging_type(ctx, 4);
- UDPC_set_callback_connected(ctx, conCallback, &testCtx);
- UDPC_set_callback_disconnected(ctx, discCallback, &testCtx);
- UDPC_set_callback_received(ctx, recCallback, &testCtx);
- while(UDPC_get_error(ctx) == UDPC_SUCCESS)
- {
- if(isClient && testCtx.isConnected == 0)
- {
- UDPC_client_initiate_connection(ctx, targetAddress, targetPort);
- }
- if(isThreaded == 0) { UDPC_update(ctx); }
- UDPC_check_events(ctx);
- if(testCtx.isConnected != 0 && UDPC_get_queue_send_available(ctx, testCtx.addr) > 0)
- {
- UDPC_queue_send(ctx, testCtx.addr, 0, sendBuffer, 7);
- updateSendBuffer(&sendIndex, sendBuffer);
- }
- thrd_sleep(&(struct timespec){0, 16666666}, NULL);
- if(testCtx.hasConnectedOnce != 0 && testCtx.isConnected == 0)
- {
- break;
- }
- }
- }
- UDPC_destroy(ctx);
-
- return 0;
-}
+++ /dev/null
-#include "UDPC_UnitTest.h"
-
-#include <stdlib.h>
-#include <UDPC_Deque.h>
-#include <UDPC_HashMap.h>
-#include <UDPConnection.h>
-
-static UnitTestState UDPC_uts = {0, 0};
-
-void TEST_DEQUE()
-{
- int arr[32];
- char *temp = NULL;
- uint32_t size;
- for(int x = 0; x < 32; ++x)
- {
- arr[x] = x;
- }
- UDPC_Deque *deque;
-
- // init
- deque = UDPC_Deque_init(sizeof(int) * 32);
- ASSERT_TRUE(deque);
- ASSERT_TRUE(deque->buf);
- ASSERT_EQ(deque->head, 0);
- ASSERT_EQ(deque->tail, 0);
- ASSERT_EQ(deque->size, 0);
- ASSERT_EQ(deque->alloc_size, sizeof(int) * 32);
-
- // realloc smaller success
- ASSERT_TRUE(UDPC_Deque_realloc(deque, sizeof(int) * 16));
- ASSERT_TRUE(deque->buf);
- ASSERT_EQ(deque->head, 0);
- ASSERT_EQ(deque->tail, 0);
- ASSERT_EQ(deque->size, 0);
- ASSERT_EQ(deque->alloc_size, sizeof(int) * 16);
-
- // 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
- ASSERT_TRUE(UDPC_Deque_realloc(deque, sizeof(int) * 32));
- ASSERT_EQ_MEM(&arr[4], deque->buf, sizeof(int) * 4);
- ASSERT_EQ_MEM(arr, &deque->buf[sizeof(int) * 4], sizeof(int) * 4);
- ASSERT_EQ(deque->alloc_size, sizeof(int) * 32);
-
- // pop front success
- UDPC_Deque_pop_front(deque, sizeof(int) * 4);
- ASSERT_EQ(deque->size, sizeof(int) * 4);
-
- // get front success
- size = sizeof(int) * 4;
- ASSERT_TRUE(UDPC_Deque_get_front(deque, (void**)&temp, &size));
- ASSERT_EQ(size, sizeof(int) * 4);
- ASSERT_EQ_MEM(arr, temp, size);
- free(temp);
-
- // pop back success
- UDPC_Deque_pop_back(deque, sizeof(int) * 4);
- ASSERT_EQ(deque->size, 0);
-
- // push front success
- ASSERT_TRUE(UDPC_Deque_push_front(deque, arr, sizeof(int) * 16));
- ASSERT_EQ(deque->size, sizeof(int) * 16);
-
- // get front success
- size = sizeof(int) * 16;
- ASSERT_TRUE(UDPC_Deque_get_front(deque, (void**)&temp, &size));
- ASSERT_EQ(size, sizeof(int) * 16);
- ASSERT_EQ_MEM(arr, temp, size);
- free(temp);
-
- // get back success
- size = sizeof(int) * 16;
- ASSERT_TRUE(UDPC_Deque_get_back(deque, (void**)&temp, &size));
- ASSERT_EQ(size, sizeof(int) * 16);
- ASSERT_EQ_MEM(arr, temp, size);
- free(temp);
-
- // realloc smaller fail
- ASSERT_FALSE(UDPC_Deque_realloc(deque, sizeof(int) * 8));
- ASSERT_EQ(deque->size, sizeof(int) * 16);
- ASSERT_EQ(deque->alloc_size, sizeof(int) * 32);
-
- // realloc smaller success
- ASSERT_TRUE(UDPC_Deque_realloc(deque, sizeof(int) * 16));
- ASSERT_EQ(deque->size, sizeof(int) * 16);
- ASSERT_EQ(deque->alloc_size, sizeof(int) * 16);
- ASSERT_EQ_MEM(deque->buf, arr, sizeof(int) * 16);
-
- // push back fail
- ASSERT_FALSE(UDPC_Deque_push_back(deque, arr, sizeof(int) * 16));
- ASSERT_EQ(deque->size, sizeof(int) * 16);
- ASSERT_EQ(deque->alloc_size, sizeof(int) * 16);
- ASSERT_EQ_MEM(deque->buf, arr, sizeof(int) * 16);
-
- // push front fail
- ASSERT_FALSE(UDPC_Deque_push_back(deque, arr, sizeof(int) * 16));
- ASSERT_EQ(deque->size, sizeof(int) * 16);
- ASSERT_EQ(deque->alloc_size, sizeof(int) * 16);
- ASSERT_EQ_MEM(deque->buf, arr, sizeof(int) * 16);
-
- // pop back
- UDPC_Deque_pop_back(deque, sizeof(int) * 8);
-
- // get front success
- size = sizeof(int) * 8;
- ASSERT_TRUE(UDPC_Deque_get_front(deque, (void**)&temp, &size));
- ASSERT_EQ(size, sizeof(int) * 8);
- ASSERT_EQ_MEM(temp, arr, sizeof(int) * 8);
- free(temp);
-
- // get front fail
- size = sizeof(int) * 16;
- ASSERT_FALSE(UDPC_Deque_get_front(deque, (void**)&temp, &size));
- ASSERT_EQ(size, sizeof(int) * 8);
- ASSERT_EQ_MEM(temp, arr, sizeof(int) * 8);
- free(temp);
-
- // get back success
- size = sizeof(int) * 8;
- ASSERT_TRUE(UDPC_Deque_get_back(deque, (void**)&temp, &size));
- ASSERT_EQ(size, sizeof(int) * 8);
- ASSERT_EQ_MEM(temp, arr, sizeof(int) * 8);
- free(temp);
-
- // get back fail
- size = sizeof(int) * 16;
- ASSERT_FALSE(UDPC_Deque_get_back(deque, (void**)&temp, &size));
- ASSERT_EQ(size, sizeof(int) * 8);
- ASSERT_EQ_MEM(temp, arr, sizeof(int) * 8);
- free(temp);
-
- // index success
- for(int x = 0; x < 8; ++x)
- {
- ASSERT_TRUE(UDPC_Deque_index(deque, sizeof(int), x, (void**)&temp));
- if(temp)
- {
- ASSERT_EQ_MEM(temp, &arr[x], sizeof(int));
- free(temp);
- }
- }
-
- // index fail
- ASSERT_FALSE(UDPC_Deque_index(deque, sizeof(int), 8, (void**)&temp));
- ASSERT_FALSE(temp);
-
- // index_rev success
- for(int x = 0; x < 8; ++x)
- {
- ASSERT_TRUE(UDPC_Deque_index_rev(deque, sizeof(int), x, (void**)&temp));
- if(temp)
- {
- ASSERT_EQ_MEM(temp, &arr[7 - x], sizeof(int));
- free(temp);
- }
- }
-
- // index_rev fail
- ASSERT_FALSE(UDPC_Deque_index_rev(deque, sizeof(int), 8, (void**)&temp));
- ASSERT_FALSE(temp);
-
- // remove success front
- ASSERT_TRUE(UDPC_Deque_remove(deque, sizeof(int), 0));
- ASSERT_EQ(sizeof(int) * 7, deque->size);
- ASSERT_EQ_MEM(deque->buf, &arr[7], sizeof(int));
-
- // remove success end
- ASSERT_TRUE(UDPC_Deque_remove(deque, sizeof(int), 6));
- ASSERT_EQ(sizeof(int) * 6, deque->size);
- ASSERT_EQ_MEM(&deque->buf[deque->tail - sizeof(int)], &arr[5], sizeof(int));
-
- // remove success middle
- ASSERT_TRUE(UDPC_Deque_remove(deque, sizeof(int), 2));
- ASSERT_EQ(sizeof(int) * 5, deque->size);
- ASSERT_EQ_MEM(&deque->buf[deque->head + sizeof(int) * 2], &arr[5], sizeof(int));
-
- // remove success until empty
- while(deque->size > 0)
- {
- ASSERT_TRUE(UDPC_Deque_remove(deque, sizeof(int), 0));
- }
- ASSERT_EQ(deque->size, 0);
-
- // test push_back_realloc
- ASSERT_EQ(deque->alloc_size, 16 * sizeof(int));
- for(int x = 0; x < 16; ++x)
- {
- ASSERT_NEQ(UDPC_Deque_push_back(deque, &x, sizeof(int)), 0);
- }
- int tempInt = 20;
- ASSERT_EQ(UDPC_Deque_push_back(deque, &tempInt, sizeof(int)), 0);
- ASSERT_NEQ(UDPC_Deque_push_back_realloc(deque, &tempInt, sizeof(int)), 0);
- ASSERT_EQ(deque->alloc_size, 32 * sizeof(int));
- ASSERT_EQ_MEM(UDPC_Deque_get_back_ptr(deque, sizeof(int)), &tempInt, sizeof(int));
-
- UDPC_Deque_pop_back(deque, sizeof(int));
- ASSERT_NEQ(UDPC_Deque_realloc(deque, 16 * sizeof(int)), 0);
-
- // test push_front_realloc
- ASSERT_EQ(UDPC_Deque_push_front(deque, &tempInt, sizeof(int)), 0);
- ASSERT_NEQ(UDPC_Deque_push_front_realloc(deque, &tempInt, sizeof(int)), 0);
- ASSERT_EQ(deque->alloc_size, 32 * sizeof(int));
- ASSERT_EQ_MEM(UDPC_Deque_get_front_ptr(deque, sizeof(int)), &tempInt, sizeof(int));
-
- /*
- for(int x = 0; x < deque->tail / sizeof(int); ++x)
- {
- temp = &deque->buf[x * sizeof(int)];
- printf("%d: %d ", x, *((int*)temp));
- }
- printf("\n");
- printf("asize %d, size %d, head %d, tail %d\n",
- deque->alloc_size, deque->size, deque->head, deque->tail);
- */
-
- UDPC_Deque_destroy(deque);
- UNITTEST_REPORT(DEQUE)
-}
-
-void TEST_ATOSTR()
-{
- UDPC_Context ctx;
- ASSERT_EQ_MEM(
- UDPC_INTERNAL_atostr(&ctx, (0xFF << 24) | (0x1 << 16) | (0x1E << 8) | 0xAC),
- "172.30.1.255",
- 13);
- UNITTEST_REPORT(ATOSTR);
-}
-
-void TEST_HASHMAP_itercall_comp(void *userData, uint32_t key, char *data)
-{
- *((int*)userData) += 1;
- int temp = *((int*)(data)) / 100;
- ASSERT_EQ(temp, key);
-}
-
-void TEST_HASHMAP()
-{
- UDPC_HashMap *hm = UDPC_HashMap_init(0, sizeof(int));
- int temp;
-
- temp = 1333;
- ASSERT_NEQ(UDPC_HashMap_insert(hm, 0, &temp), NULL);
- ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 0), &temp, sizeof(int));
- ASSERT_NEQ(UDPC_HashMap_has(hm, 0), 0);
- ASSERT_EQ(UDPC_HashMap_has(hm, 1), 0);
-
- temp = 9999;
- ASSERT_NEQ(UDPC_HashMap_insert(hm, 1, &temp), NULL);
- ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 1), &temp, sizeof(int));
- ASSERT_NEQ(UDPC_HashMap_has(hm, 0), 0);
- ASSERT_NEQ(UDPC_HashMap_has(hm, 1), 0);
- ASSERT_EQ(UDPC_HashMap_has(hm, 2), 0);
-
- temp = 1235987;
- ASSERT_NEQ(UDPC_HashMap_insert(hm, 2, &temp), NULL);
- ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 2), &temp, sizeof(int));
- ASSERT_NEQ(UDPC_HashMap_has(hm, 0), 0);
- ASSERT_NEQ(UDPC_HashMap_has(hm, 1), 0);
- ASSERT_NEQ(UDPC_HashMap_has(hm, 2), 0);
- ASSERT_EQ(UDPC_HashMap_has(hm, 3), 0);
-
- ASSERT_NEQ(UDPC_HashMap_remove(hm, 1), 0);
- temp = 1333;
- ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 0), &temp, sizeof(int));
- temp = 1235987;
- ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 2), &temp, sizeof(int));
- ASSERT_NEQ(UDPC_HashMap_has(hm, 0), 0);
- ASSERT_EQ(UDPC_HashMap_has(hm, 1), 0);
- ASSERT_NEQ(UDPC_HashMap_has(hm, 2), 0);
-
- ASSERT_EQ(UDPC_HashMap_realloc(hm, 0), 0);
- ASSERT_NEQ(UDPC_HashMap_realloc(hm, 16), 0);
-
- temp = 1333;
- ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 0), &temp, sizeof(int));
- temp = 1235987;
- ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 2), &temp, sizeof(int));
- ASSERT_NEQ(UDPC_HashMap_has(hm, 0), 0);
- ASSERT_EQ(UDPC_HashMap_has(hm, 1), 0);
- ASSERT_NEQ(UDPC_HashMap_has(hm, 2), 0);
-
- UDPC_HashMap_clear(hm);
- ASSERT_EQ(hm->size, 0);
- ASSERT_EQ(hm->capacity, 16);
-
- ASSERT_NEQ(UDPC_HashMap_realloc(hm, 8), 0);
- ASSERT_EQ(hm->size, 0);
- ASSERT_EQ(hm->capacity, 8);
-
- for(int x = 0; x < 8; ++x)
- {
- temp = x * 100;
- ASSERT_NEQ(UDPC_HashMap_insert(hm, x, &temp), NULL);
- }
- for(int x = 0; x < 8; ++x)
- {
- temp = x * 100;
- ASSERT_EQ_MEM(UDPC_HashMap_get(hm, x), &temp, sizeof(int));
- ASSERT_NEQ(UDPC_HashMap_has(hm, x), 0);
- }
- ASSERT_GTE(hm->capacity, 8);
-
- temp = 800;
- ASSERT_NEQ(UDPC_HashMap_insert(hm, 8, &temp), NULL);
- for(int x = 0; x < 9; ++x)
- {
- temp = x * 100;
- ASSERT_EQ_MEM(UDPC_HashMap_get(hm, x), &temp, sizeof(int));
- ASSERT_NEQ(UDPC_HashMap_has(hm, x), 0);
- }
- ASSERT_GTE(hm->capacity, 16);
-
- for(int x = 0; x < 9; ++x)
- {
- ASSERT_NEQ(UDPC_HashMap_remove(hm, x), 0);
- ASSERT_EQ(UDPC_HashMap_has(hm, x), 0);
- }
- ASSERT_EQ(hm->size, 0);
- ASSERT_GTE(hm->capacity, 16);
-
- for(int x = 0; x < 32; ++x)
- {
- temp = x * 100;
- ASSERT_NEQ(UDPC_HashMap_insert(hm, x, &temp), NULL);
- }
- ASSERT_EQ(hm->size, 32);
-
- for(int x = 0; x < 32; ++x)
- {
- temp = x * 100;
- ASSERT_EQ_MEM(UDPC_HashMap_get(hm, x), &temp, sizeof(int));
- ASSERT_NEQ(UDPC_HashMap_has(hm, x), 0);
- }
-
- temp = 0;
- UDPC_HashMap_itercall(hm, TEST_HASHMAP_itercall_comp, &temp);
- ASSERT_EQ(temp, 32);
-
- // TODO DEBUG
- /*
- printf("Size = %d\n", hm->size);
- printf("Capacity = %d\n", hm->capacity);
- for(int x = 0; x < hm->capacity; ++x)
- {
- for(int y = 0; y * (4 + sizeof(int)) < hm->buckets[x]->size; ++y)
- {
- printf("Bucket%d[%d] = %d\n", x, y,
- *((int*)&hm->buckets[x]->buf[y * (4 + sizeof(int)) + 4]));
- }
- }
- for(int x = 0; x < hm->overflow->size; ++x)
- {
- printf("Overflow[%d] = %d\n", x,
- *((int*)&hm->overflow->buf[x * (4 + sizeof(int)) + 4]));
- }
- */
-
- UDPC_HashMap_destroy(hm);
- UNITTEST_REPORT(HASHMAP);
-}
-
-void TEST_STRTOA()
-{
- ASSERT_EQ(0x04030201, UDPC_strtoa("1.2.3.4"));
- ASSERT_EQ(0x0100007F, UDPC_strtoa("127.0.0.1"));
- ASSERT_EQ(0xFF01A8C0, UDPC_strtoa("192.168.1.255"));
- ASSERT_EQ(0, UDPC_strtoa("1.2.3.4.5"));
- ASSERT_EQ(0, UDPC_strtoa("100.20.30"));
- ASSERT_EQ(0, UDPC_strtoa("200.400.30.50"));
- UNITTEST_REPORT(STRTOA);
-}
-
-void TEST_ATOSTRTOA()
-{
- UDPC_Context ctx;
-
- ASSERT_EQ(0x01020304, UDPC_strtoa(UDPC_INTERNAL_atostr(&ctx, 0x01020304)));
- ASSERT_EQ(0x7F000001, UDPC_strtoa(UDPC_INTERNAL_atostr(&ctx, 0x7F000001)));
- ASSERT_EQ(0xC0A801FF, UDPC_strtoa(UDPC_INTERNAL_atostr(&ctx, 0xC0A801FF)));
- ASSERT_EQ(0xFFFEFDFC, UDPC_strtoa(UDPC_INTERNAL_atostr(&ctx, 0xFFFEFDFC)));
-
- UNITTEST_REPORT(ATOSTRTOA);
-}
-
-int main()
-{
- TEST_DEQUE();
- TEST_ATOSTR();
- TEST_STRTOA();
- TEST_ATOSTRTOA();
- TEST_HASHMAP();
- return 0;
-}
+++ /dev/null
-#ifndef UDPC_UNIT_TEST_H
-#define UDPC_UNIT_TEST_H
-
-#include <stdio.h>
-#include <string.h>
-
-/*
-#include <UDPC_Deque.h>
-*/
-
-#define ASSERT_TRUE(x) \
- if(!x) { printf("%d: ASSERT_TRUE(%s) FAILED\n", __LINE__, #x); \
- ++UDPC_uts.failed; } ++UDPC_uts.total;
-#define ASSERT_FALSE(x) \
- if(x) { printf("%d: ASSERT_FALSE(%s) FAILED\n", __LINE__, #x); \
- ++UDPC_uts.failed; } ++UDPC_uts.total;
-#define ASSERT_EQ(x, y) \
- if(x != y) { printf("%d: ASSERT_EQ(%s, %s) FAILED\n", __LINE__, #x, #y); \
- ++UDPC_uts.failed; } ++UDPC_uts.total;
-#define ASSERT_NEQ(x, y) \
- if(x == y) { printf("%d: ASSERT_NEQ(%s, %s) FAILED\n", __LINE__, #x, #y); \
- ++UDPC_uts.failed; } ++UDPC_uts.total;
-#define ASSERT_EQ_MEM(x, y, size) \
- if(memcmp(x, y, size) != 0) { printf("%d: ASSERT_EQ_MEM(%s, %s, %s) FAILED\n", \
- __LINE__, #x, #y, #size); ++UDPC_uts.failed; } ++UDPC_uts.total;
-#define ASSERT_NEQ_MEM(x, y, size) \
- if(memcmp(x, y, size) == 0) { printf("%d: ASSERT_NEQ_MEM(%s, %s, %s) FAILED\n", \
- __LINE__, #x, #y, #size); ++UDPC_uts.failed; } ++UDPC_uts.total;
-#define ASSERT_GT(x, y) \
- if(x <= y) { printf("%d: ASSERT_GT(%s, %s) FAILED\n", __LINE__, #x, #y); \
- ++UDPC_uts.failed; } ++UDPC_uts.total;
-#define ASSERT_GTE(x, y) \
- if(x < y) { printf("%d: ASSERT_GTE(%s, %s) FAILED\n", __LINE__, #x, #y); \
- ++UDPC_uts.failed; } ++UDPC_uts.total;
-#define ASSERT_LT(x, y) \
- if(x >= y) { printf("%d: ASSERT_LT(%s, %s) FAILED\n", __LINE__, #x, #y); \
- ++UDPC_uts.failed; } ++UDPC_uts.total;
-#define ASSERT_LTE(x, y) \
- if(x > y) { printf("%d: ASSERT_LTE(%s, %s) FAILED\n", __LINE__, #x, #y); \
- ++UDPC_uts.failed; } ++UDPC_uts.total;
-
-#define UNITTEST_REPORT(x) { \
- printf("%s: %d/%d tests failed\n", #x, UDPC_uts.failed, UDPC_uts.total); \
- UDPC_uts.failed = 0; \
- UDPC_uts.total = 0; }
-
-
-typedef struct
-{
- int result;
-} UnitTest_Test;
-
-typedef struct
-{
- int failed;
- int total;
-} UnitTestState;
-
-static UnitTestState UDPC_uts;
-
-#endif
+++ /dev/null
-Cargo.lock
-target/
+++ /dev/null
-[package]
-name = "udpc_rs"
-version = "0.1.0"
-authors = ["Stephen Seo <seo.disparate@gmail.com>"]
-edition = "2018"
-
-[dependencies]
-
-[build-dependencies]
-bindgen = "0.42.2"
-cmake = "0.1"
+++ /dev/null
-use cmake::Config;
-use bindgen;
-
-use std::env;
-use std::path::PathBuf;
-
-fn main() {
- let mut config = Config::new("../c_impl");
- if env::var("PROFILE").unwrap().eq("release") {
- config.define("CMAKE_BUILD_TYPE", "Release");
- } else {
- config.define("CMAKE_BUILD_TYPE", "Debug");
- }
- let mut dst = config.build();
- dst.push("lib");
-
- println!("cargo:rustc-link-search=native={}", dst.display());
- println!("cargo:rustc-link-lib=static=UDPConnection");
-
- let bindings = bindgen::Builder::default()
- .header("wrapper.h")
- .whitelist_type("UDPC_callback_connected")
- .whitelist_type("UDPC_callback_disconnected")
- .whitelist_type("UDPC_callback_received")
- .whitelist_type("UDPC_Context")
- .whitelist_function("UDPC_init")
- .whitelist_function("UDPC_init_threaded_update")
- .whitelist_function("UDPC_destroy")
- .whitelist_function("UDPC_set_callback_connected")
- .whitelist_function("UDPC_set_callback_disconnected")
- .whitelist_function("UDPC_set_callback_received")
- .whitelist_function("UDPC_check_events")
- .whitelist_function("UDPC_client_initiate_connection")
- .whitelist_function("UDPC_queue_send")
- .whitelist_function("UDPC_get_queue_send_available")
- .whitelist_function("UDPC_get_accept_new_connections")
- .whitelist_function("UDPC_set_accept_new_connections")
- .whitelist_function("UDPC_drop_connection")
- .whitelist_function("UDPC_get_protocol_id")
- .whitelist_function("UDPC_set_protocol_id")
- .whitelist_function("UDPC_get_error")
- .whitelist_function("UDPC_get_error_str")
- .whitelist_function("UDPC_set_logging_type")
- .whitelist_function("UDPC_update")
- .whitelist_function("UDPC_strtoa")
- .opaque_type("UDPC_Context")
- .opaque_type("UDPC_Deque")
- .opaque_type("UDPC_HashMap")
- .generate()
- .expect("Unable to generate bindings");
-
- let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
- bindings
- .write_to_file(out_path.join("bindings.rs"))
- .expect("Couldn't write bindings!");
-}
+++ /dev/null
-#![allow(non_upper_case_globals)]
-#![allow(non_camel_case_types)]
-#![allow(non_snake_case)]
-
-include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+++ /dev/null
-#include "../c_impl/src/UDPConnection.h"