Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion cmake/openssl/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
30 changes: 27 additions & 3 deletions src/core/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,40 @@
#define CANDY_CORE_NET_H

#include <array>
#include <bit>
#include <cstdint>
#include <spdlog/spdlog.h>
#include <string>
#include <type_traits>

namespace Candy {

template <typename T> typename std::enable_if<std::is_integral<T>::value, T>::type byteswap(T value) {
static_assert(std::is_integral<T>::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 <typename T> T ntoh(T v) {
if (std::endian::native == std::endian::little) {
return std::byteswap(v);
static_assert(std::is_integral<T>::value, "ntoh requires integral type");

uint8_t *bytes = reinterpret_cast<uint8_t *>(&v);
bool isLittleEndian = true;
{
uint16_t test = 0x0001;
isLittleEndian = (*reinterpret_cast<uint8_t *>(&test) == 0x01);
}

if (isLittleEndian) {
return byteswap(v);
}
return v;
}
Expand Down
5 changes: 5 additions & 0 deletions src/main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
6 changes: 5 additions & 1 deletion src/main/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -275,14 +275,18 @@ 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;
}
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()) {
Expand Down
61 changes: 51 additions & 10 deletions src/main/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,64 @@
#include "main/config.h"
#include "utils/time.h"
#include <atomic>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <signal.h>
#include <spdlog/spdlog.h>
#include <string>

std::atomic<bool> running = true;
template <typename T> class Atomic {
public:
explicit Atomic(T initial = T()) : value_(initial) {}

T load() const {
std::lock_guard<std::mutex> lock(mutex_);
return value_;
}

void store(T new_value) {
std::lock_guard<std::mutex> lock(mutex_);
value_ = new_value;
cv_.notify_all();
}

void wait(const T &expected) {
std::unique_lock<std::mutex> lock(mutex_);
cv_.wait(lock, [this, &expected] { return value_ != expected; });
}

template <typename Predicate> void wait_until(Predicate pred) {
std::unique_lock<std::mutex> lock(mutex_);
cv_.wait(lock, pred);
}

void notify_one() {
std::lock_guard<std::mutex> lock(mutex_);
cv_.notify_one();
}

void notify_all() {
std::lock_guard<std::mutex> lock(mutex_);
cv_.notify_all();
}

private:
T value_;
mutable std::mutex mutex_;
std::condition_variable cv_;
};

Atomic<bool> 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
Expand Down Expand Up @@ -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[]) {
Expand All @@ -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));
Expand Down
1 change: 1 addition & 0 deletions src/peer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ else()
endif()

target_link_libraries(peer PRIVATE Poco::Foundation Poco::Net Poco::NetSSL)

1 change: 0 additions & 1 deletion src/peer/peer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#include <Poco/Net/IPAddress.h>
#include <Poco/Net/SocketAddress.h>
#include <algorithm>
#include <bit>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
Expand Down
2 changes: 2 additions & 0 deletions src/tun/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
5 changes: 2 additions & 3 deletions src/tun/windows.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#include "core/net.h"
#include "tun/tun.h"
#include <codecvt>
#include "utils/codecvt.h"
#include <memory>
#include <openssl/sha.h>
#include <spdlog/fmt/bin_to_hex.h>
Expand Down Expand Up @@ -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<std::codecvt_utf8_utf16<wchar_t>> 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;
Expand Down
Empty file removed src/utils/byteswap.h
Empty file.
44 changes: 44 additions & 0 deletions src/utils/codecvt.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <Poco/Platform.h>
#if POCO_OS == POCO_OS_WINDOWS_NT
#include "utils/codecvt.h"
#include <windows.h>

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
14 changes: 14 additions & 0 deletions src/utils/codecvt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT
#ifndef CANDY_UTILS_CODECVT_H
#define CANDY_UTILS_CODECVT_H

#include <string>

namespace Candy {

std::string UTF16ToUTF8(const std::wstring &utf16Str);
std::wstring UTF8ToUTF16(const std::string &utf8Str);

} // namespace Candy

#endif
2 changes: 1 addition & 1 deletion src/websocket/server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down