]> git.seodisparate.com - UDPConnection/commitdiff
Add some init/destruct stuff, thread stuff too
authorStephen Seo <seo.disparate@gmail.com>
Sat, 26 Jan 2019 07:22:31 +0000 (16:22 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Sat, 26 Jan 2019 07:22:31 +0000 (16:22 +0900)
CMakeLists.txt
src/UDPConnection.c
src/UDPConnection.h

index b6730b346516836ea1605b9c3812edf00166c9ce..9fed4fac1ee6cab584f00e6c5e7854249fe217df 100644 (file)
@@ -5,6 +5,16 @@ set(UDPConnection_SOURCES
     src/UDPConnection.c
 )
 
-add_library(UDPConnection ${UDPConnection_SOURCES})
+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})
 
+target_compile_features(UDPConnection PUBLIC c_std_11)
index 95d32e21411c615a60708a91fafb6c2b48674e3a..a78aa1819a6bd3ef87a07df9807c913c1e4c2880 100644 (file)
@@ -1 +1,161 @@
 #include "UDPConnection.h"
+
+#include <time.h>
+
+UDPC_Context UDPC_init(unsigned short listenPort)
+{
+    UDPC_Context context;
+    context.error = 0;
+    context.flags = 0;
+    context.threadFlags = 0;
+
+    // create socket
+    context.socketHandle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    if(context.socketHandle <= 0)
+    {
+        context.socketHandle = 0;
+        context.error = UDPCON_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;
+    if(bind(
+            context.socketHandle,
+            (const struct sockaddr*) &context.socketInfo,
+            sizeof(struct sockaddr_in)
+        ) < 0)
+    {
+        context.error = UDPCON_ERR_SOCKETBINDF;
+        CleanupSocket(context.socketHandle);
+        context.socketHandle = 0;
+        fprintf(stderr, "Failed to bind socket\n");
+        return context;
+    }
+
+    // set nonblocking on socket
+#if PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_LINUX
+    int nonblocking = 1;
+    if(fcntl(context.socketHandle, F_SETFL, O_NONBLOCK, nonblocking) == -1)
+    {
+#elif PLATFORM == PLATFORM_WINDOWS
+    DWORD nonblocking = 1;
+    if(ioctlsocket(context.socketHandle, FIONBIO, &nonblocking) != 0)
+    {
+#endif
+        context.error = UDPCON_ERR_SOCKETNONBF;
+        CleanupSocket(context.socketHandle);
+        context.socketHandle = 0;
+        fprintf(stderr, "Failed to set non-blocking on socket\n");
+        return context;
+    }
+
+    return context;
+}
+
+UDPC_Context UDPC_init_threaded_update(unsigned short listenPort)
+{
+    UDPC_Context context = UDPC_init(listenPort);
+
+    context.error = mtx_init(&context.tCVMtx, mtx_timed);
+    if(context.error != thrd_success)
+    {
+        CleanupSocket(context.socketHandle);
+        context.socketHandle = 0;
+        fprintf(stderr, "Failed to create mutex\n");
+        context.error = UDPCON_ERR_MTXFAIL;
+    }
+    context.error = 0;
+
+    context.error = mtx_init(&context.tflagsMtx, mtx_timed);
+    if(context.error != thrd_success)
+    {
+        CleanupSocket(context.socketHandle);
+        context.socketHandle = 0;
+        mtx_destroy(&context.tCVMtx);
+        fprintf(stderr, "Failed to create mutex\n");
+        context.error = UDPCON_ERR_MTXFAIL;
+        return context;
+    }
+    context.error = 0;
+
+    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);
+        fprintf(stderr, "Failed to create condition variable\n");
+        context.error = UDPCON_ERR_CVFAIL;
+        return context;
+    }
+    context.error = 0;
+
+    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);
+        fprintf(stderr, "Failed to create thread\n");
+        context.error = UDPCON_ERR_THREADFAIL;
+        return context;
+    }
+    context.error = 0;
+
+    return context;
+}
+
+void UDPC_destroy(UDPC_Context *ctx)
+{
+    CleanupSocket(ctx->socketHandle);
+
+    if((ctx->flags & 0x1) != 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);
+    }
+}
+
+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);
+        mtx_unlock(&ctx->tCVMtx);
+
+        mtx_lock(&ctx->tflagsMtx);
+        shouldStop = ctx->threadFlags & 0x1;
+        mtx_unlock(&ctx->tflagsMtx);
+    }
+
+    return 0;
+}
index 365b317f0847b41c025b08618437e56242346761..15e3954279355ed570e1fc681a7b0da4173f39fc 100644 (file)
@@ -1,8 +1,70 @@
 #ifndef UDPCONNECTION_H
 #define UDPCONNECTION_H
 
-struct UDPC_Context
+#include <stdio.h>
+#include <threads.h>
+
+#define PLATFORM_WINDOWS 1
+#define PLATFORM_MAC 2
+#define PLATFORM_LINUX 3
+#define PLATFORM_UNKNOWN 0
+
+#if defined _WIN32
+  #define PLATFORM PLATFORM_WINDOWS
+#elif defined __APPLE__
+  #define PLATFORM PLATFORM_MAC
+#elif defined __linux__
+  #define PLATFORM PLATFORM_LINUX
+#else
+  #define PLATFORM PLATFORM_UNKNOWN
+#endif
+
+#if PLATFORM == PLATFORM_WINDOWS
+  #include <winsock2.h>
+
+  #define CleanupSocket(x) closesocket(x)
+#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_LINUX
+  #include <sys/socket.h>
+  #include <netinet/in.h>
+  #include <fcntl.h>
+  #include <unistd.h>
+
+  #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 modified, only passed to functions that require it
+typedef struct
 {
-};
+    int error;
+    int socketHandle;
+    struct sockaddr_in socketInfo;
+    thrd_t threadHandle;
+    mtx_t tCVMtx;
+    mtx_t tflagsMtx;
+    cnd_t threadCV;
+    /*
+     * 0x1 - is threaded
+     */
+    int flags;
+    /*
+     * 0x1 - thread should stop
+     */
+    int threadFlags;
+} UDPC_Context;
+
+UDPC_Context UDPC_init(unsigned short listenPort);
+
+UDPC_Context UDPC_init_threaded_update(unsigned short listenPort);
+
+void UDPC_destroy(UDPC_Context *ctx);
+
+int UDPC_INTERNAL_threadfn(void *context); // internal usage only
 
 #endif