diff --git a/CMakeLists.txt b/CMakeLists.txt index e15e0b9..9b9a66b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,7 @@ project(UDPConnection) set(UDPConnection_SOURCES src/UDPConnection.c src/UDPC_Deque.c + src/UDPC_Defines.c ) set(CMAKE_C_FLAGS "-Wall -Wno-missing-braces") diff --git a/src/UDPC_Defines.c b/src/UDPC_Defines.c new file mode 100644 index 0000000..e6c82cb --- /dev/null +++ b/src/UDPC_Defines.c @@ -0,0 +1,8 @@ +#include "UDPC_Defines.h" + +static const char *UDPC_ERR_SOCKETFAIL_STR = "Failed to create socket"; +static const char *UDPC_ERR_SOCKETBINDF_STR = "Failed to bind socket"; +static const char *UDPC_ERR_SOCKETNONBF_STR = "Failed to set non-blocking on socket"; +static const char *UDPC_ERR_MTXFAIL_STR = "Failed to create mutex"; +static const char *UDPC_ERR_CVFAIL_STR = "Failed to create condition variable"; +static const char *UDPC_ERR_THREADFAIL_STR = "Failed to create thread"; diff --git a/src/UDPC_Defines.h b/src/UDPC_Defines.h new file mode 100644 index 0000000..d2cfa7d --- /dev/null +++ b/src/UDPC_Defines.h @@ -0,0 +1,34 @@ +#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 + +static const char *UDPC_ERR_SOCKETFAIL_STR; +static const char *UDPC_ERR_SOCKETBINDF_STR; +static const char *UDPC_ERR_SOCKETNONBF_STR; +static const char *UDPC_ERR_MTXFAIL_STR; +static const char *UDPC_ERR_CVFAIL_STR; +static const char *UDPC_ERR_THREADFAIL_STR; + +#endif diff --git a/src/UDPConnection.c b/src/UDPConnection.c index 0b6d33a..3bcf2f5 100644 --- a/src/UDPConnection.c +++ b/src/UDPConnection.c @@ -1,35 +1,37 @@ #include "UDPConnection.h" -UDPC_Context UDPC_init(uint16_t listenPort) +#include + +UDPC_Context* UDPC_init(uint16_t listenPort) { - UDPC_Context context; - context.error = 0; - context.flags = 0; - context.threadFlags = 0; + UDPC_Context *context = malloc(sizeof(UDPC_Context)); + context->error = UDPC_SUCCESS; + context->flags = 0; + context->threadFlags = 0; // create socket - context.socketHandle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if(context.socketHandle <= 0) + context->socketHandle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if(context->socketHandle <= 0) { - context.socketHandle = 0; - context.error = UDPCON_ERR_SOCKETFAIL; + context->socketHandle = 0; + context->error = UDPC_ERR_SOCKETFAIL; fprintf(stderr, "Failed to create socket\n"); return context; } // bind socket - context.socketInfo.sin_family = AF_INET; - context.socketInfo.sin_addr.s_addr = INADDR_ANY; - context.socketInfo.sin_port = listenPort; + context->socketInfo.sin_family = AF_INET; + context->socketInfo.sin_addr.s_addr = INADDR_ANY; + context->socketInfo.sin_port = listenPort; if(bind( - context.socketHandle, - (const struct sockaddr*) &context.socketInfo, + context->socketHandle, + (const struct sockaddr*) &context->socketInfo, sizeof(struct sockaddr_in) ) < 0) { - context.error = UDPCON_ERR_SOCKETBINDF; - CleanupSocket(context.socketHandle); - context.socketHandle = 0; + context->error = UDPC_ERR_SOCKETBINDF; + CleanupSocket(context->socketHandle); + context->socketHandle = 0; fprintf(stderr, "Failed to bind socket\n"); return context; } @@ -37,18 +39,18 @@ UDPC_Context UDPC_init(uint16_t listenPort) // 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) + 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) + if(ioctlsocket(context->socketHandle, FIONBIO, &nonblocking) != 0) { #else { #endif - context.error = UDPCON_ERR_SOCKETNONBF; - CleanupSocket(context.socketHandle); - context.socketHandle = 0; + context->error = UDPC_ERR_SOCKETNONBF; + CleanupSocket(context->socketHandle); + context->socketHandle = 0; fprintf(stderr, "Failed to set non-blocking on socket\n"); return context; } @@ -56,59 +58,59 @@ UDPC_Context UDPC_init(uint16_t listenPort) return context; } -UDPC_Context UDPC_init_threaded_update(uint16_t listenPort) +UDPC_Context* UDPC_init_threaded_update(uint16_t listenPort) { - UDPC_Context context = UDPC_init(listenPort); + UDPC_Context *context = UDPC_init(listenPort); - context.error = mtx_init(&context.tCVMtx, mtx_timed); - if(context.error != thrd_success) + context->error = mtx_init(&context->tCVMtx, mtx_timed); + if(context->error != thrd_success) { - CleanupSocket(context.socketHandle); - context.socketHandle = 0; + CleanupSocket(context->socketHandle); + context->socketHandle = 0; fprintf(stderr, "Failed to create mutex\n"); - context.error = UDPCON_ERR_MTXFAIL; + context->error = UDPC_ERR_MTXFAIL; } - context.error = 0; + context->error = UDPC_SUCCESS; - context.error = mtx_init(&context.tflagsMtx, mtx_timed); - if(context.error != thrd_success) + context->error = mtx_init(&context->tflagsMtx, mtx_timed); + if(context->error != thrd_success) { - CleanupSocket(context.socketHandle); - context.socketHandle = 0; - mtx_destroy(&context.tCVMtx); + CleanupSocket(context->socketHandle); + context->socketHandle = 0; + mtx_destroy(&context->tCVMtx); fprintf(stderr, "Failed to create mutex\n"); - context.error = UDPCON_ERR_MTXFAIL; + context->error = UDPC_ERR_MTXFAIL; return context; } - context.error = 0; + context->error = UDPC_SUCCESS; - context.error = cnd_init(&context.threadCV); - if(context.error != thrd_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); + CleanupSocket(context->socketHandle); + context->socketHandle = 0; + mtx_destroy(&context->tCVMtx); + mtx_destroy(&context->tflagsMtx); fprintf(stderr, "Failed to create condition variable\n"); - context.error = UDPCON_ERR_CVFAIL; + context->error = UDPC_ERR_CVFAIL; return context; } - context.error = 0; + context->error = UDPC_SUCCESS; - context.error = thrd_create( - &context.threadHandle, UDPC_INTERNAL_threadfn, &context); - if(context.error != thrd_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); + CleanupSocket(context->socketHandle); + context->socketHandle = 0; + mtx_destroy(&context->tCVMtx); + mtx_destroy(&context->tflagsMtx); + cnd_destroy(&context->threadCV); fprintf(stderr, "Failed to create thread\n"); - context.error = UDPCON_ERR_THREADFAIL; + context->error = UDPC_ERR_THREADFAIL; return context; } - context.error = 0; + context->error = UDPC_SUCCESS; return context; } @@ -130,6 +132,30 @@ void UDPC_destroy(UDPC_Context *ctx) mtx_destroy(&ctx->tflagsMtx); cnd_destroy(&ctx->threadCV); } + + free(ctx); +} + +uint32_t UDPC_get_error(UDPC_Context *ctx) +{ + uint32_t error = ctx->error; + ctx->error = 0; + 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"; + } } int UDPC_INTERNAL_threadfn(void *context) diff --git a/src/UDPConnection.h b/src/UDPConnection.h index bccf6b0..e28f8d1 100644 --- a/src/UDPConnection.h +++ b/src/UDPConnection.h @@ -6,20 +6,7 @@ #include #include -#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 +#include "UDPC_Defines.h" #if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS #include @@ -34,13 +21,6 @@ #define CleanupSocket(x) close(x) #endif -#define UDPCON_ERR_SOCKETFAIL 1 // failed to create socket -#define UDPCON_ERR_SOCKETBINDF 2 // failed to bind socket -#define UDPCON_ERR_SOCKETNONBF 3 // failed to set non-blocking on socket -#define UDPCON_ERR_MTXFAIL 4 // failed to create mutex -#define UDPCON_ERR_CVFAIL 5 // failed to create condition variable -#define UDPCON_ERR_THREADFAIL 6 // failed to create thread - // This struct should not be used outside of this library typedef struct { @@ -101,12 +81,16 @@ typedef struct cnd_t threadCV; } UDPC_Context; -UDPC_Context UDPC_init(uint16_t listenPort); +UDPC_Context* UDPC_init(uint16_t listenPort); -UDPC_Context UDPC_init_threaded_update(uint16_t listenPort); +UDPC_Context* UDPC_init_threaded_update(uint16_t listenPort); void UDPC_destroy(UDPC_Context *ctx); +uint32_t UDPC_get_error(UDPC_Context *ctx); + +const char* UDPC_get_error_str(uint32_t error); + int UDPC_INTERNAL_threadfn(void *context); // internal usage only #endif