Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
b68017bc2a | |||
b9c7cbba3c | |||
60f52a14d2 | |||
12b57e65c9 | |||
64d4255ca3 | |||
8f54951a28 | |||
8121a370ce | |||
733c5a68a3 | |||
9839fa79ea | |||
a81cc54025 | |||
13423d5172 | |||
414bc6ed75 | |||
7a6b961392 | |||
0ee24945bb | |||
2793dab420 | |||
49d6ad1974 | |||
797f8f164e | |||
61ac79c93e | |||
99607c6721 | |||
6ecf0d419a | |||
807dbdfede | |||
a5cab61603 | |||
3a32e2f0d4 | |||
41f0b5d726 | |||
99a1223e52 | |||
119f1e8f72 | |||
5bbe4f0ecd | |||
d715719a00 | |||
f176c0a8f0 | |||
29d721ab8a | |||
334df57b63 | |||
3a27934467 | |||
c4bcfebdd1 | |||
ae40b7f1a9 | |||
3ded526713 | |||
f6e7596367 |
@ -11,13 +11,7 @@ ReflowComments: true
|
|||||||
SpacesBeforeTrailingComments: 3
|
SpacesBeforeTrailingComments: 3
|
||||||
TabWidth: 4
|
TabWidth: 4
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
ColumnLimit: 110
|
ColumnLimit: 130
|
||||||
AllowShortBlocksOnASingleLine: Never
|
AllowShortBlocksOnASingleLine: Never
|
||||||
AllowShortFunctionsOnASingleLine: None
|
AllowShortFunctionsOnASingleLine: None
|
||||||
AllowShortEnumsOnASingleLine: false
|
AllowShortEnumsOnASingleLine: false
|
||||||
IncludeBlocks: Regroup
|
|
||||||
IncludeCategories:
|
|
||||||
- Regex: '^<.*>'
|
|
||||||
Priority: 1
|
|
||||||
- Regex: '^".*"'
|
|
||||||
Priority: 2
|
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@ cmake-*
|
|||||||
compile_commands.json
|
compile_commands.json
|
||||||
out
|
out
|
||||||
xpbuild
|
xpbuild
|
||||||
|
cbuild
|
||||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -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
|
||||||
|
87
.vscode/settings.json
vendored
87
.vscode/settings.json
vendored
@ -1,10 +1,8 @@
|
|||||||
{
|
{
|
||||||
"files.autoSave": "onFocusChange",
|
"files.autoSave": "onFocusChange",
|
||||||
"editor.fontSize": 14,
|
"editor.fontSize": 13,
|
||||||
"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,23 +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"
|
|
||||||
],
|
],
|
||||||
|
"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,
|
||||||
@ -43,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",
|
||||||
@ -68,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",
|
||||||
@ -98,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",
|
||||||
@ -124,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
11817
3rd/catch_amalgamated.cpp
Normal file
File diff suppressed because it is too large
Load Diff
14135
3rd/catch_amalgamated.hpp
Normal file
14135
3rd/catch_amalgamated.hpp
Normal file
File diff suppressed because it is too large
Load Diff
10497
3rd/httplib.h
Normal file
10497
3rd/httplib.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
project(transm VERSION 1.4.0 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")
|
||||||
@ -45,6 +46,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(.)
|
||||||
@ -55,6 +62,20 @@ add_subdirectory(util)
|
|||||||
add_subdirectory(server)
|
add_subdirectory(server)
|
||||||
add_subdirectory(client)
|
add_subdirectory(client)
|
||||||
add_subdirectory(filecomplete)
|
add_subdirectory(filecomplete)
|
||||||
|
add_subdirectory(tinyaes)
|
||||||
|
|
||||||
|
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||||
|
message(STATUS "tss-http can't support mingw, will not compile.")
|
||||||
|
else()
|
||||||
|
add_subdirectory(http-server)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (DEFINED USE_TRANSM_TEST)
|
||||||
|
message(STATUS "USE USE_TRANSM_TEST ${USE_TRANSM_TEST}")
|
||||||
|
add_definitions(-DUSE_TRANSM_TEST)
|
||||||
|
include(CTest)
|
||||||
|
add_subdirectory(test)
|
||||||
|
endif()
|
||||||
|
|
||||||
string(TIMESTAMP VERSION_BUILD_DATE "%Y-%m-%d %H:%M")
|
string(TIMESTAMP VERSION_BUILD_DATE "%Y-%m-%d %H:%M")
|
||||||
execute_process(
|
execute_process(
|
||||||
@ -77,6 +98,12 @@ 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(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||||
|
message(STATUS "tss-http can't support mingw, will not pack.")
|
||||||
|
else()
|
||||||
|
install(TARGETS tss-http DESTINATION bin)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (DEFINED USE_BOOST)
|
if (DEFINED USE_BOOST)
|
||||||
install(FILES ${MINGW32_DLLS} DESTINATION bin)
|
install(FILES ${MINGW32_DLLS} DESTINATION bin)
|
||||||
endif()
|
endif()
|
||||||
|
@ -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": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
131
README.md
131
README.md
@ -8,112 +8,101 @@
|
|||||||
|
|
||||||
**注**:使用安装包的用户,如果想变更安装位置的话,请先卸载旧版本(原位置更新最新版不用卸载)。
|
**注**:使用安装包的用户,如果想变更安装位置的话,请先卸载旧版本(原位置更新最新版不用卸载)。
|
||||||
|
|
||||||
# 一、简要介绍
|
# 一、说明
|
||||||
|
|
||||||
| 主要功能序号 | 简介 |
|
**注意:** 当前说明文档仅针对`v1.4.1`及其以后的版本,此前的版本需要检出对应`tag`的`README.md`或者下载对应发布版本的源码,然后解压其中的`README.md`。
|
||||||
| ------------ | ------------------------------------------------------------ |
|
|
||||||
| 1 | A端提交文件列表到服务端,B端可以从服务端查阅有哪些客户端提交的哪些任务,自行选择下载。 |
|
服务端程序支持任意个客户端相互之间**同时连接**和**同时传输**文件,吞吐瓶颈在服务端主机网络上。
|
||||||
| 2 | A端可以提交一个下载任务文件给B端,B端会自动下载列表中的文件(可用作更新远端文件)。 |
|
|
||||||
| 3 | A端可以直接给B端发送文件(v1.3.1及其以后版本)。
|
|
||||||
|
|
||||||
- `tss`和`tsc`均为命令行端程序,无GUI。
|
- `tss`和`tsc`均为命令行端程序,无GUI。
|
||||||
|
|
||||||
- `tsc`从`tss`下载文件的时候,如果本地有已存在则会被**覆盖**(注意)。
|
|
||||||
|
|
||||||
- 介绍所指的客户端`A`、`B`是泛指,实际服务端程序支持任意个客户端相互之间**同时连接**和**同时传输**文件,吞吐瓶颈在服务端主机网络上。
|
|
||||||
|
|
||||||
## 一些特点(基于最新版本)
|
## 一些特点(基于最新版本)
|
||||||
|
|
||||||
|
- 易编译。
|
||||||
- 通配符传输。
|
- 通配符传输。
|
||||||
- 终端自动文件补全。
|
- 公网传输支持加密。
|
||||||
- 自动更新远程文件。
|
|
||||||
- 多客户端可以同时互相收发文件。
|
|
||||||
- 自动检测对方掉线。
|
|
||||||
- 服务端自我安全防御(若部署到云端防止常规攻击)。
|
|
||||||
- 广泛的平台支持。
|
- 广泛的平台支持。
|
||||||
- 服务端仅转发数据,不存储数据。
|
- 终端自动文件补全。
|
||||||
|
- 自动检测对方掉线。
|
||||||
- 极小的、单个文件。
|
- 极小的、单个文件。
|
||||||
- 干净,不会在客户机环境到处遗留临时文件。
|
- 支持相对路径处理。
|
||||||
|
- 单端可以操作下载发送。
|
||||||
|
- 支持单客户端操作收发本地文件。
|
||||||
|
- 多客户端可以同时互相收发文件。
|
||||||
|
- 服务端仅转发数据,不存储数据。
|
||||||
- 运行时无其他三方二进制库依赖。
|
- 运行时无其他三方二进制库依赖。
|
||||||
- 临时公网传输,无需使用三方需要登陆软件。
|
|
||||||
- `Linux`到`Linux`文件传输保留原权限。
|
- `Linux`到`Linux`文件传输保留原权限。
|
||||||
|
- 干净,不会在客户机环境到处遗留临时文件。
|
||||||
|
- 临时公网传输,无需使用三方需要登陆软件。
|
||||||
|
- 服务端自我安全防御(若部署到云端防止常规攻击)。
|
||||||
|
- 支持拒绝同时操作同设备同路径文件,防止文件内容丢失。
|
||||||
|
|
||||||
# 二、使用说明
|
# 二、使用说明
|
||||||
|
|
||||||
## 1.程序启动
|
## 1.程序启动
|
||||||
|
|
||||||
- 对于服务端程序`tss`,绑定默认绑定`0.0.0.0`的`9898`端口,如果需要修改端口,使用参数启动,示例:`tss 9898`。
|
- 对于服务端程序`tss`,绑定默认绑定`0.0.0.0`的`9898`端口,如果需要修改端口,使用参数启动,示例:`tss 9898`。
|
||||||
- 对于客户端程序`tsc`,请使用`tsc --help`查看使用方式。
|
- 对于客户端程序`tsc`,请使用`tsc --help`查看如何启动。
|
||||||
- `Up`指令后面的文件名路径,如果是非全路径(即相对路径),程序会自动拼接到当前`tsc`工作目录(如`Up dira/test.txt`也是可以的)。
|
|
||||||
|
|
||||||
## 2.命令使用(截图可能过时,但使用方式大致如此)
|
## 2.使用
|
||||||
|
|
||||||
### 2.1 客户端 tsc 简介
|
`tsc`连接到服务端`tss`后,可以输入`h`查看所有指令的具体介绍。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### 2.2 功能一简介
|
## 3.介绍补充
|
||||||
|
|
||||||

|
- 需要传入存储路径的指令,如果未填写,默认`tsc`当前工作目录。
|
||||||
|
- `任务文件`格式统一为`UTF-8`编码。
|
||||||
|
- 支持相对路径处理。
|
||||||
|
- `UpTask`和`DownTask`指令`任务文件`格式完全一致,均为左文件,右目录,尽管是下载别人文件,目的是为了支持同一个任务文件既可以发也可以收。
|
||||||
|
|
||||||
### 2.3 功能二简介
|
具体`任务文件`内容格式如下(左侧发送端,右侧接受端),内容支持变量:
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### 3.1 Get功能
|
|
||||||
|
|
||||||
`v1.2.3`版本起(含),当某个客户端的列表文件数量过多时,只展示部分(会显示总数量)。
|
|
||||||
|
|
||||||
### 3.2 Up功能
|
|
||||||
|
|
||||||
`v1.2.3`版本起(含),`up`后路径支持`?`和`*`通配符:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
up /home/zhang/png/cloud*.png|/home/zhang/download/202?-*.exe
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3.3 Down功能
|
|
||||||
|
|
||||||
`v1.2.3`版本起(含),支持传入下载位置(默认命令所在目录):
|
|
||||||
|
|
||||||
```shell
|
|
||||||
down 1 dira/dirb
|
|
||||||
down 1 ../download
|
|
||||||
down 2 /home/zhang/document
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3.4 Update功能
|
|
||||||
|
|
||||||
命令格式为:`Update 客户端标号 列表文件`
|
|
||||||
|
|
||||||
`Update`的提交的列表文件格式为`txt`,内容为每一行格式是`A|B`,其中`A`为提交端的文件路径,`B`为要放到下载端的哪个目录 **(下载端必须存在这个目录,否则下载端拒绝自动下载)**。
|
|
||||||
|
|
||||||
示例执行:`Update 1 task.txt`,其中`task.txt`内容示例如下:
|
|
||||||
|
|
||||||
```txt
|
|
||||||
D:/文件/abc.zip|/home/zhangsan/downlaod
|
|
||||||
D:/截图/Ni.jpg|/home/zhangsan/picture
|
|
||||||
```
|
|
||||||
|
|
||||||
#### update新增(一)
|
|
||||||
|
|
||||||
`v1.2.1`版本起(含),`task.txt`支持以下变量:
|
|
||||||
|
|
||||||
- ${HOME},用户目录(发送端接收端均支持)。
|
- ${HOME},用户目录(发送端接收端均支持)。
|
||||||
- ${CURRENT},任务文件所在目录(即`task.txt`所在目录,该变量仅支持发送端,也就是`|`左侧,因为接收端没有任务文件所在路径)
|
- ${CURRENT},任务文件所在目录(该变量仅支持发送端,也就是`|`左侧,因为接收端没有任务文件所在路径)
|
||||||
|
|
||||||
```txt
|
```txt
|
||||||
${HOME}/截图/Ni.jpg|${HOME}/dira
|
${HOME}/截图/Ni.jpg|${HOME}/dira
|
||||||
${CURRENT}/xxx.zip|D:\
|
${CURRENT}/xxx.zip|D:\
|
||||||
```
|
```
|
||||||
|
|
||||||
**NOTE**: `列表文件`的格式为`UTF-8`编码。
|
### 3.1 版本内容补充
|
||||||
|
|
||||||
# 注意
|
- `v1.5.0`及其以后版本:支持数据加密传输功能(会影响速度,默认开启,可关闭)。
|
||||||
|
|
||||||
- 如果两个`tsc`客户端在同一台机器上同时收发同一个文件将导致文件丢失损坏(如果收发操作的是同一个文件)。
|
```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`构建工具。
|
||||||
|
|
||||||
|
@ -24,6 +24,10 @@ if(DEFINED USE_BOOST)
|
|||||||
target_link_directories(tsc PRIVATE ${MBOOST_LIB_DIR})
|
target_link_directories(tsc PRIVATE ${MBOOST_LIB_DIR})
|
||||||
target_link_libraries(tsc PRIVATE ${MBOOST_LIBS})
|
target_link_libraries(tsc PRIVATE ${MBOOST_LIBS})
|
||||||
endif()
|
endif()
|
||||||
|
if (DEFINED GRAB_CRASH)
|
||||||
|
message(STATUS "tsc link crashelper")
|
||||||
|
target_link_libraries(tsc PRIVATE crashelper)
|
||||||
|
endif()
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
execute_process(
|
execute_process(
|
||||||
COMMAND uname -a
|
COMMAND uname -a
|
||||||
|
@ -15,13 +15,13 @@ namespace fs = boost::filesystem;
|
|||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CClient::CClient()
|
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 +48,85 @@ CClient::~CClient()
|
|||||||
if (hearts_.joinable()) {
|
if (hearts_.joinable()) {
|
||||||
hearts_.join();
|
hearts_.join();
|
||||||
}
|
}
|
||||||
|
if (context_th_.joinable()) {
|
||||||
|
context_th_.join();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::run(const std::string& ip, const std::string& port, const std::string& config_dir)
|
void TransmClient::print_help(bool detail)
|
||||||
|
{
|
||||||
|
TLOGI("version: {}", VERSION_NUM);
|
||||||
|
TLOGI("opensource: {}", VERSION_URL);
|
||||||
|
TLOGW("SupportCmd ==>");
|
||||||
|
|
||||||
|
if (!detail) {
|
||||||
|
TLOGW("Get|Who|Where|Ls|Sub|Fetch|Up|Down|UpTask|DownTask");
|
||||||
|
TLOGI("<h> to show cmd's detail.");
|
||||||
|
TLOGI("use <end> or <ctrl-c> to exit.");
|
||||||
|
TLOGI("use <on> or <off> to oper encrypt(<?> to view).");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string sp = "==================================================";
|
||||||
|
TLOGI("{}", sp);
|
||||||
|
TLOGW("#Get#");
|
||||||
|
TLOGI(" des: Get all clients on server.");
|
||||||
|
TLOGI(" cmd: Get get g G");
|
||||||
|
TLOGI(" arg: NULL");
|
||||||
|
TLOGI("{}", sp);
|
||||||
|
TLOGW("#Who#");
|
||||||
|
TLOGI(" des: Show current client's ID.");
|
||||||
|
TLOGI(" cmd: Who who");
|
||||||
|
TLOGI(" arg: NULL");
|
||||||
|
TLOGI("{}", sp);
|
||||||
|
TLOGW("#Where#");
|
||||||
|
TLOGI(" des: Show current client's work dir.");
|
||||||
|
TLOGI(" cmd: Where where wh");
|
||||||
|
TLOGI(" arg: NULL");
|
||||||
|
TLOGI("{}", sp);
|
||||||
|
TLOGW("#Ls#");
|
||||||
|
TLOGI(" des: List one client's all files and folders.");
|
||||||
|
TLOGI(" cmd: Ls ls");
|
||||||
|
TLOGI(" arg: @id @remotedir");
|
||||||
|
TLOGI("{}", sp);
|
||||||
|
TLOGW("#Sub#");
|
||||||
|
TLOGI(" des: Submit local file's list on the server.");
|
||||||
|
TLOGI(" cmd: Sub sub");
|
||||||
|
TLOGI(" arg: @files(Separated by | if multi)");
|
||||||
|
TLOGI("{}", sp);
|
||||||
|
TLOGW("#Fetch#");
|
||||||
|
TLOGI(" des: Fetch one client's submited files.");
|
||||||
|
TLOGI(" cmd: Fetch fetch");
|
||||||
|
TLOGI(" arg: @id @savedir");
|
||||||
|
TLOGI("{}", sp);
|
||||||
|
TLOGW("#Clear#");
|
||||||
|
TLOGI(" des: clear submited list.");
|
||||||
|
TLOGI(" cmd: Clear clear c C");
|
||||||
|
TLOGI(" arg: NULL");
|
||||||
|
TLOGI("{}", sp);
|
||||||
|
TLOGW("#Up#");
|
||||||
|
TLOGI(" des: Upload local files to one client directly.");
|
||||||
|
TLOGI(" cmd: Up up");
|
||||||
|
TLOGI(" arg: @id @files(Sep by | if multi) @savedir");
|
||||||
|
TLOGI("{}", sp);
|
||||||
|
TLOGW("#Down#");
|
||||||
|
TLOGI(" des: Down one client's files directly.");
|
||||||
|
TLOGI(" cmd: Down down");
|
||||||
|
TLOGI(" arg: @id @files(Sep by | if multi) @savedir(opt)");
|
||||||
|
TLOGI("{}", sp);
|
||||||
|
TLOGW("#UpTask#");
|
||||||
|
TLOGI(" des: Upload local files to one client by taskfile.");
|
||||||
|
TLOGI(" cmd: UpTask uptask ut");
|
||||||
|
TLOGI(" arg: @id @taskfile(UTF-8)");
|
||||||
|
TLOGI("{}", sp);
|
||||||
|
TLOGW("#DownTask#");
|
||||||
|
TLOGI(" des: Down one client's files by taskfile.");
|
||||||
|
TLOGI(" cmd: DownTask downtask dt");
|
||||||
|
TLOGI(" arg: @id @taskfile(UTF-8)");
|
||||||
|
TLOGI("{}", sp);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
@ -61,7 +137,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();
|
||||||
@ -72,24 +148,29 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
get_id();
|
void TransmClient::run(const std::string& ip, const std::string& port, const std::string& config_dir)
|
||||||
if (ip == "127.0.0.1") {
|
{
|
||||||
get_task_list();
|
if (!base_init(ip, port, config_dir)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TLOGI("version: {}", VERSION_NUM);
|
print_help(false);
|
||||||
TLOGI("opensource: {}", VERSION_URL);
|
|
||||||
TLOGW("SupportCmd ==>");
|
|
||||||
TLOGW("Get|Up|Down|Cancel|Update|Who|Where|Ls|Req");
|
|
||||||
fc_append('|');
|
fc_append('|');
|
||||||
|
get_id();
|
||||||
|
|
||||||
|
if (ip == "127.0.0.1") {
|
||||||
|
get_clients();
|
||||||
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
char* readline = fc_readline();
|
char* readline = fc_readline();
|
||||||
@ -104,6 +185,29 @@ void CClient::run(const std::string& ip, const std::string& port, const std::str
|
|||||||
fc_free(readline);
|
fc_free(readline);
|
||||||
std::cout << "" << std::endl;
|
std::cout << "" << std::endl;
|
||||||
cmd_input = ofen::COfStr::trim(cmd_input);
|
cmd_input = ofen::COfStr::trim(cmd_input);
|
||||||
|
|
||||||
|
if (cmd_input == "help" || cmd_input == "h") {
|
||||||
|
print_help(true);
|
||||||
|
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));
|
||||||
@ -119,11 +223,11 @@ void CClient::run(const std::string& ip, const std::string& port, const std::str
|
|||||||
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_task_list();
|
get_clients();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (cmd_input == "Cancel" || cmd_input == "cancel" || cmd_input == "c" || cmd_input == "C") {
|
if (cmd_input == "Clear" || cmd_input == "clear" || cmd_input == "c" || cmd_input == "C") {
|
||||||
cancel_task();
|
cmd_clear_submited();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto vec = COfStr::split(cmd_input, " ");
|
auto vec = COfStr::split(cmd_input, " ");
|
||||||
@ -135,45 +239,93 @@ void CClient::run(const std::string& ip, const std::string& port, const std::str
|
|||||||
std::string scmd = param.substr(0, param.find_first_of(" "));
|
std::string scmd = param.substr(0, param.find_first_of(" "));
|
||||||
param.erase(0, param.find_first_of(" ") + 1);
|
param.erase(0, param.find_first_of(" ") + 1);
|
||||||
|
|
||||||
if (scmd == "Update" || scmd == "update") {
|
if (scmd == "UpTask" || scmd == "uptask" || scmd == "ut") {
|
||||||
request_update_list(param);
|
cmd_sub_task(param, true);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (scmd == "Send" || scmd == "send") {
|
if (scmd == "DownTask" || scmd == "downtask" || scmd == "dt") {
|
||||||
send_files(param);
|
cmd_sub_task(param, false);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (scmd == "Down" || scmd == "down") {
|
|
||||||
down_task(param);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (scmd == "Up" || scmd == "up") {
|
if (scmd == "Up" || scmd == "up") {
|
||||||
up_task(param);
|
cmd_upload_files(param);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (scmd == "Fetch" || scmd == "fetch") {
|
||||||
|
cmd_fetch_files(param);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (scmd == "Sub" || scmd == "sub") {
|
||||||
|
cmd_sub_list(param);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (scmd == "Ls" || scmd == "ls") {
|
if (scmd == "Ls" || scmd == "ls") {
|
||||||
require_dir_files(param);
|
cmd_ls(param);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (scmd == "Req" || scmd == "req") {
|
if (scmd == "Down" || scmd == "down") {
|
||||||
down_req_list(param);
|
cmd_down_list(param);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
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_task_list()
|
#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::down_task(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.....");
|
||||||
@ -209,16 +361,25 @@ bool CClient::down_task(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::up_task(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_);
|
||||||
@ -259,7 +420,7 @@ bool CClient::up_task(const std::string& param)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CMessageInfo msg_info;
|
CMessageInfo msg_info(own_id_);
|
||||||
msg_info.uuid = uuid_;
|
msg_info.uuid = uuid_;
|
||||||
msg_info.str = msg;
|
msg_info.str = msg;
|
||||||
|
|
||||||
@ -270,7 +431,7 @@ bool CClient::up_task(const std::string& param)
|
|||||||
return send_frame(buf.get());
|
return send_frame(buf.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClient::cancel_task()
|
bool TransmClient::cmd_clear_submited()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
@ -286,7 +447,7 @@ bool CClient::cancel_task()
|
|||||||
return send_frame(buf.get());
|
return send_frame(buf.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClient::send_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) {
|
||||||
@ -338,7 +499,7 @@ bool CClient::send_files(const std::string& param)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto handel_ret = handle_user_select(mre);
|
auto handel_ret = handle_user_select(mre, true);
|
||||||
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;
|
||||||
@ -347,7 +508,7 @@ bool CClient::send_files(const std::string& param)
|
|||||||
list_file_ = "auto_list";
|
list_file_ = "auto_list";
|
||||||
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
|
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
|
||||||
buf->type_ = TYPE_REQUEST_UPDATE_LIST;
|
buf->type_ = TYPE_REQUEST_UPDATE_LIST;
|
||||||
CMessageInfo msg_info;
|
CMessageInfo msg_info(own_id_);
|
||||||
msg_info.str = handel_ret;
|
msg_info.str = handel_ret;
|
||||||
serialize(msg_info, &buf->data_, buf->len_);
|
serialize(msg_info, &buf->data_, buf->len_);
|
||||||
buf->tid_ = clients_[index]->id;
|
buf->tid_ = clients_[index]->id;
|
||||||
@ -359,14 +520,21 @@ bool CClient::send_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_uuid{};
|
||||||
|
|
||||||
if (clients_.count(remote_id) == 0) {
|
if (clients_.count(remote_id) == 0) {
|
||||||
TLOGE("{} No Index Found {}.", __LINE__, remote_id);
|
TLOGW("{} No Index Found {}, Try {}", __LINE__, remote_id, list_server_id_);
|
||||||
return false;
|
ret_id = list_server_id_;
|
||||||
|
ret_uuid = list_server_uuid_;
|
||||||
|
} else {
|
||||||
|
ret_id = clients_[remote_id]->id;
|
||||||
|
ret_uuid = clients_[remote_id]->uuid;
|
||||||
}
|
}
|
||||||
auto client = clients_[remote_id];
|
|
||||||
down_->cur_remote_id_ = client->id;
|
down_->cur_remote_id_ = ret_id;
|
||||||
down_->cur_remote_file_ = file;
|
down_->cur_remote_file_ = file;
|
||||||
|
|
||||||
fs::path remote_file(ofen::COfPath::normalize(down_->cur_remote_file_));
|
fs::path remote_file(ofen::COfPath::normalize(down_->cur_remote_file_));
|
||||||
@ -377,7 +545,7 @@ bool CClient::down_one_file(int remote_id, const std::string& file, const std::s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 这里要先检查羁绊
|
// 这里要先检查羁绊
|
||||||
if (client->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;
|
||||||
@ -392,8 +560,8 @@ bool CClient::down_one_file(int remote_id, const std::string& file, const std::s
|
|||||||
// 请求下载文件
|
// 请求下载文件
|
||||||
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
|
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
|
||||||
buf->type_ = TYPE_OPEN_FILE;
|
buf->type_ = TYPE_OPEN_FILE;
|
||||||
buf->tid_ = client->id;
|
buf->tid_ = ret_id;
|
||||||
CMessageInfo msg_info;
|
CMessageInfo msg_info(own_id_);
|
||||||
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())) {
|
||||||
@ -428,7 +596,7 @@ bool CClient::down_one_file(int remote_id, const std::string& file, const std::s
|
|||||||
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.", down_->cur_file_);
|
TLOGW("down one file {} failed, size not matched.", down_->cur_file_);
|
||||||
if (!down_->file_.is_open()) {
|
if (!down_->file_.is_open()) {
|
||||||
down_->file_.close();
|
down_->file_.close();
|
||||||
fs::remove(down_->cur_file_);
|
fs::remove(down_->cur_file_);
|
||||||
@ -437,7 +605,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()) {
|
||||||
@ -470,7 +638,7 @@ void CClient::report_trans_ret(TransState state, const std::string& key)
|
|||||||
|
|
||||||
功能为,请求某个客户端,更新我所列出的文件,右侧是远端需要存储的目录(必须存在,不存在则不理会)
|
功能为,请求某个客户端,更新我所列出的文件,右侧是远端需要存储的目录(必须存在,不存在则不理会)
|
||||||
*/
|
*/
|
||||||
bool CClient::request_update_list(const std::string& param)
|
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) {
|
||||||
@ -490,20 +658,19 @@ bool CClient::request_update_list(const std::string& param)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto& sr = clients_[index];
|
const auto& sr = clients_[index];
|
||||||
bool local_trans = false;
|
|
||||||
if (sr->id == own_id_) {
|
|
||||||
TLOGW("local_trans path handle mode!!!");
|
|
||||||
local_trans = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 读取list文件
|
// 读取list文件
|
||||||
std::string list_file_full = COfPath::to_full(list_file);
|
std::string list_file_full = COfPath::to_full(list_file);
|
||||||
|
|
||||||
if (fs::is_directory(list_file_full)) {
|
if (fs::is_directory(list_file_full)) {
|
||||||
TLOGE("{} is a directory, only support file.", list_file_full);
|
TLOGE("{} is a directory, only support file.", list_file_full);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool local_trans = false;
|
||||||
|
if (sr->uuid == uuid_) {
|
||||||
|
TLOGW("local_trans path handle mode!!!");
|
||||||
|
local_trans = true;
|
||||||
|
}
|
||||||
|
|
||||||
std::ifstream in(list_file_full);
|
std::ifstream in(list_file_full);
|
||||||
if (!in.is_open()) {
|
if (!in.is_open()) {
|
||||||
TLOGE("Can't Open File:{}", list_file_full);
|
TLOGE("Can't Open File:{}", list_file_full);
|
||||||
@ -515,6 +682,7 @@ bool CClient::request_update_list(const std::string& param)
|
|||||||
in.close();
|
in.close();
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
// 从文件中读取的内容还是要手动转码一下。
|
||||||
content = CCodec::u8_to_ansi(content);
|
content = CCodec::u8_to_ansi(content);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -533,27 +701,17 @@ bool CClient::request_update_list(const std::string& param)
|
|||||||
if (v.size() >= 2) {
|
if (v.size() >= 2) {
|
||||||
auto pr = variable_handle(list_file_full, v[0], true);
|
auto pr = variable_handle(list_file_full, v[0], true);
|
||||||
pr = COfPath::standardize(pr);
|
pr = COfPath::standardize(pr);
|
||||||
if (!fs::exists(pr)) {
|
if (is_send && !fs::exists(pr)) {
|
||||||
TLOGE("file {} not exist.", pr);
|
TLOGE("file {} not exist.", pr);
|
||||||
valid = false;
|
valid = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
TLOGI("--->check pass {}:{}", line, pr);
|
if (is_send) {
|
||||||
auto sec = v[1];
|
TLOGI("--->check pass {}:{}", line, pr);
|
||||||
if (local_trans) {
|
|
||||||
sec = variable_handle(list_file_full, v[1], true);
|
|
||||||
sec = COfPath::standardize(sec);
|
|
||||||
if (!fs::is_directory(sec) || !fs::exists(sec)) {
|
|
||||||
TLOGE("not directory or {} not exist.", pr);
|
|
||||||
valid = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (COfPath::is_same_dir(pr, sec)) {
|
|
||||||
TLOGE("Local Trans Can't Transfer {} to {}", pr, sec);
|
|
||||||
valid = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
auto sec = v[1];
|
||||||
|
sec = variable_handle(list_file_full, sec, local_trans);
|
||||||
|
sec = COfPath::standardize(sec);
|
||||||
mre[line++] = pr + "|" + sec;
|
mre[line++] = pr + "|" + sec;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -566,7 +724,11 @@ bool CClient::request_update_list(const std::string& param)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto handel_ret = handle_user_select(mre);
|
#ifdef USE_TRANSM_TEST
|
||||||
|
auto handel_ret = handle_user_select(mre, false);
|
||||||
|
#else
|
||||||
|
auto handel_ret = handle_user_select(mre, is_send);
|
||||||
|
#endif
|
||||||
if (handel_ret.empty()) {
|
if (handel_ret.empty()) {
|
||||||
TLOGE("handle_user_select not pass, abort action!");
|
TLOGE("handle_user_select not pass, abort action!");
|
||||||
return false;
|
return false;
|
||||||
@ -574,8 +736,13 @@ bool CClient::request_update_list(const std::string& param)
|
|||||||
|
|
||||||
list_file_ = list_file_full;
|
list_file_ = list_file_full;
|
||||||
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
|
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
|
||||||
buf->type_ = TYPE_REQUEST_UPDATE_LIST;
|
|
||||||
CMessageInfo msg_info;
|
if (is_send) {
|
||||||
|
buf->type_ = TYPE_REQUEST_UPDATE_LIST;
|
||||||
|
} else {
|
||||||
|
buf->type_ = TYPE_REQUEST_DOWN_UPDATE_LIST;
|
||||||
|
}
|
||||||
|
CMessageInfo msg_info(own_id_);
|
||||||
msg_info.str = handel_ret;
|
msg_info.str = handel_ret;
|
||||||
serialize(msg_info, &buf->data_, buf->len_);
|
serialize(msg_info, &buf->data_, buf->len_);
|
||||||
buf->tid_ = clients_[index]->id;
|
buf->tid_ = clients_[index]->id;
|
||||||
@ -587,7 +754,8 @@ bool CClient::request_update_list(const std::string& param)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClient::check_update_list(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;
|
||||||
@ -613,16 +781,16 @@ bool CClient::check_update_list(const std::string& content, std::map<std::string
|
|||||||
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_serve_id_;
|
buf->tid_ = list_server_id_;
|
||||||
down_ = std::make_shared<TransInfomation>();
|
down_ = std::make_shared<TransInfomation>();
|
||||||
bool suc = true;
|
bool suc = true;
|
||||||
|
|
||||||
int id = -1;
|
int id = -1;
|
||||||
for (const auto& item : clients_) {
|
for (const auto& item : clients_) {
|
||||||
if (item.second->id == list_serve_id_) {
|
if (item.second->id == list_server_id_) {
|
||||||
id = item.first;
|
id = item.first;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -645,7 +813,7 @@ 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();
|
||||||
@ -665,7 +833,7 @@ bool CClient::get_dir_files(const std::string& dir, std::string& out, std::strin
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClient::require_dir_files(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) {
|
||||||
@ -683,10 +851,10 @@ bool CClient::require_dir_files(const std::string& param)
|
|||||||
const auto& sr = clients_[index];
|
const auto& sr = clients_[index];
|
||||||
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
|
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
|
||||||
buf->type_ = TYPE_GET_DIRFILES;
|
buf->type_ = TYPE_GET_DIRFILES;
|
||||||
CMessageInfo msg_info{};
|
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__);
|
||||||
@ -695,7 +863,7 @@ bool CClient::require_dir_files(const std::string& param)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClient::down_req_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) {
|
||||||
@ -731,7 +899,7 @@ bool CClient::down_req_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{};
|
||||||
@ -748,7 +916,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;
|
||||||
@ -777,7 +945,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_)) {
|
||||||
@ -796,7 +964,46 @@ std::vector<std::string> CClient::load_line_his()
|
|||||||
return history;
|
return history;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClient::save_uuid()
|
std::string TransmClient::variable_and_reverse_files(const std::string& source)
|
||||||
|
{
|
||||||
|
auto vec = COfStr::split(source, "\n");
|
||||||
|
std::string result;
|
||||||
|
bool valid = true;
|
||||||
|
for (const auto& item : vec) {
|
||||||
|
auto rl = COfStr::trim(item);
|
||||||
|
if (rl.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto vi = COfStr::split(rl, "|");
|
||||||
|
if (vi.size() != 2) {
|
||||||
|
TLOGE("Size not 2 {}", item);
|
||||||
|
valid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto pr = variable_handle("", vi[1], false);
|
||||||
|
if (!fs::exists(pr)) {
|
||||||
|
valid = false;
|
||||||
|
TLOGE("Not exist {}", pr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TLOGI("---> check pass {}", pr);
|
||||||
|
|
||||||
|
fs::path ppr(pr);
|
||||||
|
fs::path pvi(vi[0]);
|
||||||
|
|
||||||
|
auto lp = ppr.append(pvi.filename().string()).string();
|
||||||
|
auto rp = pvi.parent_path().string();
|
||||||
|
|
||||||
|
auto line = lp + "|" + rp;
|
||||||
|
result = result + line + "\n";
|
||||||
|
}
|
||||||
|
if (!valid) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)) {
|
||||||
@ -815,7 +1022,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)) {
|
||||||
@ -832,18 +1039,18 @@ 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;
|
||||||
CMessageInfo msg_info;
|
CMessageInfo msg_info(own_id_);
|
||||||
msg_info.uuid = uuid_;
|
msg_info.uuid = uuid_;
|
||||||
serialize(msg_info, &bf->data_, bf->len_);
|
serialize(msg_info, &bf->data_, bf->len_);
|
||||||
send_frame(bf);
|
send_frame(bf);
|
||||||
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__);
|
||||||
@ -857,7 +1064,7 @@ void CClient::handle_frame(CFrameBuffer* buf)
|
|||||||
}
|
}
|
||||||
case TYPE_GET_LIST: {
|
case TYPE_GET_LIST: {
|
||||||
clients_.clear();
|
clients_.clear();
|
||||||
CMessageInfo msg_info;
|
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;
|
||||||
@ -921,17 +1128,22 @@ void CClient::handle_frame(CFrameBuffer* buf)
|
|||||||
downloading_ = true;
|
downloading_ = true;
|
||||||
}
|
}
|
||||||
if (will_receive_) {
|
if (will_receive_) {
|
||||||
down_->file_.write(buf->data_, buf->len_);
|
msg_info_.id = buf->fid_;
|
||||||
|
if (!deserialize(buf->data_, buf->len_, msg_info_)) {
|
||||||
|
TLOGE("{} TRANS deserialize failed.", __LINE__);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
down_->file_.write(msg_info_.data.c_str(), msg_info_.data.size());
|
||||||
if (down_->file_.fail()) {
|
if (down_->file_.fail()) {
|
||||||
report_trans_ret(TRANS_FAILED);
|
report_trans_ret(TRANS_FAILED);
|
||||||
TLOGW("no matched write and data. {}", buf->len_);
|
TLOGW("no matched write and data. {}", msg_info_.data.size());
|
||||||
}
|
}
|
||||||
cur_down_size_ += buf->len_;
|
cur_down_size_ += msg_info_.data.size();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TYPE_GET_DIRFILES: {
|
case TYPE_GET_DIRFILES: {
|
||||||
CMessageInfo msg_info;
|
CMessageInfo msg_info(buf->fid_);
|
||||||
if (!deserialize(buf->data_, buf->len_, msg_info)) {
|
if (!deserialize(buf->data_, buf->len_, msg_info)) {
|
||||||
TLOGE("{} GetDirFiles deserialize failed.", __LINE__);
|
TLOGE("{} GetDirFiles deserialize failed.", __LINE__);
|
||||||
break;
|
break;
|
||||||
@ -942,13 +1154,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)) {
|
||||||
@ -958,7 +1169,7 @@ void CClient::handle_frame(CFrameBuffer* buf)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TYPE_GET_DIRFILES_FAILED: {
|
case TYPE_GET_DIRFILES_FAILED: {
|
||||||
CMessageInfo msg_info;
|
CMessageInfo msg_info(buf->fid_);
|
||||||
if (!deserialize(buf->data_, buf->len_, msg_info)) {
|
if (!deserialize(buf->data_, buf->len_, msg_info)) {
|
||||||
TLOGE("{} GetDirFiles deserialize failed.", __LINE__);
|
TLOGE("{} GetDirFiles deserialize failed.", __LINE__);
|
||||||
break;
|
break;
|
||||||
@ -967,7 +1178,7 @@ void CClient::handle_frame(CFrameBuffer* buf)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TYPE_GET_DIRFILES_DONE: {
|
case TYPE_GET_DIRFILES_DONE: {
|
||||||
CMessageInfo msg_info;
|
CMessageInfo msg_info(buf->fid_);
|
||||||
if (!deserialize(buf->data_, buf->len_, msg_info)) {
|
if (!deserialize(buf->data_, buf->len_, msg_info)) {
|
||||||
TLOGE("{} GetDirFiles deserialize failed.", __LINE__);
|
TLOGE("{} GetDirFiles deserialize failed.", __LINE__);
|
||||||
break;
|
break;
|
||||||
@ -994,7 +1205,7 @@ void CClient::handle_frame(CFrameBuffer* buf)
|
|||||||
}
|
}
|
||||||
case TYPE_OPEN_FILE: {
|
case TYPE_OPEN_FILE: {
|
||||||
std::string keys{};
|
std::string keys{};
|
||||||
CMessageInfo msg_info;
|
CMessageInfo msg_info(buf->fid_);
|
||||||
if (!deserialize(buf->data_, buf->len_, msg_info)) {
|
if (!deserialize(buf->data_, buf->len_, msg_info)) {
|
||||||
TLOGE("{} OpenFile deserialize failed.", __LINE__);
|
TLOGE("{} OpenFile deserialize failed.", __LINE__);
|
||||||
break;
|
break;
|
||||||
@ -1058,23 +1269,44 @@ void CClient::handle_frame(CFrameBuffer* buf)
|
|||||||
report_trans_ret(TRANS_FAILED);
|
report_trans_ret(TRANS_FAILED);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case TYPE_REQUEST_DOWN_UPDATE_LIST: {
|
||||||
|
CMessageInfo msg_info(buf->fid_);
|
||||||
|
if (!deserialize(buf->data_, buf->len_, msg_info)) {
|
||||||
|
TLOGE("{} GetList deserialize failed.", __LINE__);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
msg_info.str = variable_and_reverse_files(msg_info.str);
|
||||||
|
msg_info.id = buf->tid_;
|
||||||
|
serialize(msg_info, &buf->data_, buf->len_);
|
||||||
|
|
||||||
|
std::swap(buf->tid_, buf->fid_);
|
||||||
|
buf->type_ = TYPE_REQUEST_UPDATE_LIST;
|
||||||
|
if (!send_frame(buf)) {
|
||||||
|
TLOGE("Send Failed {}.", __LINE__);
|
||||||
|
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;
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
if (check_update_list(msg_info.str, files)) {
|
if (variable_and_parse_files(msg_info.str, files)) {
|
||||||
buf->type_ = TYPE_CONFIRM_UPDATE_LIST;
|
buf->type_ = TYPE_CONFIRM_UPDATE_LIST;
|
||||||
|
list_server_uuid_ = msg_info.uuid;
|
||||||
} else {
|
} else {
|
||||||
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__);
|
||||||
@ -1083,7 +1315,7 @@ void CClient::handle_frame(CFrameBuffer* buf)
|
|||||||
if (buf->type_ != TYPE_CONFIRM_UPDATE_LIST) {
|
if (buf->type_ != TYPE_CONFIRM_UPDATE_LIST) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
list_serve_id_ = buf->tid_;
|
list_server_id_ = buf->tid_;
|
||||||
TLOGD("Do Task From Remote {}.", buf->tid_);
|
TLOGD("Do Task From Remote {}.", buf->tid_);
|
||||||
if (update_list_th_.joinable()) {
|
if (update_list_th_.joinable()) {
|
||||||
update_list_th_.join();
|
update_list_th_.join();
|
||||||
@ -1097,10 +1329,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: {
|
||||||
@ -1112,10 +1350,14 @@ void CClient::handle_frame(CFrameBuffer* buf)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TYPE_FILE_INFO: {
|
case TYPE_FILE_INFO: {
|
||||||
std::string str_size(buf->data_, buf->len_);
|
CMessageInfo msg_info(buf->fid_);
|
||||||
auto vec = COfStr::split(str_size, ",");
|
if (!deserialize(buf->data_, buf->len_, msg_info)) {
|
||||||
|
TLOGE("{} TRANS deserialize failed.", __LINE__);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto vec = COfStr::split(msg_info.str, ",");
|
||||||
if (vec.size() < 3) {
|
if (vec.size() < 3) {
|
||||||
TLOGE("invalid file information:{}", str_size);
|
TLOGE("invalid file information:{}", msg_info.str);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
long long size = std::stoll(vec[1]);
|
long long size = std::stoll(vec[1]);
|
||||||
@ -1134,7 +1376,7 @@ void CClient::handle_frame(CFrameBuffer* buf)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@ -1150,17 +1392,19 @@ void CClient::send_file_data_th(const char* keys)
|
|||||||
|
|
||||||
TLOGI("Start Trans File {} To {}", t->cur_file_, str_key);
|
TLOGI("Start Trans File {} To {}", t->cur_file_, str_key);
|
||||||
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
|
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
|
||||||
buf->data_ = new char[g_BuffSize]{};
|
|
||||||
buf->tid_ = str_key;
|
buf->tid_ = str_key;
|
||||||
|
CMessageInfo msg_info(own_id_);
|
||||||
|
|
||||||
// ********************************************************
|
// ********************************************************
|
||||||
// TYPE_FILE_INFO格式:平台([0,win], [1,unix]),大小,权限
|
// TYPE_FILE_INFO格式:平台([0,win], [1,unix]),大小,权限
|
||||||
// ********************************************************
|
// ********************************************************
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
||||||
@ -1177,29 +1421,39 @@ void CClient::send_file_data_th(const char* keys)
|
|||||||
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, ofen::OfUtil::get_file_size(size), size,
|
||||||
str_perm);
|
str_perm);
|
||||||
buf->len_ = std::snprintf(buf->data_, g_BuffSize, "%s", info_result.c_str());
|
msg_info.str = info_result;
|
||||||
|
serialize(msg_info, &buf->data_, buf->len_);
|
||||||
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);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete[] buf->data_;
|
||||||
|
buf->data_ = nullptr;
|
||||||
|
|
||||||
buf->type_ = TYPE_TRANS_FILE;
|
buf->type_ = TYPE_TRANS_FILE;
|
||||||
buf->mark_ = 1;
|
buf->mark_ = 1;
|
||||||
|
|
||||||
|
msg_info.data.resize(g_BuffSize);
|
||||||
|
long long send_size = 0;
|
||||||
|
long long cur_send_size = 0;
|
||||||
while (!t->file_.eof()) {
|
while (!t->file_.eof()) {
|
||||||
if (t->trans_state_ == TRANS_BREAK) {
|
if (t->trans_state_ == TRANS_BREAK) {
|
||||||
TLOGW("Stop Trans {} To {} failed.", t->cur_file_, str_key);
|
TLOGW("Stop Trans {} To {} failed.", t->cur_file_, str_key);
|
||||||
report_trans_ret(TRANS_FAILED, str_key);
|
report_trans_ret(TRANS_FAILED, str_key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
t->file_.read(buf->data_, g_BuffSize);
|
t->file_.read(&msg_info.data[0], g_BuffSize);
|
||||||
buf->len_ = t->file_.gcount();
|
cur_send_size = t->file_.gcount();
|
||||||
|
msg_info.data.resize(cur_send_size);
|
||||||
|
send_size += cur_send_size;
|
||||||
|
serialize(msg_info, &buf->data_, buf->len_, true);
|
||||||
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);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buf->type_ = TYPE_TRANS_DONE;
|
buf->type_ = TYPE_TRANS_DONE;
|
||||||
@ -1207,10 +1461,10 @@ void CClient::send_file_data_th(const char* keys)
|
|||||||
TLOGE("send_file_data_th send DONE failed.");
|
TLOGE("send_file_data_th send DONE failed.");
|
||||||
}
|
}
|
||||||
report_trans_ret(TRANS_DONE, str_key);
|
report_trans_ret(TRANS_DONE, str_key);
|
||||||
TLOGD("Trans File {} To {} Done !!!", t->cur_file_, str_key);
|
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;
|
||||||
@ -1223,7 +1477,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;
|
||||||
@ -1239,17 +1493,20 @@ 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_send)
|
bool is_local)
|
||||||
{
|
{
|
||||||
std::string result(source);
|
std::string result(source);
|
||||||
// 支持的变量如下:
|
// 支持的变量如下:
|
||||||
// ${HOME} 用户目录(发送端接收端均支持)
|
// ${HOME} 用户目录(发送端接收端均支持)
|
||||||
// ${CURRENT} 任务文件所在目录(该变量仅支持发送端,因为接收端没有任务文件所在路径)
|
// ${CURRENT} 任务文件所在目录(该变量仅支持发送端,因为接收端没有任务文件所在路径)
|
||||||
if (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());
|
||||||
}
|
}
|
||||||
if (is_send && source.find("${CURRENT}") != std::string::npos) {
|
if (is_local && source.find("${CURRENT}") != std::string::npos) {
|
||||||
|
if (task_list_path.empty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
fs::path p(task_list_path);
|
fs::path p(task_list_path);
|
||||||
std::string list_dir = p.parent_path().string();
|
std::string list_dir = p.parent_path().string();
|
||||||
result = COfStr::replace(result, "${CURRENT}", list_dir);
|
result = COfStr::replace(result, "${CURRENT}", list_dir);
|
||||||
@ -1257,14 +1514,25 @@ 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)
|
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{};
|
||||||
|
|
||||||
|
if (!is_send) {
|
||||||
|
handled_content.clear(); // 清空之前的内容
|
||||||
|
for (const auto& pair : source) {
|
||||||
|
handled_content.append(pair.second + "\n");
|
||||||
|
}
|
||||||
|
return handled_content;
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
TLOGI("numbers by space, or '0' use all, 'end' to quit: ");
|
TLOGI("numbers by space, or '0' use all, 'end' to quit: ");
|
||||||
std::getline(std::cin, input);
|
// std::getline(std::cin, input);
|
||||||
|
char* readline = fc_readline();
|
||||||
|
input = std::string(readline);
|
||||||
|
fc_free(readline);
|
||||||
|
|
||||||
if (input == "end") {
|
if (input == "end") {
|
||||||
handled_content.clear();
|
handled_content.clear();
|
||||||
|
@ -38,45 +38,48 @@ 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:
|
public:
|
||||||
void run(const std::string& ip, const std::string& port, const std::string& config_dir);
|
void run(const std::string& ip, const std::string& port, const std::string& config_dir);
|
||||||
|
bool get_clients();
|
||||||
|
bool cmd_fetch_files(const std::string& param);
|
||||||
|
bool cmd_sub_list(const std::string& param);
|
||||||
|
bool cmd_clear_submited();
|
||||||
|
bool cmd_upload_files(const std::string& param);
|
||||||
|
bool cmd_sub_task(const std::string& param, bool is_send);
|
||||||
|
bool cmd_ls(const std::string& param);
|
||||||
|
bool cmd_down_list(const std::string& param);
|
||||||
|
|
||||||
public:
|
private:
|
||||||
bool get_task_list();
|
bool variable_and_parse_files(const std::string& content, std::map<std::string, std::string>& files);
|
||||||
bool down_task(const std::string& param);
|
|
||||||
bool up_task(const std::string& param);
|
|
||||||
bool cancel_task();
|
|
||||||
bool send_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 request_update_list(const std::string& param);
|
|
||||||
bool check_update_list(const std::string& content, std::map<std::string, std::string>& files);
|
|
||||||
bool down_update_file(const 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 get_dir_files(const std::string& dir, std::string& out, std::string& error);
|
||||||
bool require_dir_files(const std::string& param);
|
void report_trans_ret(TransState state, const std::string& key = "");
|
||||||
bool down_req_list(const std::string& param);
|
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);
|
||||||
std::vector<std::string> load_line_his();
|
std::vector<std::string> load_line_his();
|
||||||
|
std::string variable_and_reverse_files(const std::string& source);
|
||||||
bool save_uuid();
|
bool save_uuid();
|
||||||
std::string read_uuid();
|
std::string read_uuid();
|
||||||
void get_id();
|
void get_id();
|
||||||
|
void print_help(bool detail);
|
||||||
|
bool base_init(const std::string& ip, const std::string& port, const std::string& config_dir);
|
||||||
|
|
||||||
private:
|
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_send);
|
std::string variable_handle(const std::string& task_list_path, const std::string& source, bool is_local);
|
||||||
std::string handle_user_select(const std::unordered_map<int, std::string>& source);
|
std::string handle_user_select(const std::unordered_map<int, std::string>& source, bool is_send);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
@ -88,23 +91,47 @@ private:
|
|||||||
bool will_receive_{false};
|
bool will_receive_{false};
|
||||||
bool downloading_{false};
|
bool downloading_{false};
|
||||||
asio::io_context io_context_;
|
asio::io_context io_context_;
|
||||||
|
CMessageInfo msg_info_;
|
||||||
std::shared_ptr<CTcpClient> client_;
|
std::shared_ptr<CTcpClient> client_;
|
||||||
std::map<int, std::shared_ptr<DownClientInfo>> clients_;
|
std::map<int, std::shared_ptr<DownClientInfo>> clients_;
|
||||||
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_{};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string list_file_;
|
std::string list_file_;
|
||||||
std::string list_serve_id_;
|
std::string list_server_id_;
|
||||||
|
std::string list_server_uuid_;
|
||||||
std::thread update_list_th_;
|
std::thread update_list_th_;
|
||||||
std::string own_id_{};
|
std::string own_id_{};
|
||||||
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
|
||||||
|
@ -10,13 +10,13 @@ namespace fs = boost::filesystem;
|
|||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
#endif
|
#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 +33,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 +59,7 @@ 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,7 +71,7 @@ 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) {
|
||||||
@ -84,7 +84,7 @@ bool CServerConfig::write_ini(const std::vector<TransmSet>& set)
|
|||||||
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,7 +109,7 @@ 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;
|
||||||
@ -124,7 +124,7 @@ bool CServerConfig::remove_ini(long num)
|
|||||||
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 +137,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,7 +151,7 @@ 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")) {
|
||||||
@ -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());
|
||||||
|
@ -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();
|
||||||
|
@ -16,11 +16,21 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::shared_ptr<CServerConfig> g_Config = nullptr;
|
#if defined(GRAB_CRASH)
|
||||||
|
#ifdef USE_BOOST
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
namespace fs = boost::filesystem;
|
||||||
|
#else
|
||||||
|
#include <filesystem>
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
#endif
|
||||||
|
#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, "使用服务器地址组(值为使用--show中显示的序号)");
|
||||||
@ -156,6 +166,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 +187,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;
|
||||||
}
|
}
|
||||||
@ -234,8 +252,8 @@ int main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
1
crashelper
Submodule
1
crashelper
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 2cf72f3e5c5313527b5d1442017caf06d51a3c02
|
@ -1 +1 @@
|
|||||||
Subproject commit c477dad67e171aecf9fb5b8ce361119bf459ff8f
|
Subproject commit 4b6612cc63f21b4d092a0b5731ceb7f817f20d23
|
26
http-server/CMakeLists.txt
Normal file
26
http-server/CMakeLists.txt
Normal 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
264
http-server/main.cpp
Normal 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;
|
||||||
|
}
|
BIN
img/func1.png
BIN
img/func1.png
Binary file not shown.
Before Width: | Height: | Size: 796 KiB |
BIN
img/func2.png
BIN
img/func2.png
Binary file not shown.
Before Width: | Height: | Size: 1.1 MiB |
BIN
img/tsc_use.png
BIN
img/tsc_use.png
Binary file not shown.
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 452 KiB |
@ -23,6 +23,9 @@ 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
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include <of_path.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -13,7 +14,19 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void signal_handler(int signal)
|
#if defined(GRAB_CRASH)
|
||||||
|
#include <crashelper.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_BOOST
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
namespace fs = boost::filesystem;
|
||||||
|
#else
|
||||||
|
#include <filesystem>
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void msignal_handler(int signal)
|
||||||
{
|
{
|
||||||
if (signal == SIGINT) {
|
if (signal == SIGINT) {
|
||||||
fc_recovery_color();
|
fc_recovery_color();
|
||||||
@ -23,7 +36,14 @@ void signal_handler(int 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); });
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
@ -48,7 +68,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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
@ -135,8 +134,9 @@ void CTcpServer::trans_data(CFrameBuffer* buf)
|
|||||||
switch (buf->type_) {
|
switch (buf->type_) {
|
||||||
case TYPE_GET_LIST: {
|
case TYPE_GET_LIST: {
|
||||||
TLOGI("[{}] GetList.", buf->fid_);
|
TLOGI("[{}] GetList.", buf->fid_);
|
||||||
CMessageInfo msg_info;
|
CMessageInfo msg_info(server_ip_);
|
||||||
get_client_list(msg_info);
|
get_client_list(msg_info);
|
||||||
|
buf->fid_ = server_ip_;
|
||||||
serialize(msg_info, &buf->data_, buf->len_);
|
serialize(msg_info, &buf->data_, buf->len_);
|
||||||
if (fcli && !send_frame(fcli->socket_, buf)) {
|
if (fcli && !send_frame(fcli->socket_, buf)) {
|
||||||
TLOGE("GetList send failed.");
|
TLOGE("GetList send failed.");
|
||||||
@ -144,7 +144,7 @@ void CTcpServer::trans_data(CFrameBuffer* buf)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TYPE_UP_LIST: {
|
case TYPE_UP_LIST: {
|
||||||
CMessageInfo msg_info;
|
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;
|
||||||
@ -189,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_)) {
|
||||||
@ -219,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) {
|
||||||
@ -247,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_);
|
||||||
@ -303,7 +301,7 @@ void CTcpServer::th_client(const std::shared_ptr<asio::ip::tcp::socket>& socket,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (frame->type_ == TYPE_GET_ID) {
|
if (frame->type_ == TYPE_GET_ID) {
|
||||||
CMessageInfo msg_info;
|
CMessageInfo msg_info("");
|
||||||
if (!deserialize(frame->data_, frame->len_, msg_info)) {
|
if (!deserialize(frame->data_, frame->len_, msg_info)) {
|
||||||
TLOGE("{} GetId deserialize failed.", __LINE__);
|
TLOGE("{} GetId deserialize failed.", __LINE__);
|
||||||
delete frame;
|
delete frame;
|
||||||
@ -329,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{};
|
||||||
@ -343,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();
|
||||||
@ -368,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);
|
||||||
|
@ -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();
|
||||||
|
42
test/CMakeLists.txt
Normal file
42
test/CMakeLists.txt
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
project(transm_test LANGUAGES CXX)
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
|
set(TEST_SOURCES
|
||||||
|
../3rd/catch_amalgamated.cpp
|
||||||
|
assistant.h
|
||||||
|
assistant.cxx
|
||||||
|
)
|
||||||
|
|
||||||
|
set(TRANSM_TEST_SOURCES
|
||||||
|
../3rd/catch_amalgamated.cpp
|
||||||
|
../client/client.cpp
|
||||||
|
../client/client.h
|
||||||
|
../client/config.cpp
|
||||||
|
../client/config.h
|
||||||
|
../util/util.h
|
||||||
|
../server/server.cpp
|
||||||
|
../server/server.h
|
||||||
|
../net/net_base.h
|
||||||
|
assistant.h
|
||||||
|
assistant.cxx
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(encry_correct_test EncryptCorrect.cxx ${TEST_SOURCES})
|
||||||
|
add_executable(encry_speed_test EncryptSpeed.cxx ${TEST_SOURCES})
|
||||||
|
target_link_libraries(encry_correct_test PRIVATE tinyaes trans_util)
|
||||||
|
target_link_libraries(encry_speed_test PRIVATE tinyaes trans_util)
|
||||||
|
add_executable(transm_cmd_test Cmd.cxx ${TRANSM_TEST_SOURCES})
|
||||||
|
target_link_libraries(transm_cmd_test PRIVATE trans_net trans_util)
|
||||||
|
|
||||||
|
if (UNIX)
|
||||||
|
target_link_libraries(encry_speed_test PRIVATE pthread)
|
||||||
|
target_link_libraries(encry_correct_test PRIVATE pthread)
|
||||||
|
target_link_libraries(transm_cmd_test PRIVATE pthread)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
add_test(NAME EncryCorrectTest COMMAND encry_correct_test)
|
||||||
|
add_test(NAME EncrySpeedTest COMMAND encry_speed_test -s)
|
||||||
|
add_test(NAME CmdTest COMMAND transm_cmd_test)
|
228
test/Cmd.cxx
Normal file
228
test/Cmd.cxx
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
#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
41
test/EncryptCorrect.cxx
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
185
test/EncryptSpeed.cxx
Normal file
185
test/EncryptSpeed.cxx
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
#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
77
test/assistant.cxx
Normal 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();
|
||||||
|
}
|
109
test/assistant.h
Normal file
109
test/assistant.h
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
#ifndef ASSISTANT_H
|
||||||
|
#define ASSISTANT_H
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <functional>
|
||||||
|
#include <random>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#ifdef USE_BOOST
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
namespace fs = boost::filesystem;
|
||||||
|
#else
|
||||||
|
#include <filesystem>
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
9
tinyaes/CMakeLists.txt
Normal file
9
tinyaes/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
project(tinyaes LANGUAGES C)
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_C_EXTENSIONS OFF) # 禁用编译器扩展(保持标准)
|
||||||
|
|
||||||
|
add_library(tinyaes STATIC aes.h aes.c aes.hpp)
|
||||||
|
target_include_directories(tinyaes PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
539
tinyaes/aes.c
Normal file
539
tinyaes/aes.c
Normal file
@ -0,0 +1,539 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
This is an implementation of the AES algorithm, specifically ECB, CTR and CBC mode.
|
||||||
|
Block size can be chosen in aes.h - available choices are AES128, AES192, AES256.
|
||||||
|
|
||||||
|
The implementation is verified against the test vectors in:
|
||||||
|
National Institute of Standards and Technology Special Publication 800-38A 2001 ED
|
||||||
|
|
||||||
|
ECB-AES128
|
||||||
|
----------
|
||||||
|
|
||||||
|
plain-text:
|
||||||
|
6bc1bee22e409f96e93d7e117393172a
|
||||||
|
ae2d8a571e03ac9c9eb76fac45af8e51
|
||||||
|
30c81c46a35ce411e5fbc1191a0a52ef
|
||||||
|
f69f2445df4f9b17ad2b417be66c3710
|
||||||
|
|
||||||
|
key:
|
||||||
|
2b7e151628aed2a6abf7158809cf4f3c
|
||||||
|
|
||||||
|
resulting cipher
|
||||||
|
3ad77bb40d7a3660a89ecaf32466ef97
|
||||||
|
f5d3d58503b9699de785895a96fdbaaf
|
||||||
|
43b1cd7f598ece23881b00e3ed030688
|
||||||
|
7b0c785e27e8ad3f8223207104725dd4
|
||||||
|
|
||||||
|
|
||||||
|
NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0)
|
||||||
|
You should pad the end of the string with zeros if this is not the case.
|
||||||
|
For AES192/256 the key size is proportionally larger.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Includes: */
|
||||||
|
/*****************************************************************************/
|
||||||
|
#include "aes.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h> // CBC mode, for memset
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Defines: */
|
||||||
|
/*****************************************************************************/
|
||||||
|
// The number of columns comprising a state in AES. This is a constant in AES. Value=4
|
||||||
|
#define Nb 4
|
||||||
|
|
||||||
|
#if defined(AES256) && (AES256 == 1)
|
||||||
|
#define Nk 8
|
||||||
|
#define Nr 14
|
||||||
|
#elif defined(AES192) && (AES192 == 1)
|
||||||
|
#define Nk 6
|
||||||
|
#define Nr 12
|
||||||
|
#else
|
||||||
|
#define Nk 4 // The number of 32 bit words in a key.
|
||||||
|
#define Nr 10 // The number of rounds in AES Cipher.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// jcallan@github points out that declaring Multiply as a function
|
||||||
|
// reduces code size considerably with the Keil ARM compiler.
|
||||||
|
// See this link for more information: https://github.com/kokke/tiny-AES-C/pull/3
|
||||||
|
#ifndef MULTIPLY_AS_A_FUNCTION
|
||||||
|
#define MULTIPLY_AS_A_FUNCTION 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Private variables: */
|
||||||
|
/*****************************************************************************/
|
||||||
|
// state - array holding the intermediate results during decryption.
|
||||||
|
typedef uint8_t state_t[4][4];
|
||||||
|
|
||||||
|
// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM
|
||||||
|
// The numbers below can be computed dynamically trading ROM for RAM -
|
||||||
|
// This can be useful in (embedded) bootloader applications, where ROM is often limited.
|
||||||
|
static const uint8_t sbox[256] = {
|
||||||
|
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||||
|
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||||
|
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||||
|
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||||
|
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||||
|
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||||
|
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||||
|
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||||
|
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||||
|
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||||
|
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||||
|
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||||
|
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||||
|
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||||
|
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||||
|
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||||
|
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
|
||||||
|
|
||||||
|
static const uint8_t rsbox[256] = {
|
||||||
|
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||||
|
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||||
|
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||||
|
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||||
|
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||||
|
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||||
|
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||||
|
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||||
|
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||||
|
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||||
|
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||||
|
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||||
|
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||||
|
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||||
|
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||||
|
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d};
|
||||||
|
|
||||||
|
// The round constant word array, Rcon[i], contains the values given by
|
||||||
|
// x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8)
|
||||||
|
static const uint8_t Rcon[11] = {0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12),
|
||||||
|
* that you can remove most of the elements in the Rcon array, because they are unused.
|
||||||
|
*
|
||||||
|
* From Wikipedia's article on the Rijndael key schedule @
|
||||||
|
* https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon
|
||||||
|
*
|
||||||
|
* "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys
|
||||||
|
* are needed), up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm."
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Private functions: */
|
||||||
|
/*****************************************************************************/
|
||||||
|
/*
|
||||||
|
static uint8_t getSBoxValue(uint8_t num)
|
||||||
|
{
|
||||||
|
return sbox[num];
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#define getSBoxValue(num) (sbox[(num)])
|
||||||
|
/*
|
||||||
|
static uint8_t getSBoxInvert(uint8_t num)
|
||||||
|
{
|
||||||
|
return 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.
|
||||||
|
static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
|
||||||
|
{
|
||||||
|
unsigned i, j, k;
|
||||||
|
uint8_t tempa[4]; // Used for the column/row operations
|
||||||
|
|
||||||
|
// The first round key is the key itself.
|
||||||
|
for (i = 0; i < Nk; ++i) {
|
||||||
|
RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
|
||||||
|
RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
|
||||||
|
RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
|
||||||
|
RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
// All other round keys are found from the previous round keys.
|
||||||
|
for (i = Nk; i < Nb * (Nr + 1); ++i) {
|
||||||
|
{
|
||||||
|
k = (i - 1) * 4;
|
||||||
|
tempa[0] = RoundKey[k + 0];
|
||||||
|
tempa[1] = RoundKey[k + 1];
|
||||||
|
tempa[2] = RoundKey[k + 2];
|
||||||
|
tempa[3] = RoundKey[k + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i % Nk == 0) {
|
||||||
|
// This function shifts the 4 bytes in a word to the left once.
|
||||||
|
// [a0,a1,a2,a3] becomes [a1,a2,a3,a0]
|
||||||
|
|
||||||
|
// Function RotWord()
|
||||||
|
{
|
||||||
|
const uint8_t u8tmp = tempa[0];
|
||||||
|
tempa[0] = tempa[1];
|
||||||
|
tempa[1] = tempa[2];
|
||||||
|
tempa[2] = tempa[3];
|
||||||
|
tempa[3] = u8tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Function Subword()
|
||||||
|
{
|
||||||
|
tempa[0] = getSBoxValue(tempa[0]);
|
||||||
|
tempa[1] = getSBoxValue(tempa[1]);
|
||||||
|
tempa[2] = getSBoxValue(tempa[2]);
|
||||||
|
tempa[3] = getSBoxValue(tempa[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
tempa[0] = tempa[0] ^ Rcon[i / Nk];
|
||||||
|
}
|
||||||
|
#if defined(AES256) && (AES256 == 1)
|
||||||
|
if (i % Nk == 4) {
|
||||||
|
// Function Subword()
|
||||||
|
{
|
||||||
|
tempa[0] = getSBoxValue(tempa[0]);
|
||||||
|
tempa[1] = getSBoxValue(tempa[1]);
|
||||||
|
tempa[2] = getSBoxValue(tempa[2]);
|
||||||
|
tempa[3] = getSBoxValue(tempa[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
j = i * 4;
|
||||||
|
k = (i - Nk) * 4;
|
||||||
|
RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
|
||||||
|
RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
|
||||||
|
RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
|
||||||
|
RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key)
|
||||||
|
{
|
||||||
|
KeyExpansion(ctx->RoundKey, key);
|
||||||
|
}
|
||||||
|
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
|
||||||
|
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv)
|
||||||
|
{
|
||||||
|
KeyExpansion(ctx->RoundKey, key);
|
||||||
|
memcpy(ctx->Iv, iv, AES_BLOCKLEN);
|
||||||
|
}
|
||||||
|
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv)
|
||||||
|
{
|
||||||
|
memcpy(ctx->Iv, iv, AES_BLOCKLEN);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// This function adds the round key to state.
|
||||||
|
// The round key is added to the state by an XOR function.
|
||||||
|
static void AddRoundKey(uint8_t round, state_t* state, uint8_t* RoundKey)
|
||||||
|
{
|
||||||
|
uint8_t i, j;
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
for (j = 0; j < 4; ++j) {
|
||||||
|
(*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The SubBytes Function Substitutes the values in the
|
||||||
|
// state matrix with values in an S-box.
|
||||||
|
static void SubBytes(state_t* state)
|
||||||
|
{
|
||||||
|
uint8_t i, j;
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
for (j = 0; j < 4; ++j) {
|
||||||
|
(*state)[j][i] = getSBoxValue((*state)[j][i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The ShiftRows() function shifts the rows in the state to the left.
|
||||||
|
// Each row is shifted with different offset.
|
||||||
|
// Offset = Row number. So the first row is not shifted.
|
||||||
|
static void ShiftRows(state_t* state)
|
||||||
|
{
|
||||||
|
uint8_t temp;
|
||||||
|
|
||||||
|
// Rotate first row 1 columns to left
|
||||||
|
temp = (*state)[0][1];
|
||||||
|
(*state)[0][1] = (*state)[1][1];
|
||||||
|
(*state)[1][1] = (*state)[2][1];
|
||||||
|
(*state)[2][1] = (*state)[3][1];
|
||||||
|
(*state)[3][1] = temp;
|
||||||
|
|
||||||
|
// Rotate second row 2 columns to left
|
||||||
|
temp = (*state)[0][2];
|
||||||
|
(*state)[0][2] = (*state)[2][2];
|
||||||
|
(*state)[2][2] = temp;
|
||||||
|
|
||||||
|
temp = (*state)[1][2];
|
||||||
|
(*state)[1][2] = (*state)[3][2];
|
||||||
|
(*state)[3][2] = temp;
|
||||||
|
|
||||||
|
// Rotate third row 3 columns to left
|
||||||
|
temp = (*state)[0][3];
|
||||||
|
(*state)[0][3] = (*state)[3][3];
|
||||||
|
(*state)[3][3] = (*state)[2][3];
|
||||||
|
(*state)[2][3] = (*state)[1][3];
|
||||||
|
(*state)[1][3] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t xtime(uint8_t x)
|
||||||
|
{
|
||||||
|
return ((x << 1) ^ (((x >> 7) & 1) * 0x1b));
|
||||||
|
}
|
||||||
|
|
||||||
|
// MixColumns function mixes the columns of the state matrix
|
||||||
|
static void MixColumns(state_t* state)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
uint8_t Tmp, Tm, t;
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
t = (*state)[i][0];
|
||||||
|
Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3];
|
||||||
|
Tm = (*state)[i][0] ^ (*state)[i][1];
|
||||||
|
Tm = xtime(Tm);
|
||||||
|
(*state)[i][0] ^= Tm ^ Tmp;
|
||||||
|
Tm = (*state)[i][1] ^ (*state)[i][2];
|
||||||
|
Tm = xtime(Tm);
|
||||||
|
(*state)[i][1] ^= Tm ^ Tmp;
|
||||||
|
Tm = (*state)[i][2] ^ (*state)[i][3];
|
||||||
|
Tm = xtime(Tm);
|
||||||
|
(*state)[i][2] ^= Tm ^ Tmp;
|
||||||
|
Tm = (*state)[i][3] ^ t;
|
||||||
|
Tm = xtime(Tm);
|
||||||
|
(*state)[i][3] ^= Tm ^ Tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply is used to multiply numbers in the field GF(2^8)
|
||||||
|
// Note: The last call to xtime() is unneeded, but often ends up generating a smaller binary
|
||||||
|
// The compiler seems to be able to vectorize the operation better this way.
|
||||||
|
// See https://github.com/kokke/tiny-AES-c/pull/34
|
||||||
|
#if MULTIPLY_AS_A_FUNCTION
|
||||||
|
static uint8_t Multiply(uint8_t x, uint8_t y)
|
||||||
|
{
|
||||||
|
return (((y & 1) * x) ^ ((y >> 1 & 1) * xtime(x)) ^ ((y >> 2 & 1) * xtime(xtime(x))) ^
|
||||||
|
((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^
|
||||||
|
((y >> 4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define Multiply(x, y) \
|
||||||
|
(((y & 1) * x) ^ ((y >> 1 & 1) * xtime(x)) ^ ((y >> 2 & 1) * xtime(xtime(x))) ^ \
|
||||||
|
((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^ ((y >> 4 & 1) * xtime(xtime(xtime(xtime(x))))))
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
|
||||||
|
// MixColumns function mixes the columns of the state matrix.
|
||||||
|
// The method used to multiply may be difficult to understand for the inexperienced.
|
||||||
|
// Please use the references to gain more information.
|
||||||
|
static void InvMixColumns(state_t* state)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint8_t a, b, c, d;
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
a = (*state)[i][0];
|
||||||
|
b = (*state)[i][1];
|
||||||
|
c = (*state)[i][2];
|
||||||
|
d = (*state)[i][3];
|
||||||
|
|
||||||
|
(*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
|
||||||
|
(*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
|
||||||
|
(*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
|
||||||
|
(*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The SubBytes Function Substitutes the values in the
|
||||||
|
// state matrix with values in an S-box.
|
||||||
|
static void InvSubBytes(state_t* state)
|
||||||
|
{
|
||||||
|
uint8_t i, j;
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
for (j = 0; j < 4; ++j) {
|
||||||
|
(*state)[j][i] = getSBoxInvert((*state)[j][i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InvShiftRows(state_t* state)
|
||||||
|
{
|
||||||
|
uint8_t temp;
|
||||||
|
|
||||||
|
// Rotate first row 1 columns to right
|
||||||
|
temp = (*state)[3][1];
|
||||||
|
(*state)[3][1] = (*state)[2][1];
|
||||||
|
(*state)[2][1] = (*state)[1][1];
|
||||||
|
(*state)[1][1] = (*state)[0][1];
|
||||||
|
(*state)[0][1] = temp;
|
||||||
|
|
||||||
|
// Rotate second row 2 columns to right
|
||||||
|
temp = (*state)[0][2];
|
||||||
|
(*state)[0][2] = (*state)[2][2];
|
||||||
|
(*state)[2][2] = temp;
|
||||||
|
|
||||||
|
temp = (*state)[1][2];
|
||||||
|
(*state)[1][2] = (*state)[3][2];
|
||||||
|
(*state)[3][2] = temp;
|
||||||
|
|
||||||
|
// Rotate third row 3 columns to right
|
||||||
|
temp = (*state)[0][3];
|
||||||
|
(*state)[0][3] = (*state)[1][3];
|
||||||
|
(*state)[1][3] = (*state)[2][3];
|
||||||
|
(*state)[2][3] = (*state)[3][3];
|
||||||
|
(*state)[3][3] = temp;
|
||||||
|
}
|
||||||
|
#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
|
||||||
|
|
||||||
|
// Cipher is the main function that encrypts the PlainText.
|
||||||
|
static void Cipher(state_t* state, uint8_t* RoundKey)
|
||||||
|
{
|
||||||
|
uint8_t round = 0;
|
||||||
|
|
||||||
|
// Add the First round key to the state before starting the rounds.
|
||||||
|
AddRoundKey(0, state, RoundKey);
|
||||||
|
|
||||||
|
// There will be Nr rounds.
|
||||||
|
// The first Nr-1 rounds are identical.
|
||||||
|
// These Nr-1 rounds are executed in the loop below.
|
||||||
|
for (round = 1; round < Nr; ++round) {
|
||||||
|
SubBytes(state);
|
||||||
|
ShiftRows(state);
|
||||||
|
MixColumns(state);
|
||||||
|
AddRoundKey(round, state, RoundKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The last round is given below.
|
||||||
|
// The MixColumns function is not here in the last round.
|
||||||
|
SubBytes(state);
|
||||||
|
ShiftRows(state);
|
||||||
|
AddRoundKey(Nr, state, RoundKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
|
||||||
|
static void InvCipher(state_t* state, uint8_t* RoundKey)
|
||||||
|
{
|
||||||
|
uint8_t round = 0;
|
||||||
|
|
||||||
|
// Add the First round key to the state before starting the rounds.
|
||||||
|
AddRoundKey(Nr, state, RoundKey);
|
||||||
|
|
||||||
|
// There will be Nr rounds.
|
||||||
|
// The first Nr-1 rounds are identical.
|
||||||
|
// These Nr-1 rounds are executed in the loop below.
|
||||||
|
for (round = (Nr - 1); round > 0; --round) {
|
||||||
|
InvShiftRows(state);
|
||||||
|
InvSubBytes(state);
|
||||||
|
AddRoundKey(round, state, RoundKey);
|
||||||
|
InvMixColumns(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The last round is given below.
|
||||||
|
// The MixColumns function is not here in the last round.
|
||||||
|
InvShiftRows(state);
|
||||||
|
InvSubBytes(state);
|
||||||
|
AddRoundKey(0, state, RoundKey);
|
||||||
|
}
|
||||||
|
#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Public functions: */
|
||||||
|
/*****************************************************************************/
|
||||||
|
#if defined(ECB) && (ECB == 1)
|
||||||
|
|
||||||
|
void AES_ECB_encrypt(struct AES_ctx* ctx, uint8_t* buf)
|
||||||
|
{
|
||||||
|
// The next function call encrypts the PlainText with the Key using AES algorithm.
|
||||||
|
Cipher((state_t*)buf, ctx->RoundKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AES_ECB_decrypt(struct AES_ctx* ctx, uint8_t* buf)
|
||||||
|
{
|
||||||
|
// The next function call decrypts the PlainText with the Key using AES algorithm.
|
||||||
|
InvCipher((state_t*)buf, ctx->RoundKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // #if defined(ECB) && (ECB == 1)
|
||||||
|
|
||||||
|
#if defined(CBC) && (CBC == 1)
|
||||||
|
|
||||||
|
static void XorWithIv(uint8_t* buf, uint8_t* Iv)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size
|
||||||
|
{
|
||||||
|
buf[i] ^= Iv[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length)
|
||||||
|
{
|
||||||
|
uintptr_t i;
|
||||||
|
uint8_t* Iv = ctx->Iv;
|
||||||
|
for (i = 0; i < length; i += AES_BLOCKLEN) {
|
||||||
|
XorWithIv(buf, Iv);
|
||||||
|
Cipher((state_t*)buf, ctx->RoundKey);
|
||||||
|
Iv = buf;
|
||||||
|
buf += AES_BLOCKLEN;
|
||||||
|
// printf("Step %d - %d", i/16, i);
|
||||||
|
}
|
||||||
|
/* store Iv in ctx for next call */
|
||||||
|
memcpy(ctx->Iv, Iv, AES_BLOCKLEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length)
|
||||||
|
{
|
||||||
|
uintptr_t i;
|
||||||
|
uint8_t storeNextIv[AES_BLOCKLEN];
|
||||||
|
for (i = 0; i < length; i += AES_BLOCKLEN) {
|
||||||
|
memcpy(storeNextIv, buf, AES_BLOCKLEN);
|
||||||
|
InvCipher((state_t*)buf, ctx->RoundKey);
|
||||||
|
XorWithIv(buf, ctx->Iv);
|
||||||
|
memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN);
|
||||||
|
buf += AES_BLOCKLEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // #if defined(CBC) && (CBC == 1)
|
||||||
|
|
||||||
|
#if defined(CTR) && (CTR == 1)
|
||||||
|
|
||||||
|
/* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be
|
||||||
|
* reused with the same key */
|
||||||
|
void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length)
|
||||||
|
{
|
||||||
|
uint8_t buffer[AES_BLOCKLEN];
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
int bi;
|
||||||
|
for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi) {
|
||||||
|
if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */
|
||||||
|
{
|
||||||
|
|
||||||
|
memcpy(buffer, ctx->Iv, AES_BLOCKLEN);
|
||||||
|
Cipher((state_t*)buffer, ctx->RoundKey);
|
||||||
|
|
||||||
|
/* Increment Iv and handle overflow */
|
||||||
|
for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi) {
|
||||||
|
/* inc will owerflow */
|
||||||
|
if (ctx->Iv[bi] == 255) {
|
||||||
|
ctx->Iv[bi] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ctx->Iv[bi] += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bi = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[i] = (buf[i] ^ buffer[bi]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // #if defined(CTR) && (CTR == 1)
|
90
tinyaes/aes.h
Normal file
90
tinyaes/aes.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#ifndef _AES_H_
|
||||||
|
#define _AES_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// #define the macros below to 1/0 to enable/disable the mode of operation.
|
||||||
|
//
|
||||||
|
// CBC enables AES encryption in CBC-mode of operation.
|
||||||
|
// CTR enables encryption in counter-mode.
|
||||||
|
// ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously.
|
||||||
|
|
||||||
|
// The #ifndef-guard allows it to be configured before #include'ing or at compile time.
|
||||||
|
// #ifndef CBC
|
||||||
|
// #define CBC 1
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifndef ECB
|
||||||
|
// #define ECB 1
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifndef CTR
|
||||||
|
// #define CTR 1
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// 只启用 CTR
|
||||||
|
#define CBC 0
|
||||||
|
#define CTR 1
|
||||||
|
#define ECB 0
|
||||||
|
|
||||||
|
#define AES128 1
|
||||||
|
// #define AES192 1
|
||||||
|
// #define AES256 1
|
||||||
|
|
||||||
|
#define AES_BLOCKLEN 16 // Block length in bytes AES is 128b block only
|
||||||
|
|
||||||
|
#if defined(AES256) && (AES256 == 1)
|
||||||
|
#define AES_KEYLEN 32
|
||||||
|
#define AES_keyExpSize 240
|
||||||
|
#elif defined(AES192) && (AES192 == 1)
|
||||||
|
#define AES_KEYLEN 24
|
||||||
|
#define AES_keyExpSize 208
|
||||||
|
#else
|
||||||
|
#define AES_KEYLEN 16 // Key length in bytes
|
||||||
|
#define AES_keyExpSize 176
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct AES_ctx {
|
||||||
|
uint8_t RoundKey[AES_keyExpSize];
|
||||||
|
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
|
||||||
|
uint8_t Iv[AES_BLOCKLEN];
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
|
||||||
|
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
|
||||||
|
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
|
||||||
|
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ECB) && (ECB == 1)
|
||||||
|
// buffer size is exactly AES_BLOCKLEN bytes;
|
||||||
|
// you need only AES_init_ctx as IV is not used in ECB
|
||||||
|
// NB: ECB is considered insecure for most uses
|
||||||
|
void AES_ECB_encrypt(struct AES_ctx* ctx, uint8_t* buf);
|
||||||
|
void AES_ECB_decrypt(struct AES_ctx* ctx, uint8_t* buf);
|
||||||
|
|
||||||
|
#endif // #if defined(ECB) && (ECB == !)
|
||||||
|
|
||||||
|
#if defined(CBC) && (CBC == 1)
|
||||||
|
// buffer size MUST be mutile of AES_BLOCKLEN;
|
||||||
|
// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
|
||||||
|
// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv()
|
||||||
|
// no IV should ever be reused with the same key
|
||||||
|
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
|
||||||
|
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
|
||||||
|
|
||||||
|
#endif // #if defined(CBC) && (CBC == 1)
|
||||||
|
|
||||||
|
#if defined(CTR) && (CTR == 1)
|
||||||
|
|
||||||
|
// Same function for encrypting as for decrypting.
|
||||||
|
// IV is incremented for every block, and used after encryption as XOR-compliment for output
|
||||||
|
// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
|
||||||
|
// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv()
|
||||||
|
// no IV should ever be reused with the same key
|
||||||
|
void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
|
||||||
|
|
||||||
|
#endif // #if defined(CTR) && (CTR == 1)
|
||||||
|
|
||||||
|
#endif //_AES_H_
|
12
tinyaes/aes.hpp
Normal file
12
tinyaes/aes.hpp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef _AES_HPP_
|
||||||
|
#define _AES_HPP_
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
#error Do not include the hpp header in a c project!
|
||||||
|
#endif //__cplusplus
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "aes.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //_AES_HPP_
|
3
tinyaes/readme.md
Normal file
3
tinyaes/readme.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# 说明
|
||||||
|
|
||||||
|
来自:`https://github.com/kokke/tiny-AES-c`
|
@ -9,5 +9,5 @@ endif()
|
|||||||
|
|
||||||
set(SOURCES util.h util.cpp)
|
set(SOURCES util.h util.cpp)
|
||||||
add_library(trans_util STATIC ${SOURCES})
|
add_library(trans_util STATIC ${SOURCES})
|
||||||
target_link_libraries(trans_util PUBLIC ofen filecomplete)
|
target_link_libraries(trans_util PUBLIC ofen filecomplete tinyaes)
|
||||||
target_include_directories(trans_util PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(trans_util PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
175
util/util.cpp
175
util/util.cpp
@ -1,12 +1,15 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <aes.hpp>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <of_util.h>
|
#include <of_util.h>
|
||||||
|
#include <random>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
CTransProtocal::CTransProtocal() = default;
|
CTransProtocal::CTransProtocal() = default;
|
||||||
|
constexpr uint8_t kz = 16;
|
||||||
|
static bool use_encrypt = true;
|
||||||
CTransProtocal::~CTransProtocal() = default;
|
CTransProtocal::~CTransProtocal() = default;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -131,26 +134,39 @@ CFrameBuffer::~CFrameBuffer()
|
|||||||
len_ = 0;
|
len_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void serialize(const CMessageInfo& msg_info, char** out_buf, int& len)
|
void serialize(CMessageInfo& msg_info, char** out_buf, int& len, bool reuse_mem)
|
||||||
{
|
{
|
||||||
CMessageInfo info(msg_info);
|
auto& info = msg_info;
|
||||||
info.cmd = localtou8(info.cmd);
|
info.id = localtou8(info.id);
|
||||||
info.uuid = localtou8(info.uuid);
|
info.uuid = localtou8(info.uuid);
|
||||||
info.str = localtou8(info.str);
|
info.str = localtou8(info.str);
|
||||||
info.o = localtou8(info.o);
|
|
||||||
|
|
||||||
// 计算总长度
|
// 计算总长度
|
||||||
len = sizeof(int) * 4 + info.cmd.size() + info.uuid.size() + info.str.size() + info.o.size();
|
len = sizeof(int) * 4 + info.id.size() + info.uuid.size() + info.str.size() + info.data.size() + kz + 1;
|
||||||
*out_buf = new char[len]; // 分配内存(调用方负责释放)
|
|
||||||
|
|
||||||
char* ptr = *out_buf;
|
// 《这里为了效率》,
|
||||||
|
// 认为如果 *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 cmd_size = static_cast<int>(info.cmd.size());
|
int id_size = static_cast<int>(info.id.size());
|
||||||
memcpy(ptr, &cmd_size, sizeof(int));
|
memcpy(ptr, &id_size, sizeof(int));
|
||||||
ptr += sizeof(int);
|
ptr += sizeof(int);
|
||||||
memcpy(ptr, info.cmd.data(), cmd_size);
|
memcpy(ptr, info.id.data(), id_size);
|
||||||
ptr += cmd_size;
|
ptr += id_size;
|
||||||
|
|
||||||
// 序列化 uuid
|
// 序列化 uuid
|
||||||
int uuid_size = static_cast<int>(info.uuid.size());
|
int uuid_size = static_cast<int>(info.uuid.size());
|
||||||
@ -167,41 +183,64 @@ void serialize(const CMessageInfo& msg_info, char** out_buf, int& len)
|
|||||||
ptr += str_size;
|
ptr += str_size;
|
||||||
|
|
||||||
// 序列化 o
|
// 序列化 o
|
||||||
int o_size = static_cast<int>(info.o.size());
|
int o_size = static_cast<int>(info.data.size());
|
||||||
memcpy(ptr, &o_size, sizeof(int));
|
memcpy(ptr, &o_size, sizeof(int));
|
||||||
ptr += sizeof(int);
|
ptr += sizeof(int);
|
||||||
memcpy(ptr, info.o.data(), o_size);
|
memcpy(ptr, info.data.data(), o_size);
|
||||||
|
|
||||||
|
char* mark = *out_buf;
|
||||||
|
if (!use_encrypt) {
|
||||||
|
mark[0] = 0x00;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t ik[32]{};
|
||||||
|
hash(msg_info.id.c_str(), ik);
|
||||||
|
encrypt(ik, (uint8_t*)(*out_buf + 1), len - 1);
|
||||||
|
mark[0] = 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deserialize(const char* data, int len, CMessageInfo& msg_info)
|
bool deserialize(char* data, int len, CMessageInfo& msg_info)
|
||||||
{
|
{
|
||||||
CMessageInfo info;
|
if (len < (kz + 1)) {
|
||||||
const char* ptr = data;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& info = msg_info;
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmd_size;
|
int id_size{};
|
||||||
memcpy(&cmd_size, ptr, sizeof(int));
|
memcpy(&id_size, ptr, sizeof(int));
|
||||||
ptr += sizeof(int);
|
ptr += sizeof(int);
|
||||||
remaining -= sizeof(int);
|
remaining -= sizeof(int);
|
||||||
if (remaining < cmd_size) {
|
if (remaining < id_size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
info.cmd.assign(ptr, cmd_size);
|
info.id.assign(ptr, id_size);
|
||||||
ptr += cmd_size;
|
ptr += id_size;
|
||||||
remaining -= cmd_size;
|
remaining -= id_size;
|
||||||
|
|
||||||
// 反序列化 uuid
|
// 反序列化 uuid
|
||||||
if (remaining < static_cast<int>(sizeof(int))) {
|
if (remaining < static_cast<int>(sizeof(int))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int uuid_size;
|
int uuid_size{};
|
||||||
memcpy(&uuid_size, ptr, sizeof(int));
|
memcpy(&uuid_size, ptr, sizeof(int));
|
||||||
ptr += sizeof(int);
|
ptr += sizeof(int);
|
||||||
remaining -= sizeof(int);
|
remaining -= sizeof(int);
|
||||||
@ -218,7 +257,7 @@ bool deserialize(const char* data, int len, CMessageInfo& msg_info)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int str_size;
|
int str_size{};
|
||||||
memcpy(&str_size, ptr, sizeof(int));
|
memcpy(&str_size, ptr, sizeof(int));
|
||||||
ptr += sizeof(int);
|
ptr += sizeof(int);
|
||||||
remaining -= sizeof(int);
|
remaining -= sizeof(int);
|
||||||
@ -234,21 +273,18 @@ bool deserialize(const char* data, int len, CMessageInfo& msg_info)
|
|||||||
if (remaining < static_cast<int>(sizeof(int))) {
|
if (remaining < static_cast<int>(sizeof(int))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int o_size;
|
int o_size{};
|
||||||
memcpy(&o_size, ptr, sizeof(int));
|
memcpy(&o_size, ptr, sizeof(int));
|
||||||
ptr += sizeof(int);
|
ptr += sizeof(int);
|
||||||
remaining -= sizeof(int);
|
remaining -= sizeof(int);
|
||||||
if (remaining < o_size) {
|
if (remaining < o_size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
info.o.assign(ptr, o_size);
|
info.data.assign(ptr, o_size);
|
||||||
|
|
||||||
info.cmd = u8tolocal(info.cmd);
|
info.id = u8tolocal(info.id);
|
||||||
info.uuid = u8tolocal(info.uuid);
|
info.uuid = u8tolocal(info.uuid);
|
||||||
info.str = u8tolocal(info.str);
|
info.str = u8tolocal(info.str);
|
||||||
info.o = u8tolocal(info.o);
|
|
||||||
msg_info = info;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,15 +306,84 @@ std::string localtou8(const std::string& str)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hash(const char* data, uint8_t k[32])
|
||||||
|
{
|
||||||
|
uint32_t h = 5381;
|
||||||
|
for (const char* p = data; *p; p++) {
|
||||||
|
h = ((h << 5) + h) + *p; // DJB2
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
k[i] = (h >> (i % 4 * 8)) & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rdm(uint8_t* o, size_t size)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
需要加密安全:坚持用random_device(慢)
|
||||||
|
需要性能:用 mt19937 + uniform_int_distribution
|
||||||
|
*/
|
||||||
|
std::random_device rd;
|
||||||
|
// std::mt19937 gen(rd());
|
||||||
|
std::mt19937_64 gen(rd());
|
||||||
|
std::uniform_int_distribution<int> dist(0, 255);
|
||||||
|
std::generate(o, o + size, [&]() { return static_cast<uint8_t>(dist(gen)); });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool encrypt(const uint8_t* k, uint8_t* m, size_t len)
|
||||||
|
{
|
||||||
|
if (len < kz) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t nonce[kz]{};
|
||||||
|
rdm(nonce, sizeof(nonce) - 4);
|
||||||
|
memcpy(m, nonce, kz);
|
||||||
|
|
||||||
|
struct AES_ctx ctx{};
|
||||||
|
AES_init_ctx_iv(&ctx, k, nonce);
|
||||||
|
AES_CTR_xcrypt_buffer(&ctx, m + kz, len - kz);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool decrypt(const uint8_t* k, uint8_t* m, size_t len)
|
||||||
|
{
|
||||||
|
if (len < kz) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t nonce[kz]{};
|
||||||
|
memcpy(nonce, m, kz);
|
||||||
|
|
||||||
|
struct AES_ctx ctx{};
|
||||||
|
AES_init_ctx_iv(&ctx, k, nonce);
|
||||||
|
AES_CTR_xcrypt_buffer(&ctx, m + kz, len - kz);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_encrypt(bool encrypt)
|
||||||
|
{
|
||||||
|
use_encrypt = encrypt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_encrypt_status()
|
||||||
|
{
|
||||||
|
return use_encrypt;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMessageInfo::CMessageInfo(const std::string& id) : id(id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
CMessageInfo::CMessageInfo(const CMessageInfo& info)
|
CMessageInfo::CMessageInfo(const CMessageInfo& info)
|
||||||
{
|
{
|
||||||
if (&info == this) {
|
if (&info == this) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cmd = info.cmd;
|
id = info.id;
|
||||||
uuid = info.uuid;
|
uuid = info.uuid;
|
||||||
str = info.str;
|
str = info.str;
|
||||||
o = info.o;
|
data.assign(info.data.begin(), info.data.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
CMessageInfo& CMessageInfo::operator=(const CMessageInfo& info)
|
CMessageInfo& CMessageInfo::operator=(const CMessageInfo& info)
|
||||||
@ -286,9 +391,9 @@ CMessageInfo& CMessageInfo::operator=(const CMessageInfo& info)
|
|||||||
if (&info == this) {
|
if (&info == this) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
cmd = info.cmd;
|
id = info.id;
|
||||||
uuid = info.uuid;
|
uuid = info.uuid;
|
||||||
str = info.str;
|
str = info.str;
|
||||||
o = info.o;
|
data.assign(info.data.begin(), info.data.end());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
37
util/util.h
37
util/util.h
@ -29,6 +29,7 @@ enum FrameType : int16_t {
|
|||||||
TYPE_OFFLINE,
|
TYPE_OFFLINE,
|
||||||
TYPE_JUDGE_ACTIVE,
|
TYPE_JUDGE_ACTIVE,
|
||||||
TYPE_REQUEST_UPDATE_LIST,
|
TYPE_REQUEST_UPDATE_LIST,
|
||||||
|
TYPE_REQUEST_DOWN_UPDATE_LIST,
|
||||||
TYPE_CONFIRM_UPDATE_LIST,
|
TYPE_CONFIRM_UPDATE_LIST,
|
||||||
TYPE_UNCONFIRM_UPDATE_LIST,
|
TYPE_UNCONFIRM_UPDATE_LIST,
|
||||||
TYPE_DONE_UPDATE_LIST,
|
TYPE_DONE_UPDATE_LIST,
|
||||||
@ -43,19 +44,25 @@ enum FrameType : int16_t {
|
|||||||
|
|
||||||
// 此结构体成员顺序不可变动,涉及到序列化反序列化。
|
// 此结构体成员顺序不可变动,涉及到序列化反序列化。
|
||||||
struct CMessageInfo {
|
struct CMessageInfo {
|
||||||
CMessageInfo() = default;
|
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 cmd;
|
std::string id;
|
||||||
std::string uuid;
|
std::string uuid;
|
||||||
std::string str;
|
std::string str;
|
||||||
std::string o;
|
std::string data;
|
||||||
};
|
};
|
||||||
|
|
||||||
void serialize(const CMessageInfo& msg_info, char** out_buf, int& len);
|
void serialize(CMessageInfo& msg_info, char** out_buf, int& len, bool reuse_mem = false);
|
||||||
bool deserialize(const 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);
|
||||||
|
void hash(const char* data, uint8_t k[32]);
|
||||||
|
void rdm(uint8_t* o, size_t size);
|
||||||
|
bool encrypt(const uint8_t* k, uint8_t* m, size_t len);
|
||||||
|
bool decrypt(const uint8_t* k, uint8_t* m, size_t len);
|
||||||
|
void set_encrypt(bool encrypt);
|
||||||
|
bool get_encrypt_status();
|
||||||
|
|
||||||
using namespace ofen;
|
using namespace ofen;
|
||||||
class CFrameBuffer
|
class CFrameBuffer
|
||||||
@ -65,8 +72,8 @@ public:
|
|||||||
~CFrameBuffer();
|
~CFrameBuffer();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::string fid_{};
|
std::string fid_;
|
||||||
std::string tid_{};
|
std::string tid_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FrameType type_{};
|
FrameType type_{};
|
||||||
@ -106,8 +113,8 @@ inline std::string now_str()
|
|||||||
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), "[%Y-%m-%d %H:%M:%S") << "." << std::setfill('0')
|
timestamp << std::put_time(std::localtime(&time_t_now), "[%m-%d %H:%M:%S") << "." << std::setfill('0') << std::setw(3)
|
||||||
<< std::setw(3) << milliseconds.count() << "] ";
|
<< milliseconds.count() << "] ";
|
||||||
|
|
||||||
return timestamp.str();
|
return timestamp.str();
|
||||||
}
|
}
|
||||||
@ -115,31 +122,27 @@ inline std::string now_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();
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user