Compare commits

...

29 Commits
v1.4.2 ... main

Author SHA1 Message Date
91510be124 fix:_WIN32_WINNT define pos. 2025-05-18 00:38:30 +08:00
655cfe6fad remove:不使用boost filesystem. 2025-05-18 00:25:33 +08:00
15085a1f8f fix:修正server ctrl-c退出时终端颜色没有恢复的问题。 2025-05-16 11:43:10 +08:00
b68017bc2a fix:修正tss-http win乱码问题 2025-04-29 14:07:46 +08:00
b9c7cbba3c fix:修正编译和tss-http浏览器乱码问题。 2025-04-29 12:49:47 +08:00
60f52a14d2 tss-http: 添加musl静态链接。 2025-04-29 11:53:37 +08:00
12b57e65c9 tss-http:扩展buffer长度 2025-04-29 11:50:24 +08:00
64d4255ca3 compile:tss-http win8及以下不支持且不支持mingw,对于此环境不生成目标文件 2025-04-29 11:40:13 +08:00
8f54951a28 add:添加一个mini http服务端tss-http 2025-04-29 11:07:43 +08:00
8121a370ce fix: server ctrl-c exit recovery color 2025-04-16 11:29:07 -04:00
733c5a68a3 rec:服务端终止恢复终端颜色。 2025-04-16 22:55:46 +08:00
9839fa79ea add:添加crash模块(-DGRAB_CRASH=ON)。 2025-04-16 22:19:49 +08:00
a81cc54025 change:改为clangd引擎。 2025-04-15 08:48:41 +08:00
13423d5172 upd:测试uptask用例完成。 2025-04-13 13:22:35 +08:00
414bc6ed75 list:文件list相关测试用例进度。 2025-04-13 00:53:52 +08:00
7a6b961392 ls:第一个Ls测试用例实现。 2025-04-13 00:08:50 +08:00
0ee24945bb upd:初步添加cmd测试用例架子。 2025-04-12 22:51:06 +08:00
2793dab420 add:添加使用catch2测试用例。 2025-04-12 21:58:53 +08:00
49d6ad1974 opt: initial new memory bytes 2025-04-09 19:29:12 +08:00
797f8f164e fix:修正秘钥key问题。 2025-04-09 18:17:13 +08:00
61ac79c93e change:更改内存删除分配方式。 2025-04-09 17:29:57 +08:00
99607c6721 fix:修正一个未置nullptr错误。 2025-04-09 16:32:40 +08:00
6ecf0d419a fix:修正加解密BUG。 2025-04-09 16:20:34 +08:00
807dbdfede fix:处理一个内存错误问题。 2025-04-09 15:05:56 +08:00
a5cab61603 doc:说明修改。 2025-04-09 12:00:43 +08:00
3a32e2f0d4 doc:说明修改。 2025-04-09 10:27:29 +08:00
41f0b5d726 doc:补充说明。 2025-04-09 10:25:45 +08:00
99a1223e52 debug:加解密速度测试和开关加解密。 2025-04-09 10:20:01 +08:00
119f1e8f72 fix:修正一个内存泄漏问题。 2025-04-09 09:14:30 +08:00
38 changed files with 38158 additions and 497 deletions

View File

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

1
.gitignore vendored
View File

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

3
.gitmodules vendored
View File

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

86
.vscode/settings.json vendored
View File

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

11817
3rd/catch_amalgamated.cpp Normal file

File diff suppressed because it is too large Load Diff

14135
3rd/catch_amalgamated.hpp Normal file

File diff suppressed because it is too large Load Diff

10497
3rd/httplib.h Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,63 +0,0 @@
{
"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,7 +18,9 @@
## 一些特点(基于最新版本) ## 一些特点(基于最新版本)
- 易编译。
- 通配符传输。 - 通配符传输。
- 公网传输支持加密。
- 广泛的平台支持。 - 广泛的平台支持。
- 终端自动文件补全。 - 终端自动文件补全。
- 自动检测对方掉线。 - 自动检测对方掉线。
@ -40,7 +42,7 @@
## 1.程序启动 ## 1.程序启动
- 对于服务端程序`tss`,绑定默认绑定`0.0.0.0``9898`端口,如果需要修改端口,使用参数启动,示例:`tss 9898` - 对于服务端程序`tss`,绑定默认绑定`0.0.0.0``9898`端口,如果需要修改端口,使用参数启动,示例:`tss 9898`
- 对于客户端程序`tsc`,请使用`tsc --help`查看使用方式 - 对于客户端程序`tsc`,请使用`tsc --help`查看如何启动
## 2.使用 ## 2.使用
@ -65,6 +67,41 @@ ${HOME}/截图/Ni.jpg|${HOME}/dira
${CURRENT}/xxx.zip|D:\ ${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`构建工具。 当前项目支持`cmake`构建工具。

View File

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

View File

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

View File

@ -38,30 +38,34 @@ struct TransInfomation {
}; };
constexpr int down_check_wait = 100; // millsec constexpr int down_check_wait = 100; // millsec
class CClient class TransmClient
{ {
public: public:
CClient(); TransmClient();
~CClient(); ~TransmClient();
public:
void run(const std::string& ip, const std::string& port, const std::string& config_dir);
public: public:
void run(const std::string& ip, const std::string& port,
const std::string& config_dir);
bool get_clients(); bool get_clients();
bool cmd_fetch_files(const std::string& param); bool cmd_fetch_files(const std::string& param);
bool cmd_sub_list(const std::string& param); bool cmd_sub_list(const std::string& param);
bool cmd_clear_submited(); bool cmd_clear_submited();
bool cmd_upload_files(const std::string& param); 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 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_ls(const std::string& param);
bool cmd_down_list(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: private:
bool send_frame(CFrameBuffer* buf); bool send_frame(CFrameBuffer* buf);
void save_line_his(const std::string& input); void save_line_his(const std::string& input);
@ -71,14 +75,19 @@ private:
std::string read_uuid(); std::string read_uuid();
void get_id(); void get_id();
void print_help(bool detail); void print_help(bool detail);
bool base_init(const std::string& ip, const std::string& port,
const std::string& config_dir);
private: private:
void handle_frame(CFrameBuffer* buf); void handle_frame(CFrameBuffer* buf);
void send_file_data_th(const char* keys); void send_file_data_th(const char* keys);
void hearts(); void hearts();
void judget_down_active(); void judget_down_active();
std::string variable_handle(const std::string& task_list_path, const std::string& source, bool is_local); std::string variable_handle(const std::string& task_list_path,
std::string handle_user_select(const std::unordered_map<int, std::string>& source, bool is_send); const std::string& source, bool is_local);
std::string
handle_user_select(const std::unordered_map<int, std::string>& source,
bool is_send);
private: private:
std::mutex mutex_; std::mutex mutex_;
@ -96,6 +105,7 @@ private:
std::shared_ptr<TransInfomation> down_; std::shared_ptr<TransInfomation> down_;
std::vector<std::thread> ths_; std::vector<std::thread> ths_;
std::map<std::string, std::shared_ptr<TransInfomation>> up_; std::map<std::string, std::shared_ptr<TransInfomation>> up_;
std::thread context_th_;
std::thread th_down_active_; std::thread th_down_active_;
long long cur_file_size_{}; long long cur_file_size_{};
long long cur_down_size_{}; long long cur_down_size_{};
@ -109,6 +119,28 @@ private:
std::string config_path_{}; std::string config_path_{};
std::string uuid_path_{}; std::string uuid_path_{};
std::string uuid_{}; 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 class CFileOpr
@ -118,5 +150,6 @@ public:
~CFileOpr(); ~CFileOpr();
public: 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,22 +1,16 @@
#include "config.h" #include "config.h"
#include <cassert> #include <cassert>
#ifdef USE_BOOST
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
#else
#include <filesystem> #include <filesystem>
namespace fs = std::filesystem; namespace fs = std::filesystem;
#endif
CServerConfig::CServerConfig() ClientConfig::ClientConfig()
{ {
} }
CServerConfig::~CServerConfig() = default; ClientConfig::~ClientConfig() = default;
bool CServerConfig::baseInit() bool ClientConfig::baseInit()
{ {
fs::path tpath(COfPath::get_config_dir("transm", true)); fs::path tpath(COfPath::get_config_dir("transm", true));
config_dir_ = tpath.string(); config_dir_ = tpath.string();
@ -33,7 +27,7 @@ bool CServerConfig::baseInit()
return true; return true;
} }
bool CServerConfig::read_ini(std::vector<TransmSet>& set) bool ClientConfig::read_ini(std::vector<TransmSet>& set)
{ {
assert(init_ == true); assert(init_ == true);
long groups = ini_handle_.GetLongValue("BASE", "GROUPS"); long groups = ini_handle_.GetLongValue("BASE", "GROUPS");
@ -59,7 +53,8 @@ bool CServerConfig::read_ini(std::vector<TransmSet>& set)
return true; return true;
} }
long CServerConfig::have_ini(const std::vector<TransmSet>& set, const std::string& ip, long port) long ClientConfig::have_ini(const std::vector<TransmSet>& set,
const std::string& ip, long port)
{ {
long id = -1; long id = -1;
for (const auto& item : set) { for (const auto& item : set) {
@ -71,20 +66,22 @@ long CServerConfig::have_ini(const std::vector<TransmSet>& set, const std::strin
return id; return id;
} }
bool CServerConfig::write_ini(const std::vector<TransmSet>& set) bool ClientConfig::write_ini(const std::vector<TransmSet>& set)
{ {
assert(init_ == true); assert(init_ == true);
for (size_t start = 0; start < set.size(); ++start) { for (size_t start = 0; start < set.size(); ++start) {
std::string key = "GROUP" + std::to_string(start); std::string key = "GROUP" + std::to_string(start);
ini_handle_.SetValue(key.c_str(), "IP", set[start].ip.c_str()); ini_handle_.SetValue(key.c_str(), "IP", set[start].ip.c_str());
ini_handle_.SetLongValue(key.c_str(), "PORT", set[start].port); 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()); ini_handle_.SaveFile(config_path_.c_str());
return true; return true;
} }
long CServerConfig::append_ini(const std::string& ip, long port, const std::string& comment) long ClientConfig::append_ini(const std::string& ip, long port,
const std::string& comment)
{ {
assert(init_ == true); assert(init_ == true);
long id = -1; long id = -1;
@ -109,22 +106,24 @@ long CServerConfig::append_ini(const std::string& ip, long port, const std::stri
return id; return id;
} }
bool CServerConfig::remove_ini(long num) bool ClientConfig::remove_ini(long num)
{ {
assert(init_ == true); assert(init_ == true);
std::vector<TransmSet> set; std::vector<TransmSet> set;
if (!read_ini(set)) { if (!read_ini(set)) {
return false; return false;
} }
set.erase( set.erase(std::remove_if(
std::remove_if(set.begin(), set.end(), [&num](const TransmSet& item) { return item.grp_id == num; }), set.begin(), set.end(),
[&num](const TransmSet& item) { return item.grp_id == num; }),
set.end()); set.end());
ini_handle_.Reset(); ini_handle_.Reset();
ini_handle_.SetLongValue("BASE", "GROUPS", static_cast<long>(set.size())); ini_handle_.SetLongValue("BASE", "GROUPS", static_cast<long>(set.size()));
return write_ini(set); return write_ini(set);
} }
bool CServerConfig::get_ini(const std::vector<TransmSet>& set, long num, TransmSet& use) bool ClientConfig::get_ini(const std::vector<TransmSet>& set, long num,
TransmSet& use)
{ {
bool find = false; bool find = false;
for (const auto& item : set) { for (const auto& item : set) {
@ -137,12 +136,12 @@ bool CServerConfig::get_ini(const std::vector<TransmSet>& set, long num, TransmS
return find; return find;
} }
std::string CServerConfig::get_config_dir() const std::string ClientConfig::get_config_dir() const
{ {
return config_dir_; return config_dir_;
} }
bool CServerConfig::save_last_use(const std::string& ip, long port) bool ClientConfig::save_last_use(const std::string& ip, long port)
{ {
assert(init_ == true); assert(init_ == true);
ini_handle_.SetValue("Base", "LastUseIP", ip.c_str()); ini_handle_.SetValue("Base", "LastUseIP", ip.c_str());
@ -151,10 +150,11 @@ bool CServerConfig::save_last_use(const std::string& ip, long port)
return true; return true;
} }
bool CServerConfig::get_last_use(std::string& ip, long& port) bool ClientConfig::get_last_use(std::string& ip, long& port)
{ {
assert(init_ == true); 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."); TLOGE("Not Found Last Use Record.");
return false; return false;
} }
@ -163,7 +163,7 @@ bool CServerConfig::get_last_use(std::string& ip, long& port)
return true; return true;
} }
void CServerConfig::gen_default_ini(const std::string& path) void ClientConfig::gen_default_ini(const std::string& path)
{ {
TLOGW("Gen Default Setting Ini in [{}].", path); TLOGW("Gen Default Setting Ini in [{}].", path);
ini_handle_.LoadFile(path.c_str()); ini_handle_.LoadFile(path.c_str());

View File

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

View File

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

View File

@ -1,6 +1,3 @@
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) get_filename_component(CXX_COMPILER_PATH ${CMAKE_CXX_COMPILER} DIRECTORY)
set(MINGW32_DLLS set(MINGW32_DLLS
"${CXX_COMPILER_PATH}/libgcc_s_dw2-1.dll" "${CXX_COMPILER_PATH}/libgcc_s_dw2-1.dll"

1
crashelper Submodule

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

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

View File

@ -0,0 +1,26 @@
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()

264
http-server/main.cpp Normal file
View File

@ -0,0 +1,264 @@
#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;
}

View File

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

2
ofen

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

View File

@ -6,23 +6,18 @@ set(CMAKE_CXX_STANDARD 17)
if (MSVC) if (MSVC)
add_compile_options(/source-charset:utf-8) add_compile_options(/source-charset:utf-8)
endif() 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) add_executable(tss main.cpp server.h server.cpp)
target_link_libraries(tss PRIVATE trans_net trans_util) 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) if (UNIX)
target_link_libraries(tss PRIVATE pthread) target_link_libraries(tss PRIVATE pthread)
endif() endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Windows") if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Windows")
target_link_libraries(tss PRIVATE ws2_32 wsock32) target_link_libraries(tss PRIVATE ws2_32 wsock32)
endif() endif()
if (DEFINED GRAB_CRASH)
target_link_libraries(tss PRIVATE crashelper)
endif()
if(UNIX) if(UNIX)
execute_process( execute_process(
COMMAND uname -a COMMAND uname -a

View File

@ -3,6 +3,9 @@
#include "server.h" #include "server.h"
#include "version.h" #include "version.h"
#include <filesystem>
#include <of_path.h>
namespace fs = std::filesystem;
#ifdef _WIN32 #ifdef _WIN32
#include <fcntl.h> #include <fcntl.h>
@ -13,17 +16,28 @@
#endif #endif
#endif #endif
void signal_handler(int signal) #if defined(GRAB_CRASH)
#include <crashelper.h>
#endif
void msignal_handler(int signal)
{ {
if (signal == SIGINT) {
fc_recovery_color(); fc_recovery_color();
exit(signal); exit(signal);
}
} }
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
std::signal(SIGINT, signal_handler); #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
#ifdef _WIN32 #ifdef _WIN32
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
@ -38,7 +52,8 @@ int main(int argc, char* argv[])
delete p; 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; int port = 9898;
if (argc < 2) { if (argc < 2) {
TLOGI("Use Default Port:{}", port); TLOGI("Use Default Port:{}", port);
@ -48,7 +63,7 @@ int main(int argc, char* argv[])
TLOGI("Use Port:{}", port); TLOGI("Use Port:{}", port);
} }
asio::io_context io_context; asio::io_context io_context;
CTcpServer server(io_context); TransmServer server(io_context);
if (!server.start(port)) { if (!server.start(port)) {
return -1; return -1;
} }

View File

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

View File

@ -1,7 +1,42 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
project(test LANGUAGES CXX) project(transm_test LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
add_executable(test main.cxx) set(TEST_SOURCES
target_link_libraries(test PRIVATE tinyaes trans_util) ../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)

241
test/Cmd.cxx Normal file
View File

@ -0,0 +1,241 @@
#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);
}
}

41
test/EncryptCorrect.cxx Normal file
View File

@ -0,0 +1,41 @@
#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);
}
}

197
test/EncryptSpeed.cxx Normal file
View File

@ -0,0 +1,197 @@
#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);
}
}

77
test/assistant.cxx Normal file
View File

@ -0,0 +1,77 @@
#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();
}

106
test/assistant.h Normal file
View File

@ -0,0 +1,106 @@
#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

View File

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

View File

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

View File

@ -9,6 +9,7 @@
CTransProtocal::CTransProtocal() = default; CTransProtocal::CTransProtocal() = default;
constexpr uint8_t kz = 16; constexpr uint8_t kz = 16;
static bool use_encrypt = true;
CTransProtocal::~CTransProtocal() = default; CTransProtocal::~CTransProtocal() = default;
/* /*
@ -47,7 +48,8 @@ CFrameBuffer* CTransProtocal::parse(CMutBuffer& buffer)
int32_t len{}; int32_t len{};
std::memcpy(&type, buffer.get_data() + find + 2, sizeof(type)); std::memcpy(&type, buffer.get_data() + find + 2, sizeof(type));
std::memcpy(&mark, buffer.get_data() + find + 2 + 2, sizeof(mark)); 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; int32_t tail_index = find + 2 + 2 + 1 + 32 + 32 + 4 + len;
if (buffer.get_len() - 2 < tail_index || len < 0) { if (buffer.get_len() - 2 < tail_index || len < 0) {
@ -66,7 +68,8 @@ CFrameBuffer* CTransProtocal::parse(CMutBuffer& buffer)
result->mark_ = mark; result->mark_ = mark;
result->type_ = static_cast<FrameType>(type); result->type_ = static_cast<FrameType>(type);
if (len > 0) { 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); buffer.remove_of(0, tail_index + 2);
return result; return result;
@ -92,7 +95,8 @@ bool CTransProtocal::pack(CFrameBuffer* buf, char** out_buf, int& len)
std::memcpy(*out_buf + 2 + 2 + 1, buf->fid_.data(), buf->fid_.size()); std::memcpy(*out_buf + 2 + 2 + 1, buf->fid_.data(), buf->fid_.size());
} }
if (!buf->tid_.empty()) { 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); std::memcpy(*out_buf + 2 + 2 + 1 + 32 + 32, &buf->len_, 4);
if (buf->data_ != nullptr) { if (buf->data_ != nullptr) {
@ -133,7 +137,7 @@ CFrameBuffer::~CFrameBuffer()
len_ = 0; len_ = 0;
} }
void serialize(CMessageInfo& msg_info, char** out_buf, int& len) void serialize(CMessageInfo& msg_info, char** out_buf, int& len, bool reuse_mem)
{ {
auto& info = msg_info; auto& info = msg_info;
info.id = localtou8(info.id); info.id = localtou8(info.id);
@ -141,10 +145,26 @@ void serialize(CMessageInfo& msg_info, char** out_buf, int& len)
info.str = localtou8(info.str); info.str = localtou8(info.str);
// 计算总长度 // 计算总长度
len = sizeof(int) * 4 + info.id.size() + info.uuid.size() + info.str.size() + info.data.size() + kz; len = sizeof(int) * 4 + info.id.size() + info.uuid.size() +
*out_buf = new char[len]{}; // 分配内存(调用方负责释放) info.str.size() + info.data.size() + kz + 1;
char* ptr = *out_buf + kz; // 《这里为了效率》,
// 认为如果 *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;
// 序列化 cmd // 序列化 cmd
int id_size = static_cast<int>(info.id.size()); int id_size = static_cast<int>(info.id.size());
@ -173,29 +193,36 @@ void serialize(CMessageInfo& msg_info, char** out_buf, int& len)
ptr += sizeof(int); ptr += sizeof(int);
memcpy(ptr, info.data.data(), o_size); memcpy(ptr, info.data.data(), o_size);
uint8_t ik[32]{}; char* mark = *out_buf;
hash(msg_info.id.c_str(), ik); if (!use_encrypt) {
if (!encrypt(ik, (uint8_t*)(*out_buf), len)) { mark[0] = 0x00;
return; return;
} }
uint8_t ik[32]{};
hash(msg_info.id.c_str(), ik);
encrypt(ik, (uint8_t*)(*out_buf + 1), len - 1);
mark[0] = 0x01;
} }
bool deserialize(char* data, int len, CMessageInfo& msg_info) bool deserialize(char* data, int len, CMessageInfo& msg_info)
{ {
if (len < kz) { if (len < (kz + 1)) {
return false;
}
uint8_t ik[32]{};
hash(msg_info.id.c_str(), ik);
if (!decrypt(ik, (uint8_t*)(data), len)) {
return false; return false;
} }
auto& info = msg_info; auto& info = msg_info;
char* ptr = data + kz; char* ptr = data + kz + 1;
uint8_t mark = data[0];
int remaining = len; 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 // 反序列化 cmd
if (remaining < static_cast<int>(sizeof(int))) { if (remaining < static_cast<int>(sizeof(int))) {
return false; return false;
@ -297,9 +324,16 @@ void hash(const char* data, uint8_t k[32])
void rdm(uint8_t* o, size_t size) void rdm(uint8_t* o, size_t size)
{ {
/*
random_device
mt19937 + uniform_int_distribution
*/
std::random_device rd; std::random_device rd;
// std::mt19937 gen(rd());
std::mt19937_64 gen(rd());
std::uniform_int_distribution<int> dist(0, 255); std::uniform_int_distribution<int> dist(0, 255);
std::generate(o, o + size, [&]() { return static_cast<uint8_t>(dist(rd)); }); std::generate(o, o + size,
[&]() { return static_cast<uint8_t>(dist(gen)); });
} }
bool encrypt(const uint8_t* k, uint8_t* m, size_t len) bool encrypt(const uint8_t* k, uint8_t* m, size_t len)
@ -312,7 +346,7 @@ bool encrypt(const uint8_t* k, uint8_t* m, size_t len)
rdm(nonce, sizeof(nonce) - 4); rdm(nonce, sizeof(nonce) - 4);
memcpy(m, nonce, kz); memcpy(m, nonce, kz);
struct AES_ctx ctx; struct AES_ctx ctx{};
AES_init_ctx_iv(&ctx, k, nonce); AES_init_ctx_iv(&ctx, k, nonce);
AES_CTR_xcrypt_buffer(&ctx, m + kz, len - kz); AES_CTR_xcrypt_buffer(&ctx, m + kz, len - kz);
return true; return true;
@ -327,12 +361,22 @@ bool decrypt(const uint8_t* k, uint8_t* m, size_t len)
uint8_t nonce[kz]{}; uint8_t nonce[kz]{};
memcpy(nonce, m, kz); memcpy(nonce, m, kz);
struct AES_ctx ctx; struct AES_ctx ctx{};
AES_init_ctx_iv(&ctx, k, nonce); AES_init_ctx_iv(&ctx, k, nonce);
AES_CTR_xcrypt_buffer(&ctx, m + kz, len - kz); AES_CTR_xcrypt_buffer(&ctx, m + kz, len - kz);
return true; 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) CMessageInfo::CMessageInfo(const std::string& id) : id(id)
{ {
} }

View File

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