diff --git a/cpp_impl/.gitignore b/cpp_impl/.gitignore new file mode 100644 index 0000000..5c322f8 --- /dev/null +++ b/cpp_impl/.gitignore @@ -0,0 +1,3 @@ +build*/ +compile_commands.json +*.o diff --git a/cpp_impl/CMakeLists.txt b/cpp_impl/CMakeLists.txt new file mode 100644 index 0000000..f8b89d9 --- /dev/null +++ b/cpp_impl/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.7) +project(UDPConnection) + +set(UDPConnection_VERSION 1.0) + +set(UDPConnection_SOURCES + src/UDPConnection.cpp +) + +set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wpedantic -Wno-missing-braces") +set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") +set(CMAKE_CXX_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 cxx_std_11) +target_link_libraries(UDPConnection PUBLIC pthread) + +if(CMAKE_BUILD_TYPE MATCHES "Debug") + set(UDPC_UnitTest_SOURCES + src/test/UDPC_UnitTest.cpp) + 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.cpp) + 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 + DESTINATION include) diff --git a/cpp_impl/src/UDPC_Defines.hpp b/cpp_impl/src/UDPC_Defines.hpp new file mode 100644 index 0000000..71acb77 --- /dev/null +++ b/cpp_impl/src/UDPC_Defines.hpp @@ -0,0 +1,32 @@ +#ifndef UDPC_DEFINES_HPP +#define UDPC_DEFINES_HPP + +#define UDPC_CONTEXT_IDENTIFIER 0x902F4DB3 + +#include +#include +#include + +#include "UDPConnection.h" + +namespace UDPC { + +struct Context { + Context(bool isThreaded); + + uint_fast32_t _contextIdentifier; + /* + * 0 - isThreaded + */ + std::bitset<32> flags; + std::atomic_bool isAcceptNewConnections; + std::atomic_uint32_t protocolID; + std::atomic_uint_fast8_t loggingType; + char atostrBuf[16]; +}; // struct Context + +bool VerifyContext(void *ctx); + +} // namespace UDPC + +#endif diff --git a/cpp_impl/src/UDPConnection.cpp b/cpp_impl/src/UDPConnection.cpp new file mode 100644 index 0000000..38e1aef --- /dev/null +++ b/cpp_impl/src/UDPConnection.cpp @@ -0,0 +1,186 @@ +#include "UDPConnection.h" +#include "UDPC_Defines.hpp" + +UDPC::Context::Context(bool isThreaded) : +_contextIdentifier(UDPC_CONTEXT_IDENTIFIER), +flags(), +isAcceptNewConnections(true), +protocolID(UDPC_DEFAULT_PROTOCOL_ID), +#ifndef NDEBUG +loggingType(INFO) +#else +loggingType(WARNING) +#endif +{ + if(isThreaded) { + flags.set(0); + } else { + flags.reset(0); + } +} + +bool UDPC::VerifyContext(void *ctx) { + if(ctx == nullptr) { + return false; + } + UDPC::Context* c = (UDPC::Context*) ctx; + if(c->_contextIdentifier == UDPC_CONTEXT_IDENTIFIER) { + return true; + } else { + return false; + } +} + +void* UDPC_init(uint16_t listenPort, uint32_t listenAddr, int isClient) { + UDPC::Context *ctx = new UDPC::Context(false); + + return ctx; +} + +void* UDPC_init_threaded_update(uint16_t listenPort, uint32_t listenAddr, int isClient) { + UDPC::Context *ctx = new UDPC::Context(true); + + return ctx; +} + +void UDPC_destroy(void *ctx) { + if (UDPC::VerifyContext(ctx)) { + delete (UDPC::Context*)ctx; + } +} + +void UDPC_update(void *ctx) { + if(!UDPC::VerifyContext(ctx)) { + return; + } + UDPC::Context *c = (UDPC::Context*)ctx; + if(c->flags.test(0)) { + // is threaded, update should not be called + return; + } + + // TODO impl +} + +int UDPC_get_queue_send_available(void *ctx, uint32_t addr) { + if(!UDPC::VerifyContext(ctx)) { + return 0; + } + UDPC::Context *c = (UDPC::Context*)ctx; + // TODO impl + return 0; +} + +void UDPC_queue_send(void *ctx, uint32_t destAddr, uint16_t destPort, uint32_t isChecked, void *data, uint32_t size) { + if(!UDPC::VerifyContext(ctx)) { + return; + } + UDPC::Context *c = (UDPC::Context*)ctx; + // TODO impl +} + +int UDPC_set_accept_new_connections(void *ctx, int isAccepting) { + if(!UDPC::VerifyContext(ctx)) { + return 0; + } + UDPC::Context *c = (UDPC::Context*)ctx; + return c->isAcceptNewConnections.exchange(isAccepting == 0 ? false : true); +} + +int UDPC_drop_connection(void *ctx, uint32_t addr, uint16_t port) { + if(!UDPC::VerifyContext(ctx)) { + return 0; + } + UDPC::Context *c = (UDPC::Context*)ctx; + // TODO impl + return 0; +} + +uint32_t UDPC_set_protocol_id(void *ctx, uint32_t id) { + if(!UDPC::VerifyContext(ctx)) { + return 0; + } + UDPC::Context *c = (UDPC::Context*)ctx; + return c->protocolID.exchange(id); +} + +UDPC_LoggingType set_logging_type(void *ctx, UDPC_LoggingType loggingType) { + if(!UDPC::VerifyContext(ctx)) { + return static_cast(0); + } + UDPC::Context *c = (UDPC::Context*)ctx; + return static_cast(c->loggingType.exchange(loggingType)); +} + +PacketInfo UDPC_get_received(void *ctx) { + if(!UDPC::VerifyContext(ctx)) { + return PacketInfo{{0}, 0, 0, 0, 0, 0}; + } + UDPC::Context *c = (UDPC::Context*)ctx; + // TODO impl + return PacketInfo{{0}, 0, 0, 0, 0, 0}; +} + +const char* UDPC_atostr(void *ctx, uint32_t addr) { + if(!UDPC::VerifyContext(ctx)) { + return nullptr; + } + UDPC::Context *c = (UDPC::Context*)ctx; + int index = 0; + for(int x = 0; x < 4; ++x) + { + unsigned char temp = (addr >> (x * 8)) & 0xFF; + + if(temp >= 100) + { + c->atostrBuf[index++] = '0' + temp / 100; + } + if(temp >= 10) + { + c->atostrBuf[index++] = '0' + ((temp / 10) % 10); + } + c->atostrBuf[index++] = '0' + temp % 10; + + if(x < 3) + { + c->atostrBuf[index++] = '.'; + } + } + c->atostrBuf[index] = 0; + + return c->atostrBuf; +} + +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; + } +} diff --git a/cpp_impl/src/UDPConnection.h b/cpp_impl/src/UDPConnection.h new file mode 100644 index 0000000..784c336 --- /dev/null +++ b/cpp_impl/src/UDPConnection.h @@ -0,0 +1,92 @@ +#ifndef UDPC_CONNECTION_H +#define UDPC_CONNECTION_H + +// Determine platform macros +#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 + +// OS-based networking macros +#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS + #include + + #define CleanupSocket(x) closesocket(x) +#elif UDPC_PLATFORM == UDPC_PLATFORM_MAC || UDPC_PLATFORM == UDPC_PLATFORM_LINUX + #include + #include + #include + #include + + #define CleanupSocket(x) close(x) +#else + #define CleanupSocket(x) ((void)0) +#endif + +// other defines +#define UDPC_PACKET_MAX_SIZE 8192 +#define UDPC_DEFAULT_PROTOCOL_ID 1357924680 + +#ifdef __cplusplus +# include +extern "C" { +#else +# include +#endif + +typedef enum { + SILENT, + ERROR, + WARNING, + VERBOSE, + INFO +} UDPC_LoggingType; + +typedef struct { + char data[UDPC_PACKET_MAX_SIZE]; + uint16_t dataSize; // zero if invalid + uint32_t sender; + uint32_t receiver; + uint16_t senderPort; + uint16_t receiverPort; +} PacketInfo; + +void* UDPC_init(uint16_t listenPort, uint32_t listenAddr, int isClient); +void* UDPC_init_threaded_update(uint16_t listenPort, uint32_t listenAddr, int isClient); + +void UDPC_destroy(void *ctx); + +void UDPC_update(void *ctx); + +int UDPC_get_queue_send_available(void *ctx, uint32_t addr); + +void UDPC_queue_send(void *ctx, uint32_t destAddr, uint16_t destPort, uint32_t isChecked, void *data, uint32_t size); + +int UDPC_set_accept_new_connections(void *ctx, int isAccepting); + +int UDPC_drop_connection(void *ctx, uint32_t addr, uint16_t port); + +uint32_t UDPC_set_protocol_id(void *ctx, uint32_t id); + +UDPC_LoggingType set_logging_type(void *ctx, UDPC_LoggingType loggingType); + +PacketInfo UDPC_get_received(void *ctx); + +const char* UDPC_atostr(void *ctx, uint32_t addr); + +uint32_t UDPC_strtoa(const char *addrStr); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/cpp_impl/src/test/UDPC_NetworkTest.cpp b/cpp_impl/src/test/UDPC_NetworkTest.cpp new file mode 100644 index 0000000..b2f9976 --- /dev/null +++ b/cpp_impl/src/test/UDPC_NetworkTest.cpp @@ -0,0 +1,2 @@ +int main() { +} diff --git a/cpp_impl/src/test/UDPC_UnitTest.cpp b/cpp_impl/src/test/UDPC_UnitTest.cpp new file mode 100644 index 0000000..b2f9976 --- /dev/null +++ b/cpp_impl/src/test/UDPC_UnitTest.cpp @@ -0,0 +1,2 @@ +int main() { +}