aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/libacron/.gitignore1
-rw-r--r--client/libacron/CMakeLists.txt68
-rw-r--r--client/libacron/README.md15
-rw-r--r--client/libacron/acronc/main.c22
-rw-r--r--client/libacron/include/ids.h4
-rw-r--r--client/libacron/include/incl.h14
-rw-r--r--client/libacron/include/libac.h7
-rw-r--r--client/libacron/include/net.h7
-rw-r--r--client/libacron/include/requests.h3
-rw-r--r--client/libacron/library.c1
-rw-r--r--client/libacron/net.c46
-rw-r--r--client/libacron/private/config.h3
-rw-r--r--client/libacron/private/connection.h7
-rw-r--r--client/libacron/private/helpers.c1
-rw-r--r--client/libacron/private/win32.h15
-rw-r--r--client/libacron/setup.bat20
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