diff options
-rw-r--r-- | client/libacron/.gitignore | 1 | ||||
-rw-r--r-- | client/libacron/CMakeLists.txt | 68 | ||||
-rw-r--r-- | client/libacron/README.md | 15 | ||||
-rw-r--r-- | client/libacron/acronc/main.c | 22 | ||||
-rw-r--r-- | client/libacron/include/ids.h | 4 | ||||
-rw-r--r-- | client/libacron/include/incl.h | 14 | ||||
-rw-r--r-- | client/libacron/include/libac.h | 7 | ||||
-rw-r--r-- | client/libacron/include/net.h | 7 | ||||
-rw-r--r-- | client/libacron/include/requests.h | 3 | ||||
-rw-r--r-- | client/libacron/library.c | 1 | ||||
-rw-r--r-- | client/libacron/net.c | 46 | ||||
-rw-r--r-- | client/libacron/private/config.h | 3 | ||||
-rw-r--r-- | client/libacron/private/connection.h | 7 | ||||
-rw-r--r-- | client/libacron/private/helpers.c | 1 | ||||
-rw-r--r-- | client/libacron/private/win32.h | 15 | ||||
-rw-r--r-- | client/libacron/setup.bat | 20 |
16 files changed, 198 insertions, 36 deletions
diff --git a/client/libacron/.gitignore b/client/libacron/.gitignore index 1bab38a..6741ba2 100644 --- a/client/libacron/.gitignore +++ b/client/libacron/.gitignore @@ -1,5 +1,6 @@ cmake-build-debug/ cmake-build-release/ +json-c/ # https://raw.githubusercontent.com/github/gitignore/main/Global/JetBrains.gitignore # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider diff --git a/client/libacron/CMakeLists.txt b/client/libacron/CMakeLists.txt index ca9960e..db37671 100644 --- a/client/libacron/CMakeLists.txt +++ b/client/libacron/CMakeLists.txt @@ -3,41 +3,83 @@ project(libac C) set(CMAKE_C_STANDARD 11) -set(CMAKE_C_FLAGS_DEBUG - "${CMAKE_C_FLAGS_DEBUG} -g3 -O0 -fsanitize=address -DDEBUG") -set(CMAKE_EXE_LINKER_FLAGS_DEBUG - "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fsanitize=address") +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Debug) +endif() + add_definitions(-D_POSIX_C_SOURCE=200809L) +IF(CMAKE_BUILD_TYPE MATCHES Debug) + add_definitions(-DDEBUG) +ENDIF(CMAKE_BUILD_TYPE MATCHES Debug) -set(CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} "-Wl,--version-script='${CMAKE_SOURCE_DIR}/export.map'") +if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") + set(CMAKE_C_FLAGS_DEBUG + "${CMAKE_C_FLAGS_DEBUG} -g3 -O0 -fsanitize=address") + set(CMAKE_EXE_LINKER_FLAGS_DEBUG + "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fsanitize=address") + set(CMAKE_C_FLAGS + "${CMAKE_C_FLAGS} -fvisibility=hidden") +elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") + # TODO: MSVC ASAN + set(CMAKE_C_FLAGS_DEBUG + "${CMAKE_C_FLAGS_DEBUG} /DEBUG /Z7 /Od") + set(CMAKE_EXE_LINKER_FLAGS_DEBUG + "${CMAKE_EXE_LINKER_FLAGS_DEBUG}") +endif() -find_package(PkgConfig) -pkg_check_modules(json-c REQUIRED json-c) -add_library(ac SHARED +set(LIBAC_PUBLIC_HEADERS + include/incl.h include/libac.h include/events.h include/requests.h include/common.h include/net.h include/ids.h + ) + +set(LIBAC_PRIVATE + private/win32.h private/config.h - private/serializer.c - private/helpers.h + private/serializer.h private/helpers.c private/serializer.h - private/log.c private/log.h private/connection.h wic/include/http_parser.h wic/include/wic.h + private/serializer.c + private/helpers.c + private/log.c wic/src/http_parser.c wic/src/wic.c net.c ids.c library.c ) -target_include_directories(ac PUBLIC "${PROJECT_BINARY_DIR}" include/ private/ wic/include/) -target_link_libraries(ac json-c) + +add_library(ac SHARED + ${LIBAC_PUBLIC_HEADERS} + ${LIBAC_PRIVATE} + ) + +set(LIBAC_INCLUDES "${PROJECT_BINARY_DIR}" include/ private/ wic/include/) + +if (EXISTS ${CMAKE_SOURCE_DIR}/json-c/build/install) + message("Using in-tree JSON-C") + list(APPEND CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/json-c/build/install/lib/cmake/") +else() + message("Using system-wide JSON-C") +endif() + +if(WIN32) + set(LIBAC_DEPS ws2_32) +endif() + +find_package(json-c CONFIG) +set(LIBAC_DEPS ${LIBAC_DEPS} json-c::json-c) + +target_include_directories(ac PUBLIC ${LIBAC_INCLUDES}) +target_link_libraries(ac ${LIBAC_DEPS}) add_executable(acronc acronc/main.c diff --git a/client/libacron/README.md b/client/libacron/README.md index 11d7663..8305a5d 100644 --- a/client/libacron/README.md +++ b/client/libacron/README.md @@ -23,7 +23,7 @@ cd client/libacron/ mkdir build cd build cmake -DCMAKE_BUILD_TYPE=Release .. -make +cmake --build . ``` The shared library will be at `libac.so`. @@ -32,6 +32,19 @@ The distributable headers are at `client/libacron/include/`. To make debug builds, use the Debug build type. Debug builds will have ASAN enabled. +To build on Windows: + +```batch +git clone https://git.yuuta.moe/Minecraft/acron.git +CD acron +git submodule update --init +CD client/libacron/ +setup.bat +mkdir build +cmake -DCMAKE_BUILD_TYPE=Release .. +cmake --build . +``` + ## Usage All functions begin with `ac_`. Include `libac.h`. diff --git a/client/libacron/acronc/main.c b/client/libacron/acronc/main.c index ef3bb38..21958fd 100644 --- a/client/libacron/acronc/main.c +++ b/client/libacron/acronc/main.c @@ -5,7 +5,10 @@ #include "libac.h" #include <stdio.h> -#include <unistd.h> +#ifdef WIN32 +#include <winsock2.h> +#include <windef.h> +#endif static const char *world_name(const enum ac_world world) { switch (world) { @@ -120,6 +123,20 @@ static void handle_response(const ac_response_t *response) { int main(int argc, char **argv) { int r; +#ifdef WIN32 + WORD wVersionRequested; + WSADATA wsaData; + wVersionRequested = MAKEWORD(2, 2); + if ((r = WSAStartup(wVersionRequested, &wsaData))) { + fprintf(stderr, "WSAStartup failed with error: %d\n", r); + return r; + } + if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { + fprintf(stderr, "Could not find a usable version of Winsock.dll\n"); + WSACleanup(); + return 1; + } +#endif libac_config_t config = { #ifdef DEBUG .out = stderr, @@ -165,5 +182,8 @@ int main(int argc, char **argv) { } ac_disconnect(connection); ac_free(); +#ifdef WIN32 + WSACleanup(); +#endif return r; }
\ No newline at end of file diff --git a/client/libacron/include/ids.h b/client/libacron/include/ids.h index 80e7448..34d312e 100644 --- a/client/libacron/include/ids.h +++ b/client/libacron/include/ids.h @@ -5,6 +5,8 @@ #ifndef LIBAC_IDS_H #define LIBAC_IDS_H +#include "incl.h" + #define AC_TYPE_EVENT 0 /* 0b00000000 */ #define AC_TYPE_REQUEST 64 /* 0b01000000 */ #define AC_TYPE_RESPONSE 128 /* 0b10000000 */ @@ -26,6 +28,6 @@ typedef struct ac_obj { * @param obj Object to free. Must be a valid object. * @return AC_E_OK or an error code. When succeeds, obj is freed and no longer valid. */ -int ac_object_free(ac_obj_t *obj); +LIBAC_EXPORT int ac_object_free(ac_obj_t *obj); #endif /* LIBAC_IDS_H */ diff --git a/client/libacron/include/incl.h b/client/libacron/include/incl.h new file mode 100644 index 0000000..4ac00ab --- /dev/null +++ b/client/libacron/include/incl.h @@ -0,0 +1,14 @@ +/* + * Created by yuuta on 7/21/22. + */ + +#ifndef LIBAC_INCL_H +#define LIBAC_INCL_H + +#ifdef _MSC_VER +#define LIBAC_EXPORT __declspec(dllexport) +#else +#define LIBAC_EXPORT __attribute__ ((visibility ("default"))) extern +#endif + +#endif /* LIBAC_INCL_H */ diff --git a/client/libacron/include/libac.h b/client/libacron/include/libac.h index 542adcb..adf0310 100644 --- a/client/libacron/include/libac.h +++ b/client/libacron/include/libac.h @@ -5,13 +5,14 @@ #ifndef LIBAC_LIBAC_H #define LIBAC_LIBAC_H +#include "incl.h" #include "common.h" #include "events.h" #include "net.h" #include "requests.h" #include "ids.h" -#include <json-c/json_tokener.h> +#include <json_tokener.h> #include <stdio.h> typedef struct libac_config { @@ -23,12 +24,12 @@ typedef struct libac_config { * Initialize libac for the calling thread. * @return AC_E_OK on success. */ -int ac_init(const libac_config_t *config); +LIBAC_EXPORT int ac_init(const libac_config_t *config); /** * Destroy libac configuration for the calling thread. * @return AC_E_OK on success. */ -int ac_free(void); +LIBAC_EXPORT int ac_free(void); #endif /* LIBAC_LIBAC_H */ diff --git a/client/libacron/include/net.h b/client/libacron/include/net.h index 8fb33f8..6d8d9e7 100644 --- a/client/libacron/include/net.h +++ b/client/libacron/include/net.h @@ -5,6 +5,7 @@ #ifndef LIBAC_NET_H #define LIBAC_NET_H +#include "incl.h" #include "common.h" #include "events.h" #include "requests.h" @@ -27,7 +28,7 @@ typedef struct ac_connection_parameters { * @return AC_E_OK or an error code. When failed, *out will be untouched. * MT-Safe */ -int ac_connect(ac_connection_parameters_t parameters, void **out); +LIBAC_EXPORT int ac_connect(ac_connection_parameters_t parameters, void **out); /** * Disconnect the connection. @@ -35,7 +36,7 @@ int ac_connect(ac_connection_parameters_t parameters, void **out); * @return AC_E_OK or an error code. When failed, connection is undefined. When succeeds, connection is freed and invalid. * MT-Unsafe */ -int ac_disconnect(void *connection); +LIBAC_EXPORT int ac_disconnect(void *connection); /** * Blocks the current thread until a new response or event arrives. @@ -43,6 +44,6 @@ int ac_disconnect(void *connection); * @param response Output response of either an event or a response. May be NULL even if it succeeds. * @return AC_E_OK or an error code. When failed, *response is NULL. */ -int ac_receive(void *connection, ac_obj_t **response); +LIBAC_EXPORT int ac_receive(void *connection, ac_obj_t **response); #endif /* LIBAC_NET_H */ diff --git a/client/libacron/include/requests.h b/client/libacron/include/requests.h index 590bb2e..54c414b 100644 --- a/client/libacron/include/requests.h +++ b/client/libacron/include/requests.h @@ -5,6 +5,7 @@ #ifndef LIBAC_REQUESTS_H #define LIBAC_REQUESTS_H +#include "incl.h" #include "common.h" #include "ids.h" #include <stdbool.h> @@ -74,6 +75,6 @@ typedef struct ac_request_set_config { * @return AC_E_OK or an error code. * MT-Unsafe: Must be called on the same thread calling ac_receive(). */ -int ac_request(void *connection, const ac_request_t *request); +LIBAC_EXPORT int ac_request(void *connection, const ac_request_t *request); #endif /* LIBAC_REQUESTS_H */ diff --git a/client/libacron/library.c b/client/libacron/library.c index d401fed..c014ed9 100644 --- a/client/libacron/library.c +++ b/client/libacron/library.c @@ -1,3 +1,4 @@ +#include "win32.h" #include "libac.h" #include "config.h" #include "helpers.h" diff --git a/client/libacron/net.c b/client/libacron/net.c index cab4625..a0e8659 100644 --- a/client/libacron/net.c +++ b/client/libacron/net.c @@ -2,6 +2,7 @@ * Created by yuuta on 7/13/22. */ +#include "win32.h" #include "config.h" #include "net.h" #include "connection.h" @@ -15,11 +16,17 @@ #include <stdio.h> #include <string.h> #include <sys/types.h> -#include <sys/socket.h> -#include <netdb.h> #include <stdlib.h> #include <errno.h> + +#ifdef WIN32 +#include <winsock2.h> +#include <ws2tcpip.h> +#else +#include <sys/socket.h> +#include <netdb.h> #include <unistd.h> +#endif static void on_open_handler(struct wic_inst *inst) { struct ac_connection *conn = wic_get_app(inst); @@ -32,12 +39,13 @@ static void on_send_handler(struct wic_inst *inst, enum wic_buffer type) { struct ac_connection *conn = wic_get_app(inst); size_t pos; - ssize_t retval; + const uint8_t *ptr = data; + int retval; for (pos = 0U; pos < size; pos += retval) { size_t n = size - pos; LOGDV("write(%d, %p[%u, %u])", conn->fd, data, pos, n); - retval = write(conn->fd, &data[pos], (int) n); + retval = (int) send(conn->fd, &ptr[pos], (int) n, 0); if (retval <= 0) { /* There's no way to abort the process. */ int e = errno; @@ -154,13 +162,18 @@ int ac_connect(ac_connection_parameters_t parameters, void **out) { } if ((r = getaddrinfo(host, service, NULL, &res))) { + /* gai_strerror() seems to cause an linkage error. */ +#ifdef WIN32 + LOGEV("Resolve host: %d.", r); +#else LOGEV("Resolve host: %s.", gai_strerror(r)); +#endif r = AC_E_NET; free(conn); return r; } - int fd; + SOCKET fd; if ((fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) <= 0) { const int e = errno; LOGEV("Cannot create socket: %s (%d).", @@ -171,11 +184,17 @@ int ac_connect(ac_connection_parameters_t parameters, void **out) { return AC_E_NET; } if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) { +#ifdef WIN32 + const int e = WSAGetLastError(); + LOGEV("Cannot connect to socket: %d.", + e); +#else const int e = errno; LOGEV("Cannot connect to socket: %s (%d).", strerror2(e), e); - close(fd); +#endif + closesocket(fd); freeaddrinfo(res); free(conn); return AC_E_NET; @@ -185,7 +204,7 @@ int ac_connect(ac_connection_parameters_t parameters, void **out) { conn->fd = fd; if (wic_start(inst) != WIC_STATUS_SUCCESS) { LOGE("Cannot start the WIC client."); - close(fd); + closesocket(fd); free(conn); return AC_E_NET; } @@ -193,7 +212,7 @@ int ac_connect(ac_connection_parameters_t parameters, void **out) { /* Wait until established (ready to send). */ while (!conn->established) { ac_obj_t *obj = NULL; - r = ac_receive(conn, &obj); + r = ac_receive(conn, &obj, 0); if (obj) { LOGW("Received an object before connection is established. Dropping."); ac_object_free(obj); @@ -216,7 +235,7 @@ int ac_disconnect(void *connection) { } LOGD("Disconnecting..."); wic_close(&conn->inst); - close(conn->fd); + closesocket(conn->fd); free(conn); return AC_E_OK; } @@ -227,13 +246,18 @@ int ac_receive(void *connection, ac_obj_t **response) { struct wic_inst *inst = &conn->inst; static uint8_t buffer[1000U]; - ssize_t bytes; + int bytes; size_t retval, pos; - if ((bytes = recv(conn->fd, buffer, sizeof(buffer), 0)) <= 0) { + if ((bytes = (int) recv(conn->fd, buffer, sizeof(buffer), 0)) <= 0) { LOGDV("recv(%d) = %d", conn->fd, bytes); if (bytes < 0) { const int e = errno; + if (e == EAGAIN) { + /* Timeout */ + *response = NULL; + return AC_E_OK; + } LOGEV("Failed to receive from socket : %s (%d).", strerror2(e), e); diff --git a/client/libacron/private/config.h b/client/libacron/private/config.h index 3b670df..df907a0 100644 --- a/client/libacron/private/config.h +++ b/client/libacron/private/config.h @@ -5,9 +5,10 @@ #ifndef LIBAC_CONFIG_H #define LIBAC_CONFIG_H +#include "win32.h" #include "libac.h" -#include <json-c/json_tokener.h> +#include <json_tokener.h> #include <stdio.h> extern _Thread_local struct libac_config *config; diff --git a/client/libacron/private/connection.h b/client/libacron/private/connection.h index ad65b11..04d7639 100644 --- a/client/libacron/private/connection.h +++ b/client/libacron/private/connection.h @@ -5,10 +5,15 @@ #ifndef LIBAC_CONNECTION_H #define LIBAC_CONNECTION_H +#include "win32.h" #include "wic.h" #include "libac.h" #include <stdbool.h> +#ifdef WIN32 +#include <winsock2.h> +#endif + /** * Used to transfer deserialization result from receive handler to ac_receive(). */ @@ -24,7 +29,7 @@ struct ac_result { struct ac_connection { ac_connection_parameters_t parameters; struct wic_inst inst; - int fd; + SOCKET fd; bool established; /* Result from message handler. * Message handling will happen at the same thread as ac_receive (lib wic). */ diff --git a/client/libacron/private/helpers.c b/client/libacron/private/helpers.c index 4d4f3c8..86d65b6 100644 --- a/client/libacron/private/helpers.c +++ b/client/libacron/private/helpers.c @@ -2,6 +2,7 @@ * Created by yuuta on 7/19/22. */ +#include "win32.h" #include "helpers.h" #include "log.h" #include "common.h" diff --git a/client/libacron/private/win32.h b/client/libacron/private/win32.h new file mode 100644 index 0000000..07cdca8 --- /dev/null +++ b/client/libacron/private/win32.h @@ -0,0 +1,15 @@ +/* + * Created by yuuta on 7/21/22. + */ + +#ifndef LIBAC_WIN32_H +#define LIBAC_WIN32_H + +#ifdef WIN32 +#define _Thread_local __declspec( thread ) +#else +#define SOCKET int +#define closesocket(socket) close(socket) +#endif + +#endif /* LIBAC_WIN32_H */ diff --git a/client/libacron/setup.bat b/client/libacron/setup.bat new file mode 100644 index 0000000..52f33d1 --- /dev/null +++ b/client/libacron/setup.bat @@ -0,0 +1,20 @@ +@ECHO OFF +ECHO Setting up Windows builds ... + +git clone --depth 1 --branch json-c-0.16 https://github.com/json-c/json-c.git json-c +if %errorlevel% neq 0 exit /b %errorlevel% + +MKDIR json-c\build\ +if %errorlevel% neq 0 exit /b %errorlevel% +MKDIR json-c\build\install\ +if %errorlevel% neq 0 exit /b %errorlevel% + +CD json-c\build\ + +cmake -DCMAKE_INSTALL_PREFIX=install -DCMAKE_BUILD_TYPE=release -DBUILD_SHARED_LIBS=OFF .. +if %errorlevel% neq 0 exit /b %errorlevel% + +cmake --build . --target install +if %errorlevel% neq 0 exit /b %errorlevel% + +CD ..\..\
\ No newline at end of file |