Add some init/destruct stuff, thread stuff too
This commit is contained in:
parent
ec084d85cc
commit
909fe2e744
3 changed files with 235 additions and 3 deletions
|
@ -5,6 +5,16 @@ set(UDPConnection_SOURCES
|
||||||
src/UDPConnection.c
|
src/UDPConnection.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})
|
add_library(UDPConnection ${UDPConnection_SOURCES})
|
||||||
|
|
||||||
|
target_compile_features(UDPConnection PUBLIC c_std_11)
|
||||||
|
|
|
@ -1 +1,161 @@
|
||||||
#include "UDPConnection.h"
|
#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;
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,70 @@
|
||||||
#ifndef UDPCONNECTION_H
|
#ifndef UDPCONNECTION_H
|
||||||
#define 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
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue