Replace c_impl, remove rust_binding, with cpp_impl

This commit is contained in:
Stephen Seo 2019-11-11 13:08:36 +09:00
parent a11c99e115
commit 00c1be07dc
27 changed files with 0 additions and 3781 deletions

View file

2
c_impl/.gitignore vendored
View file

@ -1,2 +0,0 @@
build*/
compile_commands.json

View file

@ -1,49 +0,0 @@
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)

View file

@ -1,65 +0,0 @@
#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

View file

@ -1,511 +0,0 @@
#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;
}

View file

@ -1,168 +0,0 @@
#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

View file

@ -1,315 +0,0 @@
#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;
}
}
}

View file

@ -1,111 +0,0 @@
#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

File diff suppressed because it is too large Load diff

View file

@ -1,325 +0,0 @@
#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

View file

@ -1,163 +0,0 @@
#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;
}

View file

@ -1,419 +0,0 @@
#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;
}

View file

@ -1,61 +0,0 @@
#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

View file

@ -1,2 +0,0 @@
Cargo.lock
target/

View file

@ -1,11 +0,0 @@
[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"

View file

@ -1,56 +0,0 @@
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!");
}

View file

@ -1,5 +0,0 @@
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

View file

@ -1 +0,0 @@
#include "../c_impl/src/UDPConnection.h"