Compare commits

..

No commits in common. "main" and "v1.4.2" have entirely different histories.
main ... v1.4.2

38 changed files with 498 additions and 38159 deletions

View File

@ -11,7 +11,13 @@ ReflowComments: true
SpacesBeforeTrailingComments: 3
TabWidth: 4
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ColumnLimit: 80
ColumnLimit: 110
AllowShortBlocksOnASingleLine: Never
AllowShortFunctionsOnASingleLine: None
AllowShortEnumsOnASingleLine: false
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<.*>'
Priority: 1
- Regex: '^".*"'
Priority: 2

1
.gitignore vendored
View File

@ -6,4 +6,3 @@ cmake-*
compile_commands.json
out
xpbuild
cbuild

3
.gitmodules vendored
View File

@ -6,6 +6,3 @@
path = filecomplete
url = https://www.sinxmiao.cn/taynpg/filecomplete
branch = main
[submodule "crashelper"]
path = crashelper
url = https://www.sinxmiao.cn/taynpg/crashelper

86
.vscode/settings.json vendored
View File

@ -1,8 +1,10 @@
{
"files.autoSave": "onFocusChange",
"editor.fontSize": 14,
"editor.fontFamily": "'Monaspace Krypton Light', 'Monaspace Krypton Light', 'Monaspace Krypton Light'",
"terminal.integrated.fontFamily": "Monaspace Krypton Light",
"editor.fontFamily": "'Source Code Pro', 'Source Code Pro', 'Source Code Pro'",
"terminal.integrated.fontFamily": "Source Code Pro",
"editor.fontLigatures": true,
//"C_Cpp.default.configurationProvider": "tboox.xmake-vscode",
"cmake.configureOnOpen": true,
"cmake.debugConfig": {
"console": "integratedTerminal",
@ -17,20 +19,24 @@
"ignoreFailures": true
}
],
"visualizerFile": "${workspaceRoot}/.vscode/qt5.natvis",
"args": [
"9999"
"-u", "0"
]
},
"cmake.environment": {
"PATH": "${env:PATH};"
},
"cmake.configureArgs": [
"-Wno-dev",
"-DGRAB_CRASH=ON"
"-DCMAKE_PREFIX_PATH:STRING=C:/dev/wxwigets",
"-DUSE_GUI=ON",
"-DUSE_TRANSM_TEST=ON"
],
"cmake.configureSettings": {
//"CMAKE_TOOLCHAIN_FILE": "${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
},
"cmake.options.statusBarVisibility": "visible",
"cmake.generator": "Ninja",
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
"C_Cpp.default.compileCommands": "${workspaceRoot}/build/compile_commands.json",
"C_Cpp.default.cppStandard": "c++17",
"editor.inlayHints.enabled": "off",
"editor.unicodeHighlight.allowedLocales": {
"ja": true,
@ -38,27 +44,22 @@
"zh-hans": true
},
"files.associations": {
".clang-tidy": "yaml",
"filesystem": "cpp",
"regex": "cpp",
"functional": "cpp",
"xstring": "cpp",
"vector": "cpp",
"string": "cpp",
"algorithm": "cpp",
"any": "cpp",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"cinttypes": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"coroutine": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
@ -68,13 +69,13 @@
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"exception": "cpp",
"expected": "cpp",
"resumable": "cpp",
"format": "cpp",
"filesystem": "cpp",
"forward_list": "cpp",
"fstream": "cpp",
"functional": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
@ -98,22 +99,21 @@
"ratio": "cpp",
"set": "cpp",
"shared_mutex": "cpp",
"source_location": "cpp",
"sstream": "cpp",
"stack": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"string": "cpp",
"string_view": "cpp",
"strstream": "cpp",
"system_error": "cpp",
"thread": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"typeindex": "cpp",
"typeinfo": "cpp",
"unordered_map": "cpp",
"utility": "cpp",
"valarray": "cpp",
"variant": "cpp",
"vector": "cpp",
"xfacet": "cpp",
"xhash": "cpp",
"xiosbase": "cpp",
@ -125,9 +125,39 @@
"xlocnum": "cpp",
"xloctime": "cpp",
"xmemory": "cpp",
"xstring": "cpp",
"xmemory0": "cpp",
"xstddef": "cpp",
"xtr1common": "cpp",
"xtree": "cpp",
"xutility": "cpp"
}
"xutility": "cpp",
"qbytearray": "cpp",
"*.ipp": "cpp",
"xthread": "cpp",
"*.tcc": "cpp",
"regex": "cpp",
"bit": "cpp",
"memory_resource": "cpp",
"source_location": "cpp",
"charconv": "cpp",
"compare": "cpp",
"concepts": "cpp",
"coroutine": "cpp",
"format": "cpp",
"stop_token": "cpp",
"expected": "cpp",
"numbers": "cpp",
"semaphore": "cpp",
"span": "cpp",
"text_encoding": "cpp",
"*.in": "cpp",
"hash_map": "cpp",
"stdfloat": "cpp",
"unordered_set": "cpp",
"cfenv": "cpp",
"cassert": "cpp",
"version": "cpp",
"resumable": "cpp"
},
"makefile.configureOnOpen": false,
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools"
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16)
project(transm VERSION 1.5.2 LANGUAGES CXX)
project(transm VERSION 1.4.2 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@ -11,7 +11,6 @@ set(PROJECT_URL "https://www.sinxmiao.cn/taynpg/transm")
set(COMPILER_ID ${CMAKE_CXX_COMPILER_ID})
if(MSVC)
add_compile_options(/source-charset:utf-8)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Windows")
@ -20,7 +19,12 @@ add_compile_options(-finput-charset=utf-8)
add_compile_options(-fexec-charset=gbk)
add_compile_options(-Wa,-mbig-obj)
set(COMPILER_ID "mingw")
include(config/Mingw.cmake)
endif()
if(DEFINED USE_BOOST)
message(STATUS "use boost library ${USE_BOOST}")
add_definitions(-DUSE_BOOST)
include(config/MBoost.cmake)
endif()
string(TOLOWER ${COMPILER_ID} COMPILER_ID)
@ -28,18 +32,12 @@ if(DEFINED IOS_ISH)
message(STATUS "INPUT IOS_ISH ${IOS_ISH}")
endif()
if(WIN32)
execute_process(COMMAND cmd /c ver
OUTPUT_VARIABLE VER_OUTPUT
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(VER_OUTPUT MATCHES "XP")
message(STATUS "Windows XP platform.")
if(DEFINED XP_SYSTEM)
message(STATUS "transm use xp defined ${XP_SYSTEM}")
add_definitions(-D_WIN32_WINNT=0x0501)
else()
message(STATUS "Windows NT platform.")
add_definitions(-D_WIN32_WINNT=0x0601)
endif()
endif()
set(CMAKE_DEBUG_POSTFIX "d")
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE})
@ -47,12 +45,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY
${PROJECT_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE}/
)
if (DEFINED GRAB_CRASH)
message(STATUS "GRAB_CRASH ${GRAB_CRASH}")
add_subdirectory(crashelper/crashelper)
add_definitions(-DGRAB_CRASH)
endif()
add_definitions(-DFMT_HEADER_ONLY)
include_directories(3rd)
include_directories(.)
@ -65,16 +57,8 @@ add_subdirectory(client)
add_subdirectory(filecomplete)
add_subdirectory(tinyaes)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Windows")
message(STATUS "tss-http can't support mingw, will not compile.")
else()
add_subdirectory(http-server)
endif()
if (DEFINED USE_TRANSM_TEST)
message(STATUS "USE USE_TRANSM_TEST ${USE_TRANSM_TEST}")
add_definitions(-DUSE_TRANSM_TEST)
include(CTest)
add_subdirectory(test)
endif()
@ -99,15 +83,13 @@ message(STATUS "VERSION_GIT_HASH: ${VERSION_GIT_HASH}")
install(TARGETS tsc DESTINATION bin)
install(TARGETS tss DESTINATION bin)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Windows")
message(STATUS "tss-http can't support mingw, will not pack.")
else()
install(TARGETS tss-http DESTINATION bin)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Windows")
if (DEFINED USE_BOOST)
install(FILES ${MINGW32_DLLS} DESTINATION bin)
endif()
if (DEFINED USE_GUI)
message(STATUS "USE GUI ${USE_GUI}")
#add_subdirectory(gui)
endif()
# ********************************************************** pack infomation
if(CMAKE_SIZEOF_VOID_P EQUAL 8)

63
CMakeSettings.json Normal file
View File

@ -0,0 +1,63 @@
{
"configurations": [
{
"name": "x64 Local Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": ""
},
{
"name": "x64 Local Release",
"generator": "Ninja",
"configurationType": "Release",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}"
},
{
"name": "x64 Linux Debug",
"generator": "Ninja",
"configurationType": "Debug",
"cmakeExecutable": "cmake",
"remoteCopySourcesExclusionList": [ ".vs", "out" ],
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"inheritEnvironments": [ "linux_x64" ],
"remoteMachineName": "${defaultRemoteMachineName}",
"remoteCMakeListsRoot": "$HOME/vs/${projectDirName}/${workspaceHash}/src",
"remoteBuildRoot": "$HOME/vs/${projectDirName}/${workspaceHash}/out/build/${name}",
"remoteInstallRoot": "$HOME/vs/${projectDirName}/${workspaceHash}/out/install/${name}",
"remoteCopySources": true,
"rsyncCommandArgs": "-t --delete",
"remoteCopyBuildOutput": false,
"remoteCopySourcesMethod": "rsync",
"variables": []
},
{
"name": "x64 Linux Release",
"generator": "Ninja",
"configurationType": "Release",
"cmakeExecutable": "cmake",
"remoteCopySourcesExclusionList": [ ".vs", "out" ],
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"inheritEnvironments": [ "linux_x64" ],
"remoteMachineName": "${defaultRemoteMachineName}",
"remoteCMakeListsRoot": "$HOME/vs/${projectDirName}/${workspaceHash}/src",
"remoteBuildRoot": "$HOME/vs/${projectDirName}/${workspaceHash}/out/build/${name}",
"remoteInstallRoot": "$HOME/vs/${projectDirName}/${workspaceHash}/out/install/${name}",
"remoteCopySources": true,
"rsyncCommandArgs": "-t --delete",
"remoteCopyBuildOutput": false,
"remoteCopySourcesMethod": "rsync",
"variables": []
}
]
}

View File

@ -18,9 +18,7 @@
## 一些特点(基于最新版本)
- 易编译。
- 通配符传输。
- 公网传输支持加密。
- 广泛的平台支持。
- 终端自动文件补全。
- 自动检测对方掉线。
@ -42,7 +40,7 @@
## 1.程序启动
- 对于服务端程序`tss`,绑定默认绑定`0.0.0.0``9898`端口,如果需要修改端口,使用参数启动,示例:`tss 9898`
- 对于客户端程序`tsc`,请使用`tsc --help`查看如何启动
- 对于客户端程序`tsc`,请使用`tsc --help`查看使用方式
## 2.使用
@ -67,41 +65,6 @@ ${HOME}/截图/Ni.jpg|${HOME}/dira
${CURRENT}/xxx.zip|D:\
```
### 3.1 版本内容补充
- `v1.5.0`及其以后版本:支持数据加密传输功能(会影响速度,默认开启,可关闭)。
```c++
/*
测试环境 ==>
Microsoft Windows 10 Professional (x64) Build 19045.5608 (22H2)
13th Gen Intel(R) Core(TM) i5-13500H 3200.0 MHz
Debug模式 tinyaes 加密解密测试速度:
=========================================
File size: 630239232 bytes (601.043 MB)
Effective block size: 102384 bytes
Total encryption time: 41887336 μs (14.349 MB/s)
Total decryption time: 41822620 μs (14.3712 MB/s)
Data verification: PASSED
=========================================
Release模式 tinyaes 加密解密测试速度:
=========================================
File size: 630239232 bytes (601.043 MB)
Effective block size: 102384 bytes
Total encryption time: 8367460 μs (71.831 MB/s)
Total decryption time: 8150036 μs (73.7473 MB/s)
Data verification: PASSED
=========================================
*/
```
- `v1.5.2`及其以后的代码版本:新增了`tss-http`服务端,简单用于某些时候,客户机上没有`tsc``tss`程序时,通过`http`协议传输文件。
> 关于`tss-http`编译:不支持`mingw`编译,因此`win8`及以下没有此程序支持。
> 示例启动:`tss-http 8080 D:/files`(参数为端口、根目录)。
# 三、编译
当前项目支持`cmake`构建工具。

View File

@ -6,6 +6,11 @@ set(CMAKE_CXX_STANDARD 17)
if (MSVC)
add_compile_options(/source-charset:utf-8)
endif()
if(DEFINED USE_BOOST)
message(STATUS "tsc use boost lib.")
include_directories(${MBOOST_INCLUDE_DIR})
link_directories(${MBOOST_LIB_DIR})
endif()
add_executable(tsc main.cpp client.h client.cpp config.h config.cpp)
target_link_libraries(tsc PRIVATE trans_net trans_util filecomplete)
@ -15,10 +20,9 @@ endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Windows")
target_link_libraries(tsc PRIVATE ws2_32 wsock32)
endif()
if (DEFINED GRAB_CRASH)
message(STATUS "tsc link crashelper")
target_link_libraries(tsc PRIVATE crashelper)
if(DEFINED USE_BOOST)
target_link_directories(tsc PRIVATE ${MBOOST_LIB_DIR})
target_link_libraries(tsc PRIVATE ${MBOOST_LIBS})
endif()
if(UNIX)
execute_process(

View File

@ -1,21 +1,27 @@
#include "client.h"
#include <filesystem>
#include <fstream>
#include <iostream>
#include <of_path.h>
#include <of_str.h>
#include <of_util.h>
#include <version.h>
namespace fs = std::filesystem;
TransmClient::TransmClient() : msg_info_("")
#ifdef USE_BOOST
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
#else
#include <filesystem>
namespace fs = std::filesystem;
#endif
CClient::CClient() : msg_info_("")
{
client_ = std::make_shared<CTcpClient>(io_context_);
sleep_.set_timeout(5000);
}
TransmClient::~TransmClient()
CClient::~CClient()
{
th_run_ = false;
sleep_.contiune();
@ -42,12 +48,9 @@ TransmClient::~TransmClient()
if (hearts_.joinable()) {
hearts_.join();
}
if (context_th_.joinable()) {
context_th_.join();
}
}
void TransmClient::print_help(bool detail)
void CClient::print_help(bool detail)
{
TLOGI("version: {}", VERSION_NUM);
TLOGI("opensource: {}", VERSION_URL);
@ -55,9 +58,8 @@ void TransmClient::print_help(bool detail)
if (!detail) {
TLOGW("Get|Who|Where|Ls|Sub|Fetch|Up|Down|UpTask|DownTask");
TLOGI("<h> to show cmd's detail.");
TLOGI("use <end> or <ctrl-c> to exit.");
TLOGI("use <on> or <off> to oper encrypt(<?> to view).");
TLOGI("You can use 'h' to show cmd's detail.");
TLOGI("You can use 'end' or 'ctrl-c' to exit.");
return;
}
@ -120,8 +122,7 @@ void TransmClient::print_help(bool detail)
TLOGI("{}", sp);
}
bool TransmClient::base_init(const std::string& ip, const std::string& port,
const std::string& config_dir)
void CClient::run(const std::string& ip, const std::string& port, const std::string& config_dir)
{
fs::path fp(config_dir);
config_path_ = fp.append("history.txt").string();
@ -132,7 +133,7 @@ bool TransmClient::base_init(const std::string& ip, const std::string& port,
uuid_ = read_uuid();
if (uuid_.empty()) {
TLOGE("uuid is empty!");
return false;
return;
}
auto his = load_line_his();
@ -143,22 +144,13 @@ bool TransmClient::base_init(const std::string& ip, const std::string& port,
th_run_ = true;
if (!client_->connect(ip, port)) {
TLOGI("{} connect err.", __FUNCTION__);
return false;
return;
}
client_->register_func([&](CFrameBuffer* buf) { handle_frame(buf); });
client_->async_recv();
hearts_ = std::thread([&]() { hearts(); });
context_th_ = std::thread([&]() { io_context_.run(); });
std::thread thread([&]() { io_context_.run(); });
th_down_active_ = std::thread([&]() { judget_down_active(); });
return true;
}
void TransmClient::run(const std::string& ip, const std::string& port,
const std::string& config_dir)
{
if (!base_init(ip, port, config_dir)) {
return;
}
print_help(false);
fc_append('|');
@ -174,8 +166,7 @@ void TransmClient::run(const std::string& ip, const std::string& port,
break;
}
if (!th_run_ || !client_->is_normal()) {
TLOGW("The link has been closed and cannot be continued. It will "
"automatically exit.");
TLOGW("The link has been closed and cannot be continued. It will automatically exit.");
break;
}
std::string cmd_input(readline);
@ -188,23 +179,6 @@ void TransmClient::run(const std::string& ip, const std::string& port,
continue;
}
if (cmd_input == "on" || cmd_input == "On") {
set_encrypt(true);
TLOGI("Encrypt is on.");
continue;
}
if (cmd_input == "?") {
TLOGI("Encrypt is {}.", get_encrypt_status() ? "on" : "off");
continue;
}
if (cmd_input == "off" || cmd_input == "Off") {
set_encrypt(false);
TLOGI("Encrypt is off.");
continue;
}
if (cmd_input == "end" || cmd_input == "End") {
th_run_ = false;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
@ -219,13 +193,11 @@ void TransmClient::run(const std::string& ip, const std::string& port,
TLOGD("At => {}", COfPath::to_full("."));
continue;
}
if (cmd_input == "Get" || cmd_input == "get" || cmd_input == "g" ||
cmd_input == "G") {
if (cmd_input == "Get" || cmd_input == "get" || cmd_input == "g" || cmd_input == "G") {
get_clients();
continue;
}
if (cmd_input == "Clear" || cmd_input == "clear" || cmd_input == "c" ||
cmd_input == "C") {
if (cmd_input == "Clear" || cmd_input == "clear" || cmd_input == "c" || cmd_input == "C") {
cmd_clear_submited();
continue;
}
@ -269,63 +241,18 @@ void TransmClient::run(const std::string& ip, const std::string& port,
TLOGE("No matched cmd, May be param size incorrect.");
}
client_->disconnect();
thread.join();
TLOGI("{} exit.", __FUNCTION__);
}
#ifdef USE_TRANSM_TEST
bool TransmClient::connect_for_test(const std::string& ip,
const std::string& port,
const std::string& config_dir)
{
if (!base_init(ip, port, config_dir)) {
return false;
}
get_clients();
get_id();
return true;
}
std::string TransmClient::test_get_own_id() const
{
return own_id_;
}
void TransmClient::set_task_state(TaskState state)
{
task_state_ = state;
}
TransmClient::TaskState TransmClient::get_task_state() const
{
return task_state_;
}
void TransmClient::disconnect_for_test()
{
client_->disconnect();
}
int TransmClient::test_index_by_id(const std::string& id)
{
int ret = -1;
for (const auto& item : clients_) {
if (item.second->id == id) {
ret = item.first;
break;
}
}
return ret;
}
#endif
bool TransmClient::get_clients()
bool CClient::get_clients()
{
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
buf->type_ = TYPE_GET_LIST;
return send_frame(buf.get());
}
bool TransmClient::cmd_fetch_files(const std::string& param)
bool CClient::cmd_fetch_files(const std::string& param)
{
if (downloading_) {
TLOGW("Have Task Downloading, Please wait.....");
@ -361,31 +288,21 @@ bool TransmClient::cmd_fetch_files(const std::string& param)
}
// 开始传输文件
bool ret = true;
for (const auto& item : vec) {
if (!down_one_file(id, item, relative_path)) {
ret = false;
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
#ifdef USE_TRANSM_TEST
if (ret) {
task_state_ = TaskState::TASK_STATE_DONE;
} else {
task_state_ = TaskState::TASK_STATE_ERROR;
}
#endif
return true;
}
bool TransmClient::cmd_sub_list(const std::string& param)
bool CClient::cmd_sub_list(const std::string& param)
{
{
std::lock_guard<std::mutex> lock(mutex_);
for (const auto& item : up_) {
if (item.second->trans_state_ == TRANS_REDAY ||
item.second->trans_state_ == TRANS_ING) {
if (item.second->trans_state_ == TRANS_REDAY || item.second->trans_state_ == TRANS_ING) {
TLOGW("Have Task Upping, Please wait!");
return false;
}
@ -432,13 +349,12 @@ bool TransmClient::cmd_sub_list(const std::string& param)
return send_frame(buf.get());
}
bool TransmClient::cmd_clear_submited()
bool CClient::cmd_clear_submited()
{
{
std::lock_guard<std::mutex> lock(mutex_);
for (const auto& item : up_) {
if (item.second->trans_state_ == TRANS_REDAY ||
item.second->trans_state_ == TRANS_ING) {
if (item.second->trans_state_ == TRANS_REDAY || item.second->trans_state_ == TRANS_ING) {
TLOGW("Have Task Upping, Please wait!");
return false;
}
@ -449,7 +365,7 @@ bool TransmClient::cmd_clear_submited()
return send_frame(buf.get());
}
bool TransmClient::cmd_upload_files(const std::string& param)
bool CClient::cmd_upload_files(const std::string& param)
{
auto tvec = COfStr::split(param, " ");
if (tvec.size() < 3) {
@ -522,15 +438,13 @@ bool TransmClient::cmd_upload_files(const std::string& param)
return true;
}
bool TransmClient::down_one_file(int remote_id, const std::string& file,
const std::string& local_dir)
bool CClient::down_one_file(int remote_id, const std::string& file, const std::string& local_dir)
{
std::string ret_id{};
std::string ret_uuid{};
if (clients_.count(remote_id) == 0) {
TLOGW("{} No Index Found {}, Try {}", __LINE__, remote_id,
list_server_id_);
TLOGW("{} No Index Found {}, Try {}", __LINE__, remote_id, list_server_id_);
ret_id = list_server_id_;
ret_uuid = list_server_uuid_;
} else {
@ -545,17 +459,13 @@ bool TransmClient::down_one_file(int remote_id, const std::string& file,
if (local_dir.empty()) {
down_->cur_file_ = COfPath::to_full(remote_file.filename().string());
} else {
down_->cur_file_ = fs::path(local_dir)
.append(remote_file.filename().string())
.string();
down_->cur_file_ = fs::path(local_dir).append(remote_file.filename().string()).string();
}
// 这里要先检查羁绊
if (ret_uuid == uuid_ &&
COfPath::is_same_dir(remote_file.string(), down_->cur_file_)) {
if (ret_uuid == uuid_ && COfPath::is_same_dir(remote_file.string(), down_->cur_file_)) {
// 处在同一个机器上的同目录下
TLOGE("You Can't Operate File In Same Dir And In Same Machine.",
down_->cur_remote_file_);
TLOGE("You Can't Operate File In Same Dir And In Same Machine.", down_->cur_remote_file_);
return false;
}
@ -573,8 +483,7 @@ bool TransmClient::down_one_file(int remote_id, const std::string& file,
msg_info.str = file;
serialize(msg_info, &buf->data_, buf->len_);
if (!send_frame(buf.get())) {
TLOGE("{} request open file [{}] send failed.", __FUNCTION__,
down_->cur_remote_file_);
TLOGE("{} request open file [{}] send failed.", __FUNCTION__, down_->cur_remote_file_);
down_->cur_remote_id_.clear();
down_->cur_remote_file_.clear();
return false;
@ -584,8 +493,7 @@ bool TransmClient::down_one_file(int remote_id, const std::string& file,
cur_down_size_ = 0;
float percent = 0.0;
fc_disable_cur();
while (down_->trans_state_ != TRANS_DONE &&
down_->trans_state_ != TRANS_FAILED) {
while (down_->trans_state_ != TRANS_DONE && down_->trans_state_ != TRANS_FAILED) {
std::this_thread::sleep_for(std::chrono::milliseconds(down_check_wait));
if (cur_file_size_ > 0) {
percent = (float)cur_down_size_ / cur_file_size_;
@ -603,8 +511,7 @@ bool TransmClient::down_one_file(int remote_id, const std::string& file,
}
fc_enable_cur();
if (cur_down_size_ > 0 && cur_file_size_ == cur_down_size_) {
TLOGW("down one file success, total:[{}/{}]", cur_down_size_,
cur_file_size_);
TLOGW("down one file success, total:[{}/{}]", cur_down_size_, cur_file_size_);
return true;
} else {
TLOGW("down one file {} failed, size not matched.", down_->cur_file_);
@ -616,7 +523,7 @@ bool TransmClient::down_one_file(int remote_id, const std::string& file,
}
}
void TransmClient::report_trans_ret(TransState state, const std::string& key)
void CClient::report_trans_ret(TransState state, const std::string& key)
{
std::shared_ptr<TransInfomation> t = nullptr;
if (key.empty()) {
@ -649,7 +556,7 @@ void TransmClient::report_trans_ret(TransState state, const std::string& key)
*/
bool TransmClient::cmd_sub_task(const std::string& param, bool is_send)
bool CClient::cmd_sub_task(const std::string& param, bool is_send)
{
auto tvec = COfStr::split(param, " ");
if (tvec.size() < 2) {
@ -735,11 +642,7 @@ bool TransmClient::cmd_sub_task(const std::string& param, bool is_send)
return false;
}
#ifdef USE_TRANSM_TEST
auto handel_ret = handle_user_select(mre, false);
#else
auto handel_ret = handle_user_select(mre, is_send);
#endif
if (handel_ret.empty()) {
TLOGE("handle_user_select not pass, abort action!");
return false;
@ -765,8 +668,7 @@ bool TransmClient::cmd_sub_task(const std::string& param, bool is_send)
return true;
}
bool TransmClient::variable_and_parse_files(
const std::string& content, std::map<std::string, std::string>& files)
bool CClient::variable_and_parse_files(const std::string& content, std::map<std::string, std::string>& files)
{
auto vec = COfStr::split(content, "\n");
bool valid = true;
@ -792,8 +694,7 @@ bool TransmClient::variable_and_parse_files(
return valid;
}
bool TransmClient::down_update_file(
const std::map<std::string, std::string>& files)
bool CClient::down_update_file(const std::map<std::string, std::string>& files)
{
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
buf->tid_ = list_server_id_;
@ -825,8 +726,7 @@ bool TransmClient::down_update_file(
return suc;
}
bool TransmClient::get_dir_files(const std::string& dir, std::string& out,
std::string& error)
bool CClient::get_dir_files(const std::string& dir, std::string& out, std::string& error)
{
fs::path p(dir);
out.clear();
@ -846,7 +746,7 @@ bool TransmClient::get_dir_files(const std::string& dir, std::string& out,
return true;
}
bool TransmClient::cmd_ls(const std::string& param)
bool CClient::cmd_ls(const std::string& param)
{
auto tvec = COfStr::split(param, " ");
if (tvec.size() < 2) {
@ -866,8 +766,8 @@ bool TransmClient::cmd_ls(const std::string& param)
buf->type_ = TYPE_GET_DIRFILES;
CMessageInfo msg_info(own_id_);
msg_info.str = path;
buf->tid_ = sr->id;
serialize(msg_info, &buf->data_, buf->len_);
buf->tid_ = sr->id;
if (!send_frame(buf.get())) {
TLOGE("Send Failed {}", __LINE__);
@ -876,7 +776,7 @@ bool TransmClient::cmd_ls(const std::string& param)
return true;
}
bool TransmClient::cmd_down_list(const std::string& param)
bool CClient::cmd_down_list(const std::string& param)
{
auto tvec = COfStr::split(param, " ");
if (tvec.size() < 2) {
@ -885,8 +785,7 @@ bool TransmClient::cmd_down_list(const std::string& param)
}
int index = std::stoi(tvec[0]);
std::string lists = tvec[1];
std::string local =
tvec.size() > 2 ? COfPath::to_full(tvec[2]) : COfPath::to_full("");
std::string local = tvec.size() > 2 ? COfPath::to_full(tvec[2]) : COfPath::to_full("");
if (!clients_.count(index)) {
TLOGE("{} No Index Found {}.", __LINE__, index);
@ -913,7 +812,7 @@ bool TransmClient::cmd_down_list(const std::string& param)
return true;
}
bool TransmClient::send_frame(CFrameBuffer* buf)
bool CClient::send_frame(CFrameBuffer* buf)
{
char* out_buf{};
int out_len{};
@ -930,7 +829,7 @@ bool TransmClient::send_frame(CFrameBuffer* buf)
return true;
}
void TransmClient::save_line_his(const std::string& input)
void CClient::save_line_his(const std::string& input)
{
if (input.empty()) {
return;
@ -959,7 +858,7 @@ void TransmClient::save_line_his(const std::string& input)
}
}
std::vector<std::string> TransmClient::load_line_his()
std::vector<std::string> CClient::load_line_his()
{
std::vector<std::string> history;
if (!fs::exists(config_path_)) {
@ -978,7 +877,7 @@ std::vector<std::string> TransmClient::load_line_his()
return history;
}
std::string TransmClient::variable_and_reverse_files(const std::string& source)
std::string CClient::variable_and_reverse_files(const std::string& source)
{
auto vec = COfStr::split(source, "\n");
std::string result;
@ -1017,7 +916,7 @@ std::string TransmClient::variable_and_reverse_files(const std::string& source)
return result;
}
bool TransmClient::save_uuid()
bool CClient::save_uuid()
{
fs::path uuid_path(uuid_path_);
if (fs::exists(uuid_path)) {
@ -1036,7 +935,7 @@ bool TransmClient::save_uuid()
return true;
}
std::string TransmClient::read_uuid()
std::string CClient::read_uuid()
{
fs::path uuid_path(uuid_path_);
if (!fs::exists(uuid_path)) {
@ -1053,7 +952,7 @@ std::string TransmClient::read_uuid()
return uuid;
}
void TransmClient::get_id()
void CClient::get_id()
{
auto* bf = new CFrameBuffer();
bf->type_ = TYPE_GET_ID;
@ -1064,7 +963,7 @@ void TransmClient::get_id()
delete bf;
}
void TransmClient::handle_frame(CFrameBuffer* buf)
void CClient::handle_frame(CFrameBuffer* buf)
{
if (buf == nullptr) {
TLOGE("{} nullptr.", __FUNCTION__);
@ -1168,12 +1067,13 @@ void TransmClient::handle_frame(CFrameBuffer* buf)
if (!get_dir_files(msg_info.str, out, err)) {
TLOGE("Get Dir Files Failed. {}", err);
buf->type_ = TYPE_GET_DIRFILES_FAILED;
delete[] buf->data_;
msg_info.str = err;
} else {
buf->type_ = TYPE_GET_DIRFILES_DONE;
delete[] buf->data_;
msg_info.str = out;
}
msg_info.id = buf->tid_;
serialize(msg_info, &buf->data_, buf->len_);
std::swap(buf->tid_, buf->fid_);
if (!send_frame(buf)) {
@ -1228,12 +1128,10 @@ void TransmClient::handle_frame(CFrameBuffer* buf)
std::lock_guard<std::mutex> lock(mutex_);
up_[buf->fid_] = std::make_shared<TransInfomation>();
up_[buf->fid_]->cur_file_ = msg_info.str;
up_[buf->fid_]->file_.open(up_[buf->fid_]->cur_file_,
std::ios::in | std::ios::binary);
up_[buf->fid_]->file_.open(up_[buf->fid_]->cur_file_, std::ios::in | std::ios::binary);
up_[buf->fid_]->trans_state_ = TRANS_REDAY;
if (!up_[buf->fid_]->file_.is_open()) {
TLOGE("Ready Send File {} Open Failed.",
up_[buf->fid_]->cur_file_);
TLOGE("Ready Send File {} Open Failed.", up_[buf->fid_]->cur_file_);
buf->type_ = TYPE_OPEN_FAILED;
std::swap(buf->tid_, buf->fid_);
if (!send_frame(buf)) {
@ -1245,8 +1143,7 @@ void TransmClient::handle_frame(CFrameBuffer* buf)
keys = buf->fid_;
}
if (!keys.empty()) {
ths_.emplace_back(
[this, keys]() { send_file_data_th(keys.c_str()); });
ths_.emplace_back([this, keys]() { send_file_data_th(keys.c_str()); });
}
break;
}
@ -1292,10 +1189,9 @@ void TransmClient::handle_frame(CFrameBuffer* buf)
TLOGE("{} GetList deserialize failed.", __LINE__);
break;
}
delete[] buf->data_;
msg_info.str = variable_and_reverse_files(msg_info.str);
msg_info.id = buf->tid_;
serialize(msg_info, &buf->data_, buf->len_);
std::swap(buf->tid_, buf->fid_);
buf->type_ = TYPE_REQUEST_UPDATE_LIST;
if (!send_frame(buf)) {
@ -1305,12 +1201,12 @@ void TransmClient::handle_frame(CFrameBuffer* buf)
break;
};
case TYPE_REQUEST_UPDATE_LIST: {
CMessageInfo msg_info(buf->fid_);
std::map<std::string, std::string> files;
if (down_ && down_->trans_state_ == TRANS_REDAY) {
TLOGW("Update Busy......, Ignore {}", buf->fid_);
buf->type_ = TYPE_BUSY_UPDATE_LIST;
} else {
CMessageInfo msg_info(buf->fid_);
if (!deserialize(buf->data_, buf->len_, msg_info)) {
TLOGE("{} GetList deserialize failed.", __LINE__);
break;
@ -1322,8 +1218,6 @@ void TransmClient::handle_frame(CFrameBuffer* buf)
buf->type_ = TYPE_UNCONFIRM_UPDATE_LIST;
}
}
msg_info.id = buf->tid_;
serialize(msg_info, &buf->data_, buf->len_);
std::swap(buf->tid_, buf->fid_);
if (!send_frame(buf)) {
TLOGE("Send Failed {}.", __LINE__);
@ -1337,8 +1231,7 @@ void TransmClient::handle_frame(CFrameBuffer* buf)
if (update_list_th_.joinable()) {
update_list_th_.join();
}
update_list_th_ =
std::thread([this, files]() { down_update_file(files); });
update_list_th_ = std::thread([this, files]() { down_update_file(files); });
break;
}
case TYPE_CONFIRM_UPDATE_LIST: {
@ -1347,16 +1240,10 @@ void TransmClient::handle_frame(CFrameBuffer* buf)
}
case TYPE_UNCONFIRM_UPDATE_LIST: {
TLOGE("remote {} check {} not passed!", buf->fid_, list_file_);
#ifdef USE_TRANSM_TEST
task_state_ = TaskState::TASK_STATE_ERROR;
#endif
break;
}
case TYPE_DONE_UPDATE_LIST: {
TLOGI("remote {} do task {} success!", buf->fid_, list_file_);
#ifdef USE_TRANSM_TEST
task_state_ = TaskState::TASK_STATE_DONE;
#endif
break;
}
case TYPE_FAILED_UPDATE_LIST: {
@ -1364,8 +1251,7 @@ void TransmClient::handle_frame(CFrameBuffer* buf)
break;
}
case TYPE_BUSY_UPDATE_LIST: {
TLOGI("remote {} are busy, will not exec task {}", buf->fid_,
list_file_);
TLOGI("remote {} are busy, will not exec task {}", buf->fid_, list_file_);
break;
}
case TYPE_FILE_INFO: {
@ -1390,13 +1276,12 @@ void TransmClient::handle_frame(CFrameBuffer* buf)
break;
}
default:
TLOGE("UnSupport Type {}, Current Version v{}",
static_cast<int>(buf->type_), VERSION_NUM);
TLOGE("UnSupport Type {}, Current Version v{}", static_cast<int>(buf->type_), VERSION_NUM);
break;
}
}
void TransmClient::send_file_data_th(const char* keys)
void CClient::send_file_data_th(const char* keys)
{
std::string str_key(keys);
std::shared_ptr<TransInfomation> t = nullptr;
@ -1420,11 +1305,9 @@ void TransmClient::send_file_data_th(const char* keys)
// ********************************************************
// seekg 用于读,seekp 用于写。
// t->file_.seekg(0, std::ios::end);
// long long size = t->file_.tellg();
// t->file_.seekg(0, std::ios::beg);
auto size = fs::file_size(t->cur_file_);
t->file_.seekg(0, std::ios::end);
long long size = t->file_.tellg();
t->file_.seekg(0, std::ios::beg);
buf->type_ = TYPE_FILE_INFO;
std::string str_size = std::to_string(size);
@ -1439,8 +1322,8 @@ void TransmClient::send_file_data_th(const char* keys)
#endif
std::string info_result = plat + "," + str_size + "," + str_perm;
TLOGI("To {} File Size: {} [{}], permissions:{}", str_key,
ofen::OfUtil::get_file_size(size), size, str_perm);
TLOGI("To {} File Size: {} [{}], permissions:{}", str_key, ofen::OfUtil::get_file_size(size), size,
str_perm);
msg_info.str = info_result;
serialize(msg_info, &buf->data_, buf->len_);
if (!send_frame(buf.get())) {
@ -1448,10 +1331,6 @@ void TransmClient::send_file_data_th(const char* keys)
TLOGE("Stop Trans {} To {} failed.", t->cur_file_, str_key);
return;
}
delete[] buf->data_;
buf->data_ = nullptr;
buf->type_ = TYPE_TRANS_FILE;
buf->mark_ = 1;
@ -1468,7 +1347,7 @@ void TransmClient::send_file_data_th(const char* keys)
cur_send_size = t->file_.gcount();
msg_info.data.resize(cur_send_size);
send_size += cur_send_size;
serialize(msg_info, &buf->data_, buf->len_, true);
serialize(msg_info, &buf->data_, buf->len_);
if (!send_frame(buf.get())) {
report_trans_ret(TRANS_FAILED, str_key);
TLOGE("Stop Trans {} To {} failed.", t->cur_file_, str_key);
@ -1484,7 +1363,7 @@ void TransmClient::send_file_data_th(const char* keys)
TLOGD("Trans File {} To {} Done !!!, {}", t->cur_file_, str_key, send_size);
}
void TransmClient::hearts()
void CClient::hearts()
{
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
buf->type_ = TYPE_HEARTS;
@ -1497,7 +1376,7 @@ void TransmClient::hearts()
}
}
void TransmClient::judget_down_active()
void CClient::judget_down_active()
{
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
buf->type_ = TYPE_JUDGE_ACTIVE;
@ -1513,15 +1392,13 @@ void TransmClient::judget_down_active()
}
}
std::string TransmClient::variable_handle(const std::string& task_list_path,
const std::string& source,
std::string CClient::variable_handle(const std::string& task_list_path, const std::string& source,
bool is_local)
{
std::string result(source);
// 支持的变量如下:
// ${HOME} 用户目录(发送端接收端均支持)
// ${CURRENT}
// 任务文件所在目录(该变量仅支持发送端,因为接收端没有任务文件所在路径)
// ${CURRENT} 任务文件所在目录(该变量仅支持发送端,因为接收端没有任务文件所在路径)
if (is_local && source.find("${HOME}") != std::string::npos) {
result = COfStr::replace(result, "${HOME}", COfPath::get_home());
}
@ -1536,8 +1413,7 @@ std::string TransmClient::variable_handle(const std::string& task_list_path,
return result;
}
std::string TransmClient::handle_user_select(
const std::unordered_map<int, std::string>& source, bool is_send)
std::string CClient::handle_user_select(const std::unordered_map<int, std::string>& source, bool is_send)
{
std::string handled_content{};
std::string input{};
@ -1581,13 +1457,11 @@ std::string TransmClient::handle_user_select(
handled_content.append(source.at(key) + "\n");
} else {
// 如果mre中没有这个key
TLOGE("Invalid input, please enter valid numbers or "
"'0' for all.");
TLOGE("Invalid input, please enter valid numbers or '0' for all.");
break;
}
} catch (const std::exception& e) {
TLOGE("Invalid input, please enter valid numbers or '0' "
"for all.");
TLOGE("Invalid input, please enter valid numbers or '0' for all.");
break;
}
}
@ -1603,8 +1477,7 @@ CFileOpr::CFileOpr() = default;
CFileOpr::~CFileOpr() = default;
bool CFileOpr::get_file_list(const std::string& input,
std::vector<std::string>& out)
bool CFileOpr::get_file_list(const std::string& input, std::vector<std::string>& out)
{
out.clear();
auto backup = COfStr::trim(input);
@ -1626,17 +1499,14 @@ bool CFileOpr::get_file_list(const std::string& input,
}
#endif
if (ret.find("?") != std::string::npos ||
ret.find("*") != std::string::npos) {
if (ret.find("?") != std::string::npos || ret.find("*") != std::string::npos) {
auto fv = COfPath::match_files(ret);
for (const auto& v : fv) {
TLOGI("match file: {}", v);
}
std::string cof;
while (true) {
TLOGI("Detected regex's file (num = {}), please confirm if it "
"is correct? ",
fv.size());
TLOGI("Detected regex's file (num = {}), please confirm if it is correct? ", fv.size());
TLOGW("support input in [y,Y,end]", fv.size());
std::getline(std::cin, cof);
if (cof == "y" || cof == "Y") {

View File

@ -38,34 +38,30 @@ struct TransInfomation {
};
constexpr int down_check_wait = 100; // millsec
class TransmClient
class CClient
{
public:
TransmClient();
~TransmClient();
CClient();
~CClient();
public:
void run(const std::string& ip, const std::string& port, const std::string& config_dir);
public:
void run(const std::string& ip, const std::string& port,
const std::string& config_dir);
bool get_clients();
bool cmd_fetch_files(const std::string& param);
bool cmd_sub_list(const std::string& param);
bool cmd_clear_submited();
bool cmd_upload_files(const std::string& param);
bool down_one_file(int remote_id, const std::string& file, const std::string& local_dir = "");
void report_trans_ret(TransState state, const std::string& key = "");
bool cmd_sub_task(const std::string& param, bool is_send);
bool variable_and_parse_files(const std::string& content, std::map<std::string, std::string>& files);
bool down_update_file(const std::map<std::string, std::string>& files);
bool get_dir_files(const std::string& dir, std::string& out, std::string& error);
bool cmd_ls(const std::string& param);
bool cmd_down_list(const std::string& param);
private:
bool variable_and_parse_files(const std::string& content,
std::map<std::string, std::string>& files);
bool down_update_file(const std::map<std::string, std::string>& files);
bool get_dir_files(const std::string& dir, std::string& out,
std::string& error);
void report_trans_ret(TransState state, const std::string& key = "");
bool down_one_file(int remote_id, const std::string& file,
const std::string& local_dir = "");
private:
bool send_frame(CFrameBuffer* buf);
void save_line_his(const std::string& input);
@ -75,19 +71,14 @@ private:
std::string read_uuid();
void get_id();
void print_help(bool detail);
bool base_init(const std::string& ip, const std::string& port,
const std::string& config_dir);
private:
void handle_frame(CFrameBuffer* buf);
void send_file_data_th(const char* keys);
void hearts();
void judget_down_active();
std::string variable_handle(const std::string& task_list_path,
const std::string& source, bool is_local);
std::string
handle_user_select(const std::unordered_map<int, std::string>& source,
bool is_send);
std::string variable_handle(const std::string& task_list_path, const std::string& source, bool is_local);
std::string handle_user_select(const std::unordered_map<int, std::string>& source, bool is_send);
private:
std::mutex mutex_;
@ -105,7 +96,6 @@ private:
std::shared_ptr<TransInfomation> down_;
std::vector<std::thread> ths_;
std::map<std::string, std::shared_ptr<TransInfomation>> up_;
std::thread context_th_;
std::thread th_down_active_;
long long cur_file_size_{};
long long cur_down_size_{};
@ -119,28 +109,6 @@ private:
std::string config_path_{};
std::string uuid_path_{};
std::string uuid_{};
#ifdef USE_TRANSM_TEST
public:
enum TaskState {
TASK_STATE_IDLE,
TASK_STATE_RUNNING,
TASK_STATE_DONE,
TASK_STATE_ERROR
};
public:
bool connect_for_test(const std::string& ip, const std::string& port,
const std::string& config_dir);
void disconnect_for_test();
int test_index_by_id(const std::string& id);
std::string test_get_own_id() const;
void set_task_state(TaskState state);
TaskState get_task_state() const;
private:
TaskState task_state_{};
#endif
};
class CFileOpr
@ -150,6 +118,5 @@ public:
~CFileOpr();
public:
static bool get_file_list(const std::string& input,
std::vector<std::string>& out);
static bool get_file_list(const std::string& input, std::vector<std::string>& out);
};

View File

@ -1,16 +1,22 @@
#include "config.h"
#include <cassert>
#ifdef USE_BOOST
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
#else
#include <filesystem>
namespace fs = std::filesystem;
#endif
ClientConfig::ClientConfig()
CServerConfig::CServerConfig()
{
}
ClientConfig::~ClientConfig() = default;
CServerConfig::~CServerConfig() = default;
bool ClientConfig::baseInit()
bool CServerConfig::baseInit()
{
fs::path tpath(COfPath::get_config_dir("transm", true));
config_dir_ = tpath.string();
@ -27,7 +33,7 @@ bool ClientConfig::baseInit()
return true;
}
bool ClientConfig::read_ini(std::vector<TransmSet>& set)
bool CServerConfig::read_ini(std::vector<TransmSet>& set)
{
assert(init_ == true);
long groups = ini_handle_.GetLongValue("BASE", "GROUPS");
@ -53,8 +59,7 @@ bool ClientConfig::read_ini(std::vector<TransmSet>& set)
return true;
}
long ClientConfig::have_ini(const std::vector<TransmSet>& set,
const std::string& ip, long port)
long CServerConfig::have_ini(const std::vector<TransmSet>& set, const std::string& ip, long port)
{
long id = -1;
for (const auto& item : set) {
@ -66,22 +71,20 @@ long ClientConfig::have_ini(const std::vector<TransmSet>& set,
return id;
}
bool ClientConfig::write_ini(const std::vector<TransmSet>& set)
bool CServerConfig::write_ini(const std::vector<TransmSet>& set)
{
assert(init_ == true);
for (size_t start = 0; start < set.size(); ++start) {
std::string key = "GROUP" + std::to_string(start);
ini_handle_.SetValue(key.c_str(), "IP", set[start].ip.c_str());
ini_handle_.SetLongValue(key.c_str(), "PORT", set[start].port);
ini_handle_.SetValue(key.c_str(), "COMMENT",
set[start].comment.c_str());
ini_handle_.SetValue(key.c_str(), "COMMENT", set[start].comment.c_str());
}
ini_handle_.SaveFile(config_path_.c_str());
return true;
}
long ClientConfig::append_ini(const std::string& ip, long port,
const std::string& comment)
long CServerConfig::append_ini(const std::string& ip, long port, const std::string& comment)
{
assert(init_ == true);
long id = -1;
@ -106,24 +109,22 @@ long ClientConfig::append_ini(const std::string& ip, long port,
return id;
}
bool ClientConfig::remove_ini(long num)
bool CServerConfig::remove_ini(long num)
{
assert(init_ == true);
std::vector<TransmSet> set;
if (!read_ini(set)) {
return false;
}
set.erase(std::remove_if(
set.begin(), set.end(),
[&num](const TransmSet& item) { return item.grp_id == num; }),
set.erase(
std::remove_if(set.begin(), set.end(), [&num](const TransmSet& item) { return item.grp_id == num; }),
set.end());
ini_handle_.Reset();
ini_handle_.SetLongValue("BASE", "GROUPS", static_cast<long>(set.size()));
return write_ini(set);
}
bool ClientConfig::get_ini(const std::vector<TransmSet>& set, long num,
TransmSet& use)
bool CServerConfig::get_ini(const std::vector<TransmSet>& set, long num, TransmSet& use)
{
bool find = false;
for (const auto& item : set) {
@ -136,12 +137,12 @@ bool ClientConfig::get_ini(const std::vector<TransmSet>& set, long num,
return find;
}
std::string ClientConfig::get_config_dir() const
std::string CServerConfig::get_config_dir() const
{
return config_dir_;
}
bool ClientConfig::save_last_use(const std::string& ip, long port)
bool CServerConfig::save_last_use(const std::string& ip, long port)
{
assert(init_ == true);
ini_handle_.SetValue("Base", "LastUseIP", ip.c_str());
@ -150,11 +151,10 @@ bool ClientConfig::save_last_use(const std::string& ip, long port)
return true;
}
bool ClientConfig::get_last_use(std::string& ip, long& port)
bool CServerConfig::get_last_use(std::string& ip, long& port)
{
assert(init_ == true);
if (!ini_handle_.KeyExists("Base", "LastUseIP") ||
!ini_handle_.KeyExists("Base", "LastUsePort")) {
if (!ini_handle_.KeyExists("Base", "LastUseIP") || !ini_handle_.KeyExists("Base", "LastUsePort")) {
TLOGE("Not Found Last Use Record.");
return false;
}
@ -163,7 +163,7 @@ bool ClientConfig::get_last_use(std::string& ip, long& port)
return true;
}
void ClientConfig::gen_default_ini(const std::string& path)
void CServerConfig::gen_default_ini(const std::string& path)
{
TLOGW("Gen Default Setting Ini in [{}].", path);
ini_handle_.LoadFile(path.c_str());

View File

@ -25,11 +25,11 @@ struct CmdParam {
bool null_use{false};
};
class ClientConfig
class CServerConfig
{
public:
ClientConfig();
~ClientConfig();
CServerConfig();
~CServerConfig();
public:
bool baseInit();

View File

@ -16,41 +16,27 @@
#endif
#endif
#if defined(GRAB_CRASH)
#include <filesystem>
namespace fs = std::filesystem;
#include <crashelper.h>
#endif
std::shared_ptr<ClientConfig> g_Config = nullptr;
std::shared_ptr<CServerConfig> g_Config = nullptr;
int parse_cmd(int argc, char** argv, CmdParam& param)
{
std::string intro(
fmt::format("tsc cmd introduce, version: {}\nopensource: {}",
VERSION_NUM, VERSION_URL));
fmt::format("tsc cmd introduce, version: {}\nopensource: {}", VERSION_NUM, VERSION_URL));
CLI::App app(intro);
app.add_option("-u, --use", param.use_config,
"使用服务器地址组(值为使用--show中显示的序号)");
app.add_option("-a, --append", param.appendValue,
"添加服务器地址组(地址格式:127.0.0.1:9898:注释)");
app.add_option("-u, --use", param.use_config, "使用服务器地址组(值为使用--show中显示的序号)");
app.add_option("-a, --append", param.appendValue, "添加服务器地址组(地址格式:127.0.0.1:9898:注释)");
app.add_flag("-s, --show", param.showValue, "查看服务器地址组");
app.add_option("-r, --remove", param.removeValue,
"移除服务器地址组(值为使用--show中显示的序号)");
app.add_flag("-d, --direct", param.direct_use,
"添加服务器时直接使用此服务器。");
app.add_flag("-l, --last", param.last_use,
"直接使用之前最后一次使用的服务器。");
app.add_option("-r, --remove", param.removeValue, "移除服务器地址组(值为使用--show中显示的序号)");
app.add_flag("-d, --direct", param.direct_use, "添加服务器时直接使用此服务器。");
app.add_flag("-l, --last", param.last_use, "直接使用之前最后一次使用的服务器。");
app.add_flag("-n, --null", param.null_use, "先运行在选择服务器。");
app.add_option("-c, --connect", param.connectValue,
"直连服务器((地址格式:127.0.0.1:9898)。");
app.add_option("-c, --connect", param.connectValue, "直连服务器((地址格式:127.0.0.1:9898)。");
if (argc == 1) {
std::cout << app.help() << std::endl;
return 0;
}
// 这里的 CLI11_PARSE
// 在程序没有输入或者仅输入--help(-h)时,会直接返回,后面代码都不会执行。
// 这里的 CLI11_PARSE 在程序没有输入或者仅输入--help(-h)时,会直接返回,后面代码都不会执行。
// 当有自定义的参数被输入时,后面代码会执行。
try {
CLI11_PARSE(app, argc, argv);
@ -61,8 +47,7 @@ int parse_cmd(int argc, char** argv, CmdParam& param)
return 0;
}
bool select_server(const std::vector<TransmSet>& sets, std::string& ip,
long& port)
bool select_server(const std::vector<TransmSet>& sets, std::string& ip, long& port)
{
TLOGI("Please Select a Server:");
if (sets.empty()) {
@ -75,8 +60,7 @@ bool select_server(const std::vector<TransmSet>& sets, std::string& ip,
if (server.comment.empty()) {
TLOGI("[{}] {}:{}", i + 1, server.ip, server.port);
} else {
TLOGI("[{}] {}:{} ({})", i + 1, server.ip, server.port,
server.comment);
TLOGI("[{}] {}:{} ({})", i + 1, server.ip, server.port, server.comment);
}
}
@ -92,10 +76,8 @@ bool select_server(const std::vector<TransmSet>& sets, std::string& ip,
}
// 检查输入是否为空或非数字
if (input.empty() ||
!std::all_of(input.begin(), input.end(), ::isdigit)) {
TLOGE("Invalid input '{}'. Please enter a valid number or 'exit'.",
input);
if (input.empty() || !std::all_of(input.begin(), input.end(), ::isdigit)) {
TLOGE("Invalid input '{}'. Please enter a valid number or 'exit'.", input);
continue;
}
@ -104,9 +86,7 @@ bool select_server(const std::vector<TransmSet>& sets, std::string& ip,
// 检查数字是否在有效范围内
if (choice < 1 || choice > static_cast<int>(sets.size())) {
TLOGE(
"Invalid choice '{}'. Please select a number between 1 and {}.",
choice, sets.size());
TLOGE("Invalid choice '{}'. Please select a number between 1 and {}.", choice, sets.size());
continue;
}
@ -129,8 +109,7 @@ bool exec_cmd(CmdParam& param, bool& run)
return false;
}
for (const auto& item : set) {
TLOGI("{} => {}:{} {}", item.group, item.ip, item.port,
item.comment);
TLOGI("{} => {}:{} {}", item.group, item.ip, item.port, item.comment);
}
return true;
}
@ -143,8 +122,7 @@ bool exec_cmd(CmdParam& param, bool& run)
return false;
}
if (!param.appendValue.empty()) {
std::regex pattern(
R"((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+)(?::(.*))?)");
std::regex pattern(R"((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+)(?::(.*))?)");
std::smatch matches;
std::string ip, port, comment;
if (std::regex_match(param.appendValue, matches, pattern)) {
@ -163,8 +141,7 @@ bool exec_cmd(CmdParam& param, bool& run)
}
if (!param.removeValue.empty()) {
if (!g_Config->remove_ini(std::stol(param.removeValue))) {
TLOGW("remove config num=[{}] failed, please check!",
param.removeValue);
TLOGW("remove config num=[{}] failed, please check!", param.removeValue);
return false;
}
TLOGI("remove config num=[{}] success!", param.removeValue);
@ -179,14 +156,6 @@ bool exec_cmd(CmdParam& param, bool& run)
int main(int argc, char* argv[])
{
#if defined(GRAB_CRASH)
auto config_dir = COfPath::get_config_dir("transm", true);
auto err = fs::path(config_dir).append("errs").string();
backward::SetDumpFileSavePath(err);
backward::SetDumpLogSavePath(err);
CRASHELPER_MARK_ENTRY();
#endif
#ifdef _WIN32
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode;
@ -200,7 +169,7 @@ int main(int argc, char* argv[])
delete p;
});
g_Config = std::make_shared<ClientConfig>();
g_Config = std::make_shared<CServerConfig>();
if (!g_Config->baseInit()) {
return -1;
}
@ -219,8 +188,7 @@ int main(int argc, char* argv[])
std::regex pattern(R"((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+))");
std::smatch matches;
if (std::regex_match(param.connectValue, matches, pattern) &&
matches.size() == 3) {
if (std::regex_match(param.connectValue, matches, pattern) && matches.size() == 3) {
ip = matches[1].str();
port = std::stol(matches[2].str());
run = true;
@ -264,11 +232,10 @@ int main(int argc, char* argv[])
}
g_Config->save_last_use(ip, port);
}
TLOGI("Build At {} {} under {} on {}", __DATE__, __TIME__,
VERSION_GIT_COMMIT, VERSION_GIT_BRANCH);
TLOGI("Build At {} {} under {} on {}", __DATE__, __TIME__, VERSION_GIT_COMMIT, VERSION_GIT_BRANCH);
TLOGI("use ip => [{}], port => [{}]", ip, port);
std::shared_ptr<TransmClient> client = std::make_shared<TransmClient>();
client->run(ip, std::to_string(port), g_Config->get_config_dir());
CClient client;
client.run(ip, std::to_string(port), g_Config->get_config_dir());
TLOGI("exit ==========");
return 0;
}

View File

@ -1,3 +1,6 @@
set(MBOOST_INCLUDE_DIR "C:/boost/include/boost-1_83")
set(MBOOST_LIB_DIR "C:/boost/lib")
set(MBOOST_LIBS "boost_filesystem-mgw7-mt-x32-1_83")
get_filename_component(CXX_COMPILER_PATH ${CMAKE_CXX_COMPILER} DIRECTORY)
set(MINGW32_DLLS
"${CXX_COMPILER_PATH}/libgcc_s_dw2-1.dll"

@ -1 +0,0 @@
Subproject commit 1d84054da9ec3a70ae1311d6166a9404a10a356c

@ -1 +1 @@
Subproject commit 1a35e4371945b7c439a95a3e42612e9870e03e65
Subproject commit 4b6612cc63f21b4d092a0b5731ceb7f817f20d23

View File

@ -1,26 +0,0 @@
cmake_minimum_required(VERSION 3.16)
project(tss-http LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if (MSVC)
add_compile_options(/source-charset:utf-8)
endif()
add_executable(tss-http main.cpp)
if (UNIX)
target_link_libraries(tss-http PRIVATE pthread)
endif()
if(UNIX)
execute_process(
COMMAND uname -a
OUTPUT_VARIABLE UNAME_OUT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(UNAME_OUT MATCHES "alpine" OR UNAME_OUT MATCHES "Alpine")
message(STATUS "tss-http on musl static link")
target_link_libraries(tss-http PRIVATE -static;-static-libstdc++)
endif()
endif()

View File

@ -1,264 +0,0 @@
#include <filesystem>
#include <fstream>
#include <httplib.h>
#include <iostream>
#include <string>
#include <vector>
#ifdef _WIN32
#include <windows.h>
#endif
namespace fs = std::filesystem;
#ifdef _WIN32
std::string u8_to_ansi(const std::string& str)
{
int wideCharLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, nullptr, 0);
if (wideCharLen <= 0) {
return "";
}
std::wstring wideStr(wideCharLen, L'\0');
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, &wideStr[0], wideCharLen);
int gbkLen = WideCharToMultiByte(CP_ACP, 0, wideStr.c_str(), -1, nullptr, 0, nullptr, nullptr);
if (gbkLen <= 0) {
return "";
}
std::string gbkStr(gbkLen, '\0');
WideCharToMultiByte(CP_ACP, 0, wideStr.c_str(), -1, &gbkStr[0], gbkLen, nullptr, nullptr);
gbkStr.resize(gbkLen - 1);
return gbkStr;
}
std::string ansi_to_u8(const std::string& str)
{
int wideCharLen = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, nullptr, 0);
if (wideCharLen <= 0) {
return "";
}
std::wstring wideStr(wideCharLen, L'\0');
MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, &wideStr[0], wideCharLen);
int utf8Len = WideCharToMultiByte(CP_UTF8, 0, wideStr.c_str(), -1, nullptr, 0, nullptr, nullptr);
if (utf8Len <= 0) {
return "";
}
std::string utf8Str(utf8Len, '\0');
WideCharToMultiByte(CP_UTF8, 0, wideStr.c_str(), -1, &utf8Str[0], utf8Len, nullptr, nullptr);
utf8Str.resize(utf8Len - 1);
return utf8Str;
}
#endif
// 生成文件列表的HTML页面
std::string generate_file_list(const std::string& base_path, const std::string& current_path)
{
fs::path full_path = fs::path(base_path) / current_path;
std::string html = R"(
<!DOCTYPE html>
<html>
<head>
<title>File Browser</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
h1 { color: #333; }
.path { color: #666; margin-bottom: 20px; }
ul { list-style-type: none; padding: 0; }
li { margin: 8px 0; }
a { text-decoration: none; color: #0066cc; }
a:hover { text-decoration: underline; }
.file::before { content: "\1F4C4 "; }
.dir::before { content: "\1F4C1 "; }
.parent::before { content: "\2B06 "; }
.size { color: #888; font-size: 0.9em; margin-left: 10px; }
</style>
</head>
<body>
<h1>File Browser</h1>
<div class="path">Current path: /)" +
current_path + R"(</div>
<ul>
)";
// 添加返回上一级链接(如果不是根目录)
if (current_path != "") {
fs::path parent_path = fs::path(current_path).parent_path();
std::string parent_link = parent_path.empty() ? "" : parent_path.string();
html += R"(<li class="parent"><a href="/browse/)" + parent_link + R"(">..</a></li>)";
}
// 遍历目录下的文件和子目录
for (const auto& entry : fs::directory_iterator(full_path)) {
std::string filename = entry.path().filename().string();
std::string new_path = (fs::path(current_path) / filename).string();
if (entry.is_directory()) {
html += R"(<li class="dir"><a href="/browse/)" + new_path + R"(">)" + filename + R"(/</a></li>)";
} else {
// 获取文件大小并转换为MB
uintmax_t file_size = entry.file_size();
double size_mb = file_size / (1024.0 * 1024.0);
char size_str[20];
snprintf(size_str, sizeof(size_str), "%.4f MB", size_mb);
html += R"(<li class="file"><a href="/download/)" + new_path + R"(">)" + filename + R"(</a><span class="size">)" +
size_str + R"(</span></li>)";
}
}
html += R"(
</ul>
</body>
</html>
)";
#ifdef _WIN32
html = ansi_to_u8(html);
#endif
return html;
}
int main(int argc, char** argv)
{
if (argc != 3) {
std::cout << "Usage: " << argv[0] << " <port> <base_dir>" << std::endl;
return -2;
}
const std::string base_dir(argv[2]); // 基础文件目录
if (!fs::exists(base_dir)) {
std::cout << "Base directory does not exist: " << base_dir << std::endl;
return -1;
}
int port = std::stoi(argv[1]);
httplib::Server server;
// 确保基础目录存在
if (!fs::exists(base_dir)) {
fs::create_directory(base_dir);
}
// 文件浏览路由
server.Get("/browse(.*)", [&base_dir](const httplib::Request& req, httplib::Response& res) {
std::string path = req.matches[1].str();
#ifdef _WIN32
path = u8_to_ansi(path);
#endif
// 移除开头的斜杠
if (!path.empty() && path[0] == '/') {
path = path.substr(1);
}
// 安全检查:防止目录遍历攻击
if (path.find("..") != std::string::npos) {
res.set_content("Invalid path", "text/plain");
res.status = 400;
return;
}
fs::path full_path = fs::path(base_dir) / path;
if (!fs::exists(full_path)) {
res.set_content("Path not found", "text/plain");
res.status = 404;
return;
}
if (!fs::is_directory(full_path)) {
res.set_content("Not a directory", "text/plain");
res.status = 400;
return;
}
res.set_header("Content-Type", "text/html; charset=utf-8");
res.set_content(generate_file_list(base_dir, path), "text/html; charset=utf-8");
});
// 文件下载路由
server.Get("/download/(.*)", [&base_dir](const httplib::Request& req, httplib::Response& res) {
std::string path = req.matches[1];
#ifdef _WIN32
path = u8_to_ansi(path);
#endif
// 安全检查:防止目录遍历攻击
if (path.find("..") != std::string::npos) {
res.set_content("Invalid path", "text/plain");
res.status = 400;
return;
}
fs::path file_path = fs::path(base_dir) / path;
if (!fs::exists(file_path)) {
res.set_content("File not found", "text/plain");
res.status = 404;
return;
}
if (fs::is_directory(file_path)) {
res.set_content("Cannot download directory", "text/plain");
res.status = 400;
return;
}
// 设置响应头,触发浏览器下载
res.set_header("Content-Type", "application/octet-stream");
res.set_header("Content-Disposition", "attachment; filename=" + file_path.filename().string());
auto file = std::make_shared<std::ifstream>(file_path, std::ios::binary);
if (!*file) {
res.status = 500;
res.set_content("Failed to open file", "text/plain");
return;
}
// 获取文件大小
const size_t file_size = fs::file_size(file_path);
// 定义分块回调(严格匹配 ContentProvider 签名)
auto provider = [file](size_t offset, size_t length, httplib::DataSink& sink) {
file->seekg(offset);
const size_t chunk_size = std::min<size_t>(1024 * 1024, length); // 64KB或剩余长度
std::vector<char> buffer(chunk_size);
size_t remaining = length;
while (remaining > 0 && sink.is_writable() && *file) {
size_t read_size = std::min(buffer.size(), remaining);
file->read(buffer.data(), read_size);
size_t bytes_read = file->gcount();
if (bytes_read > 0) {
sink.write(buffer.data(), bytes_read);
remaining -= bytes_read;
} else {
break;
}
}
return true;
};
// 定义资源清理回调
auto releaser = [file](bool /*success*/) { file->close(); };
// 调用 set_content_provider
res.set_content_provider(file_size, // 文件总大小
"application/octet-stream", // MIME类型
provider, // 数据提供回调
releaser // 资源清理回调
);
});
// 根目录重定向到/browse
server.Get("/", [](const httplib::Request& req, httplib::Response& res) { res.set_redirect("/browse"); });
std::cout << "Server running at http://localhost:" << port << std::endl;
std::cout << "Access the root path to browse files.\n";
if (!server.listen("0.0.0.0", port)) {
std::cerr << "Failed to start server\n";
return -1;
}
return 0;
}

2
ofen

@ -1 +1 @@
Subproject commit e1624c71451febf956a98bc692c0e886366f4c34
Subproject commit fbc26d565f7b73418dd9bfaee3fc67b77a56daba

View File

@ -6,18 +6,23 @@ set(CMAKE_CXX_STANDARD 17)
if (MSVC)
add_compile_options(/source-charset:utf-8)
endif()
if(DEFINED USE_BOOST)
message(STATUS "tss use boost lib.")
include_directories(${MBOOST_INCLUDE_DIR})
endif()
add_executable(tss main.cpp server.h server.cpp)
target_link_libraries(tss PRIVATE trans_net trans_util)
if(DEFINED USE_BOOST)
target_link_directories(tss PRIVATE ${MBOOST_LIB_DIR})
target_link_libraries(tss PRIVATE ${MBOOST_LIBS})
endif()
if (UNIX)
target_link_libraries(tss PRIVATE pthread)
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Windows")
target_link_libraries(tss PRIVATE ws2_32 wsock32)
endif()
if (DEFINED GRAB_CRASH)
target_link_libraries(tss PRIVATE crashelper)
endif()
if(UNIX)
execute_process(
COMMAND uname -a

View File

@ -3,9 +3,6 @@
#include "server.h"
#include "version.h"
#include <filesystem>
#include <of_path.h>
namespace fs = std::filesystem;
#ifdef _WIN32
#include <fcntl.h>
@ -16,28 +13,17 @@ namespace fs = std::filesystem;
#endif
#endif
#if defined(GRAB_CRASH)
#include <crashelper.h>
#endif
void msignal_handler(int signal)
void signal_handler(int signal)
{
if (signal == SIGINT) {
fc_recovery_color();
exit(signal);
}
}
int main(int argc, char* argv[])
{
#if defined(GRAB_CRASH)
auto config_dir = COfPath::get_config_dir("transm", true);
auto err = fs::path(config_dir).append("errs").string();
backward::SetDumpFileSavePath(err);
backward::SetDumpLogSavePath(err);
CRASHELPER_MARK_ENTRY();
sh.register_user_sig_handler([](int sig) { msignal_handler(sig); });
#else
signal(SIGINT, msignal_handler);
#endif
std::signal(SIGINT, signal_handler);
#ifdef _WIN32
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
@ -52,8 +38,7 @@ int main(int argc, char* argv[])
delete p;
});
TLOGI("Build At {} {} under {} on {}", __DATE__, __TIME__,
VERSION_GIT_COMMIT, VERSION_GIT_BRANCH);
TLOGI("Build At {} {} under {} on {}", __DATE__, __TIME__, VERSION_GIT_COMMIT, VERSION_GIT_BRANCH);
int port = 9898;
if (argc < 2) {
TLOGI("Use Default Port:{}", port);
@ -63,7 +48,7 @@ int main(int argc, char* argv[])
TLOGI("Use Port:{}", port);
}
asio::io_context io_context;
TransmServer server(io_context);
CTcpServer server(io_context);
if (!server.start(port)) {
return -1;
}

View File

@ -7,13 +7,13 @@
using namespace ofen;
constexpr int check_idle_percycle = 1000 * 30; // 毫秒
constexpr int remove_after_time = 60; // 秒
TransmServer::TransmServer(asio::io_context& io_context) : io_context_(io_context), acceptor_(io_context)
CTcpServer::CTcpServer(asio::io_context& io_context) : io_context_(io_context), acceptor_(io_context)
{
th_run_ = true;
sleep_.set_timeout(check_idle_percycle);
}
TransmServer::~TransmServer()
CTcpServer::~CTcpServer()
{
th_run_ = false;
sleep_.contiune();
@ -22,7 +22,7 @@ TransmServer::~TransmServer()
}
}
bool TransmServer::start(unsigned short port)
bool CTcpServer::start(unsigned short port)
{
asio::ip::tcp::resolver resolver(io_context_);
asio::ip::tcp::resolver::query query(asio::ip::host_name(), "");
@ -63,7 +63,7 @@ bool TransmServer::start(unsigned short port)
return true;
}
void TransmServer::stop()
void CTcpServer::stop()
{
acceptor_.close();
std::unique_lock<std::shared_mutex> lock(cli_mut_);
@ -75,14 +75,14 @@ void TransmServer::stop()
client_threads_.clear();
}
void TransmServer::get_client_list(CMessageInfo& msg_info)
void CTcpServer::get_client_list(CMessageInfo& msg_info)
{
struct TmpInfo {
std::string id;
std::string online_time;
std::string uuid;
std::string task;
uint64_t timestamp{};
uint64_t timestamp;
};
std::vector<TmpInfo> vec;
std::string msg;
@ -101,7 +101,8 @@ void TransmServer::get_client_list(CMessageInfo& msg_info)
}
// 排序 vec 根据 client->timestamp
std::sort(vec.begin(), vec.end(), [](const TmpInfo& a, const TmpInfo& b) { return a.timestamp < b.timestamp; });
std::sort(vec.begin(), vec.end(),
[](const TmpInfo& a, const TmpInfo& b) { return a.timestamp < b.timestamp; });
int index = 1;
for (const auto& item : vec) {
@ -116,7 +117,7 @@ void TransmServer::get_client_list(CMessageInfo& msg_info)
msg_info.str = msg;
}
void TransmServer::trans_data(CFrameBuffer* buf)
void CTcpServer::trans_data(CFrameBuffer* buf)
{
std::shared_ptr<ClientCache> fcli = nullptr;
std::shared_ptr<ClientCache> tcli = nullptr;
@ -189,7 +190,8 @@ void TransmServer::trans_data(CFrameBuffer* buf)
}
}
bool TransmServer::check_double(CFrameBuffer* buf, std::shared_ptr<ClientCache>& fcli, std::shared_ptr<ClientCache>& tcli)
bool CTcpServer::check_double(CFrameBuffer* buf, std::shared_ptr<ClientCache>& fcli,
std::shared_ptr<ClientCache>& tcli)
{
std::shared_lock<std::shared_mutex> lock(cli_mut_);
if (client_map_.count(buf->fid_)) {
@ -218,7 +220,7 @@ bool TransmServer::check_double(CFrameBuffer* buf, std::shared_ptr<ClientCache>&
return true;
}
void TransmServer::accept_client()
void CTcpServer::accept_client()
{
auto socket = std::make_shared<asio::ip::tcp::socket>(io_context_);
acceptor_.async_accept(*socket, [this, socket](const asio::error_code& error) {
@ -246,14 +248,15 @@ void TransmServer::accept_client()
if (!can) {
std::this_thread::sleep_for(std::chrono::minutes(1));
} else {
client_threads_[client_key] = std::thread(&TransmServer::th_client, this, socket, client_key);
client_threads_[client_key] = std::thread(&CTcpServer::th_client, this, socket, client_key);
}
}
accept_client();
});
}
void TransmServer::th_client(const std::shared_ptr<asio::ip::tcp::socket>& socket, const std::string& client_key)
void CTcpServer::th_client(const std::shared_ptr<asio::ip::tcp::socket>& socket,
const std::string& client_key)
{
std::shared_ptr<int> deleter(new int(0), [&](int* p) {
std::unique_lock<std::shared_mutex> lock(cli_mut_);
@ -327,7 +330,7 @@ void TransmServer::th_client(const std::shared_ptr<asio::ip::tcp::socket>& socke
}
}
bool TransmServer::send_frame(const std::shared_ptr<asio::ip::tcp::socket>& socket, CFrameBuffer* buf)
bool CTcpServer::send_frame(const std::shared_ptr<asio::ip::tcp::socket>& socket, CFrameBuffer* buf)
{
char* out_buf{};
int out_len{};
@ -341,20 +344,21 @@ bool TransmServer::send_frame(const std::shared_ptr<asio::ip::tcp::socket>& sock
}
try {
if (!socket->send(asio::buffer(out_buf, out_len))) {
TLOGE("{} send failed, buf type:{}, fid:{}, tid:{}", __FUNCTION__, static_cast<int>(buf->type_), buf->fid_,
buf->tid_);
TLOGE("{} send failed, buf type:{}, fid:{}, tid:{}", __FUNCTION__, static_cast<int>(buf->type_),
buf->fid_, buf->tid_);
delete[] out_buf;
return false;
}
} catch (const std::exception& e) {
TLOGE("send failed, type:{}, fid:{}, tid:{}, mark:{}", static_cast<int>(buf->type_), buf->fid_, buf->tid_, buf->mark_);
TLOGE("send failed, type:{}, fid:{}, tid:{}, mark:{}", static_cast<int>(buf->type_), buf->fid_,
buf->tid_, buf->mark_);
}
delete[] out_buf;
return true;
}
void TransmServer::monitor_idle()
void CTcpServer::monitor_idle()
{
while (th_run_) {
sleep_.sleep();
@ -365,7 +369,9 @@ void TransmServer::monitor_idle()
std::unique_lock<std::shared_mutex> lock(cli_mut_);
for (auto& item : client_map_) {
auto now = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::seconds>(now - item.second->last_active_time_).count();
auto duration =
std::chrono::duration_cast<std::chrono::seconds>(now - item.second->last_active_time_)
.count();
if (duration >= remove_after_time) {
TLOGW("OnLine Time [{}] sec, Proactively disconnect:{}", duration, item.first);
remove_vec.push_back(item.first);

View File

@ -13,22 +13,22 @@ using namespace ofen;
using high_c = std::chrono::time_point<std::chrono::high_resolution_clock>;
struct ClientCache {
std::shared_ptr<asio::ip::tcp::socket> socket_;
CMutBuffer buffer_;
CMutBuffer buffer_{};
std::array<char, g_BuffSize> tmp_buf_{};
std::string task_;
std::string uuid;
std::string task_time_;
std::string online_time_;
std::string task_{};
std::string uuid{};
std::string task_time_{};
std::string online_time_{};
uint64_t timestamp{};
high_c last_active_time_;
FrameType cur_type_{TYPE_DEFAULT};
};
class TransmServer
class CTcpServer
{
public:
explicit TransmServer(asio::io_context& io_context);
~TransmServer();
CTcpServer(asio::io_context& io_context);
~CTcpServer();
public:
bool start(unsigned short port);
@ -39,7 +39,8 @@ private:
private:
void trans_data(CFrameBuffer* buf);
bool check_double(CFrameBuffer* buf, std::shared_ptr<ClientCache>& fcli, std::shared_ptr<ClientCache>& tcli);
bool check_double(CFrameBuffer* buf, std::shared_ptr<ClientCache>& fcli,
std::shared_ptr<ClientCache>& tcli);
private:
void accept_client();

View File

@ -1,42 +1,7 @@
cmake_minimum_required(VERSION 3.16)
project(transm_test LANGUAGES CXX)
project(test LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(TEST_SOURCES
../3rd/catch_amalgamated.cpp
assistant.h
assistant.cxx
)
set(TRANSM_TEST_SOURCES
../3rd/catch_amalgamated.cpp
../client/client.cpp
../client/client.h
../client/config.cpp
../client/config.h
../util/util.h
../server/server.cpp
../server/server.h
../net/net_base.h
assistant.h
assistant.cxx
)
add_executable(encry_correct_test EncryptCorrect.cxx ${TEST_SOURCES})
add_executable(encry_speed_test EncryptSpeed.cxx ${TEST_SOURCES})
target_link_libraries(encry_correct_test PRIVATE tinyaes trans_util)
target_link_libraries(encry_speed_test PRIVATE tinyaes trans_util)
add_executable(transm_cmd_test Cmd.cxx ${TRANSM_TEST_SOURCES})
target_link_libraries(transm_cmd_test PRIVATE trans_net trans_util)
if (UNIX)
target_link_libraries(encry_speed_test PRIVATE pthread)
target_link_libraries(encry_correct_test PRIVATE pthread)
target_link_libraries(transm_cmd_test PRIVATE pthread)
endif()
enable_testing()
add_test(NAME EncryCorrectTest COMMAND encry_correct_test)
add_test(NAME EncrySpeedTest COMMAND encry_speed_test -s)
add_test(NAME CmdTest COMMAND transm_cmd_test)
add_executable(test main.cxx)
target_link_libraries(test PRIVATE tinyaes trans_util)

View File

@ -1,241 +0,0 @@
#include <catch_amalgamated.hpp>
#include <cstdint>
#include <fstream>
#include "../client/client.h"
#include "../client/config.h"
#include "../server/server.h"
#include "../util/util.h"
#include "assistant.h"
std::shared_ptr<TransmServer> server;
std::shared_ptr<TransmClient> clientA;
std::shared_ptr<TransmClient> clientB;
std::shared_ptr<ClientConfig> config;
asio::io_context server_context;
constexpr auto ip = "127.0.0.1";
constexpr unsigned short port = 9897;
bool server_suc = false;
constexpr unsigned int max_wait = 3000;
constexpr unsigned int wait_interval = 100;
std::string str_id_a;
int ida_in_b = -1;
std::thread server_th;
std::string test_filea = "filea.dat";
std::string test_fileb = "fileb.dat";
std::string test_sub_dir = "test_sub";
std::string test_task_file = "test_task.txt";
bool test_ls();
bool random_ralated_files();
bool test_up_task(bool encrypt);
void server_run()
{
server = std::make_shared<TransmServer>(server_context);
if (!server->start(port)) {
server_suc = false;
return;
}
server_suc = true;
server_context.run();
}
bool base_connect()
{
config = std::make_shared<ClientConfig>();
if (!config->baseInit()) {
return false;
}
server_th = std::thread(server_run);
if (value_wait<bool>([]() -> bool { return server_suc; }, true,
std::equal_to<bool>(), max_wait,
wait_interval) == false) {
return false;
}
clientA = std::make_shared<TransmClient>();
if (clientA->connect_for_test(ip, std::to_string(port),
config->get_config_dir()) == false) {
return false;
}
clientB = std::make_shared<TransmClient>();
if (clientB->connect_for_test(ip, std::to_string(port),
config->get_config_dir()) == false) {
return false;
}
if (value_wait<std::string>(
[]() -> std::string { return clientA->test_get_own_id(); },
std::string(), std::not_equal_to<std::string>(), max_wait,
wait_interval) == false) {
return false;
}
if (value_wait<std::string>(
[]() -> std::string { return clientB->test_get_own_id(); },
std::string(), std::not_equal_to<std::string>(), max_wait,
wait_interval) == false) {
return false;
}
str_id_a = clientA->test_get_own_id();
std::cout << "clientA id: " << str_id_a << std::endl;
if (value_wait<int>(
[]() -> int { return clientB->test_index_by_id(str_id_a); }, -1,
std::not_equal_to<int>(), max_wait, wait_interval) == false) {
return false;
}
ida_in_b = clientB->test_index_by_id(str_id_a);
std::cout << "clientA index In B: " << ida_in_b << std::endl;
return true;
}
bool main_test()
{
ON_SCOPE_EXIT
{
fc_recovery_color();
};
if (!base_connect()) {
return false;
}
std::shared_ptr<int> deleter(new int(), [](int* p) {
if (clientA) {
clientA->disconnect_for_test();
}
if (clientB) {
clientB->disconnect_for_test();
}
if (server) {
server->stop();
}
server_context.stop();
if (server_th.joinable()) {
server_th.join();
}
delete p;
});
if (!test_ls()) {
return false;
}
if (!random_ralated_files()) {
return false;
}
if (!test_up_task(true)) {
return false;
}
if (!test_up_task(false)) {
return false;
}
std::this_thread::sleep_for(std::chrono::seconds(10));
return true;
}
// 测试 Ls
bool test_ls()
{
std::string cmd = std::to_string(ida_in_b) + " .";
if (!clientB->cmd_ls(cmd)) {
return false;
}
return true;
}
bool test_up_task(bool encrypt)
{
std::string cmd = std::to_string(ida_in_b) + " " + test_task_file;
auto fas = test_filea;
auto fat = test_sub_dir + "/" + test_filea;
auto fbs = test_fileb;
auto fbt = test_sub_dir + "/" + test_fileb;
ON_SCOPE_EXIT
{
if (fs::exists(fat)) {
fs::remove(fat);
}
if (fs::exists(fbt)) {
fs::remove(fbt);
}
};
set_encrypt(encrypt);
clientB->set_task_state(TransmClient::TaskState::TASK_STATE_IDLE);
if (!clientB->cmd_sub_task(cmd, true)) {
return false;
}
if (value_wait<TransmClient::TaskState>(
[&]() -> TransmClient::TaskState {
return clientB->get_task_state();
},
TransmClient::TaskState::TASK_STATE_IDLE,
std::not_equal_to<TransmClient::TaskState>(), max_wait * 2,
wait_interval) == false) {
return false;
}
auto r = clientB->get_task_state();
if (r != TransmClient::TaskState::TASK_STATE_DONE) {
return false;
}
if (!is_equal_filecontent(fas, fat)) {
return false;
}
if (!is_equal_filecontent(fbs, fbt)) {
return false;
}
std::cout << "****** up task done encrypt:" << encrypt << " ******"
<< std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return true;
}
bool random_ralated_files()
{
if (!random_file("filea.dat", 1024 * 1024 * 10)) {
return false;
}
if (!random_file("fileb.dat", 1024 * 1024 * 10)) {
return false;
}
if (fs::exists(test_sub_dir)) {
fs::remove_all(test_sub_dir);
}
fs::create_directories(test_sub_dir);
if (fs::exists(test_task_file)) {
fs::remove(test_task_file);
}
std::ofstream ofs(test_task_file);
ofs << "${CURRENT}/" << test_filea << "|" << test_sub_dir + "/"
<< std::endl;
ofs << test_fileb << "|" << test_sub_dir + "/" << std::endl;
ofs.close();
return true;
}
TEST_CASE("transm cmd part", "[cmd]")
{
SECTION("correctness of cmd")
{
REQUIRE(main_test() == true);
}
}

View File

@ -1,41 +0,0 @@
#include <aes.hpp>
#include <catch_amalgamated.hpp>
#include <fstream>
#include <string>
#include <util.h>
bool correctness_test()
{
std::string key = "demokey";
uint8_t ik[32]{};
hash(key.c_str(), ik);
int offset = 16;
char* msg = new char[256]{};
std::shared_ptr<int> deleter(new int(), [msg](int* p) {
delete p;
delete[] msg;
});
char source[] = "hello world";
memset(msg, 0, 256);
auto len = std::snprintf(msg + offset, 256 - offset, "%s", source);
if (!encrypt(ik, (uint8_t*)msg, len + offset)) {
return false;
}
uint8_t ik2[32]{};
hash(key.c_str(), ik2);
if (!decrypt(ik2, (uint8_t*)msg, len + offset)) {
return false;
}
return std::memcmp(source, msg + offset, len) == 0;
}
TEST_CASE("transm encry part", "[encry]")
{
SECTION("correctness of encryption")
{
REQUIRE(correctness_test() == true);
}
}

View File

@ -1,197 +0,0 @@
#include <aes.hpp>
#include <catch_amalgamated.hpp>
#include <fstream>
#include <string>
#include <util.h>
#include "assistant.h"
const size_t BLOCK_SIZE = 102400; // 100KB块大小
const size_t IV_SIZE = 16; // 随机值大小
struct SpeedRet {
std::string mode;
long long file_size;
long long encry_speed;
long long decry_speed;
bool verify;
};
bool test_speed(SpeedRet& ret)
{
std::string test_file("1.dat");
if (!random_file(test_file, 1024 * 1024 * 10)) {
std::cerr << "Failed to create test file" << std::endl;
return false;
}
ret.decry_speed = 0;
ret.encry_speed = 0;
ret.mode = "";
ret.verify = false;
std::shared_ptr<int> deleter(new int(1), [test_file](int* p) {
delete p;
if (fs::exists(test_file)) {
fs::remove(test_file);
}
});
if (!fs::exists(test_file)) {
std::cerr << "Input file not found: " << test_file << std::endl;
return false;
}
size_t file_size = fs::file_size(test_file);
ret.file_size = file_size / (1024 * 1024);
if (file_size == 0) {
std::cerr << "Input file is empty" << std::endl;
return false;
}
std::string key = "test_speed_key";
uint8_t ik[32]{};
hash(key.c_str(), ik);
fs::path decrypted_path = fs::path(test_file).replace_filename(
fs::path(test_file).stem().string() + "_decrypted" +
fs::path(test_file).extension().string());
std::ofstream decrypted_file(decrypted_path, std::ios::binary);
if (!decrypted_file) {
std::cerr << "Failed to create decrypted file" << std::endl;
return false;
}
std::ifstream in_file(test_file, std::ios::binary);
if (!in_file) {
std::cerr << "Failed to open input file" << std::endl;
return false;
}
// 测试数据缓冲区(额外预留16字节空间)
std::vector<uint8_t> original_block(BLOCK_SIZE);
std::vector<uint8_t> processing_block(BLOCK_SIZE +
IV_SIZE); // 加密/解密处理缓冲区
size_t total_bytes = 0;
size_t blocks_processed = 0;
bool verification_passed = true;
auto total_encrypt_time = std::chrono::microseconds(0);
auto total_decrypt_time = std::chrono::microseconds(0);
while (in_file) {
in_file.read(reinterpret_cast<char*>(original_block.data()),
BLOCK_SIZE - IV_SIZE);
size_t bytes_read = in_file.gcount();
if (bytes_read == 0)
break;
memcpy(processing_block.data() + IV_SIZE, original_block.data(),
bytes_read);
auto start_encrypt = std::chrono::high_resolution_clock::now();
if (!encrypt(ik, processing_block.data(), bytes_read + IV_SIZE)) {
std::cerr << "Encryption failed at block " << blocks_processed
<< std::endl;
verification_passed = false;
break;
}
auto end_encrypt = std::chrono::high_resolution_clock::now();
total_encrypt_time +=
std::chrono::duration_cast<std::chrono::microseconds>(
end_encrypt - start_encrypt);
auto start_decrypt = std::chrono::high_resolution_clock::now();
if (!decrypt(ik, processing_block.data(), bytes_read + IV_SIZE)) {
std::cerr << "Decryption failed at block " << blocks_processed
<< std::endl;
verification_passed = false;
break;
}
auto end_decrypt = std::chrono::high_resolution_clock::now();
total_decrypt_time +=
std::chrono::duration_cast<std::chrono::microseconds>(
end_decrypt - start_decrypt);
if (memcmp(original_block.data(), processing_block.data() + IV_SIZE,
bytes_read) != 0) {
std::cerr << "Data mismatch at block " << blocks_processed
<< std::endl;
verification_passed = false;
break;
}
decrypted_file.write(
reinterpret_cast<const char*>(processing_block.data() + IV_SIZE),
bytes_read);
total_bytes += bytes_read;
blocks_processed++;
}
in_file.close();
decrypted_file.close();
#if !defined(NDEBUG) || defined(_DEBUG) || defined(DEBUG)
// Debug 模式
ret.mode = "Debug";
#else
// Release 模式
ret.mode = "Release";
#endif
// 计算吞吐量(只计算有效数据部分)
double encrypt_throughput = (double)total_bytes / (1024 * 1024) /
(total_encrypt_time.count() / 1000000.0);
double decrypt_throughput = (double)total_bytes / (1024 * 1024) /
(total_decrypt_time.count() / 1000000.0);
ret.encry_speed = encrypt_throughput;
ret.decry_speed = decrypt_throughput;
ret.verify = verification_passed;
fs::remove(decrypted_path);
return verification_passed;
}
bool correctness_test()
{
std::string key = "demokey";
uint8_t ik[32]{};
hash(key.c_str(), ik);
int offset = 16;
char* msg = new char[256]{};
std::shared_ptr<int> deleter(new int(), [msg](int* p) {
delete p;
delete[] msg;
});
char source[] = "hello world";
memset(msg, 0, 256);
auto len = std::snprintf(msg + offset, 256 - offset, "%s", source);
if (!encrypt(ik, (uint8_t*)msg, len + offset)) {
return false;
}
uint8_t ik2[32]{};
hash(key.c_str(), ik2);
if (!decrypt(ik2, (uint8_t*)msg, len + offset)) {
return false;
}
return std::memcmp(source, msg + offset, len) == 0;
}
TEST_CASE("transm encry part", "[encry]")
{
SECTION("speed of encryption")
{
SpeedRet ret{};
auto r = test_speed(ret);
UNSCOPED_INFO("Encryption mode: " << ret.mode << "");
UNSCOPED_INFO("FileSize: " << ret.file_size << " MB");
UNSCOPED_INFO("Encryption speed: " << ret.encry_speed << " MB/s");
UNSCOPED_INFO("Decryption speed: " << ret.decry_speed << " MB/s");
REQUIRE(r == true);
}
}

View File

@ -1,77 +0,0 @@
#include "assistant.h"
bool random_file(const std::string& file, size_t size)
{
if (file.empty() || size == 0) {
return false;
}
std::ofstream ofs(file, std::ios::binary | std::ios::trunc);
if (!ofs) {
return false;
}
std::random_device rd;
std::mt19937_64 gen(rd());
std::uniform_int_distribution<int> dis(0, 255);
const size_t buffer_size = 4096;
std::vector<unsigned char> buffer(buffer_size);
for (size_t remaining = size; remaining > 0;) {
size_t chunk = std::min(remaining, buffer_size);
for (size_t i = 0; i < chunk; ++i) {
buffer[i] = static_cast<unsigned char>(dis(gen));
}
if (!ofs.write(reinterpret_cast<const char*>(buffer.data()), chunk)) {
return false;
}
remaining -= chunk;
}
return true;
}
/**
* @brief
*
* @param filea
* @param fileb
* @return true
* @return false
*/
bool is_equal_filecontent(const std::string& filea, const std::string& fileb)
{
std::ifstream stream_a(filea, std::ios::binary);
std::ifstream stream_b(fileb, std::ios::binary);
if (!stream_a.is_open() || !stream_b.is_open()) {
return false;
}
auto size_a = fs::file_size(filea);
auto size_b = fs::file_size(fileb);
if (size_a != size_b) {
return false;
}
const size_t buffer_size = 4096; // 4KB 缓冲区
char buffer_a[buffer_size];
char buffer_b[buffer_size];
while (stream_a.good() && stream_b.good()) {
stream_a.read(buffer_a, buffer_size);
stream_b.read(buffer_b, buffer_size);
if (stream_a.gcount() != stream_b.gcount()) {
return false;
}
if (!std::equal(buffer_a, buffer_a + stream_a.gcount(), buffer_b)) {
return false;
}
}
return !stream_a.bad() && !stream_b.bad();
}

View File

@ -1,106 +0,0 @@
#ifndef ASSISTANT_H
#define ASSISTANT_H
#include <filesystem>
#include <fstream>
#include <functional>
#include <random>
#include <string>
#include <thread>
namespace fs = std::filesystem;
/**
* @brief
*
* @param filea
* @param fileb
* @return true
* @return false
*/
bool is_equal_filecontent(const std::string& filea, const std::string& fileb);
bool random_file(const std::string& file, size_t size);
/**
* @brief
*
* @tparam T
* @tparam Compare
* @param value
* @param expected
* @param comparator ( std::equal_to)
* @param timeout_ms ()0
* @param interval_ms ()
* @return true
* @return false
*/
template <typename T, typename Compare = std::equal_to<T>>
bool value_wait(const std::function<T()>& value_ref, const T& expected,
Compare comparator = Compare(), unsigned long timeout_ms = 0,
unsigned long interval_ms = 100)
{
auto start = std::chrono::steady_clock::now();
while (true) {
T value = value_ref();
if (comparator(value, expected)) {
return true;
}
if (timeout_ms > 0) {
auto elapsed =
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start)
.count();
if (elapsed >= timeout_ms) {
return false;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(interval_ms));
}
}
class ScopeExit
{
public:
ScopeExit() = default;
template <typename F> ScopeExit(F&& f) : func_(std::forward<F>(f))
{
}
ScopeExit(const ScopeExit&) = delete;
ScopeExit& operator=(const ScopeExit&) = delete;
ScopeExit(ScopeExit&& other) noexcept : func_(std::move(other.func_))
{
other.func_ = nullptr;
}
ScopeExit& operator=(ScopeExit&& other) noexcept
{
if (this != &other) {
if (func_)
func_();
func_ = std::move(other.func_);
other.func_ = nullptr;
}
return *this;
}
~ScopeExit()
{
if (func_)
func_();
}
void dismiss() noexcept
{
func_ = nullptr;
}
private:
std::function<void()> func_;
};
#define _SCOPE_EXIT_CONCAT(a, b) a##b
#define _MAKE_ON_SCOPE_EXIT(line) \
ScopeExit _SCOPE_EXIT_CONCAT(exit_defer_, line) = [&]()
#define ON_SCOPE_EXIT _MAKE_ON_SCOPE_EXIT(__LINE__)
#endif // ASSISTANT_H

27
test/main.cxx Normal file
View File

@ -0,0 +1,27 @@
#include <aes.hpp>
#include <string>
#include <util.h>
int main()
{
std::string key = "sss";
uint8_t ik[32]{};
hash(key.c_str(), ik);
int offset = 16;
char* msg = new char[256]{};
memset(msg, 0, 256);
auto len = std::snprintf(msg + offset, 256 - offset, "%s", "hello world");
std::cout << encrypt(ik, (uint8_t*)msg, len + offset) << std::endl;
std::cout << msg + offset << std::endl;
uint8_t ik2[32]{};
hash(key.c_str(), ik2);
std::cout << decrypt(ik2, (uint8_t*)msg, len + offset) << std::endl;
std::cout << msg + offset << std::endl;
return 0;
}

View File

@ -1,12 +1,10 @@
/*
This is an implementation of the AES algorithm, specifically ECB, CTR and CBC
mode. Block size can be chosen in aes.h - available choices are AES128, AES192,
AES256.
This is an implementation of the AES algorithm, specifically ECB, CTR and CBC mode.
Block size can be chosen in aes.h - available choices are AES128, AES192, AES256.
The implementation is verified against the test vectors in:
National Institute of Standards and Technology Special Publication 800-38A
2001 ED
National Institute of Standards and Technology Special Publication 800-38A 2001 ED
ECB-AES128
----------
@ -44,8 +42,7 @@ NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0)
/*****************************************************************************/
/* Defines: */
/*****************************************************************************/
// The number of columns comprising a state in AES. This is a constant in AES.
// Value=4
// The number of columns comprising a state in AES. This is a constant in AES. Value=4
#define Nb 4
#if defined(AES256) && (AES256 == 1)
@ -61,8 +58,7 @@ NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0)
// jcallan@github points out that declaring Multiply as a function
// reduces code size considerably with the Keil ARM compiler.
// See this link for more information:
// https://github.com/kokke/tiny-AES-C/pull/3
// See this link for more information: https://github.com/kokke/tiny-AES-C/pull/3
#ifndef MULTIPLY_AS_A_FUNCTION
#define MULTIPLY_AS_A_FUNCTION 0
#endif
@ -73,77 +69,59 @@ NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0)
// state - array holding the intermediate results during decryption.
typedef uint8_t state_t[4][4];
// The lookup-tables are marked const so they can be placed in read-only storage
// instead of RAM The numbers below can be computed dynamically trading ROM for
// RAM - This can be useful in (embedded) bootloader applications, where ROM is
// often limited.
// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM
// The numbers below can be computed dynamically trading ROM for RAM -
// This can be useful in (embedded) bootloader applications, where ROM is often limited.
static const uint8_t sbox[256] = {
// 0 1 2 3 4 5 6 7 8 9 A B C
// D E F
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
0xb0, 0x54, 0xbb, 0x16};
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
static const uint8_t rsbox[256] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,
0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,
0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,
0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,
0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,
0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,
0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
0x55, 0x21, 0x0c, 0x7d};
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d};
// The round constant word array, Rcon[i], contains the values given by
// x to the power (i-1) being powers of x (x is denoted as {02}) in the field
// GF(2^8)
static const uint8_t Rcon[11] = {0x8d, 0x01, 0x02, 0x04, 0x08, 0x10,
0x20, 0x40, 0x80, 0x1b, 0x36};
// x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8)
static const uint8_t Rcon[11] = {0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
/*
* Jordan Goulder points out in PR #12
* (https://github.com/kokke/tiny-AES-C/pull/12), that you can remove most of
* the elements in the Rcon array, because they are unused.
* Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12),
* that you can remove most of the elements in the Rcon array, because they are unused.
*
* From Wikipedia's article on the Rijndael key schedule @
* https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon
*
* "Only the first some of these constants are actually used – up to rcon[10]
* for AES-128 (as 11 round keys are needed), up to rcon[8] for AES-192, up to
* rcon[7] for AES-256. rcon[0] is not used in AES algorithm."
* "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys
* are needed), up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm."
*/
/*****************************************************************************/
@ -164,8 +142,7 @@ static uint8_t getSBoxInvert(uint8_t num)
*/
#define getSBoxInvert(num) (rsbox[(num)])
// This function produces Nb(Nr+1) round keys. The round keys are used in each
// round to decrypt the states.
// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states.
static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
{
unsigned i, j, k;
@ -203,8 +180,7 @@ static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
}
// SubWord() is a function that takes a four-byte input word and
// applies the S-box to each of the four bytes to produce an output
// word.
// applies the S-box to each of the four bytes to produce an output word.
// Function Subword()
{
@ -336,33 +312,27 @@ static void MixColumns(state_t* state)
}
// Multiply is used to multiply numbers in the field GF(2^8)
// Note: The last call to xtime() is unneeded, but often ends up generating a
// smaller binary
// The compiler seems to be able to vectorize the operation better this
// way. See https://github.com/kokke/tiny-AES-c/pull/34
// Note: The last call to xtime() is unneeded, but often ends up generating a smaller binary
// The compiler seems to be able to vectorize the operation better this way.
// See https://github.com/kokke/tiny-AES-c/pull/34
#if MULTIPLY_AS_A_FUNCTION
static uint8_t Multiply(uint8_t x, uint8_t y)
{
return (((y & 1) * x) ^ ((y >> 1 & 1) * xtime(x)) ^
((y >> 2 & 1) * xtime(xtime(x))) ^
return (((y & 1) * x) ^ ((y >> 1 & 1) * xtime(x)) ^ ((y >> 2 & 1) * xtime(xtime(x))) ^
((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^
((y >> 4 & 1) *
xtime(xtime(xtime(
xtime(x)))))); /* this last call to xtime() can be omitted */
((y >> 4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */
}
#else
#define Multiply(x, y) \
(((y & 1) * x) ^ ((y >> 1 & 1) * xtime(x)) ^ \
((y >> 2 & 1) * xtime(xtime(x))) ^ \
((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^ \
((y >> 4 & 1) * xtime(xtime(xtime(xtime(x))))))
(((y & 1) * x) ^ ((y >> 1 & 1) * xtime(x)) ^ ((y >> 2 & 1) * xtime(xtime(x))) ^ \
((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^ ((y >> 4 & 1) * xtime(xtime(xtime(xtime(x))))))
#endif
#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
// MixColumns function mixes the columns of the state matrix.
// The method used to multiply may be difficult to understand for the
// inexperienced. Please use the references to gain more information.
// The method used to multiply may be difficult to understand for the inexperienced.
// Please use the references to gain more information.
static void InvMixColumns(state_t* state)
{
int i;
@ -373,14 +343,10 @@ static void InvMixColumns(state_t* state)
c = (*state)[i][2];
d = (*state)[i][3];
(*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^
Multiply(c, 0x0d) ^ Multiply(d, 0x09);
(*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^
Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
(*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^
Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
(*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^
Multiply(c, 0x09) ^ Multiply(d, 0x0e);
(*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
(*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
(*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
(*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
}
}
@ -483,15 +449,13 @@ static void InvCipher(state_t* state, uint8_t* RoundKey)
void AES_ECB_encrypt(struct AES_ctx* ctx, uint8_t* buf)
{
// The next function call encrypts the PlainText with the Key using AES
// algorithm.
// The next function call encrypts the PlainText with the Key using AES algorithm.
Cipher((state_t*)buf, ctx->RoundKey);
}
void AES_ECB_decrypt(struct AES_ctx* ctx, uint8_t* buf)
{
// The next function call decrypts the PlainText with the Key using AES
// algorithm.
// The next function call decrypts the PlainText with the Key using AES algorithm.
InvCipher((state_t*)buf, ctx->RoundKey);
}
@ -502,8 +466,7 @@ void AES_ECB_decrypt(struct AES_ctx* ctx, uint8_t* buf)
static void XorWithIv(uint8_t* buf, uint8_t* Iv)
{
uint8_t i;
for (i = 0; i < AES_BLOCKLEN;
++i) // The block in AES is always 128bit no matter the key size
for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size
{
buf[i] ^= Iv[i];
}
@ -541,8 +504,8 @@ void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length)
#if defined(CTR) && (CTR == 1)
/* Symmetrical operation: same function for encrypting as for decrypting. Note
* any IV/nonce should never be reused with the same key */
/* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be
* reused with the same key */
void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length)
{
uint8_t buffer[AES_BLOCKLEN];

View File

@ -7,11 +7,10 @@
//
// CBC enables AES encryption in CBC-mode of operation.
// CTR enables encryption in counter-mode.
// ECB enables the basic ECB 16-byte block algorithm. All can be enabled
// simultaneously.
// ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously.
// The #ifndef-guard allows it to be configured before #include'ing or at
// compile time. #ifndef CBC
// The #ifndef-guard allows it to be configured before #include'ing or at compile time.
// #ifndef CBC
// #define CBC 1
// #endif
@ -54,8 +53,7 @@ struct AES_ctx {
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key,
const uint8_t* iv);
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv);
#endif
@ -70,9 +68,8 @@ void AES_ECB_decrypt(struct AES_ctx* ctx, uint8_t* buf);
#if defined(CBC) && (CBC == 1)
// buffer size MUST be mutile of AES_BLOCKLEN;
// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for
// padding scheme NOTES: you need to set IV in ctx via AES_init_ctx_iv() or
// AES_ctx_set_iv()
// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv()
// no IV should ever be reused with the same key
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
@ -82,9 +79,8 @@ void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
#if defined(CTR) && (CTR == 1)
// Same function for encrypting as for decrypting.
// IV is incremented for every block, and used after encryption as
// XOR-compliment for output Suggesting
// https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
// IV is incremented for every block, and used after encryption as XOR-compliment for output
// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv()
// no IV should ever be reused with the same key
void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);

View File

@ -9,7 +9,6 @@
CTransProtocal::CTransProtocal() = default;
constexpr uint8_t kz = 16;
static bool use_encrypt = true;
CTransProtocal::~CTransProtocal() = default;
/*
@ -48,8 +47,7 @@ CFrameBuffer* CTransProtocal::parse(CMutBuffer& buffer)
int32_t len{};
std::memcpy(&type, buffer.get_data() + find + 2, sizeof(type));
std::memcpy(&mark, buffer.get_data() + find + 2 + 2, sizeof(mark));
std::memcpy(&len, buffer.get_data() + find + 2 + 2 + 1 + 32 + 32,
sizeof(len));
std::memcpy(&len, buffer.get_data() + find + 2 + 2 + 1 + 32 + 32, sizeof(len));
int32_t tail_index = find + 2 + 2 + 1 + 32 + 32 + 4 + len;
if (buffer.get_len() - 2 < tail_index || len < 0) {
@ -68,8 +66,7 @@ CFrameBuffer* CTransProtocal::parse(CMutBuffer& buffer)
result->mark_ = mark;
result->type_ = static_cast<FrameType>(type);
if (len > 0) {
std::memcpy(result->data_,
buffer.get_data() + find + 2 + 2 + 1 + 4 + 32 + 32, len);
std::memcpy(result->data_, buffer.get_data() + find + 2 + 2 + 1 + 4 + 32 + 32, len);
}
buffer.remove_of(0, tail_index + 2);
return result;
@ -95,8 +92,7 @@ bool CTransProtocal::pack(CFrameBuffer* buf, char** out_buf, int& len)
std::memcpy(*out_buf + 2 + 2 + 1, buf->fid_.data(), buf->fid_.size());
}
if (!buf->tid_.empty()) {
std::memcpy(*out_buf + 2 + 2 + 1 + 32, buf->tid_.data(),
buf->tid_.size());
std::memcpy(*out_buf + 2 + 2 + 1 + 32, buf->tid_.data(), buf->tid_.size());
}
std::memcpy(*out_buf + 2 + 2 + 1 + 32 + 32, &buf->len_, 4);
if (buf->data_ != nullptr) {
@ -137,7 +133,7 @@ CFrameBuffer::~CFrameBuffer()
len_ = 0;
}
void serialize(CMessageInfo& msg_info, char** out_buf, int& len, bool reuse_mem)
void serialize(CMessageInfo& msg_info, char** out_buf, int& len)
{
auto& info = msg_info;
info.id = localtou8(info.id);
@ -145,26 +141,10 @@ void serialize(CMessageInfo& msg_info, char** out_buf, int& len, bool reuse_mem)
info.str = localtou8(info.str);
// 计算总长度
len = sizeof(int) * 4 + info.id.size() + info.uuid.size() +
info.str.size() + info.data.size() + kz + 1;
len = sizeof(int) * 4 + info.id.size() + info.uuid.size() + info.str.size() + info.data.size() + kz;
*out_buf = new char[len]{}; // 分配内存(调用方负责释放)
// 《这里为了效率》,
// 认为如果 *out_buf 不为空,则直接使用,且长度符合要求
// 调用方负责确保内存够用性(len <= 可用最大空间长度)和内存可用性。
// 即,如果调用方及高频率调用 serialize, 且每次 len <=
// 已分配空间就复用内存,完了再释放。 低频率或者 len
// 不固定时,每次都释放内存,并置 nullptr。
if (*out_buf) {
if (!reuse_mem) {
delete[] *out_buf;
*out_buf = new char[len]; // 分配内存(调用方负责释放)
}
} else {
*out_buf = new char[len];
}
std::memset(*out_buf, 0x0, kz + 1);
char* ptr = *out_buf + kz + 1;
char* ptr = *out_buf + kz;
// 序列化 cmd
int id_size = static_cast<int>(info.id.size());
@ -193,36 +173,29 @@ void serialize(CMessageInfo& msg_info, char** out_buf, int& len, bool reuse_mem)
ptr += sizeof(int);
memcpy(ptr, info.data.data(), o_size);
char* mark = *out_buf;
if (!use_encrypt) {
mark[0] = 0x00;
return;
}
uint8_t ik[32]{};
hash(msg_info.id.c_str(), ik);
encrypt(ik, (uint8_t*)(*out_buf + 1), len - 1);
mark[0] = 0x01;
if (!encrypt(ik, (uint8_t*)(*out_buf), len)) {
return;
}
}
bool deserialize(char* data, int len, CMessageInfo& msg_info)
{
if (len < (kz + 1)) {
if (len < kz) {
return false;
}
uint8_t ik[32]{};
hash(msg_info.id.c_str(), ik);
if (!decrypt(ik, (uint8_t*)(data), len)) {
return false;
}
auto& info = msg_info;
char* ptr = data + kz + 1;
uint8_t mark = data[0];
char* ptr = data + kz;
int remaining = len;
if (mark != 0x00) {
uint8_t ik[32]{};
hash(msg_info.id.c_str(), ik);
if (!decrypt(ik, (uint8_t*)(data + 1), len - 1)) {
return false;
}
}
// 反序列化 cmd
if (remaining < static_cast<int>(sizeof(int))) {
return false;
@ -324,16 +297,9 @@ void hash(const char* data, uint8_t k[32])
void rdm(uint8_t* o, size_t size)
{
/*
random_device
mt19937 + uniform_int_distribution
*/
std::random_device rd;
// std::mt19937 gen(rd());
std::mt19937_64 gen(rd());
std::uniform_int_distribution<int> dist(0, 255);
std::generate(o, o + size,
[&]() { return static_cast<uint8_t>(dist(gen)); });
std::generate(o, o + size, [&]() { return static_cast<uint8_t>(dist(rd)); });
}
bool encrypt(const uint8_t* k, uint8_t* m, size_t len)
@ -346,7 +312,7 @@ bool encrypt(const uint8_t* k, uint8_t* m, size_t len)
rdm(nonce, sizeof(nonce) - 4);
memcpy(m, nonce, kz);
struct AES_ctx ctx{};
struct AES_ctx ctx;
AES_init_ctx_iv(&ctx, k, nonce);
AES_CTR_xcrypt_buffer(&ctx, m + kz, len - kz);
return true;
@ -361,22 +327,12 @@ bool decrypt(const uint8_t* k, uint8_t* m, size_t len)
uint8_t nonce[kz]{};
memcpy(nonce, m, kz);
struct AES_ctx ctx{};
struct AES_ctx ctx;
AES_init_ctx_iv(&ctx, k, nonce);
AES_CTR_xcrypt_buffer(&ctx, m + kz, len - kz);
return true;
}
void set_encrypt(bool encrypt)
{
use_encrypt = encrypt;
}
bool get_encrypt_status()
{
return use_encrypt;
}
CMessageInfo::CMessageInfo(const std::string& id) : id(id)
{
}

View File

@ -44,7 +44,7 @@ enum FrameType : int16_t {
// 此结构体成员顺序不可变动,涉及到序列化反序列化。
struct CMessageInfo {
explicit CMessageInfo(const std::string& id);
CMessageInfo(const std::string& id);
CMessageInfo(const CMessageInfo& info);
CMessageInfo& operator=(const CMessageInfo& info);
std::string id;
@ -53,8 +53,7 @@ struct CMessageInfo {
std::string data;
};
void serialize(CMessageInfo& msg_info, char** out_buf, int& len,
bool reuse_mem = false);
void serialize(CMessageInfo& msg_info, char** out_buf, int& len);
bool deserialize(char* data, int len, CMessageInfo& msg_info);
std::string u8tolocal(const std::string& str);
std::string localtou8(const std::string& str);
@ -62,8 +61,6 @@ void hash(const char* data, uint8_t k[32]);
void rdm(uint8_t* o, size_t size);
bool encrypt(const uint8_t* k, uint8_t* m, size_t len);
bool decrypt(const uint8_t* k, uint8_t* m, size_t len);
void set_encrypt(bool encrypt);
bool get_encrypt_status();
using namespace ofen;
class CFrameBuffer
@ -73,8 +70,8 @@ public:
~CFrameBuffer();
public:
std::string fid_;
std::string tid_;
std::string fid_{};
std::string tid_{};
public:
FrameType type_{};
@ -111,54 +108,43 @@ inline std::string now_str()
{
auto now = std::chrono::system_clock::now();
auto time_t_now = std::chrono::system_clock::to_time_t(now);
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch()) %
1000;
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
std::ostringstream timestamp;
timestamp << std::put_time(std::localtime(&time_t_now), "[%m-%d %H:%M:%S")
<< "." << std::setfill('0') << std::setw(3)
<< milliseconds.count() << "] ";
timestamp << std::put_time(std::localtime(&time_t_now), "[%m-%d %H:%M:%S") << "." << std::setfill('0')
<< std::setw(3) << milliseconds.count() << "] ";
return timestamp.str();
}
template <typename... Args>
void TLOGI(const std::string& format, Args&&... args)
template <typename... Args> void TLOGI(const std::string& format, Args&&... args)
{
fc_lock_print();
std::cout << ConsoleColor::Green
<< fmt::format(now_str() + format, std::forward<Args>(args)...)
std::cout << ConsoleColor::Green << fmt::format(now_str() + format, std::forward<Args>(args)...)
<< std::endl;
fc_unlock_print();
}
template <typename... Args>
void TLOGW(const std::string& format, Args&&... args)
template <typename... Args> void TLOGW(const std::string& format, Args&&... args)
{
fc_lock_print();
std::cout << ConsoleColor::Yellow
<< fmt::format(now_str() + format, std::forward<Args>(args)...)
std::cout << ConsoleColor::Yellow << fmt::format(now_str() + format, std::forward<Args>(args)...)
<< std::endl;
fc_unlock_print();
}
template <typename... Args>
void TLOGE(const std::string& format, Args&&... args)
template <typename... Args> void TLOGE(const std::string& format, Args&&... args)
{
fc_lock_print();
std::cout << ConsoleColor::Red
<< fmt::format(now_str() + format, std::forward<Args>(args)...)
std::cout << ConsoleColor::Red << fmt::format(now_str() + format, std::forward<Args>(args)...)
<< std::endl;
fc_unlock_print();
}
template <typename... Args>
void TLOGD(const std::string& format, Args&&... args)
template <typename... Args> void TLOGD(const std::string& format, Args&&... args)
{
fc_lock_print();
std::cout << ConsoleColor::Cyan
<< fmt::format(now_str() + format, std::forward<Args>(args)...)
std::cout << ConsoleColor::Cyan << fmt::format(now_str() + format, std::forward<Args>(args)...)
<< std::endl;
fc_unlock_print();
}

View File

@ -1,7 +1,7 @@
@echo off
cmake -BMinGWBuild -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release
cd MinGWBuild
cmake -Bxpbuild -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DXP_SYSTEM=ON -DUSE_BOOST=ON
cd xpbuild
cpack
if %errorlevel% neq 0 (
echo Error: cmake build failed.