From c46aac45ef4b78d69ea68e23e7f258b7470e18b0 Mon Sep 17 00:00:00 2001 From: lanthora Date: Tue, 10 Jun 2025 17:10:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=BD=8E=E7=89=88=E6=9C=AC?= =?UTF-8?q?=20C++=20=E6=A0=87=E5=87=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmake/openssl/CMakeLists.txt | 4 ++- src/core/net.h | 30 ++++++++++++++++-- src/main/CMakeLists.txt | 5 +++ src/main/config.cc | 6 +++- src/main/main.cc | 61 ++++++++++++++++++++++++++++++------ src/peer/CMakeLists.txt | 1 + src/peer/peer.cc | 1 - src/tun/CMakeLists.txt | 2 ++ src/tun/windows.cc | 5 ++- src/utils/byteswap.h | 0 src/utils/codecvt.cc | 44 ++++++++++++++++++++++++++ src/utils/codecvt.h | 14 +++++++++ src/websocket/server.cc | 2 +- 13 files changed, 155 insertions(+), 20 deletions(-) delete mode 100644 src/utils/byteswap.h create mode 100644 src/utils/codecvt.cc create mode 100644 src/utils/codecvt.h diff --git a/cmake/openssl/CMakeLists.txt b/cmake/openssl/CMakeLists.txt index a8513a3a..11c65332 100644 --- a/cmake/openssl/CMakeLists.txt +++ b/cmake/openssl/CMakeLists.txt @@ -1,5 +1,7 @@ cmake_minimum_required(VERSION 3.18.4) -cmake_policy(SET CMP0135 NEW) +if(POLICY CMP0135) + cmake_policy(SET CMP0135 NEW) +endif() project(openssl) include(ExternalProject) diff --git a/src/core/net.h b/src/core/net.h index 734963b4..926d28ec 100644 --- a/src/core/net.h +++ b/src/core/net.h @@ -3,16 +3,40 @@ #define CANDY_CORE_NET_H #include -#include #include #include #include +#include namespace Candy { +template typename std::enable_if::value, T>::type byteswap(T value) { + static_assert(std::is_integral::value, "byteswap requires integral type"); + + union { + T value; + uint8_t bytes[sizeof(T)]; + } src, dst; + + src.value = value; + for (size_t i = 0; i < sizeof(T); i++) { + dst.bytes[i] = src.bytes[sizeof(T) - i - 1]; + } + return dst.value; +} + template T ntoh(T v) { - if (std::endian::native == std::endian::little) { - return std::byteswap(v); + static_assert(std::is_integral::value, "ntoh requires integral type"); + + uint8_t *bytes = reinterpret_cast(&v); + bool isLittleEndian = true; + { + uint16_t test = 0x0001; + isLittleEndian = (*reinterpret_cast(&test) == 0x01); + } + + if (isLittleEndian) { + return byteswap(v); } return v; } diff --git a/src/main/CMakeLists.txt b/src/main/CMakeLists.txt index 4bdf2e0c..47b2210a 100644 --- a/src/main/CMakeLists.txt +++ b/src/main/CMakeLists.txt @@ -3,6 +3,11 @@ add_executable(${CANDY_EXECUTE_NAME} ${DIR_SRCS}) set_target_properties(${CANDY_EXECUTE_NAME} PROPERTIES CXX_STANDARD 23) +find_library(STDCPPFS_LIB stdc++fs) +if(STDCPPFS_LIB) + target_link_libraries(${CANDY_EXECUTE_NAME} PRIVATE ${STDCPPFS_LIB}) +endif() + if (${CANDY_STATIC_SPDLOG}) target_link_libraries(${CANDY_EXECUTE_NAME} PRIVATE spdlog::spdlog) else() diff --git a/src/main/config.cc b/src/main/config.cc index 2941db93..e885f6f0 100644 --- a/src/main/config.cc +++ b/src/main/config.cc @@ -275,6 +275,10 @@ std::string virtualMac(const std::string &name) { return initVirtualMac(); } +bool starts_with(const std::string &str, const std::string &prefix) { + return str.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), str.begin()); +} + bool hasContainerVolume(const arguments &args) { if (args.mode != "client") { return true; @@ -282,7 +286,7 @@ bool hasContainerVolume(const arguments &args) { if (!std::filesystem::exists(storageDirectory("lost"))) { return true; } - if (args.websocket.starts_with("wss://canets.org")) { + if (starts_with(args.websocket, "wss://canets.org")) { return false; } if (!args.tun.empty()) { diff --git a/src/main/main.cc b/src/main/main.cc index 0a240e85..3acb9fb2 100644 --- a/src/main/main.cc +++ b/src/main/main.cc @@ -4,22 +4,64 @@ #include "main/config.h" #include "utils/time.h" #include +#include +#include +#include #include #include #include -std::atomic running = true; +template class Atomic { +public: + explicit Atomic(T initial = T()) : value_(initial) {} + + T load() const { + std::lock_guard lock(mutex_); + return value_; + } + + void store(T new_value) { + std::lock_guard lock(mutex_); + value_ = new_value; + cv_.notify_all(); + } + + void wait(const T &expected) { + std::unique_lock lock(mutex_); + cv_.wait(lock, [this, &expected] { return value_ != expected; }); + } + + template void wait_until(Predicate pred) { + std::unique_lock lock(mutex_); + cv_.wait(lock, pred); + } + + void notify_one() { + std::lock_guard lock(mutex_); + cv_.notify_one(); + } + + void notify_all() { + std::lock_guard lock(mutex_); + cv_.notify_all(); + } + +private: + T value_; + mutable std::mutex mutex_; + std::condition_variable cv_; +}; + +Atomic running(true); namespace Candy { void shutdown(Client *client) { - running = false; - running.notify_one(); + running.store(false); } void shutdown(Server *server) { - running = false; - running.notify_one(); + running.store(false); } } // namespace Candy @@ -73,8 +115,7 @@ int serve(const arguments &args) { void signalHandler(int signal) { exitCode = 0; - running = false; - running.notify_one(); + running.store(false); } int main(int argc, char *argv[]) { @@ -86,13 +127,13 @@ int main(int argc, char *argv[]) { if (!hasContainerVolume(args)) { spdlog::critical("the container needs to add a storage volume: {}", storageDirectory()); - running = false; + running.store(false); } Candy::ntpServer = args.ntp; - while (running && serve(args) && args.restart) { - running = true; + while (running.load() && serve(args) && args.restart) { + running.store(true); Candy::useSystemTime = false; spdlog::info("service will restart in {} seconds", args.restart); std::this_thread::sleep_for(std::chrono::seconds(args.restart)); diff --git a/src/peer/CMakeLists.txt b/src/peer/CMakeLists.txt index 9fd9cdfd..f7865602 100644 --- a/src/peer/CMakeLists.txt +++ b/src/peer/CMakeLists.txt @@ -20,3 +20,4 @@ else() endif() target_link_libraries(peer PRIVATE Poco::Foundation Poco::Net Poco::NetSSL) + diff --git a/src/peer/peer.cc b/src/peer/peer.cc index 2fb7605e..f1f3436a 100644 --- a/src/peer/peer.cc +++ b/src/peer/peer.cc @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/src/tun/CMakeLists.txt b/src/tun/CMakeLists.txt index 02c74509..38a9530a 100644 --- a/src/tun/CMakeLists.txt +++ b/src/tun/CMakeLists.txt @@ -41,3 +41,5 @@ if (${CANDY_STATIC_OPENSSL}) endif() target_link_libraries(tun PRIVATE Poco::Foundation Poco::Net Poco::NetSSL) + +target_link_libraries(tun PRIVATE utils) diff --git a/src/tun/windows.cc b/src/tun/windows.cc index 6aa6cd03..74864792 100644 --- a/src/tun/windows.cc +++ b/src/tun/windows.cc @@ -4,7 +4,7 @@ #include "core/net.h" #include "tun/tun.h" -#include +#include "utils/codecvt.h" #include #include #include @@ -125,8 +125,7 @@ class WindowsTun { unsigned char hash[SHA256_DIGEST_LENGTH]; SHA256((unsigned char *)data.c_str(), data.size(), hash); memcpy(&Guid, hash, sizeof(Guid)); - std::wstring_convert> converter; - this->adapter = WintunCreateAdapter(converter.from_bytes(this->name).c_str(), L"Candy", &Guid); + this->adapter = WintunCreateAdapter(Candy::UTF8ToUTF16(this->name).c_str(), L"Candy", &Guid); if (!this->adapter) { spdlog::critical("create wintun adapter failed: {}", GetLastError()); return -1; diff --git a/src/utils/byteswap.h b/src/utils/byteswap.h deleted file mode 100644 index e69de29b..00000000 diff --git a/src/utils/codecvt.cc b/src/utils/codecvt.cc new file mode 100644 index 00000000..77213ca0 --- /dev/null +++ b/src/utils/codecvt.cc @@ -0,0 +1,44 @@ +#include +#if POCO_OS == POCO_OS_WINDOWS_NT +#include "utils/codecvt.h" +#include + +namespace Candy { + +std::string UTF16ToUTF8(const std::wstring &utf16Str) { + if (utf16Str.empty()) + return ""; + + int utf8Size = WideCharToMultiByte(CP_UTF8, 0, utf16Str.c_str(), -1, nullptr, 0, nullptr, nullptr); + + if (utf8Size == 0) { + return ""; + } + + std::string utf8Str(utf8Size, '\0'); + WideCharToMultiByte(CP_UTF8, 0, utf16Str.c_str(), -1, &utf8Str[0], utf8Size, nullptr, nullptr); + + utf8Str.resize(utf8Size - 1); + return utf8Str; +} + +std::wstring UTF8ToUTF16(const std::string &utf8Str) { + if (utf8Str.empty()) + return L""; + + int utf16Size = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, nullptr, 0); + + if (utf16Size == 0) { + return L""; + } + + std::wstring utf16Str(utf16Size, L'\0'); + MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, &utf16Str[0], utf16Size); + + utf16Str.resize(utf16Size - 1); + return utf16Str; +} + +} // namespace Candy + +#endif diff --git a/src/utils/codecvt.h b/src/utils/codecvt.h new file mode 100644 index 00000000..64002f72 --- /dev/null +++ b/src/utils/codecvt.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +#ifndef CANDY_UTILS_CODECVT_H +#define CANDY_UTILS_CODECVT_H + +#include + +namespace Candy { + +std::string UTF16ToUTF8(const std::wstring &utf16Str); +std::wstring UTF8ToUTF16(const std::string &utf8Str); + +} // namespace Candy + +#endif diff --git a/src/websocket/server.cc b/src/websocket/server.cc index 7a317032..16ed7ead 100644 --- a/src/websocket/server.cc +++ b/src/websocket/server.cc @@ -306,7 +306,7 @@ void WebSocketServer::handleExptTunMsg(WsCtx &ctx) { ctx.status = -1; return; } - } while (!exptTun.isValid() && this->ipCtxMap.contains(exptTun.Host())); + } while (!exptTun.isValid() && this->ipCtxMap.find(exptTun.Host()) != this->ipCtxMap.end()); this->dhcp = exptTun; } header->timestamp = hton(unixTime());