Skip to content

Commit

Permalink
harmony: add setProtectFd code
Browse files Browse the repository at this point in the history
Ref: #698.
  • Loading branch information
Chilledheart committed Jan 24, 2024
1 parent acd60e2 commit dc93336
Show file tree
Hide file tree
Showing 5 changed files with 291 additions and 1 deletion.
26 changes: 25 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ if (IOS)
elseif(APPLE)
list(APPEND YASS_APP_FEATURES "mac ${CMAKE_OSX_DEPLOYMENT_TARGET}")
elseif(OHOS)
list(APPEND YASS_APP_FEATURES "ohos ${OHOS_APILEVEL}")
list(APPEND YASS_APP_FEATURES "harmony ${OHOS_APILEVEL}")
elseif(ANDROID)
list(APPEND YASS_APP_FEATURES "android ${ANDROID_API_VERSION}")
elseif(MSVC)
Expand Down Expand Up @@ -1897,6 +1897,14 @@ if (ANDROID AND GUI)
set(GUI_C_CXX_FLAGS "")
set(GUI_LIBRARY_DIRS "")
set(GUI_LIBRARIES "")
elseif (OHOS AND GUI)
set(GUI_FLAVOUR "harmony")
set(GUI_USE_FILE "")
set(GUI_INCLUDE_DIRS "")
set(GUI_DEFINITIONS "")
set(GUI_C_CXX_FLAGS "")
set(GUI_LIBRARY_DIRS "")
set(GUI_LIBRARIES "libace_napi.z.so")
elseif (WIN32 AND GUI)
message(STATUS "Compiling with GUI support: Windows")
set(GUI_FLAVOUR "windows")
Expand Down Expand Up @@ -3719,6 +3727,10 @@ if (GUI)
src/android/utils.hpp
src/android/utils.cpp
)
elseif (GUI_FLAVOUR STREQUAL "harmony")
list(APPEND SRC_FILES
src/harmony/yass.cpp
)
elseif (GUI_FLAVOUR STREQUAL "windows")
set(APP_MSVC_MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/yass.manifest")
configure_file("src/win32/yass.manifest.in" "${APP_MSVC_MANIFEST}" @ONLY)
Expand Down Expand Up @@ -3871,6 +3883,15 @@ if (GUI)
target_link_libraries(${APP_NAME} PRIVATE tun2proxy)
set_target_properties(${APP_NAME} PROPERTIES
LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/android/export.lds -u Java_it_gui_yass_MainActivity_tun2ProxyInit -u Java_it_gui_yass_MainActivity_tun2ProxyRun -u Java_it_gui_yass_MainActivity_tun2ProxyDestroy")
elseif (GUI_FLAVOUR STREQUAL "harmony")
add_library(${APP_NAME} SHARED ${GUI_OPTIONS}
${SRC_FILES}
${GUI_USE_FILE}
)

# target_link_libraries(${APP_NAME} PRIVATE tun2proxy)
set_target_properties(${APP_NAME} PROPERTIES
LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/harmony/export.lds -u RegisterEntryModule")
else()
add_executable(${APP_NAME} WIN32 ${GUI_OPTIONS}
${SRC_FILES}
Expand All @@ -3888,6 +3909,9 @@ if (GUI)
if (GUI_FLAVOUR STREQUAL "android")
target_include_directories(${APP_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/android)
elseif (GUI_FLAVOUR STREQUAL "harmony")
target_include_directories(${APP_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/harmony)
elseif (GUI_FLAVOUR STREQUAL "windows")
target_include_directories(${APP_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/win32)
Expand Down
4 changes: 4 additions & 0 deletions src/harmony/export.lds
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
global: RegisterEntryModule;
local: *;
};
239 changes: 239 additions & 0 deletions src/harmony/yass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2024 Chilledheart */
#ifdef __OHOS__

#include "harmony/yass.hpp"

#include "core/logging.hpp"
#include <base/posix/eintr_wrapper.h>

#include <napi/native_api.h>
#include <js_native_api.h>
#include <js_native_api_types.h>

#include <unistd.h>

static napi_env setProtectFdCallbackEnv = nullptr;
static napi_threadsafe_function setProtectFdCallbackFunc = nullptr;

struct AsyncProtectFdEx_t {
napi_async_work work_item;
int fd;
int write_end;
};

static constexpr char kAsyncResourceName[] = "Thread-safe SetProtectFd";

static void setProtectFdExecuteWork(napi_env env, void *data) {
AsyncProtectFdEx_t *async_protect_fd_ex = (AsyncProtectFdEx_t *)data;

auto status = napi_acquire_threadsafe_function(setProtectFdCallbackFunc);
if (status != napi_ok) {
LOG(WARNING) << "napi_acquire_threadsafe_function: " << status;
return;
}

status = napi_call_threadsafe_function(setProtectFdCallbackFunc, (void*)(uintptr_t)async_protect_fd_ex->fd, napi_tsfn_blocking);
if (status != napi_ok) {
LOG(WARNING) << "napi_call_threadsafe_function: " << status;
return;
}

status = napi_release_threadsafe_function(setProtectFdCallbackFunc, napi_tsfn_release);

if (status != napi_ok) {
LOG(WARNING) << "napi_release_threadsafe_function: " << status;
return;
}
}

// This function runs on the main thread after `ExecuteWork` exited.
static void setProtectFdOnWorkComplete(napi_env env, napi_status status, void *data) {
AsyncProtectFdEx_t *async_protect_fd_ex = (AsyncProtectFdEx_t *)data;

int result = status;
if (HANDLE_EINTR(write(async_protect_fd_ex->write_end, &result, sizeof(result))) < 0) {
PLOG(WARNING) << "write failed to pipe";
}

status = napi_delete_async_work(env, async_protect_fd_ex->work_item);
if (status != napi_ok) {
LOG(WARNING) << "napi_delete_async_work: " << status;
return;
}

delete async_protect_fd_ex;
}

int setProtectFd(int fd) {
napi_env env = setProtectFdCallbackEnv;
if (env == nullptr) {
LOG(WARNING) << "null env";
return -1;
}

napi_value work_name;
// Specify a name to describe this asynchronous operation.
auto status = napi_create_string_utf8(env, kAsyncResourceName, NAPI_AUTO_LENGTH, &work_name);
if (status != napi_ok) {
LOG(WARNING) << "napi_create_string_utf8: " << status;
return -1;
}
AsyncProtectFdEx_t *async_protect_fd_ex = new AsyncProtectFdEx_t;
napi_async_work work_item;

status = napi_create_async_work(env, nullptr, work_name,
setProtectFdExecuteWork, setProtectFdOnWorkComplete, async_protect_fd_ex,
&work_item); // OUT: THE handle to the async work item
if (status != napi_ok) {
delete async_protect_fd_ex;
LOG(WARNING) << "napi_create_async_work: " << status;
return -1;
}

int pipefd[2] = {-1, -1};
if (pipe(pipefd) == -1) {
PLOG(WARNING) << "create pipe failed";
return -1;
};
int read_end = pipefd[0];
async_protect_fd_ex->work_item = work_item;
async_protect_fd_ex->fd = fd;
async_protect_fd_ex->write_end = pipefd[1];

// Queue the work item for execution.
status = napi_queue_async_work(env, work_item);
if (status != napi_ok) {
IGNORE_EINTR(close(pipefd[0]));
IGNORE_EINTR(close(pipefd[1]));
LOG(WARNING) << "napi_create_async_work: " << status;
return -1;
}

// wait on async work done
int result;
if (HANDLE_EINTR(read(read_end, &result, sizeof(result))) < 0) {
PLOG(WARNING) << "read failed from pipe";
IGNORE_EINTR(close(pipefd[0]));
IGNORE_EINTR(close(pipefd[1]));
return -1;
}
status = static_cast<napi_status>(result);
IGNORE_EINTR(close(pipefd[0]));
IGNORE_EINTR(close(pipefd[1]));
LOG(WARNING) << "setProtectFd: status: " << status;
return 0;
}

static void setProtectFdCallingJS(napi_env env, napi_value js_cb, void *context, void *data) {
// This parameter is not used.
(void)context;

if (env == nullptr) {
LOG(WARNING) << "null env";
return;
}

napi_value undefined;
napi_status status = napi_get_undefined(env, &undefined);
if (status != napi_ok) {
LOG(WARNING) << "napi_get_undefined: " << status;
return;
}
napi_value fd;
status = napi_create_int32(env, (uintptr_t)data, &fd);
if (status != napi_ok) {
LOG(WARNING) << "napi_create_int32: " << status;
return;
}
status = napi_call_function(env, undefined, js_cb, 1, &fd, NULL);
if (status != napi_ok) {
LOG(WARNING) << "napi_call_function: " << status;
return;
}
}

static napi_value setProtectFdCallback(napi_env env, napi_callback_info info) {
napi_status status;

size_t argc = 1;
napi_value args[1] = {nullptr};
status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
if (status != napi_ok) {
napi_throw_error(env, nullptr, "napi_get_cb_info failed");
return nullptr;
}

napi_value cb = args[0];
napi_valuetype type;
status = napi_typeof(env, cb, &type);
if (status != napi_ok) {
napi_throw_error(env, nullptr, "napi_typeof failed");
return nullptr;
}

if (type != napi_function) {
napi_throw_error(env, nullptr, "mismatched argument type, expected: napi_function");
return nullptr;
}

napi_value work_name;
// Specify a name to describe this asynchronous operation.
status = napi_create_string_utf8(env, kAsyncResourceName, NAPI_AUTO_LENGTH, &work_name);
if (status != napi_ok) {
napi_throw_error(env, nullptr, "napi_create_string_utf8 failed");
return nullptr;
}

// Create a thread-safe N-API callback function correspond to the C/C++ callback function
status = napi_create_threadsafe_function(env, cb, nullptr, work_name, 0, 1, nullptr,
nullptr, nullptr, setProtectFdCallingJS, // the C/C++ callback function
&setProtectFdCallbackFunc // out: the asynchronous thread-safe JavaScript function
);
if (status != napi_ok) {
napi_throw_error(env, nullptr, "napi_create_threadsafe_function failed");
return nullptr;
}

setProtectFdCallbackEnv = env;

return nullptr;
}

static napi_value setProtectFdCallbackCleanup(napi_env env, napi_callback_info info) {
if (setProtectFdCallbackFunc == nullptr) {
return nullptr;
}
// Clean up the thread-safe function and the work item associated with this
auto status = napi_release_threadsafe_function(setProtectFdCallbackFunc, napi_tsfn_release);
if (status != napi_ok) {
napi_throw_error(env, nullptr, "napi_release_threadsafe_function failed");
return nullptr;
}
return nullptr;
}

static napi_value Init(napi_env env, napi_value exports) {
napi_property_descriptor desc[] = {
{"setProtectFdCallback", nullptr, setProtectFdCallback, nullptr, nullptr, nullptr, napi_default, nullptr},
{"setProtectFdCallbackCleanup", nullptr, setProtectFdCallbackCleanup, nullptr, nullptr, nullptr, napi_default, nullptr},
};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
}

static napi_module yassModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "entry",
.nm_priv = ((void *)0),
.reserved = {0},
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void) {
napi_module_register(&yassModule);
}

#endif // __OHOS__
16 changes: 16 additions & 0 deletions src/harmony/yass.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2024 Chilledheart */
#ifndef _H_HARMONY_YASS_HPP
#define _H_HARMONY_YASS_HPP

#ifdef __OHOS__

// synchronous call
int setProtectFd(int fd);

__attribute__((visibility ("default")))
extern "C" void RegisterEntryModule(void);

#endif // __OHOS__

#endif // _H_HARMONY_YASS_HPP
7 changes: 7 additions & 0 deletions src/net/stream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
#include "net/ssl_socket.hpp"
#include "net/protocol.hpp"

#ifdef __OHOS__
#include "harmony/yass.hpp"
#endif

#ifdef HAVE_C_ARES
#include "net/c-ares.hpp"
#endif
Expand Down Expand Up @@ -382,6 +386,9 @@ class stream : public RefCountedThreadSafe<stream> {
on_async_connect_callback(ec);
return;
}
#ifdef __OHOS__
setProtectFd(socket_.native_handle());
#endif
SetTCPFastOpenConnect(socket_.native_handle(), ec);
socket_.native_non_blocking(true, ec);
socket_.non_blocking(true, ec);
Expand Down

0 comments on commit dc93336

Please sign in to comment.