Compare commits
171 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 15502b5ae5 | |||
| a2bd25f5b7 | |||
| 98265d4dc8 | |||
| 25dda4cb4c | |||
| 93d2b765ef | |||
| 25c507c699 | |||
| 504c842499 | |||
| d3ee202313 | |||
| 571eaa0fa5 | |||
| 62e41685f1 | |||
| 2acef8214d | |||
| 6510c0e85e | |||
| fa40e79a5d | |||
| e81e21f00e | |||
| 0d456eea5d | |||
| 2b929fd3c0 | |||
| 86942e45c9 | |||
| 41d3d30386 | |||
| ec10d01971 | |||
| 41c7551048 | |||
| 34e97b75aa | |||
| fd36ce87cf | |||
| aa08bfbf1b | |||
| 0fccd957b6 | |||
| 6479e31435 | |||
| b98c5f8907 | |||
| 96b5ccd17d | |||
| ec2da18050 | |||
| c9d96bbdca | |||
| f2a80275eb | |||
| 29da611864 | |||
| e243f1bd94 | |||
| ec1205c313 | |||
| 371ca06bfa | |||
| 64b4a7118b | |||
| 035f23ef23 | |||
| 423f7a7303 | |||
| 817c8f0c87 | |||
| 3e39bcc38c | |||
| 14d9936d90 | |||
| 8021c3f334 | |||
| 76342bbb96 | |||
| 6297b4cba7 | |||
| 402467fa69 | |||
| 1c7183d7f2 | |||
| c6080c175c | |||
| e0e1431745 | |||
| 8baaf1de60 | |||
| 57693f25c9 | |||
| d28b0ba316 | |||
| cb15bea748 | |||
| a42c0869bf | |||
| 73ed3a23c6 | |||
| 543e6b1abc | |||
| fe05c63882 | |||
| 1c710e2aef | |||
| 80a36e7c39 | |||
| 7c1e6d9364 | |||
| 8d186c18cd | |||
| 7693f962ca | |||
| 81e86b0df1 | |||
| 9a030bedf6 | |||
| 619e560152 | |||
| 431e2c28f2 | |||
| 8acd2396d3 | |||
| aaea9b9339 | |||
| 1de3eee117 | |||
| 12aee2c958 | |||
| 2dc48747ed | |||
| 8fc8e43b2c | |||
| 87d607335e | |||
| d8337214f0 | |||
| f5c321dd9a | |||
| a69100f689 | |||
| c7b6c0a3ba | |||
| bb2e7699dc | |||
| 10092cfab0 | |||
| 9a0fc705e1 | |||
| 66ad46cef6 | |||
| 52c20efff5 | |||
| 0ef580477f | |||
| f180f62f2c | |||
| 77a7c23a62 | |||
| 43c4277b04 | |||
| 9e41b825c0 | |||
| 158c9ea196 | |||
| b9238f1e36 | |||
| 60a12b4085 | |||
| 6564969a28 | |||
| 268dfb5bcf | |||
| 3869788b66 | |||
| b099578957 | |||
| c3a654efe9 | |||
| dfde7591cb | |||
| d5d3867456 | |||
| 4bab4ede7a | |||
| 3141a4566d | |||
| 45a32496ba | |||
| a651eb879e | |||
| b2199c8d56 | |||
| 4fa9123a31 | |||
| bf689eca59 | |||
| 14bfda467f | |||
| fb5dc72970 | |||
| b7d60361c0 | |||
| 867012d47b | |||
| e18b5e5eaf | |||
| 5efe5037c5 | |||
| 755183a144 | |||
| b9a6b1d546 | |||
| c4795f5f74 | |||
| 0d3d3cfc53 | |||
| 44fe958f31 | |||
| b68da43daf | |||
| 8a083180c1 | |||
| 55631bfb82 | |||
| 7cf7995371 | |||
| 2bb9310f78 | |||
| 84c1f94f30 | |||
| 7cf8f6c2c3 | |||
| 6fae66001e | |||
| dbb7c322a2 | |||
| 988ed00ff6 | |||
| ca00f690fd | |||
| 3e88ae46b6 | |||
| 971a84105b | |||
| b778421593 | |||
| 5cfd2c4586 | |||
| 1cd1221217 | |||
| 2d52fb9915 | |||
| fc7df4bf2a | |||
| fc365736ed | |||
| 0b2ec5ac0a | |||
| 7f1254b05e | |||
| 0bedf6c42a | |||
| 0c6fd1f864 | |||
| bf9637a82d | |||
| 46753d7a3f | |||
| b3347cfa8e | |||
| c256dd3d60 | |||
| 08ba917d02 | |||
| e46e521e9b | |||
| 1f8d51454e | |||
| 23afbf477e | |||
| 46714ae57f | |||
| e929419585 | |||
| e39f01bde5 | |||
| 7822d20efe | |||
| 155bfb3185 | |||
| 647248009d | |||
| 244b7dc0cb | |||
| 2ae00f07cd | |||
| 709d2c0f5d | |||
| de01ee9387 | |||
| 79f8c91157 | |||
| 787f911b6f | |||
| 7c490d2180 | |||
| aa3de59652 | |||
| bae6a56ed3 | |||
| f7cb93d768 | |||
| b07933ea08 | |||
| e9d4b4c6a2 | |||
| 2ac8d26687 | |||
| dcd55275b5 | |||
| e38199e6c7 | |||
| af4106614c | |||
| c720a80bc0 | |||
| 345da8394b | |||
| d465b0a4be | |||
| d4d6978d5f | |||
| e507d1f75d |
+81
-42
@@ -1,67 +1,106 @@
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
#project(TeamSpeak)
|
||||
project(TeaSpeak-Parent)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/Modules")
|
||||
set(TEASPEAK_SERVER ON)
|
||||
|
||||
include_directories(/usr/local/mysql/connector-c++-8.0/include/jdbc/)
|
||||
#end now
|
||||
#set(MEMORY_DEBUG_FLAGS " -fsanitize=leak -fsanitize=address -fstack-protector-all ")
|
||||
#set(MEMORY_DEBUG_FLAGS "-fsanitize=address")
|
||||
|
||||
if (NOT BUILD_OS_ARCH)
|
||||
set(BUILD_OS_ARCH $ENV{build_os_arch})
|
||||
endif ()
|
||||
|
||||
if (NOT BUILD_OS_ARCH)
|
||||
set(BUILD_OS_ARCH $ENV{build_os_arch})
|
||||
endif ()
|
||||
|
||||
set(LIBRARY_PATH "${CMAKE_SOURCE_DIR}/../libraries/")
|
||||
if (BUILD_INCLUDE_FILE)
|
||||
include(${BUILD_INCLUDE_FILE})
|
||||
endif ()
|
||||
|
||||
set(CMAKE_PREFIX_PATH "/home/wolverindev/clib/qt/5.6.1/5.6/gcc_64/lib/cmake")
|
||||
set(LIBEVENT_PATH "${LIBRARY_PATH}/event/build/lib/")
|
||||
|
||||
function(resolve_library VARIABLE FALLBACK PATHS)
|
||||
set( _PATHS ${PATHS} ${ARGN} ) # Merge them together
|
||||
set( _PATHS ${PATHS} ${ARGN} ) # Merge them together
|
||||
|
||||
foreach(PATH IN ITEMS ${_PATHS})
|
||||
message(STATUS "Try to use path ${PATH} for ${VARIABLE}")
|
||||
if(EXISTS ${PATH})
|
||||
message(STATUS "Setting ${VARIABLE} to ${PATH}")
|
||||
set(${VARIABLE} ${PATH} PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
endforeach()
|
||||
foreach(PATH IN ITEMS ${_PATHS})
|
||||
message(STATUS "Try to use path ${PATH} for ${VARIABLE}")
|
||||
if(EXISTS ${PATH})
|
||||
message(STATUS "Setting ${VARIABLE} to ${PATH}")
|
||||
set(${VARIABLE} ${PATH} PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(FALLBACK)
|
||||
message(WARNING "Failed to resolve library path for ${VARIABLE}. Using default ${VARIABLE}")
|
||||
else()
|
||||
message(FATAL_ERROR "Failed to find requited library. Variable: ${VARIABLE} Paths: ${_PATHS}")
|
||||
endif()
|
||||
if(FALLBACK)
|
||||
message(WARNING "Failed to resolve library path for ${VARIABLE}. Using default ${VARIABLE}")
|
||||
else()
|
||||
message(FATAL_ERROR "Failed to find requited library. Variable: ${VARIABLE} Paths: ${_PATHS}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
resolve_library(LIBRARY_TOM_MATH OFF "${LIBRARY_PATH}/tommath/build/libtommathStatic.a")
|
||||
resolve_library(LIBRARY_TOM_CRYPT OFF "${LIBRARY_PATH}/tomcrypt/libtomcrypt.a")
|
||||
resolve_library(LIBRARY_PATH_BREAKPAD OFF "${LIBRARY_PATH}/breakpad/build/src/client/linux/libbreakpad_client.a")
|
||||
resolve_library(LIBRARY_PATH_PROTOBUF OFF "${LIBRARY_PATH}/protobuf/build/libprotobuf.a")
|
||||
resolve_library(LIBRARY_PATH_BORINGSSL_SSL OFF "${LIBRARY_PATH}/boringssl/build/ssl/libssl.so")
|
||||
resolve_library(LIBRARY_PATH_BORINGSSL_CRYPTO OFF "${LIBRARY_PATH}/boringssl/build/crypto/libcrypto.so")
|
||||
resolve_library(LIBRARY_PATH_THREAD_POOL OFF "${LIBRARY_PATH}/Thread-Pool/build/libThreadPoolStatic.a")
|
||||
resolve_library(LIBRARY_PATH_TERMINAL OFF "${LIBRARY_PATH}/CXXTerminal/build/libCXXTerminalStatic.a")
|
||||
resolve_library(LIBRARY_PATH_VARIBALES OFF "${LIBRARY_PATH}/StringVariable/build/libStringVariablesStatic.a")
|
||||
resolve_library(LIBRARY_PATH_YAML OFF "${LIBRARY_PATH}/yaml-cpp/build/libyaml-cpp.a")
|
||||
resolve_library(LIBRARY_PATH_JSON OFF "${LIBRARY_PATH}/jsoncpp/build/src/lib_json/libjsoncpp.a")
|
||||
resolve_library(LIBRARY_PATH_ED255 OFF "${LIBRARY_PATH}/ed25519/build/libed25519.a")
|
||||
resolve_library(LIBRARY_PATH_DATA_PIPES OFF "${LIBRARY_PATH}/DataPipes/build/libDataPipes.so" "${LIBRARY_PATH}/DataPipes/cmake-build-release/libDataPipes.so" "${LIBRARY_PATH}/DataPipes/cmake-build-debug/libDataPipes.so")
|
||||
resolve_library(LIBRARY_PATH_OPUS OFF "${LIBRARY_PATH}/opus/build/.libs/libopus.a")
|
||||
find_package(TomMath REQUIRED)
|
||||
find_package(TomCrypt REQUIRED)
|
||||
find_package(Breakpad REQUIRED)
|
||||
find_package(Protobuf REQUIRED)
|
||||
find_package(Boringssl REQUIRED)
|
||||
find_package(ThreadPool REQUIRED)
|
||||
find_package(CXXTerminal REQUIRED)
|
||||
find_package(StringVariable REQUIRED)
|
||||
find_package(yaml-cpp REQUIRED)
|
||||
find_package(jsoncpp REQUIRED)
|
||||
find_package(Ed25519 REQUIRED)
|
||||
find_package(DataPipes REQUIRED)
|
||||
find_package(Opus REQUIRED)
|
||||
find_package(spdlog REQUIRED)
|
||||
find_package(Jemalloc REQUIRED)
|
||||
find_package(Protobuf REQUIRED)
|
||||
|
||||
#if(EXISTS ${CMAKE_SOURCE_DIR}/../libraries/mysqlconnector/build/libmysqlcppconn8.so.1)
|
||||
# set(LIBRARY_PATH_MYSQL "${CMAKE_SOURCE_DIR}/../libraries/mysqlconnector/build/libmysqlcppconn8.so.1")
|
||||
#else()
|
||||
# set(LIBRARY_PATH_MYSQL "libmysqlcppconn8-static.a")
|
||||
# message(WARNING "Could not resolve mysql! Using default resolver")
|
||||
#endif()
|
||||
include_directories(${StringVariable_INCLUDE_DIR})
|
||||
add_subdirectory(music/)
|
||||
|
||||
# LibEvent fucks up the CMAKE_FIND_LIBRARY_SUFFIXES variable
|
||||
macro(find_event static)
|
||||
set(_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
if (${static})
|
||||
set(LIBEVENT_STATIC_LINK TRUE)
|
||||
message("Use static libevent")
|
||||
endif ()
|
||||
find_package(Libevent 2.2 REQUIRED COMPONENTS core pthreads)
|
||||
if (NOT Libevent_FOUND)
|
||||
message(FATAL_ERROR "Failed to find libevent (Variable: ${LIBEVENT_FOUND})")
|
||||
endif ()
|
||||
message("Libevent version: ${Libevent_FOUND}")
|
||||
endmacro()
|
||||
find_event(TRUE)
|
||||
|
||||
check_include_file(mysql/mysql.h HAVE_MYSQL_MYSQL_H)
|
||||
if(HAVE_MYSQL_MYSQL_H)
|
||||
add_definitions(-DHAVE_MYSQL_MYSQL_H)
|
||||
endif()
|
||||
|
||||
check_include_file(mysql.h HAVE_MYSQL_H)
|
||||
if(HAVE_MYSQL_H)
|
||||
add_definitions(-DHAVE_MYSQL_H)
|
||||
endif()
|
||||
|
||||
#FIXME: Use module for this
|
||||
include_directories(${breakpad_INCLUDE_DIR})
|
||||
include_directories(${ed25519_INCLUDE_DIR})
|
||||
include_directories(${ThreadPool_INCLUDE_DIR})
|
||||
include_directories(${DataPipes_INCLUDE_DIR})
|
||||
include_directories(${LIBEVENT_INCLUDE_DIRS})
|
||||
include_directories(${StringVariable_INCLUDE_DIR})
|
||||
|
||||
add_definitions(-DINET -DINET6)
|
||||
|
||||
add_subdirectory(shared/)
|
||||
add_subdirectory(client/)
|
||||
add_subdirectory(server/)
|
||||
add_subdirectory(license/)
|
||||
add_subdirectory(flooder/)
|
||||
add_subdirectory(MusicBot/)
|
||||
add_subdirectory(music/)
|
||||
add_subdirectory(MusicBot/)
|
||||
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.6)
|
||||
project(TeaMusic)
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fpermissive -Wall -Wno-sign-compare -Wno-reorder -static-libgcc -static-libstdc++ -Wl,--enable-new-dtags,--export-dynamic")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fpermissive -Wall -Wno-sign-compare -Wno-reorder -static-libgcc -static-libstdc++")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/enviroment/)
|
||||
@@ -10,12 +10,13 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/libs/)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
include_directories(../music/include/)
|
||||
include_directories(../shared/src)
|
||||
add_definitions(-DLTM_DESC)
|
||||
|
||||
#The basic library
|
||||
add_library(TeaMusic SHARED src/MusicPlayer.cpp)
|
||||
target_link_libraries(TeaMusic PUBLIC TeaSpeak libevent::core libevent::pthreads dl)
|
||||
|
||||
#The test file
|
||||
add_executable(TeaMusicTest ${MUSIC_SOURCE_FILES} main.cpp)
|
||||
target_link_libraries(TeaMusicTest ProviderFFMpeg ProviderYT ProviderOpus TeaMusic pthread ThreadPool opus asound opusfile stdc++fs dl mpg123 avformat avcodec avutil TeaSpeak CXXTerminal event jsoncpp)
|
||||
target_link_libraries(TeaMusicTest ProviderFFMpeg ProviderYT TeaMusic pthread asound dl stdc++fs)
|
||||
#ThreadPool opus asound opusfile stdc++fs dl TeaSpeak CXXTerminal event jsoncpp
|
||||
@@ -1,249 +0,0 @@
|
||||
# Musik bot websocket protocol
|
||||
## General structure
|
||||
Transmitted data is in json format
|
||||
The json format has the structure as following:
|
||||
```
|
||||
{
|
||||
"type": <PacketType>,
|
||||
"data": [
|
||||
{
|
||||
<key>: value
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
Example:
|
||||
```
|
||||
{
|
||||
"type": "showMessage",
|
||||
"data": [
|
||||
{
|
||||
"message": "A simple info modal",
|
||||
"type": "info"
|
||||
},
|
||||
{
|
||||
"message": "A simple error modal",
|
||||
"type": "error"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
## TODO list
|
||||
* Music bot queue
|
||||
* Music bot ts3 access rights (allow other clients to use this music bot etc.)
|
||||
|
||||
## Packet types
|
||||
### General types
|
||||
#### Server `showMessage`:
|
||||
This packet should show up a message modal.
|
||||
* **[~]**
|
||||
* `message`: <msg>
|
||||
* `type`: {info|error}
|
||||
|
||||
|
||||
#### Server `reqError`:
|
||||
The server sends this if you applay a invalid request
|
||||
* **[1]**
|
||||
* `message`: <msg>
|
||||
* `requestId`: <reqestId>
|
||||
|
||||
|
||||
#### Server `disconnect`
|
||||
I send this packet before i close the comunication
|
||||
* **[1]**
|
||||
* `message`
|
||||
|
||||
___
|
||||
### Login packets
|
||||
#### Client `login`
|
||||
Try login
|
||||
* **[1]**
|
||||
* `username`
|
||||
* `password`
|
||||
* `requestId`
|
||||
|
||||
|
||||
#### Server `notifylogin`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `succeeded`: {0|1}
|
||||
* `uid` own uid. only set if login failed
|
||||
* `message` only set if login failed
|
||||
|
||||
#### Client `logout`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
|
||||
#### Server `notifylogout`
|
||||
Could be send at any time (force logout)
|
||||
* **[1]**
|
||||
* `requestId` (empty of not requested)
|
||||
* `succeeded`: {0|1}
|
||||
|
||||
___
|
||||
### Server Management
|
||||
#### Client `serverlist`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
|
||||
#### Server `notifyserverlist`
|
||||
Sends when requested or list updated
|
||||
(Lists online avariable server for the client view)
|
||||
* **[~]**
|
||||
* [1] `requestId` (empty of not requested)
|
||||
* `name`
|
||||
* `uid`
|
||||
* `serverId`
|
||||
* `status`: {online|offline}
|
||||
* `clientOnline`
|
||||
* `maxClients`
|
||||
|
||||
#### Server `notifyserverupdate`
|
||||
Sends when a server changes display properties
|
||||
* **[1]**
|
||||
* `serverId`
|
||||
* `key`: {name|onlineClients|maxClients}
|
||||
* `value`
|
||||
|
||||
___
|
||||
### Channel Management
|
||||
#### Client `channellist`
|
||||
Request a channel list
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
|
||||
#### Server `notifychannellist`
|
||||
The channel response is ordered:
|
||||
This packet would also be send if the channel tree gets updated
|
||||
```
|
||||
root
|
||||
- sub 1
|
||||
- sub sub 1
|
||||
- sub sub 2
|
||||
- sub 2
|
||||
root 2
|
||||
...
|
||||
```
|
||||
* **[~]**
|
||||
* [1] `requestId` (empty of not requested)
|
||||
* [1] `serverId`
|
||||
* `name`
|
||||
* `channelId`
|
||||
* `channelParent`
|
||||
* `channelOrder`
|
||||
|
||||
___
|
||||
### Music bot management
|
||||
#### Client `musicbotlist`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
|
||||
#### Server `notifymusikmusicbotlist`
|
||||
* **[~]**
|
||||
* [1] `requestId` (empty of not requested)
|
||||
* [1] `serverId`
|
||||
* `id`
|
||||
* `connected`: {1|0}
|
||||
* `name`
|
||||
* `channelId`
|
||||
* `ownerUid` (its your own if its matching with our own id)
|
||||
* `ownerCldbid`
|
||||
|
||||
#### Client `musicbotcreate`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
* `name`
|
||||
* `channelId`
|
||||
|
||||
#### Server `notifymusikbotcreated`
|
||||
* **[1]**
|
||||
* `requestId` (empty of not requested)
|
||||
* `serverId`
|
||||
* `id`
|
||||
* `connected`: {1|0}
|
||||
* `name`
|
||||
* `channelId`
|
||||
* `ownerUid` (its your own if its matching with our own id)
|
||||
* `ownerCldbid`
|
||||
|
||||
#### Client `musicbotdelete`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
* `name`
|
||||
* `channelId`
|
||||
|
||||
#### Server `notifymusikbotdelete`
|
||||
* **[1]**
|
||||
* `requestId` (empty of not requested)
|
||||
* `serverId`
|
||||
* `id`
|
||||
|
||||
#### Client `musicbotinfo`
|
||||
Request music bot info
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
* `id`
|
||||
|
||||
#### Server `notifymusicbotinfo`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
* `id`
|
||||
* `name`
|
||||
* `connected`
|
||||
* `phoeticName`
|
||||
* `channelId`
|
||||
* `playing`
|
||||
* `playingInfo`: <string|Current playing title etc. May need to be inproved> Empty if noting selected
|
||||
* `description`
|
||||
* `textCurrentSong`
|
||||
|
||||
#### Client `musicbotedit`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
* `id`
|
||||
* `key`
|
||||
* `value`
|
||||
|
||||
#### Server `notifymusicbotedit`
|
||||
* **[~]**
|
||||
* [1] `requestId` (empty of not requested)
|
||||
* [1] `serverId`
|
||||
* `id`
|
||||
* `key`: {connected|name|channelId|description|playing|playingInfo}
|
||||
|
||||
#### Client `musicbotplay`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
* `id`
|
||||
* `type`: {yt|file}
|
||||
* `value`
|
||||
|
||||
#### Server `notifymusicbotplay`
|
||||
Send only as answer for `musicbotplay`
|
||||
You would recive the play state update via `notifymusicbotedit`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `succeeded`
|
||||
*
|
||||
#### Client `musicbotstop`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `serverId`
|
||||
* `id`
|
||||
* `paused`: {1|0}
|
||||
|
||||
#### Server `notifymusicbotstop`
|
||||
Send only as answer for `musicbotstop`
|
||||
You would recive the play state update via `notifymusicbotedit`
|
||||
* **[1]**
|
||||
* `requestId`
|
||||
* `succeeded`
|
||||
+48
-100
@@ -3,13 +3,8 @@
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
#include <MusicPlayer.h>
|
||||
#include <teaspeak/MusicPlayer.h>
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/avutil.h>
|
||||
}
|
||||
#include <log/LogUtils.h>
|
||||
#include <CXXTerminal/Terminal.h>
|
||||
|
||||
@@ -18,18 +13,17 @@ using namespace std;
|
||||
using namespace std::chrono;
|
||||
using namespace music;
|
||||
|
||||
void die(const char* message)
|
||||
{
|
||||
void die(const char *message) {
|
||||
fprintf(stderr, "%s\n", message);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int, char**){
|
||||
logger::config::logLevel = spdlog::level::trace;
|
||||
logger::config::terminalLevel = spdlog::level::trace;
|
||||
//terminal::install();
|
||||
|
||||
logger::setup();
|
||||
int main(int, char **) {
|
||||
auto config = std::make_shared<logger::LoggerConfig>();
|
||||
config->logfileLevel = spdlog::level::off;
|
||||
config->terminalLevel = spdlog::level::trace;
|
||||
config->sync = true;
|
||||
logger::setup(config);
|
||||
logger::updateLogLevels();
|
||||
|
||||
//youtube-dl -s --dump-json https://www.youtube.com/watch?v=1ifTLj_glhc
|
||||
@@ -37,126 +31,77 @@ int main(int, char**){
|
||||
//
|
||||
|
||||
//printf("Length: %d\n", codec_context->frame_size / codec_context->framerate.den / codec_context->channels); //576 | 3
|
||||
/*
|
||||
// To initalize libao for playback
|
||||
ao_initialize();
|
||||
|
||||
int driver = ao_default_driver_id();
|
||||
music::manager::loadProviders("../../music/bin/providers/");
|
||||
|
||||
// The format of the decoded PCM samples
|
||||
ao_sample_format sample_format;
|
||||
sample_format.bits = 16;
|
||||
sample_format.channels = 2;
|
||||
sample_format.rate = 44100;
|
||||
sample_format.byte_format = AO_FMT_NATIVE;
|
||||
sample_format.matrix = 0;
|
||||
|
||||
ao_device* device = ao_open_live(driver, &sample_format, NULL);
|
||||
|
||||
AVPacket packet;
|
||||
int buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
|
||||
int8_t buffer[AVCODEC_MAX_AUDIO_FRAME_SIZE];
|
||||
|
||||
while (1) {
|
||||
|
||||
buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
|
||||
|
||||
// Read one packet into `packet`
|
||||
if (av_read_frame(container, &packet) < 0) {
|
||||
break; // End of lstream. Done decoding.
|
||||
}
|
||||
|
||||
// Decodes from `packet` into the buffer
|
||||
if (avcodec_decode_audio3(codec_context, (int16_t*)buffer, &buffer_size, &packet) < 1) {
|
||||
break; // Error in decoding
|
||||
}
|
||||
|
||||
// Send the buffer contents to the audio device
|
||||
ao_play(device, (char*)buffer, buffer_size);
|
||||
}
|
||||
|
||||
av_close_input_file(container);
|
||||
|
||||
ao_shutdown();
|
||||
|
||||
fprintf(stdout, "Done playing. Exiting...");
|
||||
*/
|
||||
|
||||
music::manager::loadProviders("providers/");
|
||||
#if false
|
||||
std::string file = "https://www.youtube.com/watch?v=GVC5adzPpiE"; //https://www.youtube.com/watch?v=eBlg2oX0Z0Q
|
||||
auto provider = music::manager::resolveProvider("YouTube", file); //test.mp3
|
||||
if(!provider) return 0;
|
||||
cout << "Using provider -> " << provider->providerName << endl;
|
||||
cout << "Using provider -> " << provider->providerDescription << endl;
|
||||
if(true) return 0;
|
||||
/*
|
||||
auto fut = provider->createPlayer(file);
|
||||
fut.waitAndGet(nullptr);
|
||||
if(fut.failed()){
|
||||
log::log(log::err, "Could not create: " + fut.errorMegssage());
|
||||
} else log::log(log::info, "Got!");
|
||||
//VALID
|
||||
/*
|
||||
auto player = provider->createPlayer("https://r5---sn-4g5edned.googlevideo.com/videoplayback?lmt=1491636391724572&key=yt6&itag=251&keepalive=yes&signature=8220B0B2D85AFE6A44CAE901A9C5A5D9A2564DA4.59183C41417E91E04552835738ED0AD1592BD05E&source=youtube&clen=4017657&sparams=clen%2Cdur%2Cei%2Cgir%2Cid%2Cinitcwndbps%2Cip%2Cipbits%2Citag%2Ckeepalive%2Clmt%2Cmime%2Cmm%2Cmn%2Cms%2Cmv%2Cpl%2Crequiressl%2Csource%2Cexpire&gir=yes&expire=1516917262&initcwndbps=856250&ei=rv1pWuvYBI-AV7SlqaAE&dur=234.061&mv=m&mt=1516895537&ms=au&requiressl=yes&ip=93.230.21.99&ipbits=0&mn=sn-4g5edned&mm=31&pl=26&mime=audio%2Fwebm&id=o-ABQnAlwQxtPQJTqHMc9SiTD-bGc1YR2yogmPcVUy1Xxp&ratebypass=yes").waitAndGet(nullptr);
|
||||
/*
|
||||
auto player = provider->createPlayer("https://r5---sn-4g5edned.googlevideo.com/videoplayback?mn=sn-4g5edned&mm=31&gir=yes&clen=4017657&requiressl=yes&mv=m&mt=1516820571&ms=au&ei=tdhoWtv0Fd5bY1wLY5qVA&lmt=1491636391724572&key=yt6&ip=80.133.238.232&expire=1516842261&dur=234.061&beids=%5B9466594%5D&id=o-AKeOawWpz0BT9Qxuqria6qw1_eTa3is7UXit4BLIC8re&initcwndbps=591250&source=youtube&sparams=clen%2Cdur%2Cei%2Cgir%2Cid%2Cinitcwndbps%2Cip%2Cipbits%2Citag%2Ckeepalive%2Clmt%2Cmime%2Cmm%2Cmn%2Cms%2Cmv%2Cpl%2Crequiressl%2Csource%2Cexpire&ipbits=0&signature=230305B8592A57E939FDBF2D4C19C16DC2FE0D68.AC475B47E4533071F4A6EA96960384398A15D801&pl=26&itag=251&mime=audio%2Fwebm&keepalive=yes&ratebypass=yes").waitAndGet(nullptr);
|
||||
*/
|
||||
auto player = provider->createPlayer(file).waitAndGet(nullptr);
|
||||
if(!player){
|
||||
#endif
|
||||
constexpr auto url = "https://streams.ilovemusic.de/iloveradio1.mp3";
|
||||
auto provider = music::manager::resolveProvider("ffmpeg", url);
|
||||
if (!provider) return 0;
|
||||
|
||||
auto player = provider->createPlayer(url, nullptr, nullptr).waitAndGet(nullptr);
|
||||
if (!player) {
|
||||
cerr << "Could not load youtube video" << endl;
|
||||
return -1;
|
||||
}
|
||||
if(!player->initialize()){
|
||||
if (!player->initialize(2)) {
|
||||
log::log(log::err, "Could not inizalisze ffmpeg player -> " + player->error());
|
||||
return 1;
|
||||
}
|
||||
player->registerEventHandler("main", [player](music::MusicEvent event){ //FIXME weak ptr
|
||||
player->registerEventHandler("main", [player](music::MusicEvent event) { //FIXME weak ptr
|
||||
log::log(log::info, "Got event " + to_string(event));
|
||||
if(event == music::EVENT_ERROR) {
|
||||
if (event == music::EVENT_ERROR) {
|
||||
log::log(log::err, "Recived error: " + player->error());
|
||||
player->clearError();
|
||||
}
|
||||
});
|
||||
player->play();
|
||||
player->forward(chrono::minutes(0));
|
||||
//player->forward(chrono::minutes(0));
|
||||
cout << "Song length " << duration_cast<seconds>(player->length()).count() << " seconds" << endl;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds{600});
|
||||
|
||||
unsigned int pcm, tmp, dir;
|
||||
#if false
|
||||
snd_pcm_t *pcm{nullptr};
|
||||
int err, tmp, dir;
|
||||
snd_pcm_t *pcm_handle;
|
||||
snd_pcm_hw_params_t *params;
|
||||
snd_pcm_uframes_t frames;
|
||||
int loops;
|
||||
|
||||
int channels = 2;
|
||||
int rate = 48000;
|
||||
unsigned int rate = 48000;
|
||||
int seconds = duration_cast<std::chrono::seconds>(player->length()).count() + 1;
|
||||
seconds = 10000;
|
||||
|
||||
if (pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0) < 0)
|
||||
printf("ERROR: Can't open \"%s\" PCM device. %s\n",
|
||||
PCM_DEVICE, snd_strerror(pcm));
|
||||
if (err = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0); err < 0)
|
||||
printf("ERROR: Can't open \"%s\" PCM device. %s\n", PCM_DEVICE, snd_strerror(err));
|
||||
|
||||
snd_pcm_hw_params_alloca(¶ms);
|
||||
|
||||
snd_pcm_hw_params_any(pcm_handle, params);
|
||||
|
||||
if (pcm = snd_pcm_hw_params_set_access(pcm_handle, params,
|
||||
SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
|
||||
printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(pcm));
|
||||
if (err = snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); err < 0)
|
||||
printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(err));
|
||||
|
||||
if (pcm = snd_pcm_hw_params_set_format(pcm_handle, params,
|
||||
SND_PCM_FORMAT_S16_LE) < 0)
|
||||
printf("ERROR: Can't set format. %s\n", snd_strerror(pcm));
|
||||
if (err = snd_pcm_hw_params_set_format(pcm_handle, params, SND_PCM_FORMAT_S16_LE); err < 0)
|
||||
printf("ERROR: Can't set format. %s\n", snd_strerror(err));
|
||||
|
||||
if (pcm = snd_pcm_hw_params_set_channels(pcm_handle, params, channels) < 0)
|
||||
printf("ERROR: Can't set channels number. %s\n", snd_strerror(pcm));
|
||||
if (err = snd_pcm_hw_params_set_channels(pcm_handle, params, channels); err < 0)
|
||||
printf("ERROR: Can't set channels number. %s\n", snd_strerror(err));
|
||||
|
||||
if (pcm = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0) < 0)
|
||||
printf("ERROR: Can't set rate. %s\n", snd_strerror(pcm));
|
||||
if (err = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0); err < 0)
|
||||
printf("ERROR: Can't set rate. %s\n", snd_strerror(err));
|
||||
|
||||
if (pcm = snd_pcm_hw_params(pcm_handle, params) < 0)
|
||||
printf("ERROR: Can't set harware parameters. %s\n", snd_strerror(pcm));
|
||||
if (err = snd_pcm_hw_params(pcm_handle, params); err < 0)
|
||||
printf("ERROR: Can't set harware parameters. %s\n", snd_strerror(err));
|
||||
|
||||
printf("PCM name: '%s'\n", snd_pcm_name(pcm_handle));
|
||||
printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(pcm_handle)));
|
||||
@@ -174,9 +119,9 @@ int main(int, char**){
|
||||
|
||||
printf("seconds: %d\n", seconds);
|
||||
|
||||
snd_pcm_hw_params_get_period_size(params, &frames, 0);
|
||||
snd_pcm_hw_params_get_period_size(params, &frames, nullptr);
|
||||
cout << "perd size: " << frames << endl;
|
||||
snd_pcm_hw_params_get_period_time(params, &tmp, NULL);
|
||||
snd_pcm_hw_params_get_period_time(params, &tmp, nullptr);
|
||||
player->preferredSampleCount(frames);
|
||||
|
||||
auto last = system_clock::now();
|
||||
@@ -184,27 +129,30 @@ int main(int, char**){
|
||||
//cout << " dur: " << duration_cast<microseconds>(system_clock::now() - last).count() << endl;
|
||||
|
||||
auto next = player->popNextSegment();
|
||||
if(!next) {
|
||||
if (!next) {
|
||||
log::log(log::info, "END!");
|
||||
continue;
|
||||
}
|
||||
retry:
|
||||
if (pcm = snd_pcm_writei(pcm_handle, next->segments, next->segmentLength) == -EPIPE) {
|
||||
if (err = snd_pcm_writei(pcm_handle, next->segments, next->segmentLength); err == -EPIPE) {
|
||||
printf("XRUN.\n");
|
||||
snd_pcm_prepare(pcm_handle);
|
||||
goto retry;
|
||||
} else if (pcm < 0) {
|
||||
printf("ERROR. Can't write to PCM device. %s\n", snd_strerror(pcm));
|
||||
printf("ERROR. Can't write to PCM device. %s\n", snd_strerror(err));
|
||||
}
|
||||
//if((system_clock::now() - last) > ::seconds(1)) {
|
||||
log::log(log::debug, "Time: " + to_string(duration_cast<milliseconds>(system_clock::now() - last).count()) + " | " + to_string(duration_cast<milliseconds>(player->currentIndex()).count()));
|
||||
last = system_clock::now();
|
||||
log::log(log::debug,
|
||||
"Time: " + to_string(duration_cast<milliseconds>(system_clock::now() - last).count()) + " | " +
|
||||
to_string(duration_cast<milliseconds>(player->currentIndex()).count()));
|
||||
last = system_clock::now();
|
||||
//}
|
||||
//TODO!
|
||||
}
|
||||
|
||||
snd_pcm_drain(pcm_handle);
|
||||
snd_pcm_close(pcm_handle);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <algorithm>
|
||||
#include <log/LogUtils.h>
|
||||
#include <experimental/filesystem>
|
||||
#include "MusicPlayer.h"
|
||||
#include "teaspeak/MusicPlayer.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace music;
|
||||
@@ -15,14 +15,14 @@ void log::log(const Level& lvl, const std::string& msg) {
|
||||
}
|
||||
|
||||
void AbstractMusicPlayer::registerEventHandler(const std::string& key, const std::function<void(MusicEvent)>& function) {
|
||||
threads::MutexLock lock(this->eventLock);
|
||||
this->eventHandlers.push_back({key, function});
|
||||
std::lock_guard lock(this->eventLock);
|
||||
this->eventHandlers.emplace_back(key, function);
|
||||
}
|
||||
|
||||
void AbstractMusicPlayer::unregisterEventHandler(const std::string& string) {
|
||||
threads::MutexLock lock(this->eventLock);
|
||||
std::lock_guard lock(this->eventLock);
|
||||
for(const auto& entry : this->eventHandlers){
|
||||
if(entry.first == string){
|
||||
if(entry.first == string) {
|
||||
this->eventHandlers.erase(find_if(this->eventHandlers.begin(), this->eventHandlers.end(), [string](const std::pair<std::string, std::function<void(MusicEvent)>>& elm){ return elm.first == string; }));
|
||||
break;
|
||||
}
|
||||
@@ -30,7 +30,7 @@ void AbstractMusicPlayer::unregisterEventHandler(const std::string& string) {
|
||||
}
|
||||
|
||||
void AbstractMusicPlayer::fireEvent(MusicEvent event) {
|
||||
threads::MutexLock lock(this->eventLock);
|
||||
std::lock_guard lock(this->eventLock);
|
||||
auto listCopy = this->eventHandlers; //Copy for remove while fire
|
||||
for(const auto& entry : listCopy)
|
||||
entry.second(event);
|
||||
@@ -38,18 +38,18 @@ void AbstractMusicPlayer::fireEvent(MusicEvent event) {
|
||||
|
||||
const char* music::stateNames[] = {"uninitialised", "playing", "paused", "stopped"};
|
||||
|
||||
static threads::Mutex staticLock;
|
||||
static std::mutex staticLock;
|
||||
static std::deque<std::shared_ptr<PlayerProvider>> types;
|
||||
|
||||
std::deque<std::shared_ptr<PlayerProvider>> manager::registeredTypes(){ return types; }
|
||||
void registerType(const std::shared_ptr<PlayerProvider>& provider) {
|
||||
threads::MutexLock l(staticLock);
|
||||
std::lock_guard l(staticLock);
|
||||
types.push_back(provider);
|
||||
}
|
||||
|
||||
//empty for not set
|
||||
std::shared_ptr<PlayerProvider> manager::resolveProvider(const std::string& provName, const std::string& str) {
|
||||
threads::MutexLock l(staticLock);
|
||||
std::lock_guard l(staticLock);
|
||||
vector<std::shared_ptr<PlayerProvider>> provs;
|
||||
for(const auto& prov : types){
|
||||
auto p = prov.get();
|
||||
@@ -111,5 +111,11 @@ void manager::loadProviders(const std::string& path) {
|
||||
}
|
||||
|
||||
void manager::register_provider(const std::shared_ptr<music::manager::PlayerProvider> &provider) {
|
||||
std::lock_guard l(staticLock);
|
||||
types.push_back(provider);
|
||||
}
|
||||
|
||||
void manager::finalizeProviders() {
|
||||
std::lock_guard l(staticLock);
|
||||
types.clear();
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
project(TeamSpeak)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -static-libgcc -static-libstdc++ -pthread ${MEMORY_DEBUG_FLAGS}")
|
||||
|
||||
include_directories(../shared/src)
|
||||
add_definitions(-DLTM_DESC)
|
||||
|
||||
set(SOURCE_FILES
|
||||
main.cpp
|
||||
src/protocol/Connection.cpp
|
||||
src/protocol/ConnectionHandschake.cpp
|
||||
src/protocol/ConnectionPacketHandler.cpp
|
||||
|
||||
src/protocol/socket/FilteredUDPSocket.cpp
|
||||
src/protocol/socket/RawUDPSocket.cpp
|
||||
|
||||
src/Identity.cpp
|
||||
src/MultithreadedIdentity.cpp
|
||||
src/protocol/HandshakeNew.cpp
|
||||
|
||||
../shared/src/License.cpp
|
||||
)
|
||||
|
||||
find_package(Protobuf REQUIRED)
|
||||
include_directories(${Protobuf_INCLUDE_DIRS})
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS proto/LicenseKey.proto)
|
||||
|
||||
add_executable(TeamSpeakClient ${SOURCE_FILES} ${PROTO_SRCS})
|
||||
target_link_libraries(TeamSpeakClient
|
||||
${LIBRARY_PATH_THREAD_POOL} #Static
|
||||
TeaSpeak #Static
|
||||
TeaLicenseHelper #Static
|
||||
TeaMusic #Static
|
||||
${LIBRARY_PATH_TERMINAL} #Static
|
||||
${LIBRARY_PATH_VARIBALES}
|
||||
${LIBRARY_PATH_YAML}
|
||||
pthread
|
||||
stdc++fs
|
||||
${LIBEVENT_PATH}/libevent.a
|
||||
${LIBEVENT_PATH}/libevent_pthreads.a
|
||||
opus.a
|
||||
${LIBRARY_PATH_JSON}
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
|
||||
DataPipes
|
||||
#${LIBWEBRTC_LIBRARIES} #ATTENTIAN! WebRTC does not work with crypto! (Already contains a crypto version)
|
||||
${LIBRARY_TOM_CRYPT}
|
||||
${LIBRARY_TOM_MATH}
|
||||
|
||||
#We're forsed to use boringssl caused by the fact that boringssl is already within webrtc!
|
||||
|
||||
#Require a so
|
||||
sqlite3
|
||||
${LIBRARY_PATH_ED255}
|
||||
|
||||
${LIBRARY_PATH_BREAKPAD}
|
||||
${LIBRARY_PATH_JDBC}
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
|
||||
${LIBRARY_PATH_BORINGSSL_SSL}
|
||||
${LIBRARY_PATH_BORINGSSL_CRYPTO}
|
||||
)
|
||||
|
||||
#strip -s -p -v TeamSpeakHash
|
||||
add_executable(TeamSpeakHash src/Identity.cpp src/MultithreadedIdentity.cpp identityHash.cpp)
|
||||
#set_target_properties(TeamSpeakHash PROPERTIES CMAKE_CXX_FLAGS "-o1")
|
||||
|
||||
target_link_libraries(TeamSpeakHash
|
||||
TeaSpeak
|
||||
ThreadPoolStatic
|
||||
pthread
|
||||
${TOM_LIBRARIES}
|
||||
${LIBRARY_TOM_CRYPT}
|
||||
${LIBRARY_TOM_MATH}
|
||||
${LIBRARY_PATH_BORINGSSL_SSL}
|
||||
${LIBRARY_PATH_BORINGSSL_CRYPTO}
|
||||
)
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/preprocessor/seq/for_each_i.hpp>
|
||||
#include <boost/preprocessor/seq/enum.hpp>
|
||||
|
||||
#define CRYPT_MACRO(r, d, i, elem) ( elem ^ ( d - i ) )
|
||||
|
||||
#define DEFINE_HIDDEN_STRING(NAME, SEED, SEQ)\
|
||||
static const char* BOOST_PP_CAT(Get, NAME)()\
|
||||
{\
|
||||
static char data[] = {\
|
||||
BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH_I(CRYPT_MACRO, SEED, SEQ)),\
|
||||
'\0'\
|
||||
};\
|
||||
\
|
||||
static bool isEncrypted = true;\
|
||||
if ( isEncrypted )\
|
||||
{\
|
||||
for (unsigned i = 0; i < ( sizeof(data) / sizeof(data[0]) ) - 1; ++i)\
|
||||
{\
|
||||
data[i] = CRYPT_MACRO(_, SEED, i, data[i]);\
|
||||
}\
|
||||
\
|
||||
isEncrypted = false;\
|
||||
}\
|
||||
\
|
||||
return data;\
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
[OUT] clientinitiv alpha=kXZSTZ7qaOhblA== omega=MEwDAgcAAgEgAiA5+ycSoMRRdugndbohYtH7PqS6Q6h3TV1VnGRKoZNMsQIhANn2rszHVipB13LBcY2Zf3APg7HX7ix3WWiaT5hjQrUv ot=1 ip=84.200.62.248
|
||||
[ IN] initivexpand2 l=AQCBIiOUkbXLeQ\/6UhNB+8iJnwLYGZJglZoDFSTt+7awWgAJFtlwLxmo8AAAACVUZWFtU3BlYWsgU3lzdGVtcyBHbWJIAADtwskuiFg0FkafvNvS1uwz67b2lEhMnOkAygPvo0waGAAJQrh2HBxqvQAAACRUZWFtU3BlYWsgc3lzdGVtcyBHbWJIAADd85KDiA8UeqB5G9MBtNZ879CYBnfbjc\/OVj0j0xMcqQIJQ7qACi5lgAYAAAAAVGVhbVNwZWFrIFN5c3RlbXMgR21iSAAAitZK9P6JEXiiy+uERaapfw\/I5na7S5M+Se5IoOb\/24kgCV6OnAlfN1w= beta=5cB\/vUHLQ7GbVPNRStMLnZlyo572IFPzdgTTgxJ3zF4JBehh7nLudpdzk1hdbcglx4n3JmqX omega=MEwDAgcAAgEgAiEA83r2Er9vHr5sSEcm9g\/\/rdLjOdTMtwX\/Lkbi02+24FkCIB2P804l26yketcG8WxZQJ1z4ukU0e3SqEzm4pKHzMRY ot=1 proof=MEUCIAgYSvrPo0OKKD8aRmjeKVS1EVF6L\/DXLBT+XFkZlMVPAiEAnSMVOp8DOEMzcE42hna72+aWr+Z4+a76x23hmDJa4Uk= tvd=AQAAAABaQjKEblQQgGczKfB+CSS7IY5qli8LRS9jDltkab8leo6ltwQH82VUU\/WwnpCbazVbnh4iNbcobdxv\/MTX5Y3+6xpqDgEAEa1\/SLpE\/CIg2X7GX9mtDCCvP1KdQGaT\/RKoofPSsTkACRbZcAr4DPAAAAASVGVhbVNwZWFrIFN5c3RlbXMgR21iSAAAPgFaQLsu0h3FTQax+i0qXFXX\/Bn7VcGJH8SE5AOAiuQECVvUYwlenQk= time=1514211836
|
||||
[OUT] clientek ek=n4+LesWAJf+8ha6LlF5kWilUbj59qX+zV31asaniK8U= proof=MEQCIC+NxeqTNUQWqHz914BHkFfC3LTF8BkYAYktMB62sET7AiBPmnfN6yoB381g\/GAnZVwMkeCPIjKi9vHUk15yOdT5FQ==
|
||||
[OUT] clientinit client_nickname=P3nisBaum client_version=3.1.7\s[Build:\s1513163251] client_platform=Windows client_input_hardware=1 client_output_hardware=1 client_default_channel client_default_channel_password client_server_password client_meta_data client_version_sign=tdNngCAZ1ImAf7BxJzO4RXv5nBRsUERsrSOnMKVUFNQg6BS4Bzag0RFgLVzs2DRj19AC8+q5cXgH+5Ms50mTCA== client_key_offset=15848377 client_nickname_phonetic client_default_token client_badges=Overwolf=0 hwid=3036580947951600a7de06cd796bb0f1,7209e96ac1f60ff7772b7301919e0878
|
||||
[OUT] clientinit client_nickname=P3nisBaum client_version=3.1.7\s[Build:\s1513163251] client_platform=Windows client_input_hardware=1 client_output_hardware=1 client_default_channel client_default_channel_password client_server_password client_meta_data client_version_sign=tdNngCAZ1ImAf7BxJzO4RXv5nBRsUERsrSOnMKVUFNQg6BS4Bzag0RFgLVzs2DRj19AC8+q5cXgH+5Ms50mTCA== client_key_offset=15848377 client_nickname_phonetic client_default_token client_badges=Overwolf=0 hwid=3036580947951600a7de06cd796bb0f1,7209e96ac1f60ff7772b7301919e0878
|
||||
[ IN] error id=521 msg=too\smany\sclones\salready\sconnected
|
||||
|
||||
|
||||
|
||||
-> ot & ip needs to be set
|
||||
-> ack needs to be unencripted as look clientinitiv not done
|
||||
|
||||
|
||||
initivexpand2 l=AQCBIiOUkbXLeQ\/6UhNB+8iJnwLYGZJglZoDFSTt+7awWgAJFtlwLxmo8AAAACVUZWFtU3BlYWsgU3lzdGVtcyBHbWJIAADtwskuiFg0FkafvNvS1uwz67b2lEhMnOkAygPvo0waGAAJQrh2HBxqvQAAACRUZWFtU3BlYWsgc3lzdGVtcyBHbWJIAADd85KDiA8UeqB5G9MBtNZ879CYBnfbjc\/OVj0j0xMcqQIJQ7qACi5lgAYAAAAAVGVhbVNwZWFrIFN5c3RlbXMgR21iSAAA5Szd\/YkuL5NUF7SeHfvSKi5byOOMvYME0\/WRwlTHK8ogCV6hYglfSiI= beta=W\/D9NTwuZi6L1sbFpA+KiDBMSgl8y6Jy6vFVSGszJy1BPy8zEhNDQ62msazyAgk0CdbY0B+E omega=MEwDAgcAAgEgAiEA83r2Er9vHr5sSEcm9g\/\/rdLjOdTMtwX\/Lkbi02+24FkCIB2P804l26yketcG8WxZQJ1z4ukU0e3SqEzm4pKHzMRY ot=1 proof=MEUCIA3dgrIlXFIjkLrxJ1Yni7OqQYwPing03Xz\/zkQFrmdHAiEA8a0delCktJ21TIrj91QZbA76vtZUL38XVm+P2bR9M7c= tvd=AQAAAABaQjKEblQQgGczKfB+CSS7IY5qli8LRS9jDltkab8leo6ltwQH82VUU\/WwnpCbazVbnh4iNbcobdxv\/MTX5Y3+6xpqDgEAEa1\/SLpE\/CIg2X7GX9mtDCCvP1KdQGaT\/RKoofPSsTkACRbZcAr4DPAAAAASVGVhbVNwZWFrIFN5c3RlbXMgR21iSAAAPgFaQLsu0h3FTQax+i0qXFXX\/Bn7VcGJH8SE5AOAiuQECVvUYwlenQk= time=1514216642
|
||||
|
||||
|
||||
Nr 1
|
||||
[OUT] clientinitiv alpha=DBiidVqi8kTYAQ== omega=MEwDAgcAAgEgAiA5+ycSoMRRdugndbohYtH7PqS6Q6h3TV1VnGRKoZNMsQIhANn2rszHVipB13LBcY2Zf3APg7HX7ix3WWiaT5hjQrUv ot=1 ip=84.200.62.248
|
||||
[ IN] initivexpand2 l=AQCBIiOUkbXLeQ\/6UhNB+8iJnwLYGZJglZoDFSTt+7awWgAJFtlwLxmo8AAAACVUZWFtU3BlYWsgU3lzdGVtcyBHbWJIAADtwskuiFg0FkafvNvS1uwz67b2lEhMnOkAygPvo0waGAAJQrh2HBxqvQAAACRUZWFtU3BlYWsgc3lzdGVtcyBHbWJIAADd85KDiA8UeqB5G9MBtNZ879CYBnfbjc\/OVj0j0xMcqQIJQ7qACi5lgAYAAAAAVGVhbVNwZWFrIFN5c3RlbXMgR21iSAAALYVev\/rqwinxd2zrGZla8+69t03410Iyo9N6lV7bajMgCV6ioQlfS2E= beta=\/Eg8SA2j45sSVi28kVwBVpxT98G1w0tlenDVYuKy\/7Cn1ZZiNiwu8Z9XhGBxwrzPXrMHPEMJ omega=MEwDAgcAAgEgAiEA83r2Er9vHr5sSEcm9g\/\/rdLjOdTMtwX\/Lkbi02+24FkCIB2P804l26yketcG8WxZQJ1z4ukU0e3SqEzm4pKHzMRY ot=1 proof=MEUCIFFa+q1zdgA0OtXgdgn9gxSOMp7GBvc3vPW0YDTU2+e6AiEA8sjW3XDikxQADPoSaSw7lwL6gfXr6gwO0Hvro3RZBHU= tvd=AQAAAABaQjKEblQQgGczKfB+CSS7IY5qli8LRS9jDltkab8leo6ltwQH82VUU\/WwnpCbazVbnh4iNbcobdxv\/MTX5Y3+6xpqDgEAEa1\/SLpE\/CIg2X7GX9mtDCCvP1KdQGaT\/RKoofPSsTkACRbZcAr4DPAAAAASVGVhbVNwZWFrIFN5c3RlbXMgR21iSAAAPgFaQLsu0h3FTQax+i0qXFXX\/Bn7VcGJH8SE5AOAiuQECVvUYwlenQk= time=1514216961
|
||||
[OUT] clientek ek=19doGY4WwwAeW\/zHnmFJTpnE8h9MUJZSYFNpz4aUabs= proof=MEUCIGTwtZ1E+HjDPLqlyTuaHtvWmjYW\/\/tnQgugaC5u1swtAiEA9DN+kuwxuXG80FDzKnICGQYQGZZBySQv8Nhflg\/1FwQ=
|
||||
|
||||
|
||||
[OUT] clientinitiv alpha=3Pcn19zISkIB5g== omega=MEwDAgcAAgEgAiA5+ycSoMRRdugndbohYtH7PqS6Q6h3TV1VnGRKoZNMsQIhANn2rszHVipB13LBcY2Zf3APg7HX7ix3WWiaT5hjQrUv ot=1 ip=84.200.62.248
|
||||
[ IN] initivexpand2 l=AQCBIiOUkbXLeQ\/6UhNB+8iJnwLYGZJglZoDFSTt+7awWgAJFtlwLxmo8AAAACVUZWFtU3BlYWsgU3lzdGVtcyBHbWJIAADtwskuiFg0FkafvNvS1uwz67b2lEhMnOkAygPvo0waGAAJQrh2HBxqvQAAACRUZWFtU3BlYWsgc3lzdGVtcyBHbWJIAADd85KDiA8UeqB5G9MBtNZ879CYBnfbjc\/OVj0j0xMcqQIJQ7qACi5lgAYAAAAAVGVhbVNwZWFrIFN5c3RlbXMgR21iSAAASpEEQfPJOP8aeecPLtzcu8iYmtqBJn8MWq+8lSQljYcgCV6iyAlfS4g= beta=JLFcgyWwlYNzy5lsTGJKGz6rvmShHrb6YEZfq4TXwTLSiWDGqckf6ywiMOP2MGAc1y1yQsEi omega=MEwDAgcAAgEgAiEA83r2Er9vHr5sSEcm9g\/\/rdLjOdTMtwX\/Lkbi02+24FkCIB2P804l26yketcG8WxZQJ1z4ukU0e3SqEzm4pKHzMRY ot=1 proof=MEYCIQCpKZJCmQCHyC2PLIleZVAl1fSTdnzqcNxhiXxVAHtUHgIhAPvPfziHtiqn36nB7KSVuKV+gMA29OL87bI1HP6CJNw2 tvd=AQAAAABaQjKEblQQgGczKfB+CSS7IY5qli8LRS9jDltkab8leo6ltwQH82VUU\/WwnpCbazVbnh4iNbcobdxv\/MTX5Y3+6xpqDgEAEa1\/SLpE\/CIg2X7GX9mtDCCvP1KdQGaT\/RKoofPSsTkACRbZcAr4DPAAAAASVGVhbVNwZWFrIFN5c3RlbXMgR21iSAAAPgFaQLsu0h3FTQax+i0qXFXX\/Bn7VcGJH8SE5AOAiuQECVvUYwlenQk= time=1514217000
|
||||
[OUT] clientek ek=yGZb1Qp0Y\/V7T+rMwcqtzUeOTIGgE6+7gcKxAw2OMPU= proof=MEQCIHdgsGlufstf\/ab1TvvM740Azs56jyGFmo93ijr53k1FAiBHNhWkV9xLUG19jpZGGe86SgCDli7GdSrv61ZGr3jD9g==
|
||||
|
||||
bM5HB+Ox/Wht38dd6/VeB7L76ebcpP9YgKzWAk4lmQ8=
|
||||
@@ -1,63 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <src/Identity.h>
|
||||
#include <sstream>
|
||||
#include "HideString.h"
|
||||
DEFINE_HIDDEN_STRING(HeaderMessage, 0x44, ('#')('#')('#')('#')('#')('#')('#')('#')('#')('#')('#')('#')('#')('#')('#')('#')('#')(' ')('T')('S')('3')(' ')('H')('a')('s')('h')(' ')('b')('y')(' ')('W')('o')('l')('v')('e')('r')('i')('n')('D')('E')('V')(' ')('#')('#')('#')('#')('#')('#')('#')('#')('#')('#')('#')('#')('#')('#')('#')('#')('#'));
|
||||
|
||||
using namespace ts;
|
||||
using namespace std;
|
||||
|
||||
inline string crypt(string in){
|
||||
stringstream result;
|
||||
result << "DEFINE_HIDDEN_STRING(EncryptionKey, 0xA5, ";
|
||||
|
||||
for(char c : in)
|
||||
result << "('" << c << "')";
|
||||
|
||||
result << ");";
|
||||
return result.str();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
cout << GetHeaderMessage() << endl;
|
||||
if(argc < 3) {
|
||||
cerr << "Invalid arguments. ./TSHash <threads> <MaxLevel> [<BlockSize> = 1.000.000]" << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
init_LTM();
|
||||
if(register_prng(&sprng_desc) == -1) {
|
||||
cerr << "could not setup prng" << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (register_cipher(&rijndael_desc) == -1) {
|
||||
cerr << "could not setup rijndael" << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int threads = atoi(argv[1]);
|
||||
int level = atoi(argv[2]);
|
||||
int blockSize = argc > 3 ? atoi(argv[3]) : 1 * 1000 * 1000;
|
||||
|
||||
cout << "# Creating new identity (Threads: " << threads << " Level: " << level << " Size: " << blockSize << ")" << endl;
|
||||
auto identity = Identity::createNew();
|
||||
cout << "IDENTITY: " << identity->exportIdentity() << endl;
|
||||
cout << "# Start hashing" << endl;
|
||||
if(!identity->improveSecurityLevelMultithreaded(level, threads, blockSize, 0, true)) {
|
||||
cout << "ERROR: Could not improve identity!" << endl;
|
||||
return 1;
|
||||
}
|
||||
cout << "INFO: Found identity!" << endl;
|
||||
cout << "IDENTITY: " << identity->exportIdentity() << endl;
|
||||
cout << "LEVEL: " << identity->getSecurityLevel() << endl;
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
#IDENTITY: 5513931022VPXfjXSN1qRa2IZvTpS3xs+L7YvcBI2lTfXgOWAkaAQwQVgR8BXtWJ1MKUSh/HGNGNgdVGWYHcCg1BgQie3pValZZB39hVE4HBStcAA5SUz9Tf1JbXVABBVUJUwFmFkJZLlZUfCtaZXFBaUVBZ1poOXlQd09KSzN6ejYxMjVnaGN3bmtSKzRPOXdvZWJObVpaT3gyOTA3ND0=
|
||||
#LEVEL: 36
|
||||
|
||||
#IDENTITY: 0VdYzXyIWNlPR991zQZLQoGLDYA4JvCX9GQ3MAYzpBRABWAHZTAmJvNQUAMxEEKGQDJVlnanF1YDdQQn0GewlXVWoAQmVMLX9FVyZaMAI7KlAIeXpPKGMCJ3BTVAJHLGlUHARbBlpqSUNJUURISXY1UXJCYmlBMHlZOVV3dFdRRXovM0lkU1hzNFJvWTkwT1JienA5bVRRPT0=
|
||||
Current level = 41 at 1233527956186
|
||||
Current offset index: 3750576000000 block size: 1000000
|
||||
|
||||
*/
|
||||
-1176
File diff suppressed because it is too large
Load Diff
@@ -1,17 +0,0 @@
|
||||
syntax = "proto2";
|
||||
|
||||
package ts.proto.license.teamspeak;
|
||||
|
||||
message LicenseData { //_ZTIN3com10teamspeak310accounting8protobuf19Signed_License_InfoE => Signed_License_Info
|
||||
required bytes chain = 1;
|
||||
required bytes root = 2;
|
||||
required int32 slots = 3;
|
||||
required int32 servers = 4;
|
||||
required string type = 5;
|
||||
}
|
||||
|
||||
message License {
|
||||
required LicenseData license = 1;
|
||||
required bytes sign_chain = 2;
|
||||
required bytes license_sign = 3;
|
||||
}
|
||||
@@ -1,218 +0,0 @@
|
||||
//
|
||||
// Created by wolverindev on 07.10.17.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <openssl/sha.h>
|
||||
#include "misc/base64.h"
|
||||
#include "Identity.h"
|
||||
|
||||
#define ECC_TYPE_INDEX 5
|
||||
|
||||
using namespace std;
|
||||
|
||||
static const char *TSKEY =
|
||||
"b9dfaa7bee6ac57ac7b65f1094a1c155"
|
||||
"e747327bc2fe5d51c512023fe54a2802"
|
||||
"01004e90ad1daaae1075d53b7d571c30"
|
||||
"e063b5a62a4a017bb394833aa0983e6e";
|
||||
|
||||
static int obfuscateInplace(char *data, uint32_t length) {
|
||||
int dataSize = min((uint32_t) 100, length);
|
||||
for (int i = 0; i < dataSize; i++) {
|
||||
data[i] ^= TSKEY[i];
|
||||
}
|
||||
|
||||
char hash[20];
|
||||
hash_state ctx;
|
||||
if (sha1_init(&ctx) != CRYPT_OK)
|
||||
{ return -1; }
|
||||
if (sha1_process(&ctx, (uint8_t*)data + 20, strlen(data + 20)) != CRYPT_OK)
|
||||
{ return -1; }
|
||||
if (sha1_done(&ctx, (uint8_t*)hash) != CRYPT_OK)
|
||||
{ return -1; }
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
data[i] ^= hash[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int deObfuscateInplace(char *data, uint32_t length) {
|
||||
char hash[20];
|
||||
hash_state ctx;
|
||||
if (sha1_init(&ctx) != CRYPT_OK)
|
||||
{ return -1; }
|
||||
if (sha1_process(&ctx, (uint8_t*)data + 20, strlen(data + 20)) != CRYPT_OK)
|
||||
{ return -1; }
|
||||
if (sha1_done(&ctx, (uint8_t*)hash) != CRYPT_OK)
|
||||
{ return -1; }
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
data[i] ^= hash[i];
|
||||
}
|
||||
|
||||
int dataSize = min((uint32_t) 100, length);
|
||||
for (int i = 0; i < dataSize; i++) {
|
||||
data[i] ^= TSKEY[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace ts {
|
||||
Identity* Identity::createNew() {
|
||||
auto result = new Identity();
|
||||
|
||||
prng_state rndState{};
|
||||
memset(&rndState, 0, sizeof(prng_state));
|
||||
int err;
|
||||
|
||||
result->keyPair = new ecc_key;
|
||||
|
||||
cout << " -> " << find_prng("sprng") << endl;
|
||||
if((err = ecc_make_key_ex(&rndState, find_prng("sprng"), result->keyPair, <c_ecc_sets[ECC_TYPE_INDEX])) != CRYPT_OK) {
|
||||
cerr << "Cant create a new identity (Keygen)" << endl;
|
||||
cerr << "Message: " << error_to_string(err) << endl;
|
||||
delete result;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Identity::Identity(std::string asnStruct, int64_t keyOffset, int64_t lastCheckedOffset) {
|
||||
this->keyOffset = keyOffset;
|
||||
this->lastCheckedOffset = lastCheckedOffset;
|
||||
importKey(asnStruct);
|
||||
}
|
||||
|
||||
Identity::Identity(std::string data) : Identity() {
|
||||
int vindex = data.find('V');
|
||||
assert(vindex > 0);
|
||||
|
||||
auto slevel = data.substr(0, vindex);
|
||||
assert(slevel.find_first_not_of("0123456789") == std::string::npos);
|
||||
this->keyOffset = stol(slevel);
|
||||
|
||||
data = data.substr(vindex + 1);
|
||||
data = base64::decode(data);
|
||||
if(deObfuscateInplace((char *) data.data(), data.length()) < 0) {
|
||||
cerr << "Cand decript identitry data" << endl;
|
||||
return;
|
||||
}
|
||||
importKey(base64::decode(data));
|
||||
}
|
||||
|
||||
Identity::Identity() {
|
||||
this->keyOffset = 0;
|
||||
this->lastCheckedOffset = 0;
|
||||
this->keyPair = nullptr;
|
||||
}
|
||||
|
||||
Identity::~Identity() {
|
||||
delete this->keyPair;
|
||||
this->keyPair = nullptr;
|
||||
}
|
||||
|
||||
void Identity::importKey(std::string asnStruct) {
|
||||
this->keyPair = new ecc_key;
|
||||
int err;
|
||||
if((err = ecc_import_ex((const unsigned char *) asnStruct.data(), asnStruct.length(), this->keyPair, <c_ecc_sets[ECC_TYPE_INDEX])) != CRYPT_OK){
|
||||
delete this->keyPair;
|
||||
this->keyPair = nullptr;
|
||||
|
||||
cerr << "Cant import identity from asn structure" << endl;
|
||||
cerr << "Message: " << error_to_string(err) << endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Identity::exportIdentity() {
|
||||
string data = privateKey();
|
||||
obfuscateInplace((char *) data.data(), data.length());
|
||||
return to_string(this->lastValidKeyOffset()) + "V" + base64_encode(data);
|
||||
}
|
||||
|
||||
std::string Identity::publicKey() {
|
||||
assert(this->keyPair);
|
||||
|
||||
size_t bufferLength = 1028;
|
||||
char buffer[bufferLength];
|
||||
ecc_export((unsigned char *) buffer, &bufferLength, PK_PUBLIC, this->keyPair);
|
||||
|
||||
return base64_encode(string(buffer, bufferLength));
|
||||
}
|
||||
|
||||
std::string Identity::privateKey() {
|
||||
assert(this->keyPair);
|
||||
|
||||
size_t bufferLength = 1028;
|
||||
char buffer[bufferLength];
|
||||
ecc_export((unsigned char *) buffer, &bufferLength, PK_PRIVATE, this->keyPair);
|
||||
|
||||
return base64_encode(string(buffer, bufferLength));
|
||||
}
|
||||
|
||||
ecc_key& Identity::getPrivateKey() {
|
||||
return *keyPair;
|
||||
}
|
||||
|
||||
#define MaxUlongString 20
|
||||
|
||||
bool Identity::improveSecurityLevel(int target) {
|
||||
auto publicKey = this->publicKey();
|
||||
char hashBuffer[publicKey.length() + MaxUlongString];
|
||||
memcpy(hashBuffer, publicKey.data(), publicKey.length());
|
||||
|
||||
this->lastCheckedOffset = max(this->lastCheckedOffset, this->keyOffset);
|
||||
int best = getSecurityLevel(hashBuffer, publicKey.length(), this->lastCheckedOffset);
|
||||
while(true){
|
||||
if(best >= target) return true;
|
||||
|
||||
int currentLevel = getSecurityLevel(hashBuffer, publicKey.length(), this->lastCheckedOffset);
|
||||
if(currentLevel >= best){
|
||||
this->keyOffset = this->lastCheckedOffset;
|
||||
best = currentLevel;
|
||||
}
|
||||
this->lastCheckedOffset++;
|
||||
}
|
||||
}
|
||||
|
||||
int Identity::getSecurityLevel() {
|
||||
auto length = publicKey().length();
|
||||
char hashBuffer[length + MaxUlongString];
|
||||
|
||||
auto publicKey = this->publicKey();
|
||||
memcpy(hashBuffer, publicKey.data(), publicKey.length());
|
||||
|
||||
return getSecurityLevel(hashBuffer, publicKey.length(), this->keyOffset);
|
||||
}
|
||||
|
||||
int Identity::getSecurityLevel(char *hashBuffer, size_t keyLength, int64_t offset) {
|
||||
char numBuffer[MaxUlongString];
|
||||
int numLen = 0;
|
||||
do {
|
||||
numBuffer[numLen] = '0' + (offset % 10);
|
||||
offset /= 10;
|
||||
numLen++;
|
||||
} while(offset > 0);
|
||||
for(int i = 0; i < numLen; i++)
|
||||
hashBuffer[keyLength + i] = numBuffer[numLen - (i + 1)];
|
||||
|
||||
char shaBuffer[SHA_DIGEST_LENGTH];
|
||||
SHA1((const unsigned char *) hashBuffer, keyLength + numLen, (unsigned char *) shaBuffer);
|
||||
|
||||
//Leading zero bits
|
||||
register int zeroBits = 0;
|
||||
register int i;
|
||||
for(i = 0; i < SHA_DIGEST_LENGTH; i++)
|
||||
if(shaBuffer[i] == 0) zeroBits += 8;
|
||||
else break;
|
||||
if(i < SHA_DIGEST_LENGTH)
|
||||
for(int bit = 0; bit < 8; bit++)
|
||||
if((shaBuffer[i] & (1 << bit)) == 0) zeroBits++;
|
||||
else break;
|
||||
return zeroBits;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <tomcrypt.h>
|
||||
#include <string>
|
||||
|
||||
namespace ts {
|
||||
class Identity {
|
||||
public:
|
||||
static Identity* createNew();
|
||||
|
||||
explicit Identity(std::string data);
|
||||
Identity(std::string asnStruct,int64_t keyOffset,int64_t lastCheckedOffset);
|
||||
~Identity();
|
||||
|
||||
bool valid(){ return keyPair != nullptr; }
|
||||
|
||||
std::string publicKey();
|
||||
std::string privateKey();
|
||||
std::string exportIdentity();
|
||||
|
||||
ecc_key* getKeyPair(){
|
||||
return keyPair;
|
||||
}
|
||||
|
||||
ecc_key& getPrivateKey();
|
||||
|
||||
bool improveSecurityLevel(int target);
|
||||
bool improveSecurityLevelMultithreaded(int target, int nthread = 4, size_t nblockSize = 1000, size_t baseOffset = 0, bool verbose = false);
|
||||
|
||||
int getSecurityLevel();
|
||||
|
||||
int64_t lastValidKeyOffset(){ return keyOffset; }
|
||||
int64_t lastTestedKeyOffset(){ return lastCheckedOffset; }
|
||||
private:
|
||||
Identity();
|
||||
|
||||
int getSecurityLevel(char* hasBuffer, size_t keyLength, int64_t offset);
|
||||
void importKey(std::string asn1);
|
||||
|
||||
ecc_key* keyPair = nullptr;
|
||||
size_t keyOffset;
|
||||
size_t lastCheckedOffset;
|
||||
};
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
//
|
||||
// Created by wolverindev on 14.10.17.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <openssl/sha.h>
|
||||
#include <ThreadPool/Thread.h>
|
||||
#include <vector>
|
||||
#include <ThreadPool/Mutex.h>
|
||||
#include <zconf.h>
|
||||
#include "misc/base64.h"
|
||||
#include "Identity.h"
|
||||
|
||||
#define ECC_TYPE_INDEX 5
|
||||
|
||||
#define USE_OPENSSL_SHA1
|
||||
using namespace std::chrono;
|
||||
using namespace std;
|
||||
namespace ts {
|
||||
|
||||
inline int calculateSecutityLevel(uint8_t* hashBuffer, uint8_t* bufferToHash, int length){
|
||||
register int zeroBits = 0;
|
||||
register int bit;
|
||||
register int i;
|
||||
|
||||
SHA1(bufferToHash, length, hashBuffer);
|
||||
|
||||
//Leading zero bits
|
||||
for(i = 0; i < SHA_DIGEST_LENGTH; i++)
|
||||
if(hashBuffer[i] == 0) zeroBits += 8;
|
||||
else break;
|
||||
if(i < SHA_DIGEST_LENGTH)
|
||||
for(bit = 0; bit < 8; bit++)
|
||||
if((hashBuffer[i] & (1 << bit)) == 0) zeroBits++;
|
||||
else break;
|
||||
|
||||
return zeroBits;
|
||||
}
|
||||
|
||||
inline void increaseNumBuffer(char* buffer, int numOffset, int* length){
|
||||
int index = *length - 1;
|
||||
|
||||
while(true){
|
||||
if(buffer[index] == '9'){
|
||||
if(index - 1 < numOffset) {
|
||||
buffer[index] = '1';
|
||||
buffer[*length] = '0';
|
||||
*length += 1;
|
||||
return;
|
||||
}
|
||||
buffer[index--] = '0';
|
||||
} else {
|
||||
buffer[index] += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define MaxUlongString 20
|
||||
bool Identity::improveSecurityLevelMultithreaded(int target, int nthread, size_t nblockSize, size_t baseOffset, bool verbose) {
|
||||
if(this->getSecurityLevel() >= target)
|
||||
return false;
|
||||
|
||||
vector<threads::Thread*> threads;
|
||||
|
||||
auto publicKey = this->publicKey();
|
||||
|
||||
size_t currentBlockIndex = max(max(this->lastCheckedOffset, this->keyOffset), baseOffset);
|
||||
threads::Mutex blockIndexLock;
|
||||
|
||||
auto activeDigging = new bool(true);
|
||||
threads::Thread* thread;
|
||||
for(int threadId = 0; threadId < nthread; threadId++){
|
||||
thread = new threads::Thread([&](){
|
||||
size_t offset = 0;
|
||||
size_t endOffset = 0;
|
||||
size_t bestOffset = 0;
|
||||
|
||||
char shaHashBuffer[SHA_DIGEST_LENGTH];
|
||||
char hashBuffer[publicKey.length() + MaxUlongString];
|
||||
memcpy(hashBuffer, publicKey.data(), publicKey.length());
|
||||
|
||||
#ifndef SLOW
|
||||
//Setup some stuff
|
||||
size_t pubKeyLength = publicKey.length();
|
||||
|
||||
#endif
|
||||
while(*activeDigging){
|
||||
//Get next range
|
||||
blockIndexLock.lock();
|
||||
offset = currentBlockIndex;
|
||||
endOffset = currentBlockIndex + nblockSize;
|
||||
currentBlockIndex += nblockSize;
|
||||
blockIndexLock.unlock();
|
||||
|
||||
int bestLevel = this->getSecurityLevel(hashBuffer, publicKey.length(), this->keyOffset);
|
||||
#ifdef SLOW
|
||||
while(offset < endOffset){
|
||||
int currentLevel = getSecurityLevel(hashBuffer, publicKey.length(), offset);
|
||||
if(currentLevel >= best){
|
||||
bestOffset = offset;
|
||||
best = currentLevel;
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
blockIndexLock.lock();
|
||||
if(best > this->getSecurityLevel()){
|
||||
if(verbose) cout << "Improved -> " << best << "/" << target << endl;
|
||||
this->lastCheckedOffset = bestOffset;
|
||||
this->keyOffset = bestOffset;
|
||||
cout << "Got level: " << best << endl;
|
||||
|
||||
if(best >= target){
|
||||
cout << "Done!" << endl;
|
||||
*activeDigging = false;
|
||||
}
|
||||
}
|
||||
blockIndexLock.unlock();
|
||||
if(verbose) cout << "round done: highest -> " << best << endl;
|
||||
#else
|
||||
|
||||
string strStartOffset = to_string(offset);
|
||||
ssize_t roundsLeft = nblockSize;
|
||||
|
||||
auto hashBufferLength = static_cast<int>(publicKey.length() + strStartOffset.length());
|
||||
memcpy(&hashBuffer[pubKeyLength], strStartOffset.c_str(), strStartOffset.length());
|
||||
|
||||
while(roundsLeft-- >= 0){
|
||||
auto level = calculateSecutityLevel(reinterpret_cast<uint8_t *>(shaHashBuffer), reinterpret_cast<uint8_t *>(hashBuffer), hashBufferLength);
|
||||
if(level > bestLevel){
|
||||
{
|
||||
threads::MutexLock l(blockIndexLock);
|
||||
|
||||
auto strOffset = string(&hashBuffer[pubKeyLength], hashBufferLength - pubKeyLength);
|
||||
bestOffset = stoull(strOffset);
|
||||
auto got = this->getSecurityLevel();
|
||||
if(got >= level) {
|
||||
cout << "Already got bedder level! (" << got << ")" << endl;
|
||||
bestLevel = got;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(verbose) cout << "Improved -> " << level << "/" << target << " [" << strOffset << "]" << endl;
|
||||
this->lastCheckedOffset = bestOffset;
|
||||
this->keyOffset = bestOffset;
|
||||
bestLevel = level;
|
||||
|
||||
if(bestLevel >= target){
|
||||
cout << "Done! (" << bestLevel << ")" << endl;
|
||||
*activeDigging = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
increaseNumBuffer(hashBuffer, pubKeyLength + 1, &hashBufferLength);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
});
|
||||
thread->name("IdentityHashDigger #" + to_string(threadId));
|
||||
threads.push_back(thread);
|
||||
}
|
||||
|
||||
if(verbose){
|
||||
thread = new threads::Thread([&](){
|
||||
auto lastIndex = currentBlockIndex;
|
||||
while(*activeDigging){
|
||||
for(int count = 0; count < 1000 && *activeDigging; count++)
|
||||
usleep(1000);
|
||||
|
||||
blockIndexLock.lock();
|
||||
cout << "Current level = " << this->getSecurityLevel() << " at " << this->keyOffset << endl;
|
||||
cout << "Current offset index: " << currentBlockIndex << " block size: " << nblockSize << endl;
|
||||
cout << "speed: " << (currentBlockIndex - lastIndex) / 1000 / 1000.f << " Mio. attemps/sec" << endl;
|
||||
lastIndex = currentBlockIndex;
|
||||
blockIndexLock.unlock();
|
||||
}
|
||||
});
|
||||
thread->name("Status printer");
|
||||
threads.push_back(thread);
|
||||
}
|
||||
|
||||
for(auto elm : threads){
|
||||
if(elm->state() == threads::ThreadState::RUNNING)
|
||||
elm->join();
|
||||
delete elm;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* TinySHA1 - a header only implementation of the SHA1 algorithm in C++. Based
|
||||
* on the implementation in boost::uuid::details.
|
||||
*
|
||||
* SHA1 Wikipedia Page: http://en.wikipedia.org/wiki/SHA-1
|
||||
*
|
||||
* Copyright (c) 2012-22 SAURAV MOHAPATRA <mohaps@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#ifndef _TINY_SHA1_HPP_
|
||||
#define _TINY_SHA1_HPP_
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <stdint.h>
|
||||
namespace sha1
|
||||
{
|
||||
class SHA1
|
||||
{
|
||||
public:
|
||||
typedef uint32_t digest32_t[5];
|
||||
typedef uint8_t digest8_t[20];
|
||||
inline static uint32_t LeftRotate(uint32_t value, size_t count) {
|
||||
return (value << count) ^ (value >> (32-count));
|
||||
}
|
||||
SHA1(){ reset(); }
|
||||
virtual ~SHA1() {}
|
||||
SHA1(const SHA1& s) { *this = s; }
|
||||
const SHA1& operator = (const SHA1& s) {
|
||||
memcpy(m_digest, s.m_digest, 5 * sizeof(uint32_t));
|
||||
memcpy(m_block, s.m_block, 64);
|
||||
m_blockByteIndex = s.m_blockByteIndex;
|
||||
m_byteCount = s.m_byteCount;
|
||||
return *this;
|
||||
}
|
||||
SHA1& reset() {
|
||||
m_digest[0] = 0x67452301;
|
||||
m_digest[1] = 0xEFCDAB89;
|
||||
m_digest[2] = 0x98BADCFE;
|
||||
m_digest[3] = 0x10325476;
|
||||
m_digest[4] = 0xC3D2E1F0;
|
||||
m_blockByteIndex = 0;
|
||||
m_byteCount = 0;
|
||||
return *this;
|
||||
}
|
||||
SHA1& processByte(uint8_t octet) {
|
||||
this->m_block[this->m_blockByteIndex++] = octet;
|
||||
++this->m_byteCount;
|
||||
if(m_blockByteIndex == 64) {
|
||||
this->m_blockByteIndex = 0;
|
||||
processBlock();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
SHA1& processBlock(const void* const start, const void* const end) {
|
||||
const uint8_t* begin = static_cast<const uint8_t*>(start);
|
||||
const uint8_t* finish = static_cast<const uint8_t*>(end);
|
||||
while(begin != finish) {
|
||||
processByte(*begin);
|
||||
begin++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
SHA1& processBytes(const void* const data, size_t len) {
|
||||
const uint8_t* block = static_cast<const uint8_t*>(data);
|
||||
processBlock(block, block + len);
|
||||
return *this;
|
||||
}
|
||||
const uint32_t* getDigest(digest32_t digest) {
|
||||
size_t bitCount = this->m_byteCount * 8;
|
||||
processByte(0x80);
|
||||
if (this->m_blockByteIndex > 56) {
|
||||
while (m_blockByteIndex != 0) {
|
||||
processByte(0);
|
||||
}
|
||||
while (m_blockByteIndex < 56) {
|
||||
processByte(0);
|
||||
}
|
||||
} else {
|
||||
while (m_blockByteIndex < 56) {
|
||||
processByte(0);
|
||||
}
|
||||
}
|
||||
processByte(0);
|
||||
processByte(0);
|
||||
processByte(0);
|
||||
processByte(0);
|
||||
processByte( static_cast<unsigned char>((bitCount>>24) & 0xFF));
|
||||
processByte( static_cast<unsigned char>((bitCount>>16) & 0xFF));
|
||||
processByte( static_cast<unsigned char>((bitCount>>8 ) & 0xFF));
|
||||
processByte( static_cast<unsigned char>((bitCount) & 0xFF));
|
||||
|
||||
memcpy(digest, m_digest, 5 * sizeof(uint32_t));
|
||||
return digest;
|
||||
}
|
||||
const uint8_t* getDigestBytes(digest8_t digest) {
|
||||
digest32_t d32;
|
||||
getDigest(d32);
|
||||
size_t di = 0;
|
||||
digest[di++] = ((d32[0] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[0] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[0] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[0]) & 0xFF);
|
||||
|
||||
digest[di++] = ((d32[1] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[1] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[1] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[1]) & 0xFF);
|
||||
|
||||
digest[di++] = ((d32[2] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[2] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[2] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[2]) & 0xFF);
|
||||
|
||||
digest[di++] = ((d32[3] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[3] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[3] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[3]) & 0xFF);
|
||||
|
||||
digest[di++] = ((d32[4] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[4] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[4] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[4]) & 0xFF);
|
||||
return digest;
|
||||
}
|
||||
|
||||
protected:
|
||||
void processBlock() {
|
||||
uint32_t w[80];
|
||||
for (size_t i = 0; i < 16; i++) {
|
||||
w[i] = (m_block[i*4 + 0] << 24);
|
||||
w[i] |= (m_block[i*4 + 1] << 16);
|
||||
w[i] |= (m_block[i*4 + 2] << 8);
|
||||
w[i] |= (m_block[i*4 + 3]);
|
||||
}
|
||||
for (size_t i = 16; i < 80; i++) {
|
||||
w[i] = LeftRotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1);
|
||||
}
|
||||
|
||||
uint32_t a = m_digest[0];
|
||||
uint32_t b = m_digest[1];
|
||||
uint32_t c = m_digest[2];
|
||||
uint32_t d = m_digest[3];
|
||||
uint32_t e = m_digest[4];
|
||||
|
||||
for (std::size_t i=0; i<80; ++i) {
|
||||
uint32_t f = 0;
|
||||
uint32_t k = 0;
|
||||
|
||||
if (i<20) {
|
||||
f = (b & c) | (~b & d);
|
||||
k = 0x5A827999;
|
||||
} else if (i<40) {
|
||||
f = b ^ c ^ d;
|
||||
k = 0x6ED9EBA1;
|
||||
} else if (i<60) {
|
||||
f = (b & c) | (b & d) | (c & d);
|
||||
k = 0x8F1BBCDC;
|
||||
} else {
|
||||
f = b ^ c ^ d;
|
||||
k = 0xCA62C1D6;
|
||||
}
|
||||
uint32_t temp = LeftRotate(a, 5) + f + e + k + w[i];
|
||||
e = d;
|
||||
d = c;
|
||||
c = LeftRotate(b, 30);
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
|
||||
m_digest[0] += a;
|
||||
m_digest[1] += b;
|
||||
m_digest[2] += c;
|
||||
m_digest[3] += d;
|
||||
m_digest[4] += e;
|
||||
}
|
||||
private:
|
||||
digest32_t m_digest;
|
||||
uint8_t m_block[64];
|
||||
size_t m_blockByteIndex;
|
||||
size_t m_byteCount;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
@@ -1,454 +0,0 @@
|
||||
//
|
||||
// Created by wolverindev on 07.10.17.
|
||||
//
|
||||
|
||||
#include <log/LogUtils.h>
|
||||
#include "Connection.h"
|
||||
#include "misc/base64.h"
|
||||
#include <misc/endianness.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <poll.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <bitset>
|
||||
#include <protocol/Packet.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace ts;
|
||||
using namespace ts::connection;
|
||||
using namespace ts::protocol;
|
||||
|
||||
ServerConnection::ServerConnection() {
|
||||
cryptionHandler = new CryptionHandler();
|
||||
cryptionHandler->reset();
|
||||
|
||||
compressionHandler = new CompressionHandler();
|
||||
|
||||
readQueue = (buffer::SortedBufferQueue<ServerPacket> **) malloc(16 * sizeof(void*));
|
||||
for(int i = 0; i < 16; i++) {
|
||||
auto type = ts::protocol::PacketTypeInfo::fromid(i);
|
||||
if(type != PacketTypeInfo::Undefined){
|
||||
readQueue[i] = new buffer::SortedBufferQueue<ServerPacket>(ts::protocol::PacketTypeInfo::fromid(i), PacketTypeInfo::Command != type); //Ignore command low
|
||||
} else {
|
||||
readQueue[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ServerConnection::~ServerConnection() {
|
||||
for(int i = 0; i < 16; i++)
|
||||
if(readQueue[i])
|
||||
delete readQueue[i];
|
||||
free(readQueue);
|
||||
this->rwThread->join();
|
||||
}
|
||||
|
||||
static int sourcePort = 50000;
|
||||
|
||||
void ServerConnection::disconnect() {
|
||||
//this->rwThread->cancel();
|
||||
//this->handleThread->cancel();
|
||||
this->connected = false;
|
||||
if(this->socket) this->socket->close();
|
||||
}
|
||||
|
||||
bool ServerConnection::connect(std::string host, std::string port, Identity *identity) {
|
||||
this->clientIdentity = identity;
|
||||
|
||||
memset(&remoteAddress, 0, sizeof(remoteAddress));
|
||||
remoteAddress.sin_family = AF_INET;
|
||||
remoteAddress.sin_port = htons((uint16_t) std::stoi(port));
|
||||
remoteAddress.sin_addr.s_addr = inet_addr(host.c_str());
|
||||
#ifdef NoQt
|
||||
/*
|
||||
this->socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
int allow = 1;
|
||||
setsockopt(this->socketfd, SOL_SOCKET, SO_REUSEADDR, &allow, sizeof(int));
|
||||
|
||||
memset(&localAddress, 0, sizeof(localAddress));
|
||||
localAddress.sin_family = AF_INET;
|
||||
localAddress.sin_addr.s_addr = htonl (INADDR_ANY);
|
||||
localAddress.sin_port = htons (sourcePort++);
|
||||
::connect(this->socketfd, (const sockaddr *) &remoteHost, sizeof(this->remoteAddress));
|
||||
//bind(this->socketfd, (struct sockaddr *) &localAddress, sizeof(localAddress));
|
||||
|
||||
*/
|
||||
this->socket = new UdpSocket;
|
||||
if(!this->socket->setup(&remoteAddress)){
|
||||
cerr << "Invalid socket setup" << endl;
|
||||
}
|
||||
#else
|
||||
|
||||
#endif
|
||||
this->rwThread = new threads::Thread(THREAD_SAVE_OPERATIONS, [&]() {
|
||||
#ifndef NoQt
|
||||
this->qtSocket = new QUdpSocket();
|
||||
|
||||
QObject::connect(qtSocket,SIGNAL(bytesWritten(qint64)),this,SLOT(bytesWritten(qint64)));
|
||||
QObject::connect(this->qtSocket, SIGNAL(readyRead()), this, SLOT(attempDatagramRead()));
|
||||
this->qtSocket->bind(QHostAddress::Any, 23111);
|
||||
|
||||
this->socketfd = qtSocket->socketDescriptor();
|
||||
cout << "Sock fd: " << this->socketfd << endl;
|
||||
#endif
|
||||
/*
|
||||
auto cthread = QThread::currentThread();
|
||||
cout << "ex" << endl;
|
||||
runOnThread(qtSocket->thread(), [&](){
|
||||
cout << "try" << endl;
|
||||
qtSocket->moveToThread(cthread);
|
||||
cout << "Moved" << endl;
|
||||
});
|
||||
cout << "Start rw" << endl;
|
||||
*/
|
||||
|
||||
this->rwExecutor();
|
||||
});
|
||||
|
||||
/*
|
||||
this->handleThread = new threads::Thread([&]() {
|
||||
this->handleExecutor();
|
||||
});
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef NoQt
|
||||
void ServerConnection::bytesWritten(qint64 b) {
|
||||
cout << "written " << b << endl;
|
||||
}
|
||||
|
||||
void ServerConnection::attempDatagramRead() {
|
||||
cout << "Data " << endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
//this->socket->socketDescriptor()
|
||||
void ServerConnection::rwExecutor() {
|
||||
pollfd pollData = {this->socket->getSocketDescriptor(), POLLRDHUP | POLLIN | POLLOUT, 0};
|
||||
buffer::RawBuffer readBuffer(512);
|
||||
std::shared_ptr<protocol::ServerPacket> readedPacket;
|
||||
while (socket->getSocketDescriptor() > 0 && this->connected) {
|
||||
int rfds = poll(&pollData, 1, -1);
|
||||
bool select = false;
|
||||
if(rfds == 0) {
|
||||
usleep(5 * 1000);;
|
||||
continue;
|
||||
} else if(rfds < 0) {
|
||||
break;
|
||||
}
|
||||
if (pollData.revents & POLLRDHUP || pollData.revents & POLLHUP) {
|
||||
select = 1;
|
||||
cerr << "Connection hang up!" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pollData.revents & POLLIN) {
|
||||
select = 1;
|
||||
ssize_t readedBytes = -1;
|
||||
#ifdef NoQt
|
||||
readedBytes = socket->read(readBuffer.buffer, readBuffer.length);
|
||||
#ifdef DEBUG
|
||||
cout << "Read bytes (" << readedBytes << ")" << endl;
|
||||
#endif
|
||||
#else
|
||||
QHostAddress senderAddr;
|
||||
quint16 senderPort;
|
||||
readedBytes = this->qtSocket->readDatagram(readBuffer.buffer, readBuffer.length, &senderAddr, &senderPort);
|
||||
#endif
|
||||
if (readedBytes < 0) {
|
||||
cout << "fatal read error: " << errno << "/" << strerror(errno) << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
readedPacket = std::make_shared<ServerPacket>(pipes::buffer_view(readBuffer.buffer, readedBytes));
|
||||
if(!preProgressPacket(readedPacket)){
|
||||
cerr << "Invalid packet preprocess!" << endl;
|
||||
readedPacket = nullptr;
|
||||
goto exitRead;
|
||||
}
|
||||
|
||||
if(readedPacket->type().type() < 0 || readedPacket->type().type() > 16){
|
||||
cerr << "Invalid packet id!" << endl;
|
||||
readedPacket = nullptr;
|
||||
goto exitRead;
|
||||
}
|
||||
//Deserelize packet
|
||||
this->bufferQueueLock.lock();
|
||||
if(!this->readQueue[readedPacket->type().type()]->push_pack(readedPacket)){
|
||||
//TODO error handling
|
||||
cout << "pkId: " << be2le16((char*) readedPacket->data().data_ptr()) << " -> " << readedPacket->type().name() << endl;
|
||||
}
|
||||
this->bufferQueueLock.unlock();
|
||||
while(this->handleNextPacket());
|
||||
exitRead:;
|
||||
}
|
||||
|
||||
if (pollData.revents & POLLOUT) {
|
||||
this->bufferQueueLock.lock();
|
||||
if (!this->writeQueue.empty()) {
|
||||
select = 1;
|
||||
buffer::RawBuffer buffer = this->writeQueue.front();
|
||||
|
||||
#ifdef NoQt
|
||||
auto res = this->socket->write(buffer.buffer, buffer.length);
|
||||
if (res == -1) {
|
||||
cout << "having write error: " << errno << "/" << strerror(errno) << " -> " << buffer.length << endl;
|
||||
}
|
||||
//cout << string() + "Write: " + PacketType::fromid(buffer.type()).name() << endl;
|
||||
#else
|
||||
this->qtSocket->writeDatagram(buffer.buffer, buffer.length, QHostAddress("localhost"), htons(this->remoteAddress.sin_port));
|
||||
#endif
|
||||
|
||||
/*
|
||||
if(!PacketTypeInfo::fromid(buffer.type()).requireAcknowledge()){ //Than we need a ack!
|
||||
//Wait for acknowlage
|
||||
this->acknowlageQueueLock.lock();
|
||||
this->acknowlageQueue.push_back(buffer);
|
||||
this->acknowlageQueueLock.unlock();
|
||||
}
|
||||
*/
|
||||
|
||||
this->writeQueue.pop_front();
|
||||
}
|
||||
this->bufferQueueLock.unlock();
|
||||
}
|
||||
if (!select) {
|
||||
usleep(5 * 10000);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
cerr << "rw loop broken!" << endl;
|
||||
}
|
||||
|
||||
bool ServerConnection::preProgressPacket(std::shared_ptr<protocol::ServerPacket> packet){
|
||||
packet->setEncrypted(!packet->hasFlag(PacketFlag::Unencrypted));
|
||||
packet->setCompressed(packet->hasFlag(PacketFlag::Compressed));
|
||||
packet->setFragmentedEntry(packet->hasFlag(PacketFlag::Fragmented));
|
||||
|
||||
if(packet->type() == PacketTypeInfo::Init1){
|
||||
|
||||
}
|
||||
if (packet->isEncrypted()) {
|
||||
string error = "success";
|
||||
if (!cryptionHandler->progressPacketIn(packet.get(), error, false)) {
|
||||
cerr << "Cant decript packet! Message: " << error << endl;
|
||||
cerr << "Dropping it!" << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
cout << "[IN] Packet type -> " << packet->type().name() << " flags " << packet->flags() << " Length: " << packet->data().length() << endl;
|
||||
#endif
|
||||
if(packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow){ //needs an acknowledge
|
||||
sendAcknowledge(packet->packetId(), packet->type() == PacketTypeInfo::CommandLow);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//TODO right packet recive order!
|
||||
void ServerConnection::handleExecutor() {
|
||||
shared_ptr<protocol::ServerPacket> packet = nullptr;
|
||||
string error = "success";
|
||||
while(this->connected){
|
||||
while(this->handleNextPacket());
|
||||
usleep(10 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
bool ServerConnection::handleNextPacket() {
|
||||
shared_ptr<protocol::ServerPacket> packet = nullptr;
|
||||
string error = "success";
|
||||
|
||||
if(this->autoHandle){
|
||||
handleQueueLock.lock();
|
||||
if(!this->handleQueue.empty()) {
|
||||
packet = this->handleQueue.front();
|
||||
this->handleQueue.pop_front();
|
||||
}
|
||||
handleQueueLock.unlock();
|
||||
|
||||
if(packet){
|
||||
if(packet->type() == PacketTypeInfo::Ack || packet->type() == PacketTypeInfo::AckLow){
|
||||
handlePacketAck(packet);
|
||||
} else if(packet->type() == PacketTypeInfo::Command || packet->type() == PacketTypeInfo::CommandLow){
|
||||
handlePacketCommand(packet);
|
||||
} else if(packet->type() == PacketTypeInfo::Ping || packet->type() == PacketTypeInfo::Pong){
|
||||
handlePacketPing(packet);
|
||||
} else if(packet->type() == PacketTypeInfo::Voice || packet->type() == PacketTypeInfo::VoiceWhisper){
|
||||
handlePacketVoice(packet);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for(int index = 0; index < 16; index++){
|
||||
if(this->readQueue[index]) {
|
||||
if(this->readQueue[index]->available() > 0){
|
||||
auto npacket = this->readQueue[index]->peekNext(0);
|
||||
packet = make_shared<ServerPacket>(npacket->buffer());
|
||||
packet->setEncrypted(npacket->isEncrypted());
|
||||
packet->setCompressed(npacket->isCompressed());
|
||||
packet->setFragmentedEntry(npacket->isFragmentEntry());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if(!packet) return false;
|
||||
if(packet->isFragmentEntry()){
|
||||
packet->setFragmentedEntry(false);
|
||||
int deltaPacketIndex = 0;
|
||||
while(this->connected){
|
||||
std::shared_ptr<protocol::ServerPacket> nextElm = this->readQueue[packet->type().type()]->peekNext(++deltaPacketIndex);
|
||||
if(!nextElm)
|
||||
return false;
|
||||
|
||||
if(!nextElm) {
|
||||
cerr << "Dropped fragment?" << endl;
|
||||
packet = nullptr;
|
||||
break;
|
||||
}
|
||||
packet->append_data({nextElm->data()});
|
||||
if(nextElm->hasFlag(protocol::PacketFlag::Fragmented)) break; //Tail end
|
||||
nextElm = nullptr;
|
||||
}
|
||||
this->readQueue[packet->type().type()]->pop_packets(deltaPacketIndex);
|
||||
}
|
||||
this->readQueue[packet->type().type()]->pop_packets(1);
|
||||
|
||||
if(packet->type() != PacketTypeInfo::Init1 && !this->compressionHandler->progressPacketIn(packet.get(), error)){
|
||||
cerr << "Cant decompress packet! (" << error << ")" << endl;
|
||||
packet = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(DEBUG_PACKET_LOG)
|
||||
cout << "Parsed packet " << packet->type().name() << " with id " << packet->packetId() << ". Data:" << endl;
|
||||
hexDump((void *) packet->data().data_ptr(), packet->data().length(), 16, 8, [](std::string line) {
|
||||
cout << "[IN] " << line << endl;
|
||||
});
|
||||
#endif
|
||||
handleQueueLock.lock();
|
||||
this->handleQueue.push_back(packet);
|
||||
handleQueueLock.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
using namespace std::chrono;
|
||||
std::shared_ptr<protocol::ServerPacket> ServerConnection::readNextPacket(bool block) {
|
||||
auto start = system_clock::now();
|
||||
attempGet:
|
||||
if(system_clock::now() - start > seconds(5)) return nullptr;
|
||||
|
||||
this->handleQueueLock.lock();
|
||||
if (this->handleQueue.empty()) {
|
||||
this->handleQueueLock.unlock();
|
||||
if (!block) return nullptr;
|
||||
usleep(5 * 1000);
|
||||
goto attempGet;
|
||||
}
|
||||
|
||||
std::shared_ptr<protocol::ServerPacket> packet = std::move(this->handleQueue.front());
|
||||
this->handleQueue.pop_front();
|
||||
this->handleQueueLock.unlock();
|
||||
return packet;
|
||||
}
|
||||
|
||||
bool ServerConnection::setupSharedSecret(std::string alpha, std::string beta, std::string sharedKey, std::string &error) {
|
||||
return this->cryptionHandler->setupSharedSecret(alpha, beta, sharedKey, error);
|
||||
}
|
||||
|
||||
//Packet splitting not working correctly! (On clientinit dosnt wait for the second)
|
||||
void ServerConnection::sendPacket(ts::protocol::ClientPacket &packet) {
|
||||
int maxDataLength = 500 - packet.header().length();
|
||||
|
||||
if(packet.data().length() > maxDataLength){
|
||||
string error;
|
||||
/*
|
||||
packet.enableFlag(PacketFlag::Compressed);
|
||||
if(!this->compressionHandler->progressPacketOut(&packet, error)){
|
||||
cerr << "Compress error!" << endl;
|
||||
return;
|
||||
}
|
||||
packet.enableFlag(PacketFlag::Compressed);
|
||||
*/
|
||||
if(packet.data().length() > maxDataLength){
|
||||
std::vector<shared_ptr<ClientPacket>> siblings;
|
||||
siblings.reserve(8);
|
||||
|
||||
|
||||
{ //Split packets
|
||||
auto buffer = packet.data();
|
||||
|
||||
const auto max_length = packet.type().max_length();
|
||||
while(buffer.length() > max_length * 2) {
|
||||
siblings.push_back(make_shared<ClientPacket>(packet.type(), buffer.view(0, max_length)));
|
||||
buffer = buffer.range(max_length);
|
||||
}
|
||||
|
||||
if(buffer.length() > max_length) { //Divide rest by 2
|
||||
siblings.push_back(make_shared<ClientPacket>(packet.type(), buffer.view(0, buffer.length() / 2)));
|
||||
buffer = buffer.range(buffer.length() / 2);
|
||||
}
|
||||
siblings.push_back(make_shared<ClientPacket>(packet.type(), buffer));
|
||||
|
||||
for(const auto& frag : siblings) {
|
||||
frag->setFragmentedEntry(true);
|
||||
frag->enableFlag(PacketFlag::NewProtocol);
|
||||
}
|
||||
}
|
||||
|
||||
for(const auto& entry : siblings)
|
||||
this->sendPacket(*entry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(!packet.memory_state.id_branded)
|
||||
packet.applyPacketId(idManager);
|
||||
packet.clientId(this->clientId);
|
||||
|
||||
string error = "success";
|
||||
if (!this->cryptionHandler->progressPacketOut(&packet, error, false)) {
|
||||
cerr << "Invalid crypt -> " << error << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
buffer::RawBuffer buffer(packet.buffer().length());
|
||||
|
||||
memcpy(&buffer.buffer[0], packet.buffer().data_ptr(), packet.buffer().length());
|
||||
|
||||
this->bufferQueueLock.lock();
|
||||
this->writeQueue.push_back(buffer);
|
||||
#if defined(DEBUG_PACKET_LOG)
|
||||
cout << "Send packet " << packet.type().name() << " fragmented -> " << packet.isFragmentEntry() << " length " << packet.data().length() << " flags " << packet.flags() << " ID: " << packet.packetId() << endl;
|
||||
hexDump(buffer.buffer, buffer.length, buffer.length, buffer.length);
|
||||
#endif
|
||||
this->bufferQueueLock.unlock();
|
||||
}
|
||||
|
||||
void ServerConnection::sendCommand(ts::Command command, bool low) {
|
||||
auto data = command.build();
|
||||
protocol::ClientPacket pkt(low ? protocol::PacketTypeInfo::CommandLow : protocol::PacketTypeInfo::Command, pipes::buffer_view{(void*) data.data(), data.length()});
|
||||
#ifdef DEBUG
|
||||
cout << "[Client -> Server][" << pkt.type().name() << "] " << pkt.data() << endl;
|
||||
#endif
|
||||
if(!low) pkt.enableFlag(PacketFlag::NewProtocol);
|
||||
sendPacket(pkt);
|
||||
}
|
||||
|
||||
void ServerConnection::sendAcknowledge(uint16_t packetId, bool low) {
|
||||
if(breakAck) return;
|
||||
char buffer[2];
|
||||
le2be16(packetId, buffer);
|
||||
protocol::ClientPacket pkt(low ? protocol::PacketTypeInfo::AckLow : protocol::PacketTypeInfo::Ack, pipes::buffer_view(buffer, 2));
|
||||
#ifdef DEBUG
|
||||
cout << "Sending packet acknowledge for " << packetId << " (Encrypt: " << encriptAck << ")" << endl;
|
||||
#endif
|
||||
if(!encriptAck)
|
||||
pkt.enableFlag(PacketFlag::Unencrypted);
|
||||
if(!low) pkt.toggle(protocol::PacketFlag::NewProtocol, true);
|
||||
sendPacket(pkt);
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <ThreadPool/Thread.h>
|
||||
#include <ThreadPool/Mutex.h>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <netinet/in.h>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <protocol/Packet.h>
|
||||
#include <protocol/buffers.h>
|
||||
#include <src/protocol/socket/FilteredUDPSocket.h>
|
||||
#include <src/Identity.h>
|
||||
#include <protocol/CryptionHandler.h>
|
||||
#include <protocol/CompressionHandler.h>
|
||||
|
||||
#define NoQt
|
||||
#ifndef NoQt
|
||||
#include <QUdpSocket>
|
||||
#endif
|
||||
|
||||
#define DEBUG_PACKET_LOG
|
||||
//#define LOG_CMD
|
||||
namespace ts {
|
||||
namespace connection {
|
||||
namespace ConnectionState {
|
||||
enum ConnectionState {
|
||||
UNCONNECTED,
|
||||
LLHANDSCHAKE,
|
||||
HANDSCHAKE,
|
||||
CONNECTED,
|
||||
DISCONNECTED
|
||||
};
|
||||
}
|
||||
|
||||
class ServerConnection
|
||||
#ifndef NoQt
|
||||
: public QObject {
|
||||
Q_OBJECT
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
public:
|
||||
ServerConnection();
|
||||
~ServerConnection();
|
||||
|
||||
bool connect(std::string host, std::string port, Identity* identity);
|
||||
void disconnect();
|
||||
|
||||
ConnectionState::ConnectionState getConnectionState(){ return cstate; }
|
||||
|
||||
bool handshake(std::string &errorMessage);
|
||||
bool handshakeNew(Command &cmd, const std::string& alpha, std::string &errorMessage);
|
||||
|
||||
void sendPacket(ts::protocol::ClientPacket& packet);
|
||||
void sendCommand(ts::Command command, bool low = false);
|
||||
void sendAcknowledge(uint16_t packetId, bool low = false);
|
||||
|
||||
std::shared_ptr<protocol::ServerPacket> readNextPacket(bool block = true);
|
||||
|
||||
uint16_t getClientId(){
|
||||
return this->clientId;
|
||||
}
|
||||
|
||||
void setClientId(uint16_t id){
|
||||
this->clientId = id;
|
||||
}
|
||||
|
||||
#ifndef NoQt
|
||||
public slots:
|
||||
void attempDatagramRead();
|
||||
void bytesWritten(qint64);
|
||||
#endif
|
||||
private:
|
||||
bool encriptAck = false;
|
||||
|
||||
bool preProgressPacket(std::shared_ptr<protocol::ServerPacket> packet);
|
||||
|
||||
void rwExecutor();
|
||||
void handleExecutor();
|
||||
bool handleNextPacket();
|
||||
|
||||
bool setupSharedSecret(std::string alpha, std::string beta, std::string sharedKey, std::string& error);
|
||||
|
||||
|
||||
void handlePacketPing(std::shared_ptr<protocol::ServerPacket> packet);
|
||||
void handlePacketCommand(std::shared_ptr<protocol::ServerPacket> packet);
|
||||
void handlePacketAck(std::shared_ptr<protocol::ServerPacket> packet);
|
||||
void handlePacketVoice(std::shared_ptr<protocol::ServerPacket> packet);
|
||||
|
||||
bool connected = true;
|
||||
|
||||
sockaddr_in remoteAddress;
|
||||
sockaddr_in localAddress;
|
||||
|
||||
|
||||
UdpSocket* socket;
|
||||
threads::Thread* rwThread = nullptr;
|
||||
std::deque<buffer::RawBuffer> writeQueue;
|
||||
#ifndef NoQt
|
||||
QUdpSocket* qtSocket = nullptr;
|
||||
#endif
|
||||
|
||||
threads::Mutex bufferQueueLock;
|
||||
buffer::SortedBufferQueue<protocol::ServerPacket>** readQueue = nullptr;
|
||||
|
||||
//std::deque<RawBuffer> readQueue;
|
||||
|
||||
std::deque<buffer::RawBuffer> acknowlageQueue;
|
||||
threads::Mutex acknowlageQueueLock;
|
||||
|
||||
protocol::PacketIdManager idManager;
|
||||
threads::Thread* handleThread = nullptr;
|
||||
std::list<std::shared_ptr<protocol::ServerPacket>> handleQueue; //Parsed packets
|
||||
threads::Mutex handleQueueLock;
|
||||
bool autoHandle = false;
|
||||
|
||||
ts::connection::CryptionHandler* cryptionHandler = nullptr;
|
||||
ts::connection::CompressionHandler* compressionHandler = nullptr;
|
||||
|
||||
std::string remoteHost;
|
||||
uint16_t remotePort;
|
||||
|
||||
Identity* clientIdentity;
|
||||
|
||||
ConnectionState::ConnectionState cstate = ConnectionState::UNCONNECTED;
|
||||
|
||||
|
||||
bool breakAck = false;
|
||||
/**
|
||||
* TS3 Client data
|
||||
*/
|
||||
|
||||
uint16_t clientId = 0;
|
||||
|
||||
std::deque<ChannelId> channels;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,361 +0,0 @@
|
||||
//
|
||||
// Created by wolverindev on 08.10.17.
|
||||
//
|
||||
|
||||
#include <tommath.h>
|
||||
#include <bitset>
|
||||
#include <openssl/sha.h>
|
||||
#include "Connection.h"
|
||||
#include "misc/base64.h"
|
||||
#include "misc/endianness.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
using namespace ts;
|
||||
using namespace ts::connection;
|
||||
using namespace ts::protocol;
|
||||
|
||||
const int InitVersionLength = 4;
|
||||
const uint8_t InitVersion[InitVersionLength] = {0x09, 0x83, 0x8C, 0xCF};
|
||||
|
||||
/**
|
||||
* Maybe memset to 0 for security?
|
||||
*/
|
||||
#define RESET_DATA \
|
||||
bufferIndex = 0; \
|
||||
delete pkt; \
|
||||
pkt = nullptr;
|
||||
|
||||
|
||||
inline ClientPacket *solvePuzzle(shared_ptr<ServerPacket> response, Identity *, std::string &);
|
||||
|
||||
inline std::string toString(mp_int* num){
|
||||
char buffer[2048];
|
||||
memset(buffer, 0, 2048);
|
||||
auto len = mp_todecimal(num, buffer);
|
||||
return string(buffer);
|
||||
}
|
||||
|
||||
|
||||
extern void hexdump(std::ostream& outs, const std::string& s, size_t line_len = 16);
|
||||
bool ServerConnection::handshake(std::string &errorMessage) {
|
||||
//setup the init mac
|
||||
/**
|
||||
* Low level
|
||||
*/
|
||||
ts::protocol::ClientPacket *pkt;
|
||||
shared_ptr<ServerPacket> response;
|
||||
int maxBufferSize = 512;
|
||||
size_t bufferIndex = 0;
|
||||
uint8_t buffer[maxBufferSize];
|
||||
memset(buffer, 0, maxBufferSize);
|
||||
int err = 0;
|
||||
string error = "success";
|
||||
|
||||
beginCoocie:
|
||||
memcpy(buffer, InitVersion, InitVersionLength);
|
||||
bufferIndex += InitVersionLength;
|
||||
buffer[bufferIndex++] = 0x00; //Login state
|
||||
|
||||
auto millis = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||
memcpy(&buffer[bufferIndex], &millis, 4);
|
||||
bufferIndex += 4;
|
||||
//generate the alpha key
|
||||
for (int i = 0; i < 4; i++) buffer[bufferIndex++] = (uint8_t) std::rand();
|
||||
bufferIndex += 8; //Reserved bytes
|
||||
|
||||
pkt = new ts::protocol::ClientPacket(ts::protocol::PacketTypeInfo::Init1, pipes::buffer_view((void *) buffer, bufferIndex));
|
||||
pkt->clientId(0);
|
||||
pkt->toggle(ts::protocol::PacketFlag::Unencrypted, true);
|
||||
pkt->applyPacketId(101, 0);
|
||||
this->sendPacket(*pkt);
|
||||
RESET_DATA;
|
||||
|
||||
response = readNextPacket();
|
||||
if (!response) {
|
||||
errorMessage = "could not get a valid response!";
|
||||
return false;
|
||||
}
|
||||
if (response->type() != protocol::PacketTypeInfo::Init1) {
|
||||
errorMessage = "invalid response type. Got: " + response->type().name();
|
||||
return false;
|
||||
}
|
||||
if (response->data()[0] != 1) {
|
||||
errorMessage = "iInvalid requested login type (" + to_string((int) response->data()[0]) + " == 1)";
|
||||
return false;
|
||||
}
|
||||
|
||||
//the second request of the manager
|
||||
memcpy(buffer, InitVersion, InitVersionLength);
|
||||
bufferIndex += InitVersionLength;
|
||||
buffer[bufferIndex++] = 0x02; //Login state
|
||||
if(response)
|
||||
memcpy(&buffer[bufferIndex], response->data().string().substr(1, 16).data(), 16);
|
||||
bufferIndex += 16; //Servers 16 bytes
|
||||
if(response)
|
||||
memcpy(&buffer[bufferIndex], response->data().string().substr(17, 4).data(), 4);
|
||||
bufferIndex += 4; //My own 16 bytes, reversed
|
||||
|
||||
pkt = new ts::protocol::ClientPacket(ts::protocol::PacketTypeInfo::Init1, pipes::buffer_view((void *) buffer, bufferIndex));
|
||||
pkt->clientId(0);
|
||||
pkt->toggle(ts::protocol::PacketFlag::Unencrypted, true);
|
||||
pkt->applyPacketId(101, 0);
|
||||
this->sendPacket(*pkt);
|
||||
RESET_DATA;
|
||||
|
||||
//We got the RSA challenge
|
||||
response = readNextPacket();
|
||||
if (!response) {
|
||||
errorMessage = "could not get a valid response!";
|
||||
return false;
|
||||
}
|
||||
if (response->type() != protocol::PacketTypeInfo::Init1) {
|
||||
errorMessage = "invalid response type";
|
||||
return false;
|
||||
}
|
||||
if (response->data()[0] != 3) {
|
||||
if(response->data()[0] == 127) {
|
||||
cout << "COOCIE RESET!" << endl;
|
||||
goto beginCoocie;
|
||||
}
|
||||
hexdump(cout, response->data().string());
|
||||
errorMessage = "Invalid requested login type (" + to_string((int) response->data()[0]) + " == 3 | unencripted -> " + (response->hasFlag(PacketFlag::Unencrypted) ? "true" : "false") + ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
//Generate puzzel response
|
||||
std::string alpha;
|
||||
pkt = solvePuzzle(response, this->clientIdentity, alpha);
|
||||
pkt->applyPacketId(101, 0);
|
||||
this->sendPacket(*pkt);
|
||||
RESET_DATA;
|
||||
|
||||
cout << "manager init done" << endl;
|
||||
this->encriptAck = true;
|
||||
|
||||
response = readNextPacket();
|
||||
if (!response) {
|
||||
errorMessage = "could not get a valid response!";
|
||||
return false;
|
||||
}
|
||||
if (response->type() != protocol::PacketTypeInfo::Command) {
|
||||
errorMessage = "invalid response type: " + response->type().name();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
auto command = response->asCommand();
|
||||
if (command.getCommand().compare("initivexpand") != 0) {
|
||||
// errorMessage = "invalid response command. Got: " + command.getCommand() + " Expected: initivexpand";
|
||||
return this->handshakeNew(command, alpha, errorMessage);
|
||||
}
|
||||
|
||||
//std::string alpha = base64::decode(command[0]["alpha"]);
|
||||
std::string beta = base64::decode(command[0]["beta"]);
|
||||
std::string omega = base64::decode(command[0]["omega"]); //Remotes public key
|
||||
cout << "RESPONSE! -> " << command.build() << endl;
|
||||
//Read public key
|
||||
ecc_key remotePublicKey{};
|
||||
if ((err = ecc_import((const unsigned char *) omega.data(), omega.length(), &remotePublicKey)) != CRYPT_OK) {
|
||||
errorMessage = "ecc_import(...) returned " + to_string(err) + "/" + error_to_string(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(strcmp(remotePublicKey.dp->name, "ECC-256") != 0){
|
||||
errorMessage = "invalid imported public key! Curve found " + string(remotePublicKey.dp->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t sharedSecretLength = 32;
|
||||
char sharedSecret[sharedSecretLength];
|
||||
|
||||
if ((err = ecc_shared_secret(clientIdentity->getKeyPair(), &remotePublicKey, (unsigned char *) sharedSecret, &sharedSecretLength)) != CRYPT_OK) {
|
||||
errorMessage = "ecc_shared_secret(...) returned " + to_string(err) + "/" + error_to_string(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!setupSharedSecret(alpha, beta, string(sharedSecret, sharedSecretLength), error)) {
|
||||
errorMessage = "setupSharedSecret(...) failed: " + error;
|
||||
return false;
|
||||
}
|
||||
|
||||
//this->readQueue[PacketType::Command.type()]->reset();
|
||||
|
||||
//TS 3.1
|
||||
/*
|
||||
response = readNextPacket();
|
||||
if (!response) {
|
||||
errorMessage = "could not get a valid response!";
|
||||
return false;
|
||||
}
|
||||
if (response->type() != protocol::PacketType::Command) {
|
||||
errorMessage = "invalid response type: " + response->type().name();
|
||||
return false;
|
||||
}
|
||||
command = response->asCommand();
|
||||
cout << "Having initiv2 -> " << response->data() << endl;
|
||||
*/
|
||||
|
||||
this->idManager.nextPacketId(PacketTypeInfo::Command);
|
||||
Command clientinit("clientinit");
|
||||
//94ec66de-5940-4e38-b002-970df0cf6c94,62444179-0d99-42ba-a45c-c6b1557d079a,d95f9901-c42d-4bac-8849-7164fd9e2310
|
||||
//clientinit["client_badges"] = "badges=450f81c1-ab41-4211-a338-222fa94ed157,c9e97536-5a2d-4c8e-a135-af404587a472,94ec66de-5940-4e38-b002-970df0cf6c94"; //,62444179-0d99-42ba-a45c-c6b1557d079a
|
||||
clientinit["client_nickname"] = "Wolf C++ XXXX";
|
||||
clientinit["client_version"] = "3.1 [Build: 1471417187]";
|
||||
clientinit["client_platform"] = "Windows";
|
||||
clientinit["client_version_sign"] = "Vr9F7kbVorcrkV5b/Iw+feH9qmDGvfsW8tpa737zhc1fDpK5uaEo6M5l2DzgaGqqOr3GKl5A7PF9Sj6eTM26Aw==";
|
||||
clientinit["client_input_hardware"] = true;
|
||||
clientinit["client_output_hardware"] = true;
|
||||
clientinit["client_default_channel"] = "";
|
||||
clientinit["client_default_channel_password"] = "";
|
||||
|
||||
string password;
|
||||
if(!password.empty()){
|
||||
char passwordBuffer[SHA_DIGEST_LENGTH];
|
||||
SHA1((const unsigned char *) password.data(), password.length(), (unsigned char *) passwordBuffer);
|
||||
password = base64_encode(string(passwordBuffer, SHA_DIGEST_LENGTH));
|
||||
}
|
||||
clientinit["client_server_password"] = password;
|
||||
clientinit["client_meta_data"] = "";
|
||||
clientinit["client_key_offset"] = this->clientIdentity->lastValidKeyOffset();
|
||||
clientinit["client_nickname_phonetic"] = "";
|
||||
clientinit["client_default_token"] = "";
|
||||
clientinit["hwid"] = "123,456123123123";
|
||||
sendCommand(clientinit);
|
||||
|
||||
while(true){
|
||||
response = readNextPacket();
|
||||
if (!response) {
|
||||
errorMessage = "could not get a valid response!";
|
||||
return false;
|
||||
}
|
||||
if(response->type() == PacketTypeInfo::Ack) continue;
|
||||
break;
|
||||
}
|
||||
|
||||
//TODO check ack id
|
||||
|
||||
if (!response) {
|
||||
errorMessage = "could not get a valid response!";
|
||||
return false;
|
||||
}
|
||||
if (response->type() != protocol::PacketTypeInfo::Command) {
|
||||
errorMessage = "invalid response type: " + response->type().name();
|
||||
return false;
|
||||
}
|
||||
if(response->asCommand().getCommand() == "initserver"){ //Got success
|
||||
this->handleQueueLock.lock();
|
||||
this->handleQueue.push_front(response);
|
||||
this->handleQueueLock.unlock();
|
||||
|
||||
this->setClientId(response->asCommand()["aclid"]);
|
||||
|
||||
this->autoHandle = true;
|
||||
cout << "Successfull connected!" << endl;
|
||||
|
||||
/*
|
||||
std::thread([&](){
|
||||
usleep(1000 * 1000);
|
||||
cout << " -> send extra command" << endl;
|
||||
//this->sendCommand(Command("channelsubscribeall return_code=1:i"));
|
||||
|
||||
while(true){
|
||||
//this->sendCommand(Command("getconnectioninfo clid=320 return_code=1:112"));
|
||||
//this->sendCommand(Command("ftgetfilelist cid=0 cpw path=\\/icons return_code=1:z0"));
|
||||
this->sendCommand(Command("servergrouppermlist sgid=6 return_code=1:112"));
|
||||
usleep(10 * 1000 * 1000);
|
||||
}
|
||||
//Command cmd("channelgetdescription cid=1 return_code=1:3o");
|
||||
//Command cmd("clientupdate client_nickname=WolverinDEV22 return_code=__1_");
|
||||
//Command cmd("clientdisconnect reasonid=8 reasonmsg=leaving");
|
||||
//this->sendCommand(Command("permissionlist return_code=__1_"));
|
||||
//this->sendCommand(Command("clientgetvariables clid=" + to_string(this->clientId)));
|
||||
}).detach();
|
||||
*/
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
cout << "Invalid connect: " << response->data() << endl;
|
||||
//TODO error handling
|
||||
return true;
|
||||
}
|
||||
|
||||
inline ClientPacket* solvePuzzle(shared_ptr<ServerPacket> response, Identity *identity, std::string &alpha) {
|
||||
uint32_t puzzelLength = be2le32(&((char*) response->data().data_ptr())[1 + 128]); //1 for the first byte (the state byte)
|
||||
|
||||
auto buffer = (char*) response->data().data_ptr();
|
||||
|
||||
char alphaBuffer[10];
|
||||
for (int index = 0; index < 10; index++)
|
||||
alphaBuffer[index] = 0; //rand();
|
||||
alpha = string(alphaBuffer, 10);
|
||||
|
||||
//Generating command
|
||||
auto pkey = identity->publicKey();
|
||||
ts::Command command("clientinitiv", {
|
||||
{"alpha", base64_encode(alphaBuffer, 10)},
|
||||
{"omega", pkey},
|
||||
{"ip", ""},
|
||||
{"ot", 1} //Required by 3.1
|
||||
});
|
||||
std::string cmd = command.build();
|
||||
|
||||
//Sloving puzzel
|
||||
mp_int x{};
|
||||
mp_int n{};
|
||||
mp_int result{};
|
||||
|
||||
//mp_init_multi(&x, &n, &result);
|
||||
mp_init(&x);
|
||||
mp_init(&n);
|
||||
mp_init(&result);
|
||||
|
||||
char numBuffer[2048];
|
||||
mp_read_unsigned_bin(&x, (const unsigned char *) &response->data()[1], 64); //One offset
|
||||
mp_read_unsigned_bin(&n, (const unsigned char *) &response->data()[1 + 64], 64); //1 + 64 offset
|
||||
|
||||
cout << "X: " << toString(&x) << endl;
|
||||
cout << "N: " << toString(&n) << endl;
|
||||
cout << "Length: " << puzzelLength << endl;
|
||||
|
||||
mp_int exp{};
|
||||
mp_init(&exp);
|
||||
mp_2expt(&exp, puzzelLength);
|
||||
|
||||
|
||||
//x ** (2 ** puzzelLength) mod n
|
||||
int err = 0;
|
||||
if ((err = mp_exptmod(&x, &exp, &n, &result)) != CRYPT_OK) {
|
||||
cerr << "Invalid crypt: " << err << "/" << error_to_string(err) << endl;
|
||||
}
|
||||
|
||||
int resultBufferLength = mp_unsigned_bin_size(&result);
|
||||
char resultBuffer[resultBufferLength];
|
||||
mp_to_unsigned_bin(&result, (unsigned char *) resultBuffer);
|
||||
|
||||
|
||||
//mp_clear_multi(&x, &n, &exp, &result);
|
||||
mp_clear(&x);
|
||||
mp_clear(&n);
|
||||
mp_clear(&exp);
|
||||
mp_clear(&result);
|
||||
|
||||
size_t packetBufferLength = InitVersionLength + 1 + 232 + 64 + cmd.length();
|
||||
char packetBuffer[packetBufferLength];
|
||||
memset(packetBuffer, 0, packetBufferLength);
|
||||
|
||||
memcpy(packetBuffer, InitVersion, InitVersionLength);
|
||||
packetBuffer[InitVersionLength] = 0x04;
|
||||
|
||||
//Copy old data
|
||||
memcpy(&packetBuffer[InitVersionLength + 1], &response->data()[1], 232);
|
||||
memcpy(&packetBuffer[InitVersionLength + 1 + 232 + (64 - resultBufferLength)], resultBuffer, resultBufferLength);
|
||||
memcpy(&packetBuffer[InitVersionLength + 1 + 232 + 64], cmd.data(), cmd.length());
|
||||
|
||||
cout << "sending puzzel sulution" << endl;
|
||||
auto pkt = new ts::protocol::ClientPacket(ts::protocol::PacketTypeInfo::Init1, pipes::buffer_view((void *) packetBuffer, packetBufferLength));
|
||||
pkt->clientId(0);
|
||||
pkt->toggle(ts::protocol::PacketFlag::Unencrypted, true);
|
||||
return pkt;
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
#include <protocol/Packet.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "Connection.h"
|
||||
#include "misc/base64.h"
|
||||
#include "misc/endianness.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace ts;
|
||||
using namespace ts::connection;
|
||||
using namespace ts::protocol;
|
||||
|
||||
//notifystatusfiletransfer clientftfid=4093 status=2063 msg=lost\sfile\stransfer\sconnection size=16384
|
||||
|
||||
extern void hexdump(std::ostream& outs, const std::string& s, size_t line_len = 16);
|
||||
inline void downloadStuff(std::string key, uint16_t port, uint64_t size){
|
||||
threads::Thread([key, port, size](){
|
||||
int socketId = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
assert(socketId > 1);
|
||||
|
||||
sockaddr_in server;
|
||||
server.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_port = htons( port );
|
||||
|
||||
//Connect to remote server
|
||||
if (connect(socketId , (struct sockaddr *)&server , sizeof(server)) < 0)
|
||||
{
|
||||
perror("connect failed. Error");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t readed = 0;
|
||||
assert(send(socketId, key.data(), key.length(), 0) > 0);
|
||||
|
||||
while(readed < size + 3){
|
||||
char buffer[size];
|
||||
auto readedBytes = recv(socketId, buffer, size - readed, MSG_DONTWAIT);
|
||||
if(readedBytes < 0) {
|
||||
//cerr << "Invalid ft read" << endl;
|
||||
continue;
|
||||
}
|
||||
if(readedBytes == 0){
|
||||
continue;
|
||||
}
|
||||
hexdump(cout, string(buffer, readedBytes));
|
||||
readed += readedBytes;
|
||||
}
|
||||
cout << "File downloaded!" << endl;
|
||||
}).detach();
|
||||
}
|
||||
|
||||
void ServerConnection::handlePacketAck(std::shared_ptr<protocol::ServerPacket> packet) {
|
||||
auto packetId = be2le16((const char*) packet->data().data_ptr());
|
||||
#if defined(DEBUG_PACKET_LOG) || defined(LOG_ACK)
|
||||
cout << "Got ack for " << packetId << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ServerConnection::handlePacketCommand(std::shared_ptr<protocol::ServerPacket> packet) {
|
||||
auto command = packet->asCommand();
|
||||
#if defined(DEBUG_PACKET_LOG) || defined(LOG_CMD)
|
||||
cout << "[Server -> Client][" << packet->type().name() << "] " << packet->data() << endl;
|
||||
#endif
|
||||
if (command.getCommand().compare("notifyconnectioninforequest") == 0) { //TODO
|
||||
cout << "Send response" << endl;
|
||||
Command cmd(
|
||||
string("setconnectioninfo"), {
|
||||
{"connection_ping", 10000000},
|
||||
{"connection_ping_deviation", 10000000},
|
||||
{"connection_packets_sent_speech", 0},
|
||||
{"connection_packets_sent_keepalive", 0},
|
||||
{"connection_packets_sent_control", rand()},
|
||||
{"connection_bytes_sent_speech", 0},
|
||||
{"connection_bytes_sent_keepalive", 0},
|
||||
{"connection_bytes_sent_control", 0},
|
||||
{"connection_packets_received_speech", 0},
|
||||
{"connection_packets_received_keepalive", 0},
|
||||
{"connection_packets_received_control", 0},
|
||||
{"connection_bytes_received_speech", 0},
|
||||
{"connection_bytes_received_keepalive", 0},
|
||||
{"connection_bytes_received_control", 0},
|
||||
{"connection_server2client_packetloss_speech", 10000000},
|
||||
{"connection_server2client_packetloss_keepalive", 10000000},
|
||||
{"connection_server2client_packetloss_control", 10000000},
|
||||
{"connection_server2client_packetloss_total", 10000000},
|
||||
{"connection_bandwidth_sent_last_second_speech", 0},
|
||||
{"connection_bandwidth_sent_last_second_keepalive", 0},
|
||||
{"connection_bandwidth_sent_last_second_control", 0},
|
||||
{"connection_bandwidth_sent_last_minute_speech", 0},
|
||||
{"connection_bandwidth_sent_last_minute_keepalive", 0},
|
||||
{"connection_bandwidth_sent_last_minute_control", 0},
|
||||
{"connection_bandwidth_received_last_second_speech", 0},
|
||||
{"connection_bandwidth_received_last_second_keepalive", 0},
|
||||
{"connection_bandwidth_received_last_second_control", 0},
|
||||
{"connection_bandwidth_received_last_minute_speech", 0},
|
||||
{"connection_bandwidth_received_last_minute_keepalive", 0},
|
||||
{"connection_bandwidth_received_last_minute_control", 0}
|
||||
}
|
||||
);
|
||||
sendCommand(cmd, true);
|
||||
} else if (command.command() == "notifyserverupdated") {
|
||||
#if defined(DEBUG_PACKET_LOG) || defined(LOG_CMD)
|
||||
cout << "notifyserverupdated -> " << endl;
|
||||
cout << "Last data: " << packet->data().string().substr(packet->data().length() - 10) << endl;
|
||||
#endif
|
||||
} else if (command.command() == "notifystartdownload") {
|
||||
cout << "Client download: " << command.build() << endl;
|
||||
auto port = command["port"].as<uint16_t>();
|
||||
auto key = command["ftkey"].string();
|
||||
auto size = command["size"].as<uint64_t>();
|
||||
downloadStuff(key, port, size);
|
||||
} else if (command.command() == "channellist") {
|
||||
cout << "Breaking ack" << endl;
|
||||
for (int index = 0; index < command.bulkCount(); index++) {
|
||||
this->channels.push_back(command[index]["cid"].as<ChannelId>());
|
||||
}
|
||||
}
|
||||
}
|
||||
void ServerConnection::handlePacketVoice(std::shared_ptr<protocol::ServerPacket> packet) {}
|
||||
|
||||
static int pingIndex = 0;
|
||||
void ServerConnection::handlePacketPing(std::shared_ptr<protocol::ServerPacket> packet) {
|
||||
if(packet->type() == PacketTypeInfo::Pong){
|
||||
//cout << "[PING] gota " << be2le16(packet->data().data()) << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[2];
|
||||
le2be16(packet->packetId(), buffer);
|
||||
|
||||
ClientPacket pkt(PacketTypeInfo::Pong, pipes::buffer_view{buffer, 2});
|
||||
pkt.enableFlag(PacketFlag::Unencrypted);
|
||||
sendPacket(pkt);
|
||||
|
||||
ClientPacket ping(PacketTypeInfo::Ping, pipes::buffer_view{buffer, 0});
|
||||
ping.enableFlag(PacketFlag::Unencrypted);
|
||||
sendPacket(ping);
|
||||
//cout << "[PING] Reqe " << ping.packetId() << endl;
|
||||
|
||||
//cout << "[PONG] Send " << packet->packetId() << endl;
|
||||
|
||||
if(this->clientId > 0 && this->channels.size() > 0) {
|
||||
Command command("clientmove");
|
||||
command["clid"] = this->clientId;
|
||||
|
||||
auto idx = rand() % this->channels.size();
|
||||
command["cid"] = this->channels[idx];
|
||||
this->sendCommand(command);
|
||||
|
||||
std::thread([&] {
|
||||
threads::self::sleep_for(chrono::seconds(1));
|
||||
|
||||
Command cmd("channelcreate");
|
||||
cmd["channel_name"] = to_string(rand()) + "_" + to_string(rand());
|
||||
//this->sendCommand(cmd);
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
#include <ed25519/ed25519.h>
|
||||
#include <ed25519/sha512.h>
|
||||
#include <misc/base64.h>
|
||||
#include <misc/digest.h>
|
||||
#include "Connection.h"
|
||||
#include "License.h"
|
||||
#include <log/LogUtils.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
using namespace ts;
|
||||
using namespace license::teamspeak;
|
||||
using namespace ts::connection;
|
||||
using namespace ts::protocol;
|
||||
|
||||
|
||||
int __ed_sha512_init(sha512_context* ctx) {
|
||||
//assert(!ctx->context);
|
||||
|
||||
ctx->context = new hash_state{};
|
||||
return sha512_init((hash_state*) ctx->context) == CRYPT_OK;
|
||||
}
|
||||
|
||||
int __ed_sha512_final(sha512_context* ctx, unsigned char *out) {
|
||||
assert(ctx->context);
|
||||
|
||||
auto result = sha512_done((hash_state*) ctx->context, out) == CRYPT_OK;
|
||||
delete (hash_state*) ctx->context;
|
||||
return result;
|
||||
}
|
||||
int __ed_sha512_update(sha512_context* ctx, const unsigned char *msg, size_t len) {
|
||||
assert(ctx->context);
|
||||
return sha512_process((hash_state*) ctx->context, msg, len) == CRYPT_OK;
|
||||
}
|
||||
|
||||
static sha512_functions __ed_sha512_functions {
|
||||
__ed_sha512_init,
|
||||
__ed_sha512_final,
|
||||
__ed_sha512_update
|
||||
};
|
||||
|
||||
|
||||
bool ServerConnection::handshakeNew(Command &initivexpand2, const std::string& alpha, std::string &errorMessage) {
|
||||
if(&__ed_sha512_functions != &_ed_sha512_functions)
|
||||
_ed_sha512_functions = __ed_sha512_functions;
|
||||
|
||||
cout << initivexpand2.build() << endl;
|
||||
u_char seed[32 * 2];
|
||||
u_char clientPrivateKey[32];
|
||||
u_char clientPublicKey[32];
|
||||
ed25519_create_keypair(clientPublicKey, clientPrivateKey, seed);
|
||||
cout << "Client key: " << base64::encode((char*) clientPrivateKey, 32) << endl;
|
||||
cout << "Privet key:" << endl;
|
||||
hexDump(clientPrivateKey, 32);
|
||||
cout << "Public key:" << endl;
|
||||
hexDump(clientPublicKey, 32);
|
||||
auto license = base64::decode(initivexpand2["l"]);
|
||||
|
||||
auto licensestream = stringstream(license);
|
||||
auto chain = LicenseChain::parse(licensestream, errorMessage);
|
||||
if(!chain) return false;
|
||||
chain->print();
|
||||
|
||||
unique_ptr<ecc_key> serverPublic(new ecc_key{});
|
||||
auto omega = base64::decode(initivexpand2["omega"]);
|
||||
ecc_import((u_char*) omega.data(), omega.length(), serverPublic.get());
|
||||
|
||||
//7B 1E AC 02 CE 77 35 0E EF C4 5C 1C F7 54 04 87 A9 A7 64 A7 8F 04 F7 53 58 64 84 D7 0A 97 F2 63
|
||||
//[0x7b, 0x1e, 0xac, 0x2, 0xce, 0x77, 0x35, 0xe, 0xef, 0xc4, 0x5c, 0x1c, 0xf7, 0x54, 0x4, 0x87, 0xa9, 0xa7, 0x64, 0xa7, 0x8f, 0x4, 0xf7, 0x53, 0x58, 0x64, 0x84, 0xd7, 0xa, 0x97, 0xf2, 0xe3]
|
||||
//License signed from server :)
|
||||
auto licenseHash = digest::sha256(license);
|
||||
auto licenseSign = base64::decode(initivexpand2["proof"]);
|
||||
|
||||
int state;
|
||||
assert(ecc_verify_hash((u_char*) licenseSign.c_str(), licenseSign.length(), (u_char*) licenseHash.c_str(), licenseHash.length(), &state, serverPublic.get()) == CRYPT_OK);
|
||||
cout << "State: " << state << endl;
|
||||
assert(state == 1);
|
||||
|
||||
//EK!
|
||||
this->idManager.nextPacketId(PacketTypeInfo::Command);
|
||||
cout << this->idManager.currentPacketId(PacketTypeInfo::Command) << endl;
|
||||
Command clientek("clientek");
|
||||
clientek["ek"] = base64::encode((char*) clientPublicKey, 32);
|
||||
auto rawProof = string((char*) clientPublicKey, 32) + base64::decode(initivexpand2["beta"]);
|
||||
cout << " -> " << rawProof.length() << endl;
|
||||
size_t signBufferLength = 120;
|
||||
char signBuffer[signBufferLength];
|
||||
prng_state prngState{};
|
||||
memset(&prngState, 0, sizeof(prngState));
|
||||
|
||||
cout << "Data: " << base64::encode(rawProof) << endl;
|
||||
cout << "KEY: " << this->clientIdentity->privateKey() << endl;
|
||||
rawProof = digest::sha256(rawProof);
|
||||
assert(ecc_sign_hash((u_char*) rawProof.data(), rawProof.length(), (u_char*) signBuffer, &signBufferLength, &prngState, find_prng("sprng"), this->clientIdentity->getKeyPair()) == CRYPT_OK);
|
||||
cout << "ecc_sign_hash() -> " << base64::encode(signBuffer, signBufferLength) << endl;
|
||||
clientek["proof"] = base64::encode(signBuffer, signBufferLength);
|
||||
this->sendCommand(clientek, false);
|
||||
|
||||
//TODO magic stuff
|
||||
shared_ptr<ServerPacket> response;
|
||||
response = readNextPacket();
|
||||
if (!response) {
|
||||
errorMessage = "could not get a valid response!";
|
||||
return false;
|
||||
}
|
||||
cout << "Type: " << response->type().name() << endl;
|
||||
cout << "ID: " << (int) response->data()[0] << " " << (int) response->data()[1] << endl;
|
||||
|
||||
|
||||
LicensePublicKey serverroot;
|
||||
memcpy(serverroot, public_root, 32);
|
||||
if(initivexpand2[0].has("root")) {
|
||||
cout << "Cot costume server root!" << endl;
|
||||
auto root = base64::decode(initivexpand2["root"]);
|
||||
memcpy(serverroot, root.data(), 32);
|
||||
}
|
||||
cout << "Public root key: " << endl;
|
||||
for(const auto& e : serverroot)
|
||||
cout << hex << "0x" << (int) (uint8_t) e << " " << endl;
|
||||
|
||||
string sharedData;
|
||||
this->cryptionHandler->setupSharedSecretNew(alpha, base64::decode(initivexpand2["beta"]), (char*) clientPrivateKey, (char*) chain->generatePublicKey(serverroot).data());
|
||||
//this->cryptionHandler->setupSharedSecretNew(alpha, base64::decode(initivexpand2["beta"]), (char*) clientPrivateKey, (char*) public_tea_root);
|
||||
|
||||
threads::self::sleep_for(milliseconds(250));
|
||||
Command clientinit("clientinit");
|
||||
//94ec66de-5940-4e38-b002-970df0cf6c94,62444179-0d99-42ba-a45c-c6b1557d079a,d95f9901-c42d-4bac-8849-7164fd9e2310
|
||||
//clientinit["client_badges"] = "badges=450f81c1-ab41-4211-a338-222fa94ed157,c9e97536-5a2d-4c8e-a135-af404587a472,94ec66de-5940-4e38-b002-970df0cf6c94"; //,62444179-0d99-42ba-a45c-c6b1557d079a
|
||||
clientinit["client_nickname"] = "Wolf C++ XX";
|
||||
clientinit["client_version"] = "3.1.8 [Build: 1516614607]";
|
||||
clientinit["client_platform"] = "Windows";
|
||||
clientinit["client_version_sign"] = "gDEgQf/BiOQZdAheKccM1XWcMUj2OUQqt75oFuvF2c0MQMXyv88cZQdUuckKbcBRp7RpmLInto4PIgd7mPO7BQ==";
|
||||
clientinit["client_input_hardware"] = true;
|
||||
clientinit["client_output_hardware"] = true;
|
||||
clientinit["client_default_channel"] = "";
|
||||
clientinit["client_default_channel_password"] = "";
|
||||
clientinit["client_server_password"] = "";
|
||||
clientinit["client_meta_data"] = "";
|
||||
clientinit["client_key_offset"] = this->clientIdentity->lastValidKeyOffset();
|
||||
clientinit["client_nickname_phonetic"] = "";
|
||||
clientinit["client_default_token"] = "";
|
||||
clientinit["hwid"] = "123,456123123123";
|
||||
sendCommand(clientinit);
|
||||
|
||||
this->autoHandle = true;
|
||||
/*
|
||||
response = readNextPacket();
|
||||
if (!response) {
|
||||
errorMessage = "could not get a valid response!";
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
//
|
||||
// Created by root on 13.10.17.
|
||||
//
|
||||
|
||||
#include "FilteredUDPSocket.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <ifaddrs.h>
|
||||
#include <netinet/udp.h> //Provides declarations for udp header
|
||||
#include <netinet/ip.h> //Provides declarations for ip header
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/filter.h>
|
||||
#include <chrono>
|
||||
#include <zconf.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
using namespace ts::connection;
|
||||
|
||||
FilteredUdpSocket::FilteredUdpSocket() {}
|
||||
FilteredUdpSocket::~FilteredUdpSocket() {}
|
||||
|
||||
|
||||
bool FilteredUdpSocket::setup(sockaddr_in * remoteAddr) {
|
||||
srand(system_clock::now().time_since_epoch().count()); // should only be called once
|
||||
int r = (lrand48() % (50 * 1000)) + 1000; // returns a pseudo-random integer between 0 and RAND_MAX
|
||||
|
||||
|
||||
this->remoteAdress = new sockaddr_in;
|
||||
memcpy(this->remoteAdress, remoteAddr, sizeof(sockaddr_in));
|
||||
|
||||
this->socketDescriptor = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if(this->socketDescriptor < 0){
|
||||
cerr << "Invalid socket create: " << errno << " - " << this->socketDescriptor << " -> " << strerror(errno) << endl;
|
||||
}
|
||||
int allow = 1;
|
||||
setsockopt(this->socketDescriptor, SOL_SOCKET, SO_REUSEADDR, &allow, sizeof(int));
|
||||
|
||||
this->localAdress = new sockaddr_in;
|
||||
memset((char *) this->localAdress, 0, sizeof(sockaddr_in));
|
||||
localAdress->sin_family = AF_INET;
|
||||
localAdress->sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
localAdress->sin_port = htons(r);
|
||||
|
||||
|
||||
/* sudo tcpdump -q udp port 256 -dd */
|
||||
struct sock_filter code[ ] = {
|
||||
{ 0x28, 0, 0, 0x0000000c },
|
||||
{ 0x15, 0, 8, 0x000086dd },
|
||||
{ 0x30, 0, 0, 0x00000014 },
|
||||
{ 0x15, 2, 0, 0x00000084 },
|
||||
{ 0x15, 1, 0, 0x00000006 },
|
||||
{ 0x15, 0, 17, 0x00000011 },
|
||||
{ 0x28, 0, 0, 0x00000036 },
|
||||
{ 0x15, 14, 0, 0x00002fbd },
|
||||
{ 0x28, 0, 0, 0x00000038 },
|
||||
{ 0x15, 12, 13, 0x00002fbd },
|
||||
{ 0x15, 0, 12, 0x00000800 },
|
||||
{ 0x30, 0, 0, 0x00000017 },
|
||||
{ 0x15, 2, 0, 0x00000084 },
|
||||
{ 0x15, 1, 0, 0x00000006 },
|
||||
{ 0x15, 0, 8, 0x00000011 },
|
||||
{ 0x28, 0, 0, 0x00000014 },
|
||||
{ 0x45, 6, 0, 0x00001fff },
|
||||
{ 0xb1, 0, 0, 0x0000000e },
|
||||
{ 0x48, 0, 0, 0x0000000e },
|
||||
{ 0x15, 2, 0, 0x00002fbd },
|
||||
{ 0x48, 0, 0, 0x00000010 },
|
||||
{ 0x15, 0, 1, 0x00002fbd },
|
||||
{ 0x6, 0, 0, 0x00040000 },
|
||||
{ 0x6, 0, 0, 0x00000000 },
|
||||
|
||||
};
|
||||
|
||||
struct sock_fprog bpf = {
|
||||
.len = sizeof(code) / sizeof(*code),
|
||||
.filter = code,
|
||||
};
|
||||
|
||||
//auto response = setsockopt(this->socketDescriptor, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf));
|
||||
//if (response < 0) cerr << "Invalid attach!" << endl;
|
||||
/* ... bail out ... */
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
if(connect(this->socketDescriptor, (const sockaddr *) remoteAddr, sizeof(sockaddr_in)) < 0){
|
||||
cerr << "Invalid connect" << endl;
|
||||
}
|
||||
*/
|
||||
if(bind(this->socketDescriptor, (const sockaddr *) localAdress, sizeof(sockaddr_in)) < 0) cout << "XXX" << endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FilteredUdpSocket::close() {
|
||||
if(this->socketDescriptor > 0) {
|
||||
shutdown(this->socketDescriptor, SHUT_RDWR);
|
||||
::close(this->socketDescriptor);
|
||||
this->socketDescriptor = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t FilteredUdpSocket::write(const char *buffer, size_t size) {
|
||||
return sendto(this->socketDescriptor, buffer, size, 0, (const sockaddr *) this->remoteAdress, sizeof(sockaddr_in));
|
||||
}
|
||||
|
||||
ssize_t FilteredUdpSocket::read(char *buffer, size_t size) {
|
||||
return recv(this->socketDescriptor, (void *) buffer, size, 0);
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
namespace ts {
|
||||
namespace connection {
|
||||
class FilteredUdpSocket {
|
||||
public:
|
||||
FilteredUdpSocket();
|
||||
~FilteredUdpSocket();
|
||||
|
||||
bool setup(sockaddr_in*);
|
||||
void close();
|
||||
|
||||
ssize_t read(char* buffer, size_t size);
|
||||
ssize_t write(const char* buffer, size_t size);
|
||||
|
||||
int getSocketDescriptor(){ return socketDescriptor; }
|
||||
private:
|
||||
int socketDescriptor;
|
||||
sockaddr_in* remoteAdress = nullptr;
|
||||
sockaddr_in* localAdress = nullptr;
|
||||
};
|
||||
|
||||
typedef FilteredUdpSocket UdpSocket;
|
||||
}
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
//
|
||||
// Created by wolverindev on 12.10.17.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <ifaddrs.h>
|
||||
#include <netinet/udp.h> //Provides declarations for udp header
|
||||
#include <netinet/ip.h> //Provides declarations for ip header
|
||||
#include <arpa/inet.h>
|
||||
#include "RawUDPSocket.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace ts::connection;
|
||||
|
||||
/*
|
||||
96 bit (12 bytes) pseudo header needed for udp header checksum calculation
|
||||
*/
|
||||
struct pseudo_header
|
||||
{
|
||||
u_int32_t source_address;
|
||||
u_int32_t dest_address;
|
||||
u_int8_t placeholder;
|
||||
u_int8_t protocol;
|
||||
u_int16_t udp_length;
|
||||
};
|
||||
|
||||
RawUdpSocket::RawUdpSocket() {}
|
||||
|
||||
RawUdpSocket::~RawUdpSocket() {}
|
||||
|
||||
uint16_t RawUdpSocket::buildCheckSum(uint16_t* buffer, size_t size) {
|
||||
register long sum;
|
||||
unsigned short oddbyte;
|
||||
register short answer;
|
||||
|
||||
sum = 0;
|
||||
while (size > 1) {
|
||||
sum += *buffer++;
|
||||
size -= 2;
|
||||
}
|
||||
if (size == 1) {
|
||||
oddbyte = 0;
|
||||
*((u_char *) &oddbyte) = *(u_char *) buffer;
|
||||
sum += oddbyte;
|
||||
}
|
||||
|
||||
sum = (sum >> 16) + (sum & 0xffff);
|
||||
sum = sum + (sum >> 16);
|
||||
answer = (short) ~sum;
|
||||
|
||||
return (answer);
|
||||
}
|
||||
|
||||
int RawUdpSocket::read(char *buffer, size_t size) {}
|
||||
|
||||
int RawUdpSocket::write(const char *buffer, size_t size) {
|
||||
char datagram[4096];
|
||||
memset(datagram, 0, 4096);
|
||||
memcpy(&datagram[sizeof(iphdr) + sizeof(udphdr)], buffer, size);
|
||||
|
||||
//IP header
|
||||
struct iphdr *iph = (struct iphdr *) datagram;
|
||||
//UDP header
|
||||
struct udphdr *udph = (struct udphdr *) (datagram + sizeof(struct ip));
|
||||
|
||||
//Setup the ip header
|
||||
iph->ihl = 5;
|
||||
iph->version = 4;
|
||||
iph->tos = 0;
|
||||
iph->tot_len = sizeof(iphdr) + sizeof(udphdr) + size; //Total length
|
||||
iph->id = htonl(12); //TODO increase
|
||||
iph->frag_off = 0;
|
||||
iph->ttl = 255; //Max 255 hops maybe change it to default 64
|
||||
iph->protocol = IPPROTO_UDP;
|
||||
iph->saddr = localAdress->sin_addr.s_addr;
|
||||
iph->daddr = remoteAdress->sin_addr.s_addr;
|
||||
iph->check = this->buildCheckSum ((unsigned short *) datagram, iph->tot_len);
|
||||
|
||||
udph->source = localAdress->sin_port;
|
||||
udph->dest = remoteAdress->sin_port;
|
||||
udph->len = htons(8 + size);
|
||||
|
||||
size_t csumLength = sizeof(struct pseudo_header) + sizeof(struct udphdr) + size;
|
||||
char csumData[csumLength];
|
||||
|
||||
pseudo_header psh;
|
||||
//Now the UDP checksum using the pseudo header
|
||||
psh.source_address = localAdress->sin_addr.s_addr;
|
||||
psh.dest_address = remoteAdress->sin_addr.s_addr;
|
||||
psh.placeholder = 0;
|
||||
psh.protocol = IPPROTO_UDP;
|
||||
psh.udp_length = htons(sizeof(struct udphdr) + size);
|
||||
memcpy(csumData , (char*) &psh , sizeof (struct pseudo_header));
|
||||
memcpy(csumData + sizeof(struct pseudo_header) , udph , sizeof(struct udphdr) + size);
|
||||
|
||||
udph->check = buildCheckSum((uint16_t *) csumData, csumLength);
|
||||
|
||||
auto written = sendto(this->socketDescriptor, datagram, iph->tot_len, 0, (struct sockaddr *) this->remoteAdress, sizeof(sockaddr));
|
||||
if(written != iph->tot_len){
|
||||
cerr << "Invalid write: " << written << endl;
|
||||
return -1;
|
||||
}
|
||||
cout << "Write: " << written << endl;
|
||||
return size;
|
||||
}
|
||||
|
||||
bool RawUdpSocket::setup(sockaddr_in *remoteAdress) {
|
||||
this->remoteAdress = new sockaddr_in;
|
||||
memcpy(this->remoteAdress, remoteAdress, sizeof(sockaddr_in));
|
||||
this->socketDescriptor = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
|
||||
if(this->socketDescriptor < 0){
|
||||
if(this->socketDescriptor == EPERM){
|
||||
cerr << "Invalid permission. Dont have permission to create a new RAW socket!";
|
||||
return false;
|
||||
}
|
||||
cerr << "Invalid socket create: " << errno << " - " << this->socketDescriptor << " -> " << strerror(errno) << endl;
|
||||
}
|
||||
|
||||
//get local addr
|
||||
this->localAdress = new sockaddr_in;
|
||||
struct ifaddrs *ifAddrStruct = NULL;
|
||||
getifaddrs(&ifAddrStruct);
|
||||
|
||||
for (ifaddrs* ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
|
||||
if (!ifa->ifa_addr) {
|
||||
continue;
|
||||
}
|
||||
if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4
|
||||
// is a valid IP4 Address
|
||||
memcpy(this->localAdress, ifa->ifa_addr, sizeof(sockaddr_in));
|
||||
/*
|
||||
tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
|
||||
char addressBuffer[INET_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
|
||||
*/
|
||||
}
|
||||
/*
|
||||
else if (ifa->ifa_addr->sa_family == AF_INET6) { // check it is IP6
|
||||
// is a valid IP6 Address
|
||||
tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
|
||||
char addressBuffer[INET6_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
|
||||
}
|
||||
*/
|
||||
}
|
||||
if (ifAddrStruct != NULL) freeifaddrs(ifAddrStruct);
|
||||
this->localAdress->sin_port = 1232;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
namespace ts {
|
||||
namespace connection {
|
||||
class RawUdpSocket {
|
||||
public:
|
||||
RawUdpSocket();
|
||||
~RawUdpSocket();
|
||||
|
||||
bool setup(sockaddr_in*);
|
||||
|
||||
int read(char* buffer, size_t size);
|
||||
int write(const char* buffer, size_t size);
|
||||
uint16_t buildCheckSum(uint16_t* buffer, size_t size);
|
||||
|
||||
int getSocketDescriptor(){ return socketDescriptor; }
|
||||
private:
|
||||
int socketDescriptor;
|
||||
sockaddr_in* remoteAdress = nullptr;
|
||||
sockaddr_in* localAdress = nullptr;
|
||||
};
|
||||
|
||||
|
||||
typedef RawUdpSocket UdpSocket;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
if (NOT TARGET Gabime::Spdlog)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_path(SPDLOG_INCLUDE_DIR NAMES spdlog/spdlog.h)
|
||||
find_package_handle_standard_args(Spdlog DEFAULT_MSG SPDLOG_INCLUDE_DIR)
|
||||
add_library(spdlog INTERFACE)
|
||||
target_include_directories(spdlog INTERFACE ${SPDLOG_INCLUDE_DIR})
|
||||
add_library(Gabime::Spdlog ALIAS spdlog)
|
||||
endif ()
|
||||
@@ -0,0 +1,57 @@
|
||||
# - Try to find mysql include dirs and libraries
|
||||
#
|
||||
# Usage of this module as follows:
|
||||
#
|
||||
# find_package(mysql)
|
||||
#
|
||||
# Variables used by this module, they can change the default behaviour and need
|
||||
# to be set before calling find_package:
|
||||
#
|
||||
# mysql_ROOT_DIR Set this variable to the root installation of
|
||||
# mysql if the module has problems finding the
|
||||
# proper installation path.
|
||||
#
|
||||
# Variables defined by this module:
|
||||
#
|
||||
# mysql_FOUND System has mysql, include and library dirs found
|
||||
# mysql_INCLUDE_DIR The mysql include directories.
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
function(find_mysql)
|
||||
find_path(mysql_ROOT_DIR
|
||||
NAMES include/mysql.h include/mysql_version.h
|
||||
HINTS ${mysql_ROOT_DIR}
|
||||
)
|
||||
|
||||
find_path(mysql_INCLUDE_DIR
|
||||
NAMES mysql.h mysql_version.h
|
||||
HINTS ${mysql_ROOT_DIR}/include/
|
||||
)
|
||||
|
||||
if (NOT TARGET mysql::client::static)
|
||||
find_library(MYSQL_CLIENT_STATIC
|
||||
NAMES mysql.lib libmysqlclient.a
|
||||
HINTS ${mysql_ROOT_DIR} ${mysql_ROOT_DIR}/lib
|
||||
)
|
||||
|
||||
if(MYSQL_CLIENT_STATIC)
|
||||
add_library(mysql::client::static STATIC IMPORTED)
|
||||
set_target_properties(mysql::client::static PROPERTIES
|
||||
IMPORTED_LOCATION ${MYSQL_CLIENT_STATIC}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${mysql_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
find_package_handle_standard_args(mysql DEFAULT_MSG
|
||||
mysql_INCLUDE_DIR
|
||||
)
|
||||
|
||||
mark_as_advanced(
|
||||
mysql_ROOT_DIR
|
||||
mysql_INCLUDE_DIR
|
||||
MYSQL_CLIENT_STATIC
|
||||
)
|
||||
endfunction()
|
||||
find_mysql()
|
||||
@@ -1,25 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
project(TeamSpeak)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
|
||||
include_directories(../shared/src)
|
||||
add_definitions(-DLTM_DESC)
|
||||
|
||||
set(SOURCE_FILES
|
||||
main.cpp
|
||||
src/ProxiedClient.cpp
|
||||
src/PorxiedClientSock5.cpp
|
||||
src/TSClient.cpp
|
||||
)
|
||||
|
||||
add_executable(TeamSpeakFloodClient ${SOURCE_FILES})
|
||||
target_link_libraries(TeamSpeakFloodClient
|
||||
TeaSpeak
|
||||
pthread ThreadPool
|
||||
${TOM_LIBRARIES}
|
||||
crypto
|
||||
event
|
||||
event_pthreads
|
||||
/usr/local/lib/libjsoncpp.so
|
||||
)
|
||||
@@ -1,81 +0,0 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <src/ProxiedClient.h>
|
||||
#include <event2/thread.h>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace std;
|
||||
using namespace ts::flood;
|
||||
|
||||
void hexout(std::ostream& os, unsigned char c)
|
||||
{
|
||||
unsigned char uc = static_cast<unsigned char>(c);
|
||||
os << std::setw(2) << std::setfill('0') << (unsigned int)uc << ' ';
|
||||
}
|
||||
|
||||
void hexdump(std::ostream& outs, const std::string& s, size_t line_len = 16)
|
||||
{
|
||||
std::ostringstream os;
|
||||
const std::string::size_type slen(s.size());
|
||||
int i(0);
|
||||
std::string::size_type pos(0);
|
||||
const std::streamsize lines(slen / line_len);
|
||||
const std::streamsize chars(slen % line_len);
|
||||
std::ios::fmtflags f(os.flags());
|
||||
|
||||
os << "Length: " << s.length() << "/" << std::hex << "0x" << s.length() << endl;
|
||||
for(std::streamsize line = 0; line <= lines - (chars == 0 ? 1 : 0); ++line)
|
||||
{
|
||||
os << std::hex << setfill('0') << setw(3) << line * line_len << " | ";
|
||||
for(i = 0; i < line_len; ++i)
|
||||
{
|
||||
if(pos < s.length())
|
||||
hexout(os, s[pos]);
|
||||
else os << " ";
|
||||
pos++;
|
||||
}
|
||||
os << " | ";
|
||||
if(pos - line_len < s.length()){
|
||||
auto av = s.substr(pos - line_len);
|
||||
for(char c : av.substr(0, min(av.length(), line_len))){
|
||||
if(isprint(c))
|
||||
os << c << " ";
|
||||
else
|
||||
os << "." << " ";
|
||||
}
|
||||
}
|
||||
os << '\n';
|
||||
}
|
||||
os.flags(f);
|
||||
outs << os.str() << endl;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv){
|
||||
sockaddr_in remoteAddress{}, proxyAddress{};
|
||||
memset(&remoteAddress, 0, sizeof(remoteAddress));
|
||||
memset(&proxyAddress, 0, sizeof(proxyAddress));
|
||||
|
||||
|
||||
proxyAddress.sin_family = AF_INET;
|
||||
proxyAddress.sin_port = htons(1085);
|
||||
proxyAddress.sin_addr.s_addr = inet_addr("185.89.100.17");
|
||||
|
||||
/*
|
||||
proxyAddress.sin_family = AF_INET;
|
||||
proxyAddress.sin_port = htons(1080);
|
||||
proxyAddress.sin_addr.s_addr = inet_addr("54.38.22.7");
|
||||
*/
|
||||
|
||||
remoteAddress.sin_family = AF_INET;
|
||||
remoteAddress.sin_port = htons(1100);
|
||||
remoteAddress.sin_addr.s_addr = inet_addr("87.106.252.164");
|
||||
|
||||
assert(evthread_use_pthreads() == 0);
|
||||
event_base* evBase = event_base_new();
|
||||
|
||||
ProxiedClient client(evBase, proxyAddress, remoteAddress);
|
||||
client.connect();
|
||||
|
||||
event_base_dispatch(evBase);
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
#include <mutex>
|
||||
#include <arpa/inet.h>
|
||||
#include <ThreadPool/Thread.h>
|
||||
#include "ProxiedClient.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
using namespace ts::flood;
|
||||
|
||||
#define CERROR(msg) \
|
||||
do { \
|
||||
cerr << msg << endl;\
|
||||
this->disconnect();\
|
||||
return;\
|
||||
} while(0)
|
||||
|
||||
static int port = 10000;
|
||||
static threads::Mutex portLock;
|
||||
void ProxiedClient::handleProxyMessage(const std::string &msg) {
|
||||
if(this->state == PROXY_INIT_METHODS){
|
||||
if(msg[0] != 0x05) CERROR("Invalid proxy version response (methode exchange)");
|
||||
if(msg[1] != 0x00) CERROR("Invalid respond methode");
|
||||
this->state = PROXY_INIT_CONNECTION;
|
||||
|
||||
char buffer[128];
|
||||
int index = 0;
|
||||
buffer[index++] = 0x05; //Version
|
||||
buffer[index++] = 0x03; //Udp weiterleitung
|
||||
buffer[index++] = 0x00; //Resv
|
||||
buffer[index++] = 0x01; //Addr type = IPv4
|
||||
|
||||
auto addr = IPv4{this->remoteAddr->sin_addr.s_addr};
|
||||
buffer[index++] = addr._1;
|
||||
buffer[index++] = addr._2;
|
||||
buffer[index++] = addr._3;
|
||||
buffer[index++] = addr._4;
|
||||
|
||||
buffer[index++] = (ntohs(this->remoteAddr->sin_port) >> 8) & 0xFF;
|
||||
buffer[index++] = (ntohs(this->remoteAddr->sin_port) >> 0) & 0xFF;
|
||||
this->sendMessage(string(buffer, index));
|
||||
} else if(this->state = PROXY_INIT_CONNECTION){
|
||||
cout << "res!" << endl;
|
||||
|
||||
int index = 0;
|
||||
if(msg[index++] != 0x05) CERROR("Invalid proxy version response (connection request)");
|
||||
if(msg[index++] != 0x00) CERROR("Could not create connection (" + to_string((int) msg[1]) + ")");
|
||||
if(msg[index++] != 0x00) CERROR("Invalid proxy rsv response (connection request)");
|
||||
if(msg[index++] != 0x01) CERROR("Invalid proxy ip response type");
|
||||
|
||||
auto rAddr = IPv4{};
|
||||
rAddr._1 = msg[index++];
|
||||
rAddr._2 = msg[index++];
|
||||
rAddr._3 = msg[index++];
|
||||
rAddr._4 = msg[index++];
|
||||
|
||||
uint16_t pHigh = ((uint16_t) msg[index++]) & 0xFF;
|
||||
uint16_t pLow = ((uint16_t) msg[index++]) & 0xFF;
|
||||
uint16_t rPort = (pHigh << 8) | pLow;
|
||||
cout << "Got udp relay " << rAddr.string() << ":" << rPort << endl;
|
||||
|
||||
//Delete old connection
|
||||
//shutdown(this->fileDescriptor, SHUT_RDWR);
|
||||
|
||||
event_del(this->wEvent);
|
||||
event_del(this->rEvent);
|
||||
this->fileDescriptor = 0;
|
||||
|
||||
//Setup relay
|
||||
this->relayAddr = new sockaddr_in{};
|
||||
memset(relayAddr, 0, sizeof(*relayAddr));
|
||||
relayAddr->sin_family = AF_INET;
|
||||
relayAddr->sin_port = htons(rPort);
|
||||
relayAddr->sin_addr.s_addr = rAddr.addr;
|
||||
cout << "Relay addr: " << inet_ntoa(relayAddr->sin_addr) << ":" << ntohs(relayAddr->sin_port) << endl;
|
||||
|
||||
this->localAddr = new sockaddr_in{};
|
||||
memset(localAddr, 0, sizeof(*localAddr));
|
||||
localAddr->sin_family = AF_INET;
|
||||
{
|
||||
lock_guard<threads::Mutex> l(portLock);
|
||||
localAddr->sin_port = this->remoteAddr->sin_port; // = htons(10000 + (port++ % 30000));
|
||||
}
|
||||
localAddr->sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
this->fileDescriptor = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
cout << "fd -> " << this->fileDescriptor << endl;
|
||||
int allow = 1;
|
||||
if(setsockopt(this->fileDescriptor, SOL_SOCKET, SO_REUSEADDR, &allow, sizeof(int)) < 0) CERROR("Could not enable reuse addr");
|
||||
if(bind(this->fileDescriptor, reinterpret_cast<const sockaddr *>(this->localAddr), sizeof(*this->localAddr)) < 0) CERROR("Could nto bind to relay");
|
||||
cout << "Bind on " << inet_ntoa(this->localAddr->sin_addr) << ":" << ntohs(this->localAddr->sin_port) << endl;
|
||||
this->state = PROXY_CONNECTED;
|
||||
|
||||
this->rEvent = event_new(this->evBase, this->fileDescriptor, EV_READ | EV_PERSIST, ProxiedClient::handleEventRead, this);
|
||||
this->wEvent = event_new(this->evBase, this->fileDescriptor, EV_WRITE, ProxiedClient::handleEventWrite, this);
|
||||
event_add(rEvent, nullptr);
|
||||
|
||||
threads::Thread([&](){
|
||||
threads::self::sleep_for(seconds(1));
|
||||
this->proxyInizalisized();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ProxiedClient::requestProxyConnection() {
|
||||
char buffer[3];
|
||||
buffer[0] = 0x05; //Version
|
||||
buffer[1] = 1; //One methode
|
||||
buffer[2] = 0x00; //No auth required
|
||||
|
||||
this->sendMessage(string(buffer, 3));
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
#include <mutex>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "ProxiedClient.h"
|
||||
#include "TSClient.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace ts::flood;
|
||||
|
||||
ProxiedClient::ProxiedClient(event_base* base, const sockaddr_in &proxyAddr, const sockaddr_in &remoteAddr) : evBase(base) {
|
||||
this->proxyAddr = new sockaddr_in{};
|
||||
this->remoteAddr = new sockaddr_in{};
|
||||
|
||||
memcpy(this->proxyAddr, &proxyAddr, sizeof(proxyAddr));
|
||||
memcpy(this->remoteAddr, &remoteAddr, sizeof(proxyAddr));
|
||||
|
||||
this->client = new TSClient(this);
|
||||
}
|
||||
|
||||
ProxiedClient::~ProxiedClient() {
|
||||
delete this->proxyAddr;
|
||||
delete this->remoteAddr;
|
||||
}
|
||||
|
||||
#define CERR(msg) \
|
||||
do { \
|
||||
cerr << "Could not connect: " << msg << "(" << errno << "/" << strerror(errno) << ")" << endl; \
|
||||
return false; \
|
||||
} while(0)
|
||||
|
||||
#if defined(TCP_CORK) && !defined(TCP_NOPUSH)
|
||||
#define TCP_NOPUSH TCP_CORK
|
||||
#endif
|
||||
|
||||
static int enabled = 1;
|
||||
static int disabled = 0;
|
||||
|
||||
bool ProxiedClient::connect() {
|
||||
assert(this->state == ProxyState::PROXY_UNCONNECTED);
|
||||
TAILQ_INIT(&this->writeQueue);
|
||||
|
||||
this->fileDescriptor = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(this->fileDescriptor < 0) CERR("Socket setup failed");
|
||||
if(::connect(this->fileDescriptor, reinterpret_cast<const sockaddr *>(this->proxyAddr), sizeof(*this->proxyAddr)) < 0) CERR("connect() failed");
|
||||
if(setsockopt(this->fileDescriptor, SOL_SOCKET, SO_REUSEADDR, &enabled, sizeof(enabled)) < 0) CERR("could not set reuse addr");
|
||||
if(setsockopt(this->fileDescriptor, IPPROTO_TCP, TCP_NOPUSH, &disabled, sizeof(disabled)) < 0) CERR("could not set no push");
|
||||
|
||||
cout << "Connected to " << inet_ntoa(this->proxyAddr->sin_addr) << endl;
|
||||
|
||||
this->rEvent = event_new(this->evBase, this->fileDescriptor, EV_READ | EV_PERSIST, ProxiedClient::handleEventRead, this);
|
||||
this->wEvent = event_new(this->evBase, this->fileDescriptor, EV_WRITE, ProxiedClient::handleEventWrite, this);
|
||||
|
||||
event_add(rEvent, nullptr);
|
||||
this->state = ProxyState::PROXY_INIT_METHODS;
|
||||
|
||||
this->requestProxyConnection();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ProxiedClient::disconnect() {
|
||||
this->closeConnection();
|
||||
}
|
||||
|
||||
void ProxiedClient::closeConnection() {
|
||||
{
|
||||
lock_guard<threads::Mutex> lock(this->stateLock);
|
||||
if(this->state == PROXY_UNCONNECTED) return;
|
||||
this->state = PROXY_UNCONNECTED;
|
||||
}
|
||||
|
||||
event_del(this->wEvent);
|
||||
event_del(this->rEvent);
|
||||
|
||||
this->wEvent = nullptr;
|
||||
this->rEvent = nullptr;
|
||||
}
|
||||
|
||||
void ProxiedClient::sendMessage(const std::string& message) {
|
||||
buffer::RawBuffer* buffer;
|
||||
if(this->state != PROXY_CONNECTED){
|
||||
buffer = new buffer::RawBuffer{message.length()};
|
||||
memcpy(buffer->buffer, message.data(), message.length());
|
||||
} else {
|
||||
cout << "Send " << message.length() << " bytes with relay" << endl;
|
||||
int relayHeaderLength = 2 + 1 + 1 + 4 + 2;
|
||||
buffer = new buffer::RawBuffer{relayHeaderLength + message.length()};
|
||||
buffer->index = 0;
|
||||
char preBuffer[relayHeaderLength];
|
||||
preBuffer[0] = 0x00;
|
||||
preBuffer[1] = 0x00;
|
||||
preBuffer[2] = 0x00;
|
||||
preBuffer[3] = 0x01;
|
||||
|
||||
IPv4 addr{this->relayAddr->sin_addr.s_addr};
|
||||
preBuffer[4] = addr._1;
|
||||
preBuffer[5] = addr._2;
|
||||
preBuffer[6] = addr._3;
|
||||
preBuffer[7] = addr._4;
|
||||
|
||||
preBuffer[8] = (ntohs(this->relayAddr->sin_port) >> 8) & 0xFF;
|
||||
preBuffer[9] = (ntohs(this->relayAddr->sin_port) >> 0) & 0xFF;
|
||||
//memset(&preBuffer[4], 0, 6);
|
||||
|
||||
memcpy(&buffer->buffer[0], preBuffer, relayHeaderLength);
|
||||
memcpy(&buffer->buffer[relayHeaderLength], message.data(), message.length());
|
||||
}
|
||||
|
||||
{
|
||||
lock_guard<threads::Mutex> lock(this->queueLock);
|
||||
TAILQ_INSERT_TAIL(&this->writeQueue, buffer, tail);
|
||||
}
|
||||
event_add(this->wEvent, nullptr);
|
||||
}
|
||||
|
||||
void ProxiedClient::handleMessage(const std::string &message) {
|
||||
if(this->state == PROXY_UNCONNECTED) return;
|
||||
if(this->state == PROXY_CONNECTED) return; //TODO
|
||||
this->handleProxyMessage(message);
|
||||
}
|
||||
|
||||
extern void hexdump(std::ostream& outs, const std::string& s, size_t line_len = 16);
|
||||
void ProxiedClient::handleEventWrite(int fd, short, void* ptrClient) {
|
||||
auto* client = static_cast<ProxiedClient *>(ptrClient);
|
||||
|
||||
buffer::RawBuffer* buffer = nullptr;
|
||||
{
|
||||
lock_guard<threads::Mutex> lock(client->queueLock);
|
||||
buffer = TAILQ_FIRST(&client->writeQueue);
|
||||
if(!buffer) return;
|
||||
|
||||
ssize_t writtenBytes = 0;
|
||||
if(client->state == PROXY_CONNECTED){
|
||||
cout << "Write bytes to relay - " << fd << " - " << inet_ntoa(client->relayAddr->sin_addr) << ":" << ntohs(client->relayAddr->sin_port) << endl;
|
||||
hexdump(cout, string((const char*) buffer->buffer, buffer->length));
|
||||
writtenBytes = sendto(fd, buffer->buffer, buffer->length, 0, (const sockaddr *) client->relayAddr, sizeof(*client->relayAddr));
|
||||
} else
|
||||
writtenBytes = send(fd, &buffer->buffer[buffer->index], buffer->length - buffer->index, 0);
|
||||
buffer->index += writtenBytes;
|
||||
cout << "Written: " << writtenBytes << endl;
|
||||
|
||||
if(buffer->index >= buffer->length || client->state == PROXY_CONNECTED) {
|
||||
TAILQ_REMOVE(&client->writeQueue, buffer, tail);
|
||||
delete buffer;
|
||||
}
|
||||
if(!TAILQ_EMPTY(&client->writeQueue))
|
||||
event_add(client->wEvent, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void ProxiedClient::handleEventRead(int fd, short, void* ptrClient) {
|
||||
auto* client = static_cast<ProxiedClient *>(ptrClient);
|
||||
|
||||
char buffer[1024];
|
||||
sockaddr_in remoteAddr{};
|
||||
socklen_t remoteAddrSize = sizeof(remoteAddr);
|
||||
auto read = recvfrom(fd, buffer, 1024, MSG_DONTWAIT, reinterpret_cast<sockaddr *>(&remoteAddr), &remoteAddrSize);
|
||||
cout << "Read " << read << " bytes" << endl;
|
||||
if(read < 0){
|
||||
if(errno == EWOULDBLOCK) return;
|
||||
cerr << "Invalid read: " << errno << "/" << strerror(errno) << endl;
|
||||
client->disconnect();
|
||||
return;
|
||||
} else if(read == 0){
|
||||
cerr << "Client hangs up!" << endl;
|
||||
client->closeConnection();
|
||||
return;
|
||||
}
|
||||
|
||||
hexdump(cout, string(buffer, read));
|
||||
client->handleMessage(string(buffer, read));
|
||||
}
|
||||
|
||||
void ProxiedClient::proxyInizalisized() {
|
||||
this->client->startConnect();
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <netinet/in.h>
|
||||
#include <misc/queue.h>
|
||||
#include <protocol/buffers.h>
|
||||
#include <event.h>
|
||||
|
||||
namespace ts {
|
||||
namespace flood {
|
||||
union IPv4 {
|
||||
uint32_t addr;
|
||||
struct __attribute__ ((__packed__)) {
|
||||
uint8_t _1;
|
||||
uint8_t _2;
|
||||
uint8_t _3;
|
||||
uint8_t _4;
|
||||
};
|
||||
|
||||
inline std::string string(){
|
||||
std::stringstream ss;
|
||||
ss << (int) _1 << "." << (int) _2 << "." << (int) _3 << "." << (int) _4;
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
class TSClient;
|
||||
enum ProxyState {
|
||||
PROXY_UNCONNECTED,
|
||||
PROXY_INIT_METHODS,
|
||||
PROXY_INIT_CONNECTION,
|
||||
PROXY_CONNECTED
|
||||
};
|
||||
|
||||
class ProxiedClient {
|
||||
public:
|
||||
ProxiedClient(event_base*,const sockaddr_in& proxyAddr, const sockaddr_in& remoteAddr);
|
||||
~ProxiedClient();
|
||||
|
||||
bool connect();
|
||||
void disconnect();
|
||||
void closeConnection();
|
||||
|
||||
void handleMessage(const std::string& message);
|
||||
void sendMessage(const std::string &);
|
||||
private:
|
||||
static void handleEventRead(int, short, void*);
|
||||
static void handleEventWrite(int, short, void*);
|
||||
|
||||
void requestProxyConnection();
|
||||
void handleProxyMessage(const std::string &);
|
||||
|
||||
void proxyInizalisized();
|
||||
|
||||
event_base* evBase = nullptr;
|
||||
event* rEvent = nullptr;
|
||||
event* wEvent = nullptr;
|
||||
int fileDescriptor;
|
||||
ProxyState state = ProxyState::PROXY_UNCONNECTED;
|
||||
threads::Mutex stateLock;
|
||||
sockaddr_in* proxyAddr = nullptr;
|
||||
sockaddr_in* relayAddr = nullptr;
|
||||
sockaddr_in* localAddr = nullptr;
|
||||
sockaddr_in* remoteAddr = nullptr;
|
||||
|
||||
TAILQ_HEAD(, buffer::RawBuffer) writeQueue;
|
||||
threads::Mutex queueLock;
|
||||
|
||||
TSClient* client = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
//
|
||||
// Created by wolverindev on 06.01.18.
|
||||
//
|
||||
|
||||
#include "TSClient.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
using namespace ts::flood;
|
||||
using namespace ts::protocol;
|
||||
|
||||
TSClient::TSClient(ProxiedClient* con) : connection(con) {
|
||||
this->cryptionHandler = new connection::CryptionHandler();
|
||||
this->cryptionHandler->reset();
|
||||
}
|
||||
|
||||
TSClient::~TSClient() {}
|
||||
|
||||
void TSClient::handleMessageRead(const std::string& message) {
|
||||
if(message.length() < MAC_SIZE + SERVER_HEADER_SIZE) {
|
||||
cerr << "Invalid pkt length!" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
shared_ptr<ServerPacket> packet = make_shared<ServerPacket>(message);
|
||||
cout << "Having packet " << packet->type().name() << endl;
|
||||
}
|
||||
|
||||
void TSClient::sendPacket(ts::protocol::ClientPacket &packet, int32_t packetId) {
|
||||
size_t maxDataLength = 500 - packet.header().length();
|
||||
|
||||
if(packet.data().length() > maxDataLength){
|
||||
cout << "Split packet" << endl;
|
||||
string error;
|
||||
|
||||
|
||||
/*
|
||||
if(!compressPacket(&packet, error)){
|
||||
cerr << "Compress error!" << endl;
|
||||
return;
|
||||
}
|
||||
packet.enableFlag(PacketFlag::Compressed);
|
||||
*/
|
||||
if(packet.data().length() > maxDataLength){
|
||||
std::vector<ClientPacket*> siblings;
|
||||
|
||||
ClientPacket* root = new ClientPacket(packet.type(), packet.flagMask(), packet.data());
|
||||
root->enableFlag(PacketFlag::Fragmented);
|
||||
//assert(root->hasFlag(PacketFlag::Compressed));
|
||||
siblings.push_back(root);
|
||||
|
||||
//Max len - mac - header
|
||||
while(siblings.back()->data().length() > maxDataLength){
|
||||
auto overhead = siblings.back()->data().substr(maxDataLength);
|
||||
siblings.back()->data(siblings.back()->data().substr(0, maxDataLength));
|
||||
|
||||
ClientPacket* sib = new ClientPacket(packet.type(), packet.flagMask(), overhead);
|
||||
sib->toggle(PacketFlag::Fragmented, false);
|
||||
siblings.push_back(sib);
|
||||
}
|
||||
siblings.back()->enableFlag(PacketFlag::Fragmented);
|
||||
for(auto elm : siblings){
|
||||
sendPacket(*elm);
|
||||
delete elm;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (packetId == -1)
|
||||
packet.applyPacketId(pktIdManager);
|
||||
else packet.applyPacketId((uint16_t) packetId, 0);
|
||||
packet.clientId(this->clientId);
|
||||
|
||||
string error = "success";
|
||||
if (!this->cryptionHandler->progressPacketOut(&packet, error)) {
|
||||
cerr << "Invalid crypt -> " << error << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
this->connection->sendMessage(packet.mac() + packet.header() + packet.data());
|
||||
}
|
||||
|
||||
const int InitVersionLength = 4;
|
||||
const uint8_t InitVersion[InitVersionLength] = {0x06, 0x3b, 0xEC, 0xE9};
|
||||
|
||||
void TSClient::startConnect() {
|
||||
int maxBufferSize = 512;
|
||||
size_t bufferIndex = 0;
|
||||
uint8_t buffer[maxBufferSize];
|
||||
string error = "success";
|
||||
|
||||
memcpy(buffer, InitVersion, InitVersionLength);
|
||||
bufferIndex += InitVersionLength;
|
||||
buffer[bufferIndex++] = 0x00; //Login state
|
||||
|
||||
int64_t millis = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||
memcpy(&buffer[5], &millis, 4);
|
||||
bufferIndex += 4;
|
||||
//generate the alpha key
|
||||
for (int i = 0; i < 4; i++) buffer[bufferIndex++] = (uint8_t) std::rand();
|
||||
bufferIndex += 8; //Reserved bytes
|
||||
|
||||
ClientPacket pkt(ts::protocol::PacketTypeInfo::Init1, string((char *) buffer, bufferIndex));
|
||||
pkt.clientId(0);
|
||||
pkt.toggle(ts::protocol::PacketFlag::Unencrypted, true);
|
||||
this->sendPacket(pkt, 101);
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ProxiedClient.h"
|
||||
#include <string>
|
||||
#include <Definitions.h>
|
||||
#include <protocol/CryptionHandler.h>
|
||||
|
||||
namespace ts {
|
||||
namespace flood {
|
||||
enum TSClientConnectionState {
|
||||
TSC_UNCONNECTED,
|
||||
TSC_PRE,
|
||||
TSC_RSA,
|
||||
TSC_HIGH,
|
||||
TSC_CONNECTED
|
||||
};
|
||||
|
||||
class TSClient {
|
||||
public:
|
||||
TSClient(ProxiedClient*);
|
||||
~TSClient();
|
||||
|
||||
void startConnect();
|
||||
void handleMessageRead(const std::string&);
|
||||
|
||||
void sendPacket(ts::protocol::ClientPacket &packet, int32_t packetId = -1);
|
||||
private:
|
||||
ProxiedClient* connection;
|
||||
TSClientConnectionState state = TSClientConnectionState::TSC_UNCONNECTED;
|
||||
protocol::PacketIdManager pktIdManager;
|
||||
ts::connection::CryptionHandler* cryptionHandler = nullptr;
|
||||
|
||||
ClientId clientId = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
+1
-1
Submodule git-teaspeak updated: 819ba6d090...9a26231c1f
+38
-68
@@ -14,86 +14,65 @@ include_directories(../shared/src)
|
||||
add_definitions(-DLTM_DESC)
|
||||
|
||||
set(LICENCE_SOURCE_FILES
|
||||
shared/LicenseRequest.cpp
|
||||
shared/LicenseRequestHandler.cpp
|
||||
shared/License.cpp
|
||||
../shared/src/log/LogUtils.cpp
|
||||
shared/src/license.cpp
|
||||
shared/src/client.cpp
|
||||
)
|
||||
|
||||
#Protobuf
|
||||
find_package(Protobuf REQUIRED)
|
||||
include_directories(${Protobuf_INCLUDE_DIRS})
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS packets/LicenseRequest.proto packets/LicenseManager.proto)
|
||||
protobuf_generate_cpp(PROTO_SRCS TeaLicenseHelper_PROTOCOL_HEADERS shared/packets/LicenseRequest.proto shared/packets/LicenseManager.proto)
|
||||
|
||||
#The actual librarie
|
||||
add_library(TeaLicenseHelper STATIC ${LICENCE_SOURCE_FILES} ${PROTO_SRCS} ${PROTO_HDRS})
|
||||
#The actual shared library
|
||||
add_library(TeaLicenseHelper STATIC ${LICENCE_SOURCE_FILES} ${PROTO_SRCS})
|
||||
target_link_libraries(TeaLicenseHelper PUBLIC
|
||||
TeaSpeak
|
||||
protobuf::libprotobuf
|
||||
libevent::core libevent::pthreads
|
||||
openssl::ssl::shared
|
||||
openssl::crypto::shared
|
||||
|
||||
${StringVariable_LIBRARIES_STATIC}
|
||||
${ed25519_LIBRARIES_STATIC}
|
||||
stdc++fs
|
||||
)
|
||||
target_include_directories(TeaLicenseHelper PUBLIC shared/include/)
|
||||
target_include_directories(TeaLicenseHelper PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
#The license server
|
||||
add_executable(TeaLicenseServer ${LICENCE_SOURCE_FILES} ${PROTO_SRCS} ${PROTO_HDRS}
|
||||
add_executable(TeaLicenseServer ${LICENCE_SOURCE_FILES}
|
||||
server/KeyIdCache.cpp
|
||||
server/LicenseServer.cpp
|
||||
server/LicenseServerHandler.cpp
|
||||
server/LicenseManager.cpp
|
||||
LicenseServerMain.cpp
|
||||
server/DatabaseHandler.cpp
|
||||
server/WebAPI.cpp
|
||||
server/StatisticManager.cpp
|
||||
server/UserManager.cpp
|
||||
LicenseServerMain.cpp
|
||||
MySQLLibSSLFix.c
|
||||
)
|
||||
|
||||
target_link_libraries(TeaLicenseServer
|
||||
TeaSpeak #Static
|
||||
${LIBRARY_PATH_DATA_PIPES}
|
||||
${LIBRARY_PATH_TERMINAL} #Static
|
||||
${LIBRARY_PATH_THREAD_POOL} #Static
|
||||
${PROJECT_SOURCE_DIR}/../../libraries/event/build/lib/libevent.a
|
||||
${PROJECT_SOURCE_DIR}/../../libraries/event/build/lib/libevent_pthreads.a
|
||||
pthread
|
||||
${LIBRARY_PATH_BORINGSSL_SSL}
|
||||
${LIBRARY_PATH_BORINGSSL_CRYPTO}
|
||||
${LIBRARY_PATH_VARIBALES}
|
||||
${LIBRARY_PATH_BREAKPAD}
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
TeaSpeak
|
||||
TeaLicenseHelper #Static
|
||||
threadpool::static #Static
|
||||
CXXTerminal::static #Static
|
||||
libevent::core libevent::pthreads
|
||||
|
||||
${LIBRARY_TOM_MATH}
|
||||
${LIBRARY_TOM_CRYPT}
|
||||
mysqlclient
|
||||
jsoncpp_lib
|
||||
DataPipes::core::shared
|
||||
openssl::ssl::shared
|
||||
openssl::crypto::shared
|
||||
|
||||
${LIBRARY_PATH_BREAKPAD}
|
||||
${TOM_LIBRARIES}
|
||||
${LIBRARY_PATH_JDBC}
|
||||
jsoncpp.a
|
||||
stdc++fs.a
|
||||
pthread
|
||||
dl
|
||||
z
|
||||
)
|
||||
|
||||
#The test license client
|
||||
add_executable(TeaLicenseClient
|
||||
LicenseClientMain.cpp
|
||||
${LICENCE_SOURCE_FILES} ${PROTO_SRCS} ${PROTO_HDRS}
|
||||
)
|
||||
target_link_libraries(TeaLicenseClient
|
||||
${LIBRARY_PATH_DATA_PIPES}
|
||||
${LIBRARY_PATH_TERMINAL} #Static
|
||||
${LIBRARY_PATH_THREAD_POOL} #Static
|
||||
${PROJECT_SOURCE_DIR}/../../libraries/event/build/lib/libevent.a
|
||||
${PROJECT_SOURCE_DIR}/../../libraries/event/build/lib/libevent_pthreads.a
|
||||
pthread
|
||||
${LIBRARY_PATH_VARIBALES}
|
||||
${LIBRARY_PATH_BREAKPAD}
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
|
||||
${LIBRARY_TOM_MATH}
|
||||
${LIBRARY_TOM_CRYPT}
|
||||
stdc++fs.a
|
||||
|
||||
${LIBRARY_PATH_BORINGSSL_SSL}
|
||||
${LIBRARY_PATH_BORINGSSL_CRYPTO}
|
||||
${LIBRARY_PATH_BREAKPAD}
|
||||
${TOM_LIBRARIES}
|
||||
${LIBRARY_PATH_JDBC}
|
||||
TeaSpeak #Static
|
||||
jsoncpp.a
|
||||
)
|
||||
add_executable(TeaLicenseClient LicenseClientMain.cpp)
|
||||
target_link_libraries(TeaLicenseClient TeaLicenseHelper)
|
||||
|
||||
#The license manager
|
||||
if(NOT DISABLE_QT)
|
||||
@@ -134,6 +113,7 @@ if(NOT DISABLE_QT)
|
||||
|
||||
${LIBRARY_TOM_MATH}
|
||||
${LIBRARY_TOM_CRYPT}
|
||||
${LIBRARY_PATH_ED255}
|
||||
stdc++fs
|
||||
jsoncpp.a
|
||||
${LIBRARY_PATH_DATA_PIPES}
|
||||
@@ -147,16 +127,6 @@ add_executable(LicenseCLI
|
||||
manager/ServerConnection.cpp
|
||||
manager/ServerConnectionExecutor.cpp
|
||||
manager/ServerConnectionHandler.cpp
|
||||
shared/License.cpp
|
||||
${PROTO_SRCS} ${PROTO_HDRS}
|
||||
)
|
||||
|
||||
target_link_libraries(LicenseCLI
|
||||
${LIBRARY_PATH_THREAD_POOL} #Static
|
||||
${PROJECT_SOURCE_DIR}/../../libraries/event/build/lib/libevent.a
|
||||
${PROJECT_SOURCE_DIR}/../../libraries/event/build/lib/libevent_pthreads.a
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
${LIBRARY_TOM_MATH} #Static
|
||||
${LIBRARY_TOM_CRYPT} #Static
|
||||
pthread
|
||||
)
|
||||
target_link_libraries(LicenseCLI TeaLicenseHelper)
|
||||
+116
-25
@@ -1,7 +1,12 @@
|
||||
#include <iostream>
|
||||
#include <shared/License.h>
|
||||
#include <shared/LicenseRequest.h>
|
||||
#include <shared/include/license/license.h>
|
||||
#include <shared/include/license/LicenseRequest.h>
|
||||
#include <event2/thread.h>
|
||||
#include "shared/include/license/client.h"
|
||||
|
||||
#include <random>
|
||||
#include <ed25519/ed25519.h>
|
||||
#include <misc/base64.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
@@ -21,10 +26,68 @@ using namespace license;
|
||||
inline bool isValid() { return (end.time_since_epoch().count() == 0 || std::chrono::system_clock::now() < this->end); }
|
||||
};
|
||||
*/
|
||||
|
||||
std::array<uint8_t, 195> intermediate_key{0x02, 0x00, 0x2d, 0x6b, 0xe3, 0x4d, 0x3c, 0xbb, 0x19, 0x1e, 0x46, 0x25, 0x72, 0x22, 0xa3, 0x53, 0x6d, 0x2d, 0xc3, 0xd1, 0x2c, 0xc8, 0xea, 0xf2, 0xf8, 0xe5, 0xd5, 0x0f, 0x6c, 0x7f, 0xeb, 0x63, 0x8a, 0xc4, 0x37, 0xb2, 0x33, 0x5e, 0x06, 0x31, 0xcf, 0x2c, 0xc6, 0xbe, 0x5e, 0x9c, 0xf1, 0xe6, 0xb3, 0xc3, 0x69, 0xd7, 0xf0, 0x05, 0x90, 0x2f, 0x65, 0x03, 0x60, 0x12, 0xa0, 0x20, 0x83, 0xe2, 0x6b, 0x4f, 0x46, 0xab, 0xfd, 0xa6, 0x22, 0x0b, 0x11, 0x9a, 0x34, 0xfe, 0x7b, 0xa3, 0x1b, 0x12, 0xce, 0x30, 0xf7, 0x0a, 0x32, 0x26, 0x23, 0x10, 0xfe, 0x58, 0xb6, 0xc7, 0x5d, 0x3d, 0xc6, 0x14, 0xdc, 0x10, 0xa0, 0xc0, 0x78, 0x10, 0x45, 0x41, 0x36, 0x1a, 0x1c, 0x9f, 0x60, 0x25, 0xd9, 0x69, 0xc9, 0x0b, 0xb7, 0xb4, 0x64, 0xab, 0x6c, 0x22, 0xff, 0xaf, 0x86, 0x26, 0x94, 0xcc, 0x7f, 0x59, 0x52, 0xa3, 0x56, 0x7f, 0x3e, 0x86, 0x04, 0x4c, 0xe0, 0x0e, 0xb3, 0xb1, 0x23, 0x51, 0xf7, 0xf0, 0x14, 0x5d, 0xfd, 0x48, 0xfb, 0x16, 0xe6, 0xc6, 0xca, 0xf2, 0x8d, 0xc8, 0xce, 0xf1, 0x2b, 0x12, 0x9e, 0xd1, 0x7a, 0x80, 0x3a, 0x9b, 0x46, 0xe7, 0xca, 0x34, 0x04, 0xae, 0x3d, 0x12, 0xcd, 0x4a, 0xc6, 0xe1, 0xf1, 0xe4, 0xd8, 0xca, 0x68, 0x36, 0xd3, 0x94, 0x0d, 0xef, 0x93, 0x86, 0xb9, 0x3a, 0xa4, 0x10, 0x52};
|
||||
int main(int ac, char** av){
|
||||
auto state = evthread_use_pthreads();
|
||||
assert(state == 0);
|
||||
string error;
|
||||
uint8_t errc = 0;
|
||||
|
||||
#if 0
|
||||
std::array<uint8_t, 32> prv_key{};
|
||||
auto license = v2::License::create({}, prv_key);
|
||||
assert(license->private_data_editable());
|
||||
|
||||
license->push_entry<v2::hierarchy::Intermediate>(system_clock::now(), system_clock::now() + hours{24 * 365 * 1000}, "TeaSpeak (Test)");
|
||||
assert(license->write_private_data({0}));
|
||||
error = license->write(errc);
|
||||
assert(errc == 0);
|
||||
|
||||
cout << "Intermediate: " << hex;
|
||||
for(size_t index = 0; index < error.length(); index++) {
|
||||
uint8_t e = error[index];
|
||||
cout << " 0x" << (e <= 0xF ? "0" : "") << (uint32_t) e << ",";
|
||||
}
|
||||
cout << endl;
|
||||
cout << "Intermediate: " << base64::encode(error) << endl;
|
||||
#endif
|
||||
#if 0
|
||||
auto license = v2::License::read(intermediate_key.data(), intermediate_key.size(), errc);
|
||||
|
||||
license->push_entry<v2::hierarchy::Server>(system_clock::now(), system_clock::now() + hours{24 * 365 * 1000}, "TeaSpeak Official server", "contact@teaspeak.de");
|
||||
assert(license->write_private_data({0}));
|
||||
error = license->write(errc);
|
||||
assert(errc == 0);
|
||||
__asm__("nop");
|
||||
cout << "Errc: " << errc << endl;
|
||||
cout << "Write: " << base64::encode(error) << endl;
|
||||
#endif
|
||||
#if 0
|
||||
std::array<uint8_t, 32> private_key, public_key;
|
||||
|
||||
std::random_device rd;
|
||||
std::uniform_int_distribution<uint8_t> d;
|
||||
|
||||
uint8_t root_seed[64];
|
||||
for(auto& e : root_seed)
|
||||
e = d(rd);
|
||||
ed25519_create_keypair(public_key.data(), private_key.data(), root_seed);
|
||||
|
||||
cout << "Key Pair generated:" << endl;
|
||||
cout << "Private Key:" << hex;
|
||||
for(auto& e : private_key)
|
||||
cout << " 0x" << (e <= 0xF ? "0" : "") << (uint32_t) e << ",";
|
||||
cout << endl;
|
||||
|
||||
cout << "Public Key :" << hex;
|
||||
for(auto& e : public_key)
|
||||
cout << " 0x" << (e <= 0xF ? "0" : "") << (uint32_t) e << ",";
|
||||
cout << endl;
|
||||
|
||||
return true;
|
||||
#endif
|
||||
#if 0
|
||||
srand(system_clock::now().time_since_epoch().count());
|
||||
cout << "Generating new license" << endl;
|
||||
|
||||
@@ -60,28 +123,56 @@ int main(int ac, char** av){
|
||||
auto data = make_shared<LicenseRequestData>();
|
||||
data->license = license;
|
||||
data->info = make_shared<ServerInfo>();
|
||||
while(true) {
|
||||
LicenceRequest request(data, serv_addr);
|
||||
try {
|
||||
cout << "Requesting license" << endl;
|
||||
auto info = request.requestInfo().waitAndGet(nullptr);
|
||||
if(!info) {
|
||||
cout << "Invalid result! Error: " << (request.exception() ? "yes => " + string(request.exception()->what()) : "no") << endl;
|
||||
throw *request.exception();
|
||||
}
|
||||
cout << "Got result!" << endl;
|
||||
cout << "Valid: " << info->license_valid << endl;
|
||||
if(info->license) {
|
||||
cout << "License:" << endl;
|
||||
cout << " Type: " << info->license->type << endl;
|
||||
cout << " User name: " << info->license->username << endl;
|
||||
cout << " First name: " << info->license->first_name << endl;
|
||||
cout << " Last name: " << info->license->last_name << endl;
|
||||
cout << " EMail: " << info->license->email << endl;
|
||||
} else cout << "License: none";
|
||||
} catch (const std::exception& ex){
|
||||
cerr << "Could not load info after throwing: " << endl << ex.what() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
LicenceRequest request(data, serv_addr);
|
||||
try {
|
||||
cout << "Requesting license" << endl;
|
||||
auto info = request.requestInfo().waitAndGet(nullptr);
|
||||
if(!info) {
|
||||
cout << "Invalid result! Error: " << (request.exception() ? "yes => " + string(request.exception()->what()) : "no") << endl;
|
||||
throw *request.exception();
|
||||
}
|
||||
cout << "Got result!" << endl;
|
||||
cout << "Valid: " << info->license_valid << endl;
|
||||
if(info->license) {
|
||||
cout << "License:" << endl;
|
||||
cout << " Type: " << info->license->type << endl;
|
||||
cout << " User name: " << info->license->username << endl;
|
||||
cout << " First name: " << info->license->first_name << endl;
|
||||
cout << " Last name: " << info->license->last_name << endl;
|
||||
cout << " EMail: " << info->license->email << endl;
|
||||
} else cout << "License: none";
|
||||
} catch (const std::exception& ex){
|
||||
cerr << "Could not load info after throwing: " << endl << ex.what() << endl;
|
||||
}
|
||||
#endif
|
||||
#if 1
|
||||
sockaddr_in serv_addr{};
|
||||
serv_addr.sin_family = AF_INET;
|
||||
|
||||
serv_addr.sin_addr.s_addr = ((in_addr*) gethostbyname("localhost")->h_addr)->s_addr;
|
||||
serv_addr.sin_port = htons(27786);
|
||||
|
||||
client::LicenseServerClient client{serv_addr, 3};
|
||||
client.callback_connected = [&]{
|
||||
std::cout << "Connected" << std::endl;
|
||||
client.disconnect("client closed", std::chrono::system_clock::now() + std::chrono::seconds{5});
|
||||
};
|
||||
client.callback_message = [&](auto type, const void* buffer, size_t length) {
|
||||
std::cout << "Received an message" << std::endl;
|
||||
};
|
||||
client.callback_disconnected = [&](bool expected, const std::string& reason) {
|
||||
std::cout << "Received disconnect (expected: " << expected << "): " << reason << std::endl;
|
||||
};
|
||||
|
||||
if(!client.start_connection(error)) {
|
||||
std::cout << "Failed to start connection" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds{2});
|
||||
client.disconnect("client closed", std::chrono::system_clock::now() + std::chrono::seconds{5});
|
||||
std::cout << "Disconnect result: " << client.await_disconnect() << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <event2/thread.h>
|
||||
#include <misc/base64.h>
|
||||
|
||||
#include "manager/ServerConnection.h"
|
||||
|
||||
@@ -63,16 +64,18 @@ class CLIParser {
|
||||
std::vector<std::string> tokens;
|
||||
};
|
||||
|
||||
#define REQ_CMD(variable, message, ...) \
|
||||
if(!options.option_exists({__VA_ARGS__}, false)) { \
|
||||
cerr << "missing user" << endl; \
|
||||
return 1; \
|
||||
} \
|
||||
auto variable = url_decode(options.get_option({__VA_ARGS__})) \
|
||||
#define _str(x) #x
|
||||
|
||||
#define REQ_CMD(variable, message, skey, lkey, ...) \
|
||||
if(!options.option_exists({skey, lkey, #__VA_ARGS__}, false)) { \
|
||||
cerr << message << " (" << _str(skey) << " or " << _str(lkey) << ")" << endl; \
|
||||
return 1; \
|
||||
} \
|
||||
auto variable = url_decode(options.get_option({skey, lkey, #__VA_ARGS__})) \
|
||||
|
||||
#define NO_OPEN_SSL
|
||||
#include <misc/digest.h>
|
||||
#include <misc/base64.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
CLIParser options(argc, argv);
|
||||
|
||||
@@ -84,11 +87,13 @@ int main(int argc, char **argv) {
|
||||
REQ_CMD(email, "missing email", "-m", "--email");
|
||||
REQ_CMD(license_type, "missing license_type", "-l", "--license-type");
|
||||
|
||||
REQ_CMD(auth_user, "missing authentification user", "-au", "--auth-user");
|
||||
REQ_CMD(auth_pass, "missing authentification user", "-ap", "--auth-pass");
|
||||
REQ_CMD(auth_user, "missing authentication user", "-au", "--auth-user");
|
||||
REQ_CMD(auth_pass, "missing authentication user", "-ap", "--auth-pass");
|
||||
|
||||
REQ_CMD(server_host, "missing server host", "-h", "--server-host");
|
||||
REQ_CMD(server_port, "missing server port", "-p", "--server-port");
|
||||
REQ_CMD(server_port, "missing server port", "-p", "--server-port");
|
||||
|
||||
REQ_CMD(old_key, "missing old license key", "-ol", "--old-license");
|
||||
|
||||
auto state = evthread_use_pthreads();
|
||||
if(state != 0) {
|
||||
@@ -96,6 +101,7 @@ int main(int argc, char **argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string error{};
|
||||
ServerConnection connection;
|
||||
connection.verbose = false;
|
||||
try {
|
||||
@@ -112,15 +118,24 @@ int main(int argc, char **argv) {
|
||||
{
|
||||
auto future = connection.login(auth_user, auth_pass);
|
||||
if(!future.waitAndGet(false, system_clock::now() + seconds(5))) {
|
||||
cerr << "failed to athentificate (" << future.errorMegssage() << ")" << endl;
|
||||
cerr << "failed to authenticate (" << future.errorMegssage() << ")" << endl;
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<License> old_license{nullptr};
|
||||
if(!old_key.empty() && old_key != "none") {
|
||||
old_license = license::readLocalLicence(old_key, error);
|
||||
if(!old_license) {
|
||||
cerr << "failed to decode old license: " << error << endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
system_clock::time_point timestamp_begin = system_clock::time_point() + seconds(stoll(begin));
|
||||
system_clock::time_point timestamp_end = system_clock::time_point() + seconds(stoll(end));
|
||||
auto future = connection.registerLicense(first_name, last_name, user, email, (LicenseType) stoll(license_type), timestamp_end, timestamp_begin);
|
||||
auto future = connection.registerLicense(first_name, last_name, user, email, (LicenseType) stoll(license_type), timestamp_end, timestamp_begin, old_license ? old_license->key() : "none");
|
||||
auto result = future.waitAndGet({nullptr, nullptr}, system_clock::now() + seconds(5));
|
||||
if(!result.first || !result.second) {
|
||||
cerr << "failed to create license! (" << future.errorMegssage() << ")" << endl;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <iostream>
|
||||
#include <shared/License.h>
|
||||
#include <shared/LicenseRequest.h>
|
||||
#include <shared/include/license/license.h>
|
||||
#include <shared/include/license/LicenseRequest.h>
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <manager/ui/LicenseGenerator.h>
|
||||
#include <manager/ServerConnection.h>
|
||||
@@ -43,7 +43,7 @@ int main(int ac, char** av){
|
||||
auto license = license::readLocalLicence(data, error);
|
||||
cout << "Key: " << base64::encode(license->key()) << endl;
|
||||
cout << "Key: " << string_to_hex(license->key()) << endl;
|
||||
return false;
|
||||
//return false;
|
||||
|
||||
connection = new ServerConnection();
|
||||
if(!connection->connect("mcgalaxy.de", 27786).waitAndGet(false)) {
|
||||
|
||||
+106
-32
@@ -1,17 +1,16 @@
|
||||
#include <iostream>
|
||||
#include <shared/License.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <server/LicenseServer.h>
|
||||
#include <log/LogUtils.h>
|
||||
#include <CXXTerminal/Terminal.h>
|
||||
#include <sql/mysql/MySQL.h>
|
||||
#include <pipes/misc/http.h>
|
||||
#include "server/WebAPI.h"
|
||||
#include "server/StatisticManager.h"
|
||||
#include <event2/thread.h>
|
||||
#include "server/UserManager.h"
|
||||
|
||||
#include <misc/base64.h>
|
||||
#include <misc/digest.h>
|
||||
#include <misc/hex.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
@@ -24,6 +23,7 @@ using namespace license;
|
||||
* Requests (license) / ip: SELECT DISTINCT `ip`, COUNT(`ip`) FROM `license_request` WHERE `keyId` = ? GROUP BY `ip`
|
||||
*
|
||||
* SELECT DISTINCT(`ip`), `keyId` FROM `license_request` WHERE `timestamp` > (UNIX_TIMESTAMP() - 2 * 60 * 60) * 1000
|
||||
* //462
|
||||
*
|
||||
* SELECT DISTINCT(`ip`), `license_request`.`keyId`, `license_info`.`username` FROM `license_request` LEFT JOIN `license_info` ON `license_info`.`keyId` = `license_request`.`keyId` WHERE `timestamp` > (UNIX_TIMESTAMP() - 2 * 60 * 60) * 1000
|
||||
*
|
||||
@@ -34,13 +34,66 @@ using namespace license;
|
||||
*/
|
||||
bool handle_command(string& line);
|
||||
|
||||
shared_ptr<server::LicenseManager> license_manager;
|
||||
shared_ptr<server::database::DatabaseHandler> license_manager;
|
||||
shared_ptr<stats::StatisticManager> statistic_manager;
|
||||
shared_ptr<ts::ssl::SSLManager> ssl_manager;
|
||||
shared_ptr<license::web::WebStatistics> web_server;
|
||||
shared_ptr<LicenseServer> license_server;
|
||||
shared_ptr<UserManager> user_manager;
|
||||
|
||||
inline std::shared_ptr<WebCertificate> load_web_certificate() {
|
||||
std::string certificate_file{"web_certificate.txt"}, certificate{};
|
||||
std::string key_file{"web_key.txt"}, key{};
|
||||
std::string error{};
|
||||
|
||||
auto context = ssl_manager->initializeContext("web_shared_cert", key_file, certificate_file, error);
|
||||
if(!context) {
|
||||
logError(0, "Failed to load web certificated: {}", error);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<BIO> bio{nullptr};
|
||||
const uint8_t* mem_ptr{nullptr};
|
||||
size_t length{0};
|
||||
|
||||
{
|
||||
bio = shared_ptr<BIO>(BIO_new(BIO_s_mem()), ::BIO_free);
|
||||
if(PEM_write_bio_PrivateKey(&*bio, &*context->privateKey, nullptr, nullptr, 0, nullptr, nullptr) != 1) {
|
||||
logError(0, "Failed to export certificate");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(!BIO_mem_contents(&*bio, &mem_ptr, &length)) {
|
||||
logError(0, "Failed to receive memptr to private key");
|
||||
return nullptr;
|
||||
}
|
||||
key.resize(length);
|
||||
memcpy(key.data(), mem_ptr, length);
|
||||
}
|
||||
|
||||
{
|
||||
bio = shared_ptr<BIO>(BIO_new(BIO_s_mem()), ::BIO_free);
|
||||
if(PEM_write_bio_X509(&*bio, &*context->certificate) != 1) {
|
||||
logError(0, "Failed to export certificate");
|
||||
return nullptr;
|
||||
}
|
||||
if(!BIO_mem_contents(&*bio, &mem_ptr, &length)) {
|
||||
logError(0, "Failed to receive memptr to certificate");
|
||||
return nullptr;
|
||||
}
|
||||
certificate.resize(length);
|
||||
memcpy(certificate.data(), mem_ptr, length);
|
||||
}
|
||||
|
||||
auto response = std::make_shared<WebCertificate>();
|
||||
response->key = key;
|
||||
response->certificate = certificate;
|
||||
response->revision = digest::sha512(response->key + response->certificate);
|
||||
logMessage(0, "Web certificate revision: {}", hex::hex(response->revision));
|
||||
return response;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if(argc < 2) {
|
||||
cerr << "Invalid arguments! Need MySQL connection" << endl;
|
||||
@@ -48,16 +101,17 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
evthread_use_pthreads();
|
||||
http::decode_url("xxx");
|
||||
srand(system_clock::now().time_since_epoch().count());
|
||||
terminal::install();
|
||||
if(!terminal::active()){ cerr << "could not setup terminal!" << endl; return -1; }
|
||||
|
||||
//terminal::install();
|
||||
//if(!terminal::active()){ cerr << "could not setup terminal!" << endl; return -1; }
|
||||
|
||||
auto config = std::make_shared<logger::LoggerConfig>();
|
||||
config->vs_group_size = 0;
|
||||
config->logfileLevel = spdlog::level::trace;
|
||||
config->terminalLevel = spdlog::level::trace;
|
||||
config->logPath = "logs/log_${time}(%Y-%m-%d_%H:%M:%S).log";
|
||||
config->sync = !terminal::active();
|
||||
logger::setup(config);
|
||||
|
||||
string error;
|
||||
@@ -65,8 +119,8 @@ int main(int argc, char** argv) {
|
||||
bool db_connected = true;
|
||||
((sql::mysql::MySQLManager*) database)->listener_disconnected = [&](bool wanted){
|
||||
if(wanted) return;
|
||||
logCritical("Lost connection to MySQL server!");
|
||||
logCritical("Stopping server!");
|
||||
logCritical(LOG_GENERAL, "Lost connection to MySQL server!");
|
||||
logCritical(LOG_GENERAL, "Stopping server!");
|
||||
db_connected = false;
|
||||
};
|
||||
|
||||
@@ -74,7 +128,7 @@ int main(int argc, char** argv) {
|
||||
logMessage(LOG_GENERAL, "Connecting to {}", argv[1]);
|
||||
auto connect_result = database->connect(string(argv[1]));
|
||||
if(!connect_result) {
|
||||
logError("Could not connect to mysql server! (" + connect_result.fmtStr() + ")");
|
||||
logError(LOG_GENERAL, "Could not connect to mysql server! (" + connect_result.fmtStr() + ")");
|
||||
return 0;
|
||||
}
|
||||
#if false
|
||||
@@ -86,15 +140,16 @@ int main(int argc, char** argv) {
|
||||
}, (void*) nullptr) << endl;
|
||||
#endif
|
||||
|
||||
license_manager = make_shared<server::LicenseManager>(database);
|
||||
license_manager = make_shared<server::database::DatabaseHandler>(database);
|
||||
if(!license_manager->setup(error)) {
|
||||
logError("Could not start license manager! (" +error + ")");
|
||||
logError(LOG_GENERAL, "Could not start license manager! (" +error + ")");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
statistic_manager = make_shared<stats::StatisticManager>(license_manager);
|
||||
|
||||
#if false
|
||||
/*
|
||||
{
|
||||
auto _now = system_clock::now();
|
||||
@@ -110,9 +165,18 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
{
|
||||
*/
|
||||
#endif
|
||||
|
||||
#if false
|
||||
/*
|
||||
{
|
||||
ofstream _file_out("version_history.txt");
|
||||
|
||||
auto _now = system_clock::now();
|
||||
auto statistics = license_manager->list_statistics_version(_now - hours(24) * 9, _now, duration_cast<milliseconds>(hours(1)));
|
||||
cout << "Getting statistics" << endl;
|
||||
auto statistics = license_manager->list_statistics_version(_now - hours(24) * 32 * 12, _now, duration_cast<milliseconds>(hours(1)));
|
||||
cout << "Grouping statistics" << endl;
|
||||
std::deque<std::string> versions;
|
||||
const auto version_name = [](const std::string& key) {
|
||||
auto space = key.find(' ');
|
||||
@@ -130,6 +194,7 @@ int main(int argc, char** argv) {
|
||||
versions.push_back(name);
|
||||
}
|
||||
}
|
||||
cout << "Sorting statistics" << endl;
|
||||
sort(versions.begin(), versions.end(), [](const std::string& a, const std::string& b) {
|
||||
const auto index_a = a.find_last_of('.');
|
||||
const auto index_b = b.find_last_of('.');
|
||||
@@ -141,10 +206,11 @@ int main(int argc, char** argv) {
|
||||
return patch_a > patch_b;
|
||||
});
|
||||
|
||||
cout << "Date";
|
||||
for(auto it = versions.begin(); it != versions.end(); it++)
|
||||
cout << "," << *it;
|
||||
cout << endl;
|
||||
cout << "Writing statistics" << endl;
|
||||
_file_out << "Date";
|
||||
for(auto & version : versions)
|
||||
_file_out << "," << version;
|
||||
_file_out << endl;
|
||||
|
||||
for(const auto& entry : statistics) {
|
||||
auto time = system_clock::to_time_t(entry->timestamp);
|
||||
@@ -158,14 +224,18 @@ int main(int argc, char** argv) {
|
||||
version_count[name] += version.second;
|
||||
}
|
||||
|
||||
cout << string_time;
|
||||
_file_out << string_time;
|
||||
for(const auto& name : versions) {
|
||||
cout << "," << version_count[name];
|
||||
_file_out << "," << version_count[name];
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
*/
|
||||
_file_out << endl;
|
||||
}s
|
||||
cout << "Done statistics" << endl;
|
||||
_file_out.flush();
|
||||
}
|
||||
return 0;
|
||||
*/
|
||||
#endif
|
||||
|
||||
ssl_manager = make_shared<ts::ssl::SSLManager>();
|
||||
{
|
||||
@@ -181,7 +251,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
{
|
||||
web_server = make_shared<license::web::WebStatistics>(license_manager, statistic_manager);
|
||||
logMessage("Starting web server on [:::]:27788");
|
||||
logMessage(LOG_GENERAL, "Starting web server on [:::]:27788");
|
||||
if(!web_server->start(error, 27788, ssl_manager->getContext("web_stats"))) {
|
||||
logError(LOG_GENERAL, "Failed to start web statistics server!");
|
||||
return 0;
|
||||
@@ -192,7 +262,7 @@ int main(int argc, char** argv) {
|
||||
user_manager = make_shared<UserManager>(database);
|
||||
}
|
||||
{
|
||||
logMessage("Starting license server on [:::]:27786");
|
||||
logMessage(LOG_GENERAL, "Starting license server on [:::]:27786");
|
||||
struct sockaddr_in listen_addr{};
|
||||
memset(&listen_addr, 0, sizeof(listen_addr));
|
||||
listen_addr.sin_family = AF_INET;
|
||||
@@ -200,23 +270,27 @@ int main(int argc, char** argv) {
|
||||
listen_addr.sin_port = htons(27786);
|
||||
|
||||
license_server = make_shared<LicenseServer>(listen_addr, license_manager, statistic_manager, web_server, user_manager);
|
||||
license_server->startServer();
|
||||
license_server->web_certificate = load_web_certificate();
|
||||
license_server->start();
|
||||
}
|
||||
|
||||
while(db_connected && web_server->running() && license_server->isRunning()) {
|
||||
if(!terminal::instance()) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds{10});
|
||||
continue;
|
||||
}
|
||||
auto line = terminal::instance()->readLine("§a> §f");
|
||||
if(line.empty()){
|
||||
usleep(500);
|
||||
continue;
|
||||
}
|
||||
if(!handle_command(line)) {
|
||||
terminal::instance()->writeMessage("§aStopping server...");
|
||||
if(!handle_command(line))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
terminal::instance()->writeMessage("§aStopping server...");
|
||||
web_server->stop();
|
||||
license_server->stopServer();
|
||||
license_server->stop();
|
||||
if(database) database->disconnect();
|
||||
|
||||
logger::uninstall();
|
||||
@@ -235,6 +309,6 @@ bool handle_command(string& line) {
|
||||
logMessage(LOG_LICENSE_WEB, " {} clients are currently connected!", clients.size());
|
||||
return true;
|
||||
}
|
||||
logError("Invalid command: " + line);
|
||||
logError(LOG_GENERAL, "Invalid command: " + line);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const EVP_CIPHER *EVP_aes_128_cfb1(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_192_cfb1(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_256_cfb1(void){ return 0; }
|
||||
|
||||
const EVP_CIPHER *EVP_aes_128_cfb8(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_192_cfb8(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_256_cfb8(void){ return 0; }
|
||||
|
||||
const EVP_CIPHER *EVP_aes_128_cfb128(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_192_cfb128(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_256_cfb128(void){ return 0; }
|
||||
|
||||
int EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) {
|
||||
return EVP_EncryptFinal_ex(ctx, out, out_len);
|
||||
}
|
||||
|
||||
int EVP_DecryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) {
|
||||
return EVP_DecryptFinal_ex(ctx, out, out_len);
|
||||
}
|
||||
|
||||
int SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DTLSv1_get_timeout DTLSv1_get_timeout
|
||||
#define DTLSv1_handle_timeout DTLSv1_handle_timeout
|
||||
#define SSL_CTX_add0_chain_cert SSL_CTX_add0_chain_cert
|
||||
#define SSL_CTX_add1_chain_cert SSL_CTX_add1_chain_cert
|
||||
#define SSL_CTX_add_extra_chain_cert SSL_CTX_add_extra_chain_cert
|
||||
#define SSL_CTX_clear_extra_chain_certs SSL_CTX_clear_extra_chain_certs
|
||||
#define SSL_CTX_clear_chain_certs SSL_CTX_clear_chain_certs
|
||||
#define SSL_CTX_clear_mode SSL_CTX_clear_mode
|
||||
#define SSL_CTX_clear_options SSL_CTX_clear_options
|
||||
#define SSL_CTX_get0_chain_certs SSL_CTX_get0_chain_certs
|
||||
#define SSL_CTX_get_extra_chain_certs SSL_CTX_get_extra_chain_certs
|
||||
#define SSL_CTX_get_max_cert_list SSL_CTX_get_max_cert_list
|
||||
#define SSL_CTX_get_mode SSL_CTX_get_mode
|
||||
#define SSL_CTX_get_options SSL_CTX_get_options
|
||||
#define SSL_CTX_get_read_ahead SSL_CTX_get_read_ahead
|
||||
#define SSL_CTX_get_session_cache_mode SSL_CTX_get_session_cache_mode
|
||||
#define SSL_CTX_get_tlsext_ticket_keys SSL_CTX_get_tlsext_ticket_keys
|
||||
#define SSL_CTX_need_tmp_RSA SSL_CTX_need_tmp_RSA
|
||||
#define SSL_CTX_sess_get_cache_size SSL_CTX_sess_get_cache_size
|
||||
#define SSL_CTX_sess_number SSL_CTX_sess_number
|
||||
#define SSL_CTX_sess_set_cache_size SSL_CTX_sess_set_cache_size
|
||||
#define SSL_CTX_set0_chain SSL_CTX_set0_chain
|
||||
#define SSL_CTX_set1_chain SSL_CTX_set1_chain
|
||||
#define SSL_CTX_set1_curves SSL_CTX_set1_curves
|
||||
#define SSL_CTX_set_max_cert_list SSL_CTX_set_max_cert_list
|
||||
#define SSL_CTX_set_max_send_fragment SSL_CTX_set_max_send_fragment
|
||||
#define SSL_CTX_set_mode SSL_CTX_set_mode
|
||||
#define SSL_CTX_set_msg_callback_arg SSL_CTX_set_msg_callback_arg
|
||||
#define SSL_CTX_set_options SSL_CTX_set_options
|
||||
#define SSL_CTX_set_read_ahead SSL_CTX_set_read_ahead
|
||||
#define SSL_CTX_set_session_cache_mode SSL_CTX_set_session_cache_mode
|
||||
#define SSL_CTX_set_tlsext_servername_arg SSL_CTX_set_tlsext_servername_arg
|
||||
#define SSL_CTX_set_tlsext_servername_callback \
|
||||
SSL_CTX_set_tlsext_servername_callback
|
||||
#define SSL_CTX_set_tlsext_ticket_key_cb SSL_CTX_set_tlsext_ticket_key_cb
|
||||
#define SSL_CTX_set_tlsext_ticket_keys SSL_CTX_set_tlsext_ticket_keys
|
||||
#define SSL_CTX_set_tmp_dh SSL_CTX_set_tmp_dh
|
||||
#define SSL_CTX_set_tmp_ecdh SSL_CTX_set_tmp_ecdh
|
||||
#define SSL_CTX_set_tmp_rsa SSL_CTX_set_tmp_rsa
|
||||
#define SSL_add0_chain_cert SSL_add0_chain_cert
|
||||
#define SSL_add1_chain_cert SSL_add1_chain_cert
|
||||
#define SSL_clear_chain_certs SSL_clear_chain_certs
|
||||
#define SSL_clear_mode SSL_clear_mode
|
||||
#define SSL_clear_options SSL_clear_options
|
||||
#define SSL_get0_certificate_types SSL_get0_certificate_types
|
||||
#define SSL_get0_chain_certs SSL_get0_chain_certs
|
||||
#define SSL_get_max_cert_list SSL_get_max_cert_list
|
||||
#define SSL_get_mode SSL_get_mode
|
||||
#define SSL_get_options SSL_get_options
|
||||
#define SSL_get_secure_renegotiation_support \
|
||||
SSL_get_secure_renegotiation_support
|
||||
#define SSL_need_tmp_RSA SSL_need_tmp_RSA
|
||||
#define SSL_num_renegotiations SSL_num_renegotiations
|
||||
#define SSL_session_reused SSL_session_reused
|
||||
#define SSL_set0_chain SSL_set0_chain
|
||||
#define SSL_set1_chain SSL_set1_chain
|
||||
#define SSL_set1_curves SSL_set1_curves
|
||||
#define SSL_set_max_cert_list SSL_set_max_cert_list
|
||||
#define SSL_set_max_send_fragment SSL_set_max_send_fragment
|
||||
#define SSL_set_mode SSL_set_mode
|
||||
#define SSL_set_msg_callback_arg SSL_set_msg_callback_arg
|
||||
#define SSL_set_mtu SSL_set_mtu
|
||||
#define SSL_set_options SSL_set_options
|
||||
#define SSL_set_tlsext_host_name SSL_set_tlsext_host_name
|
||||
#define SSL_set_tmp_dh SSL_set_tmp_dh
|
||||
#define SSL_set_tmp_ecdh SSL_set_tmp_ecdh
|
||||
#define SSL_set_tmp_rsa SSL_set_tmp_rsa
|
||||
#define SSL_total_renegotiations SSL_total_renegotiations
|
||||
|
||||
long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
@@ -3,10 +3,11 @@
|
||||
//
|
||||
|
||||
#include <netinet/tcp.h>
|
||||
#include <shared/crypt.h>
|
||||
#include <shared/License.h>
|
||||
#include <shared/src/crypt.h>
|
||||
#include <shared/include/license/license.h>
|
||||
#include <memory>
|
||||
#include <misc/std_unique_ptr.h>
|
||||
#include <ThreadPool/ThreadHelper.h>
|
||||
#include "ServerConnection.h"
|
||||
|
||||
using namespace std;
|
||||
@@ -49,21 +50,21 @@ threads::Future<bool> ServerConnection::connect(const std::string &host, uint16_
|
||||
if(this->network.file_descriptor < 0) CERR("Socket setup failed");
|
||||
if(::connect(this->network.file_descriptor, reinterpret_cast<const sockaddr *>(&this->network.address_remote), sizeof(this->network.address_remote)) < 0) CERR("connect() failed (" + to_string(errno) + " | " + strerror(errno) + ")");
|
||||
int enabled = 1, disabled = 0;
|
||||
if(setsockopt(this->network.file_descriptor, SOL_SOCKET, SO_REUSEADDR, &enabled, sizeof(enabled)) < 0) CERR("could not set reuse addr");
|
||||
if(setsockopt(this->network.file_descriptor, IPPROTO_TCP, TCP_CORK, &disabled, sizeof(disabled)) < 0) CERR("could not set no push");
|
||||
if(setsockopt(this->network.file_descriptor, SOL_SOCKET, SO_REUSEADDR, &enabled, sizeof(enabled)) < 0); // CERR("could not set reuse addr");
|
||||
if(setsockopt(this->network.file_descriptor, IPPROTO_TCP, TCP_CORK, &disabled, sizeof(disabled)) < 0); // CERR("could not set no push");
|
||||
|
||||
this->network.event_base = event_base_new();
|
||||
this->network.event_read = event_new(this->network.event_base, this->network.file_descriptor, EV_READ | EV_PERSIST, ServerConnection::handleEventRead, this);
|
||||
this->network.event_write = event_new(this->network.event_base, this->network.file_descriptor, EV_WRITE, ServerConnection::handleEventWrite, this);
|
||||
event_add(this->network.event_read, nullptr);
|
||||
|
||||
this->network.event_base_dispatch = new threads::Thread(THREAD_SAVE_OPERATIONS, [&](){
|
||||
this->network.event_base_dispatch = std::thread{[&]{
|
||||
event_base_dispatch(this->network.event_base);
|
||||
if(this->verbose)
|
||||
cout << "ev ended!" << endl;
|
||||
});
|
||||
}};
|
||||
this->network.state = ConnectionState::CONNECTED;
|
||||
this->protocol.state = protocol::HANDSCAKE;
|
||||
this->protocol.state = protocol::HANDSCHAKE;
|
||||
this->protocol.ping_thread = thread([&]{
|
||||
while(true) {
|
||||
{
|
||||
@@ -82,7 +83,7 @@ threads::Future<bool> ServerConnection::connect(const std::string &host, uint16_
|
||||
handshakeBuffer[0] = 0xC0;
|
||||
handshakeBuffer[1] = 0xFF;
|
||||
handshakeBuffer[2] = 0xEE;
|
||||
handshakeBuffer[3] = LICENSE_PROT_VERSION;
|
||||
handshakeBuffer[3] = 2;
|
||||
handshakeBuffer[4] = 1; //Im a manager
|
||||
this->sendPacket(protocol::packet{protocol::PACKET_CLIENT_HANDSHAKE, string((const char*) handshakeBuffer, 5)}); //Initialise packet
|
||||
}).detach();
|
||||
@@ -104,7 +105,7 @@ void ServerConnection::closeConnection() {
|
||||
if(this->network.state == ConnectionState::UNCONNECTED) return;
|
||||
this->network.state = ConnectionState::DISCONNECTING;
|
||||
|
||||
if(this->network.event_base_dispatch && *this->network.event_base_dispatch == threads::self::id()) {
|
||||
if(this->network.event_base_dispatch.get_id() == this_thread::get_id()) {
|
||||
this->network.flush_thread = new threads::Thread(THREAD_SAVE_OPERATIONS, [&](){ this->closeConnection(); });
|
||||
return;
|
||||
}
|
||||
@@ -126,11 +127,7 @@ void ServerConnection::closeConnection() {
|
||||
cerr << "could not stop event loop!" << endl;
|
||||
}
|
||||
}
|
||||
if(this->network.event_base_dispatch) {
|
||||
this->network.event_base_dispatch->join();
|
||||
delete this->network.event_base_dispatch;
|
||||
this->network.event_base_dispatch = nullptr;
|
||||
}
|
||||
threads::save_join(this->network.event_base_dispatch);
|
||||
if(this->network.event_base) {
|
||||
event_base_free(this->network.event_base);
|
||||
this->network.event_base = nullptr;
|
||||
@@ -159,8 +156,8 @@ void ServerConnection::handleEventRead(int fd, short, void* _connection) {
|
||||
auto connection = (ServerConnection*) _connection;
|
||||
|
||||
char buffer[1024];
|
||||
auto read = recv(fd, buffer, 1024, SOCK_NONBLOCK);
|
||||
if(read < 0) {
|
||||
auto read = recv(fd, buffer, 1024, MSG_DONTWAIT);
|
||||
if(read <= 0) {
|
||||
if(connection->verbose)
|
||||
cout << "Invalid read: " << strerror(errno) << endl;
|
||||
connection->local_disconnect_message = "invalid read";
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
#include <event.h>
|
||||
#include <ThreadPool/Future.h>
|
||||
#include <deque>
|
||||
#include "shared/License.h"
|
||||
#include <thread>
|
||||
#include <ThreadPool/Thread.h>
|
||||
#include "shared/include/license/license.h"
|
||||
|
||||
#define FLSUCCESS(listener, object) \
|
||||
do { \
|
||||
@@ -23,91 +25,93 @@ do { \
|
||||
} while(0)
|
||||
|
||||
|
||||
namespace license {
|
||||
namespace manager {
|
||||
enum ConnectionState {
|
||||
UNCONNECTED,
|
||||
CONNECTING,
|
||||
CONNECTED,
|
||||
DISCONNECTING
|
||||
};
|
||||
class ServerConnection {
|
||||
public:
|
||||
ServerConnection();
|
||||
~ServerConnection();
|
||||
namespace license::manager {
|
||||
enum ConnectionState {
|
||||
UNCONNECTED,
|
||||
CONNECTING,
|
||||
CONNECTED,
|
||||
DISCONNECTING
|
||||
};
|
||||
class ServerConnection {
|
||||
public:
|
||||
ServerConnection();
|
||||
~ServerConnection();
|
||||
|
||||
threads::Future<bool> connect(const std::string& host, uint16_t port);
|
||||
void disconnect(const std::string&);
|
||||
threads::Future<bool> connect(const std::string& host, uint16_t port);
|
||||
void disconnect(const std::string&);
|
||||
|
||||
void ping();
|
||||
void ping();
|
||||
|
||||
threads::Future<bool> login(const std::string&, const std::string&);
|
||||
threads::Future<std::pair<std::shared_ptr<license::License>, std::shared_ptr<license::LicenseInfo>>> registerLicense(
|
||||
const std::string& first_name,
|
||||
const std::string& last_name,
|
||||
const std::string& username,
|
||||
const std::string& email,
|
||||
license::LicenseType type,
|
||||
const std::chrono::system_clock::time_point& end,
|
||||
const std::chrono::system_clock::time_point& begin = std::chrono::system_clock::now()
|
||||
);
|
||||
threads::Future<bool> login(const std::string&, const std::string&);
|
||||
threads::Future<std::pair<std::shared_ptr<license::License>, std::shared_ptr<license::LicenseInfo>>> registerLicense(
|
||||
const std::string& first_name,
|
||||
const std::string& last_name,
|
||||
const std::string& username,
|
||||
const std::string& email,
|
||||
license::LicenseType type,
|
||||
const std::chrono::system_clock::time_point& end,
|
||||
const std::chrono::system_clock::time_point& begin,
|
||||
const std::string& old_license
|
||||
);
|
||||
|
||||
threads::Future<std::map<std::string, std::shared_ptr<license::LicenseInfo>>> list(int offset, int count);
|
||||
threads::Future<bool> deleteLicense(const std::string& key, bool full = false);
|
||||
threads::Future<std::map<std::string, std::shared_ptr<license::LicenseInfo>>> list(int offset, int count);
|
||||
threads::Future<bool> deleteLicense(const std::string& key, bool full = false);
|
||||
|
||||
bool verbose = true;
|
||||
private:
|
||||
struct {
|
||||
ConnectionState state = ConnectionState::UNCONNECTED;
|
||||
sockaddr_in address_remote;
|
||||
int file_descriptor = 0;
|
||||
bool verbose = true;
|
||||
private:
|
||||
struct {
|
||||
ConnectionState state = ConnectionState::UNCONNECTED;
|
||||
sockaddr_in address_remote;
|
||||
int file_descriptor = 0;
|
||||
|
||||
event* event_read = nullptr;
|
||||
event* event_write = nullptr;
|
||||
struct event_base* event_base = nullptr;
|
||||
threads::Thread* event_base_dispatch = nullptr;
|
||||
event* event_read = nullptr;
|
||||
event* event_write = nullptr;
|
||||
struct event_base* event_base = nullptr;
|
||||
std::thread event_base_dispatch;
|
||||
|
||||
threads::Thread* flush_thread = nullptr;
|
||||
threads::Thread* flush_thread = nullptr;
|
||||
|
||||
threads::Mutex queue_lock;
|
||||
std::deque<std::string> queue_write;
|
||||
threads::Mutex queue_lock;
|
||||
std::deque<std::string> queue_write;
|
||||
|
||||
std::unique_ptr<protocol::packet> current_packet;
|
||||
} network;
|
||||
std::unique_ptr<protocol::packet> current_packet;
|
||||
|
||||
|
||||
struct {
|
||||
protocol::RequestState state;
|
||||
std::string crypt_key = "";
|
||||
std::string overhead;
|
||||
} network;
|
||||
|
||||
std::mutex ping_lock;
|
||||
std::condition_variable ping_notify;
|
||||
std::thread ping_thread;
|
||||
} protocol;
|
||||
|
||||
struct {
|
||||
std::unique_ptr<threads::Future<bool>> future_connect;
|
||||
std::unique_ptr<threads::Future<bool>> future_login;
|
||||
std::unique_ptr<threads::Future<std::pair<std::shared_ptr<license::License>, std::shared_ptr<license::LicenseInfo>>>> future_register;
|
||||
std::unique_ptr<threads::Future<std::map<std::string, std::shared_ptr<license::LicenseInfo>>>> future_list;
|
||||
std::unique_ptr<threads::Future<bool>> future_delete;
|
||||
} listener;
|
||||
struct {
|
||||
protocol::RequestState state;
|
||||
std::string crypt_key = "";
|
||||
|
||||
std::string local_disconnect_message;
|
||||
std::mutex ping_lock;
|
||||
std::condition_variable ping_notify;
|
||||
std::thread ping_thread;
|
||||
} protocol;
|
||||
|
||||
static void handleEventRead(int, short, void*);
|
||||
static void handleEventWrite(int, short, void*);
|
||||
struct {
|
||||
std::unique_ptr<threads::Future<bool>> future_connect;
|
||||
std::unique_ptr<threads::Future<bool>> future_login;
|
||||
std::unique_ptr<threads::Future<std::pair<std::shared_ptr<license::License>, std::shared_ptr<license::LicenseInfo>>>> future_register;
|
||||
std::unique_ptr<threads::Future<std::map<std::string, std::shared_ptr<license::LicenseInfo>>>> future_list;
|
||||
std::unique_ptr<threads::Future<bool>> future_delete;
|
||||
} listener;
|
||||
|
||||
void closeConnection();
|
||||
void sendPacket(const protocol::packet&);
|
||||
void handleMessage(const std::string&);
|
||||
std::string local_disconnect_message;
|
||||
|
||||
void handlePacketDisconnect(const std::string&);
|
||||
void handlePacketHandshake(const std::string&);
|
||||
void handlePacketAuthResponse(const std::string&);
|
||||
void handlePacketCreateResponse(const std::string&);
|
||||
void handlePacketListResponse(const std::string&);
|
||||
void handlePacketDeleteResponse(const std::string&);
|
||||
};
|
||||
}
|
||||
static void handleEventRead(int, short, void*);
|
||||
static void handleEventWrite(int, short, void*);
|
||||
|
||||
void closeConnection();
|
||||
void sendPacket(const protocol::packet&);
|
||||
void handleMessage(const std::string&);
|
||||
|
||||
void handlePacketDisconnect(const std::string&);
|
||||
void handlePacketHandshake(const std::string&);
|
||||
void handlePacketAuthResponse(const std::string&);
|
||||
void handlePacketCreateResponse(const std::string&);
|
||||
void handlePacketListResponse(const std::string&);
|
||||
void handlePacketDeleteResponse(const std::string&);
|
||||
};
|
||||
}
|
||||
@@ -35,7 +35,8 @@ threads::Future<std::pair<std::shared_ptr<license::License>, std::shared_ptr<lic
|
||||
const std::string &email,
|
||||
license::LicenseType type,
|
||||
const std::chrono::system_clock::time_point& end,
|
||||
const std::chrono::system_clock::time_point& start
|
||||
const std::chrono::system_clock::time_point& start,
|
||||
const std::string& old_license
|
||||
) {
|
||||
|
||||
this->listener.future_register = std::make_unique<threads::Future<std::pair<std::shared_ptr<license::License>, std::shared_ptr<license::LicenseInfo>>>>();
|
||||
@@ -48,6 +49,9 @@ threads::Future<std::pair<std::shared_ptr<license::License>, std::shared_ptr<lic
|
||||
request.set_type(type);
|
||||
request.set_begin(duration_cast<milliseconds>(start.time_since_epoch()).count());
|
||||
request.set_end(duration_cast<milliseconds>(end.time_since_epoch()).count());
|
||||
if(!old_license.empty() && old_license != "none")
|
||||
request.set_old_key(old_license);
|
||||
|
||||
this->sendPacket({protocol::PACKET_CLIENT_LICENSE_CREATE_REQUEST, request});
|
||||
|
||||
if(this->network.state != ConnectionState::CONNECTED)
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
#include <misc/endianness.h>
|
||||
#include <LicenseRequest.pb.h>
|
||||
#include <LicenseManager.pb.h>
|
||||
#include <shared/crypt.h>
|
||||
#include <shared/License.h>
|
||||
#include <shared/src/crypt.h>
|
||||
#include <shared/include/license/license.h>
|
||||
#include <misc/std_unique_ptr.h>
|
||||
#include "ServerConnection.h"
|
||||
|
||||
@@ -27,8 +27,7 @@ void ServerConnection::handleMessage(const std::string& message) {
|
||||
packet->data += message;
|
||||
} else {
|
||||
packet->data += message.substr(0, left);
|
||||
if(this->verbose)
|
||||
cerr << "Dropping overhead! FIXME!" << endl;
|
||||
this->network.overhead = message.substr(left);
|
||||
}
|
||||
} else {
|
||||
if(message.length() < sizeof(protocol::packet::header)) {
|
||||
@@ -41,7 +40,8 @@ void ServerConnection::handleMessage(const std::string& message) {
|
||||
memcpy(packet.get(), message.data(), sizeof(protocol::packet::header));
|
||||
packet->data = message.substr(sizeof(protocol::packet::header));
|
||||
}
|
||||
if(packet->data.length() < packet->header.length) return;
|
||||
if(packet->data.length() < packet->header.length)
|
||||
return;
|
||||
|
||||
if(!this->protocol.crypt_key.empty())
|
||||
xorBuffer((char*) packet->data.data(), packet->data.length(), this->protocol.crypt_key.data(), this->protocol.crypt_key.length());
|
||||
@@ -70,6 +70,11 @@ void ServerConnection::handleMessage(const std::string& message) {
|
||||
cout << "Invalid packet type: " << packet->header.packetId << endl;
|
||||
}
|
||||
packet.reset();
|
||||
if(!this->network.overhead.empty()) {
|
||||
auto oh = this->network.overhead;
|
||||
this->network.overhead = "";
|
||||
this->handleMessage(oh);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerConnection::handlePacketDisconnect(const std::string& message) {
|
||||
@@ -79,11 +84,11 @@ void ServerConnection::handlePacketDisconnect(const std::string& message) {
|
||||
}
|
||||
|
||||
void ServerConnection::handlePacketHandshake(const std::string& data) {
|
||||
if(this->protocol.state != protocol::HANDSCAKE) LERROR("Protocol state mismatch");
|
||||
if(this->protocol.state != protocol::HANDSCHAKE) LERROR("Protocol state mismatch");
|
||||
if(data.length() < 3) LERROR("Invalid packet size");
|
||||
|
||||
if((uint8_t) data[0] != 0xAF || (uint8_t) data[1] != 0xFE) LERROR("Invalid handshake");
|
||||
if((uint8_t) data[2] != LICENSE_PROT_VERSION) LERROR("Invalid license protocol version. Please update TeaSpeak!");
|
||||
if((uint8_t) data[2] != 2) LERROR("Invalid license protocol version. Please update this client!");
|
||||
|
||||
auto key_length = be2le16(data.data(), 3);
|
||||
if(data.length() < key_length + 3) LERROR("Invalid packet size");
|
||||
|
||||
@@ -158,7 +158,7 @@ void Overview::btn_refresh_clicked() {
|
||||
this->ui.licenses->removeRow(0);
|
||||
this->entries.clear();
|
||||
|
||||
auto fut = connection->list(0, 0);
|
||||
auto fut = connection->list(0, 100);
|
||||
fut.waitAndGetLater([&, fut](std::map<std::string, std::shared_ptr<license::LicenseInfo>> response) {
|
||||
if(!fut.succeeded()) {
|
||||
runOnThread(this->thread(), [&, fut](){
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
#include "LicenseManager.h"
|
||||
#include "DatabaseHandler.h"
|
||||
#include <misc/base64.h>
|
||||
#include <log/LogUtils.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
using namespace license;
|
||||
using namespace license::server;
|
||||
using namespace license::server::database;
|
||||
using namespace sql;
|
||||
|
||||
LicenseManager::LicenseManager(sql::SqlManager* database) : database(database){
|
||||
DatabaseHandler::DatabaseHandler(sql::SqlManager* database) : database(database){
|
||||
this->id_cache = make_shared<KeyIdCache>(this);
|
||||
}
|
||||
LicenseManager::~LicenseManager() { }
|
||||
DatabaseHandler::~DatabaseHandler() { }
|
||||
|
||||
/*
|
||||
LicenseType type;
|
||||
@@ -40,7 +41,7 @@ res = command(this->database, cmd).execute(); \
|
||||
version = ver; \
|
||||
sql::command(this->database, "UPDATE `general` SET `value` = :version WHERE `key` = 'version'", variable{":version", version}).execute();
|
||||
|
||||
bool LicenseManager::setup(std::string& error) {
|
||||
bool DatabaseHandler::setup(std::string& error) {
|
||||
result res;
|
||||
int version = -1;
|
||||
sql::command(this->database, "SELECT `value` FROM `general` WHERE `key` = 'version'").query([](int* version, int lnegth, string* values, string* names) {
|
||||
@@ -59,7 +60,7 @@ bool LicenseManager::setup(std::string& error) {
|
||||
|
||||
SET_VERSION(0);
|
||||
case 0:
|
||||
logMessage("Updating database! To version 1");
|
||||
logMessage(LOG_GENERAL, "Updating database! To version 1");
|
||||
CTBL("CREATE TABLE IF NOT EXISTS `history_speach` (`keyId` INT, `timestamp` BIGINT, `total` BIGINT, `dead` BIGINT, `online` BIGINT, `varianz` BIGINT)");
|
||||
CTBL("CREATE TABLE IF NOT EXISTS `history_online` (`keyId` INT, `timestamp` BIGINT, `server` INT, `clients` INT, `web` INT, `music` INT, `queries` INT)");
|
||||
|
||||
@@ -106,20 +107,33 @@ bool LicenseManager::setup(std::string& error) {
|
||||
|
||||
case 4:
|
||||
CTBL("CREATE TABLE IF NOT EXISTS `users` (`username` VARCHAR(64) NOT NULL PRIMARY KEY, `password_hash` VARCHAR(128), `status` INT, `owner` VARCHAR(64))");
|
||||
SET_VERSION(5);
|
||||
|
||||
case 5:
|
||||
CTBL("CREATE TABLE `license_upgrades` (`upgrade_id` INT PRIMARY KEY NOT NULL, `old_key_id` INT, `new_key_id` INT, `timestamp_begin` BIGINT, `timestamp_end` BIGINT, `valid` INT, `use_count` INT, `license` BLOB);");
|
||||
CTBL("ALTER TABLE `license_upgrades` ADD INDEX(`old_key_id`)");
|
||||
CTBL("ALTER TABLE `license` ADD INDEX(`keyId`);");
|
||||
CTBL("ALTER TABLE `license` ADD COLUMN `upgrade_id` INT DEFAULT 0;");
|
||||
SET_VERSION(6);
|
||||
|
||||
case 6:
|
||||
CTBL("CREATE TABLE license_upgrade_log (`upgrade_id` INT, `timestamp` INT, `unique_id` VARCHAR(64), `server_ip` INT, `succeeded` TINYINT);");
|
||||
CIDX("CREATE INDEX `upgrade_id_timestamp` ON `license_upgrade_log` (`upgrade_id`, `timestamp`)");
|
||||
SET_VERSION(7);
|
||||
|
||||
default:;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LicenseManager::registerLicense(const std::string& key, const shared_ptr<LicenseInfo>& info, const std::string& issuer) {
|
||||
bool DatabaseHandler::register_license(const std::string& key, const shared_ptr<LicenseInfo>& info, const std::string& issuer) {
|
||||
result res;
|
||||
res = command(this->database, "INSERT INTO `license` (`key`, `type`, `deleted`, `issuer`) VALUES (:key, :type, :deleted, :issuer)", variable{":key", key}, variable{":type", (uint32_t) info->type}, variable{":deleted", false}, variable{":issuer", issuer}).execute();
|
||||
if(!res) {
|
||||
logError("Could not register new license (" + res.fmtStr() + ")");
|
||||
logError(LOG_GENERAL, "Could not register new license (" + res.fmtStr() + ")");
|
||||
return false;
|
||||
}
|
||||
auto keyId = this->id_cache->getKeyId(key);
|
||||
auto keyId = this->id_cache->get_key_id_from_key(key);
|
||||
if(keyId == 0) return false;
|
||||
|
||||
res = command(this->database, "INSERT INTO `license_info` (`keyId`, `username`, `first_name`, `last_name`, `email`, `begin`, `end`, `generated`) VALUES (:key, :username, :first_name, :last_name, :email, :begin, :end, :generated)",
|
||||
@@ -133,43 +147,43 @@ bool LicenseManager::registerLicense(const std::string& key, const shared_ptr<Li
|
||||
variable{":end", duration_cast<milliseconds>(info->end.time_since_epoch()).count()}
|
||||
).execute();
|
||||
if(!res) {
|
||||
logError("Could not register new license info (" + res.fmtStr() + ")");
|
||||
logError(LOG_GENERAL, "Could not register new license info (" + res.fmtStr() + ")");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LicenseManager::deleteLicense(const std::string& key, bool full) {
|
||||
bool DatabaseHandler::delete_license(const std::string& key, bool full) {
|
||||
if(full) {
|
||||
auto keyId = this->id_cache->getKeyId(key);
|
||||
auto keyId = this->id_cache->get_key_id_from_key(key);
|
||||
if(keyId == 0) return false; //Never exists
|
||||
|
||||
auto res = command(this->database, "DELETE FROM `license` WHERE `key` = :key", variable{":key", key}).execute();
|
||||
if(!res) logError("Could not delete license (" + res.fmtStr() + ")");
|
||||
if(!res) logError(LOG_GENERAL, "Could not delete license (" + res.fmtStr() + ")");
|
||||
res = command(this->database, "DELETE FROM `license_info` WHERE `keyId` = :key", variable{":keyId", keyId}).execute();
|
||||
if(!res) logError("Could not delete license (" + res.fmtStr() + ")");
|
||||
if(!res) logError(LOG_GENERAL, "Could not delete license (" + res.fmtStr() + ")");
|
||||
return !!res;
|
||||
} else {
|
||||
auto res = command(this->database, "UPDATE `license` SET `deleted` = :true WHERE `key` = :key", variable{":true", true}, variable{":key", key}).execute();
|
||||
if(!res) logError("Could not delete license (" + res.fmtStr() + ")");
|
||||
if(!res) logError(LOG_GENERAL, "Could not delete license (" + res.fmtStr() + ")");
|
||||
return !!res;
|
||||
}
|
||||
}
|
||||
|
||||
bool LicenseManager::validLicenseKey(const std::string& key) {
|
||||
bool DatabaseHandler::validLicenseKey(const std::string& key) {
|
||||
bool valid = false;
|
||||
auto res = command(this->database, "SELECT * FROM `license` WHERE `key` = :key AND `deleted` = :false LIMIT 1", variable{":false", false}, variable{":key", key}).query([](bool* flag, int, char**, char**) {
|
||||
*flag = true;
|
||||
return 0;
|
||||
}, &valid);
|
||||
if(!res) logError("Could not validate license (" + res.fmtStr() + ")");
|
||||
if(!res) logError(LOG_GENERAL, "Could not validate license (" + res.fmtStr() + ")");
|
||||
return !!res && valid;
|
||||
}
|
||||
|
||||
inline std::map<std::string, std::shared_ptr<LicenseInfo>> query_license(SqlManager* mgr, std::string key, int offset, int length) {
|
||||
inline std::map<std::string, std::shared_ptr<LicenseInfo>> query_license(SqlManager* mgr, const std::string& key, int offset, int length) {
|
||||
std::map<std::string, std::shared_ptr<LicenseInfo>> result;
|
||||
|
||||
auto query = string() + "SELECT `key`, `username`, `first_name`, `last_name`, `email`, `begin`, `end`, `generated`, `deleted` FROM `license_info` INNER JOIN `license` ON `license_info`.`keyId` = `license`.`keyId`";
|
||||
auto query = string() + "SELECT `key`, `username`, `first_name`, `last_name`, `email`, `begin`, `end`, `generated`, `deleted`, `upgrade_id` FROM `license_info` INNER JOIN `license` ON `license_info`.`keyId` = `license`.`keyId`";
|
||||
if(!key.empty())
|
||||
query += "WHERE `key` = :key";
|
||||
else
|
||||
@@ -203,6 +217,8 @@ inline std::map<std::string, std::shared_ptr<LicenseInfo>> query_license(SqlMana
|
||||
info->creation = system_clock::time_point() + milliseconds(stoll(values[index]));
|
||||
else if(names[index] == "deleted")
|
||||
info->deleted = values[index] == "1" || values[index] == "true";
|
||||
else if(names[index] == "upgrade_id")
|
||||
info->upgrade_id = std::stol(values[index]);
|
||||
else
|
||||
logError(LOG_GENERAL, "Unknown field {}", names[index]);
|
||||
} catch (std::exception& ex) {
|
||||
@@ -214,24 +230,24 @@ inline std::map<std::string, std::shared_ptr<LicenseInfo>> query_license(SqlMana
|
||||
return 0;
|
||||
}, &result);
|
||||
logTrace(LOG_GENERAL, "Query returned {} results", result.size());
|
||||
if(!res) logError("Could not query license (" + res.fmtStr() + ")");
|
||||
if(!res) logError(LOG_GENERAL, "Could not query license (" + res.fmtStr() + ")");
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<LicenseInfo> LicenseManager::licenseInfo(const std::string& key) {
|
||||
std::shared_ptr<LicenseInfo> DatabaseHandler::query_license_info(const std::string& key) {
|
||||
auto result = query_license(this->database, key, 0, 0);
|
||||
if(result.empty()) return nullptr;
|
||||
return result.begin()->second;
|
||||
}
|
||||
|
||||
std::map<std::string, std::shared_ptr<LicenseInfo>> LicenseManager::listLicenses(int offset, int limit) {
|
||||
std::map<std::string, std::shared_ptr<LicenseInfo>> DatabaseHandler::list_licenses(int offset, int limit) {
|
||||
return query_license(this->database, "", offset, limit);
|
||||
}
|
||||
|
||||
bool LicenseManager::logRequest(const std::string& key, const std::string& unique_id, const std::string& ip, const std::string& version, int state) {
|
||||
bool DatabaseHandler::logRequest(const std::string& key, const std::string& unique_id, const std::string& ip, const std::string& version, int state) {
|
||||
result res;
|
||||
|
||||
auto keyId = this->id_cache->getKeyId(key);
|
||||
auto keyId = this->id_cache->get_key_id_from_key(key);
|
||||
if(keyId == 0) {
|
||||
logError(LOG_GENERAL, "Failed to log license request (could not resolve key id)");
|
||||
return false;
|
||||
@@ -246,7 +262,7 @@ bool LicenseManager::logRequest(const std::string& key, const std::string& uniqu
|
||||
variable{":unique_id", unique_id},
|
||||
variable{":result", state}).execute();
|
||||
if(!res) {
|
||||
logError("Could not log license validation (" + res.fmtStr() + ")");
|
||||
logError(LOG_GENERAL, "Could not log license validation (" + res.fmtStr() + ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -258,17 +274,17 @@ bool LicenseManager::logRequest(const std::string& key, const std::string& uniqu
|
||||
variable{":version", version}
|
||||
).execute();
|
||||
if(!res)
|
||||
logError("Could not log license version statistic (" + res.fmtStr() + ")");
|
||||
logError(LOG_GENERAL, "Could not log license version statistic (" + res.fmtStr() + ")");
|
||||
res = {};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LicenseManager::logStatistic(const std::string &key, const std::string& unique_id, const std::string &ip,
|
||||
const ts::proto::license::PropertyUpdateRequest &data) {
|
||||
bool DatabaseHandler::logStatistic(const std::string &key, const std::string& unique_id, const std::string &ip,
|
||||
const ts::proto::license::PropertyUpdateRequest &data) {
|
||||
result res;
|
||||
|
||||
auto keyId = this->id_cache->getKeyId(key);
|
||||
auto keyId = this->id_cache->get_key_id_from_key(key);
|
||||
if(keyId == 0) return false;
|
||||
|
||||
auto time = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||
@@ -284,7 +300,7 @@ bool LicenseManager::logStatistic(const std::string &key, const std::string& uni
|
||||
variable{":query", data.queries_online()}
|
||||
).execute();
|
||||
if(!res)
|
||||
logError("Could not log license statistics (" + res.fmtStr() + ")");
|
||||
logError(LOG_GENERAL, "Could not log license statistics (" + res.fmtStr() + ")");
|
||||
res = {};
|
||||
}
|
||||
//SELECT * FROM `license_info` WHERE `keyId` IN (SELECT `keyId` FROM `license` WHERE `key` = '000')
|
||||
@@ -299,107 +315,158 @@ bool LicenseManager::logStatistic(const std::string &key, const std::string& uni
|
||||
variable{":varianz", data.speach_varianz()}
|
||||
).execute();
|
||||
if(!res)
|
||||
logError("Could not log license statistics (" + res.fmtStr() + ")");
|
||||
logError(LOG_GENERAL, "Could not log license statistics (" + res.fmtStr() + ")");
|
||||
res = {};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::deque<std::unique_ptr<LicenseManager::GlobalUserStatistics>> LicenseManager::list_statistics_user(const system_clock::time_point &begin, const system_clock::time_point &end, const milliseconds &interval) {
|
||||
map<std::string, deque<unique_ptr<LicenseManager::UserStatistics>>> server_statistics;
|
||||
std::shared_ptr<DatabaseHandler::UserHistory> DatabaseHandler::list_statistics_user(const system_clock::time_point &begin, const system_clock::time_point &end, const milliseconds &interval) {
|
||||
auto timeout = hours(2) + minutes(10); //TODO timeout configurable?
|
||||
|
||||
auto state = command(this->database,"SELECT * FROM `history_online` WHERE `timestamp` >= :timestamp_start AND `timestamp` <= :timestamp_end ORDER BY `timestamp` ASC",
|
||||
/* initialize the result */
|
||||
auto allocated_records = (size_t) floor((end - begin) / interval) + 1;
|
||||
auto _result = (UserHistory*) malloc(sizeof(UserHistory) + sizeof(GlobalUserStatistics) * allocated_records);
|
||||
new (_result) UserHistory();
|
||||
|
||||
auto result = shared_ptr<UserHistory>(_result, [](UserHistory* ptr){
|
||||
ptr->~UserHistory();
|
||||
free(ptr);
|
||||
});
|
||||
|
||||
|
||||
result->record_count = 0;
|
||||
result->begin = begin;
|
||||
result->end = end;
|
||||
result->interval = interval;
|
||||
|
||||
memset(&result->history[0], 0, allocated_records * sizeof(GlobalUserStatistics));
|
||||
auto info = &_result->history[0];
|
||||
|
||||
/* temp db variables */
|
||||
map<std::string, DatabaseHandler::DatabaseUserStatistics> server_statistics;
|
||||
|
||||
bool have_key, have_uid;
|
||||
DatabaseHandler::DatabaseUserStatistics temp_stats; /* temp struct for stats parsing */
|
||||
DatabaseHandler::DatabaseUserStatistics* stats_ptr; /* pointer to the target stats */
|
||||
std::chrono::system_clock::time_point current_timestamp = begin + interval; /* upper limit of the current interval */
|
||||
|
||||
auto state = command(this->database, "SELECT * FROM `history_online` WHERE `timestamp` >= :timestamp_start AND `timestamp` <= :timestamp_end ORDER BY `timestamp` ASC",
|
||||
variable{":timestamp_start", duration_cast<milliseconds>(begin.time_since_epoch() - timeout).count()},
|
||||
variable{":timestamp_end", duration_cast<milliseconds>(end.time_since_epoch()).count()}
|
||||
).query([&server_statistics](int columns, std::string* values, std::string* names){
|
||||
size_t key_id = 0;
|
||||
std::string unique_id;
|
||||
auto info = make_unique<LicenseManager::UserStatistics>();
|
||||
for(int index = 0; index < columns; index++) {
|
||||
try {
|
||||
if(names[index] == "keyId")
|
||||
key_id = stoull(values[index]);
|
||||
else if(names[index] == "unique_id")
|
||||
unique_id = values[index];
|
||||
else if(names[index] == "timestamp")
|
||||
info->timestamp = system_clock::time_point() + milliseconds(stoll(values[index]));
|
||||
else if(names[index] == "server")
|
||||
info->servers_online = stoull(values[index]);
|
||||
else if(names[index] == "clients")
|
||||
info->clients_online = stoull(values[index]);
|
||||
else if(names[index] == "web")
|
||||
info->web_clients_online = stoull(values[index]);
|
||||
else if(names[index] == "music")
|
||||
info->bots_online = stoull(values[index]);
|
||||
else if(names[index] == "queries")
|
||||
info->queries_online = stoull(values[index]);
|
||||
} catch (std::exception& ex) {
|
||||
logError("Failed to parse column " + names[index] + " => " + ex.what() + " (Value: " + values[index] + ")");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(key_id == 0) return 0;
|
||||
).query([&](int columns, std::string* values, std::string* names) {
|
||||
/* find the user statistic ptr */
|
||||
{
|
||||
size_t key_id = 0;
|
||||
std::string unique_id;
|
||||
|
||||
server_statistics[to_string(key_id) + "_" + unique_id].push_back(std::move(info));
|
||||
have_key = false;
|
||||
have_uid = false;
|
||||
for(int index = 0; index < columns; index++) {
|
||||
if(names[index] == "keyId") {
|
||||
key_id = strtol(values[index].c_str(), nullptr, 10);
|
||||
if(key_id == 0) return 0; /* invalid key id */
|
||||
|
||||
have_key = true;
|
||||
if(have_key && have_uid) goto process_tag;
|
||||
} else if(names[index] == "unique_id") {
|
||||
unique_id = values[index];
|
||||
have_uid = true;
|
||||
|
||||
if(have_key && have_uid) goto process_tag;
|
||||
}
|
||||
}
|
||||
return 0; /* key or uid haven't been found */
|
||||
|
||||
process_tag:
|
||||
stats_ptr = &server_statistics[to_string(key_id) + "_" + unique_id];
|
||||
}
|
||||
|
||||
for(int index = 0; index < columns; index++) {
|
||||
if(names[index] == "timestamp")
|
||||
temp_stats.timestamp = system_clock::time_point() + milliseconds(stoll(values[index]));
|
||||
else if(names[index] == "server")
|
||||
temp_stats.servers_online = strtol(values[index].c_str(), nullptr, 10);
|
||||
else if(names[index] == "clients")
|
||||
temp_stats.clients_online = strtol(values[index].c_str(), nullptr, 10);
|
||||
else if(names[index] == "web")
|
||||
temp_stats.web_clients_online = strtol(values[index].c_str(), nullptr, 10);
|
||||
else if(names[index] == "music")
|
||||
temp_stats.bots_online = strtol(values[index].c_str(), nullptr, 10);
|
||||
else if(names[index] == "queries")
|
||||
temp_stats.queries_online = strtol(values[index].c_str(), nullptr, 10);
|
||||
}
|
||||
|
||||
/* because the query could only be oldest to newest */
|
||||
while(temp_stats.timestamp > current_timestamp) {
|
||||
assert(_result->record_count < allocated_records); /* ensure we write to valid memory */
|
||||
|
||||
auto min_timestamp = current_timestamp - timeout;
|
||||
for(auto& server : server_statistics) {
|
||||
auto& second = server.second;
|
||||
if(second.timestamp < min_timestamp || second.timestamp.time_since_epoch().count() == 0)
|
||||
continue; /* last server request is too old to be counted */
|
||||
|
||||
info->instance_online++;
|
||||
info->queries_online += second.queries_online;
|
||||
info->bots_online += second.bots_online;
|
||||
info->web_clients_online += second.web_clients_online;
|
||||
info->clients_online += second.clients_online;
|
||||
info->servers_online += second.servers_online;
|
||||
}
|
||||
|
||||
info++;
|
||||
_result->record_count++;
|
||||
current_timestamp += interval; /* lets gather for the next interval */
|
||||
}
|
||||
|
||||
/* write the "new" statistic */
|
||||
memcpy(stats_ptr, &temp_stats, sizeof(temp_stats));
|
||||
return 0;
|
||||
});
|
||||
|
||||
if(!state) {
|
||||
logError("Could not read license statistics (" + state.fmtStr() + ")");
|
||||
logError(LOG_GENERAL, "Could not read license statistics (" + state.fmtStr() + ")");
|
||||
return {};
|
||||
}
|
||||
|
||||
std::deque<std::unique_ptr<LicenseManager::GlobalUserStatistics>> result;
|
||||
system_clock::time_point current_timestamp = begin;
|
||||
while(current_timestamp <= end) {
|
||||
auto info = make_unique<LicenseManager::GlobalUserStatistics>();
|
||||
info->timestamp = current_timestamp;
|
||||
/* flush the last record */
|
||||
do {
|
||||
assert(_result->record_count < allocated_records); /* ensure we write to valid memory */
|
||||
|
||||
auto min_timestamp = current_timestamp - timeout;
|
||||
for(auto& server : server_statistics) {
|
||||
while(!server.second.empty()) {
|
||||
auto& first = *server.second.begin();
|
||||
if(first->timestamp > current_timestamp) break; //Entry within the future
|
||||
if(first->timestamp + timeout < current_timestamp) { //Entry within the past
|
||||
server.second.pop_front();
|
||||
continue;
|
||||
}
|
||||
if(server.second.size() > 1) {
|
||||
auto& second = *(server.second.begin() + 1);
|
||||
if(second->timestamp <= current_timestamp) {
|
||||
server.second.pop_front(); //The next entry is more up 2 date
|
||||
continue;
|
||||
}
|
||||
}
|
||||
auto& second = server.second;
|
||||
if(second.timestamp < min_timestamp)
|
||||
continue; /* last server request is too old to be counted */
|
||||
|
||||
info->instance_online++;
|
||||
info->queries_online += first->queries_online;
|
||||
info->bots_online += first->bots_online;
|
||||
info->web_clients_online += first->web_clients_online;
|
||||
info->clients_online += first->clients_online;
|
||||
info->servers_online += first->servers_online;
|
||||
break;
|
||||
}
|
||||
info->instance_online++;
|
||||
info->queries_online += second.queries_online;
|
||||
info->bots_online += second.bots_online;
|
||||
info->web_clients_online += second.web_clients_online;
|
||||
info->clients_online += second.clients_online;
|
||||
info->servers_online += second.servers_online;
|
||||
}
|
||||
|
||||
result.push_back(std::move(info));
|
||||
info++;
|
||||
_result->record_count++;
|
||||
current_timestamp += interval;
|
||||
}
|
||||
} while(current_timestamp < end);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::deque<std::unique_ptr<LicenseManager::GlobalVersionsStatistic>> LicenseManager::list_statistics_version(const std::chrono::system_clock::time_point &begin, const std::chrono::system_clock::time_point &end, const std::chrono::milliseconds &interval) {
|
||||
map<std::string, deque<unique_ptr<LicenseManager::GlobalVersionsStatistic>>> server_statistics;
|
||||
std::deque<std::unique_ptr<DatabaseHandler::GlobalVersionsStatistic>> DatabaseHandler::list_statistics_version(const std::chrono::system_clock::time_point &begin, const std::chrono::system_clock::time_point &end, const std::chrono::milliseconds &interval) {
|
||||
map<std::string, deque<unique_ptr<DatabaseHandler::GlobalVersionsStatistic>>> server_statistics;
|
||||
auto timeout = hours(2) + minutes(10); //TODO timeout configurable?
|
||||
|
||||
auto state = command(this->database,"SELECT * FROM `history_version` WHERE `timestamp` >= :timestamp_start AND `timestamp` <= :timestamp_end ORDER BY `timestamp` ASC",
|
||||
auto state = command(this->database, "SELECT * FROM `history_version` WHERE `timestamp` >= :timestamp_start AND `timestamp` <= :timestamp_end ORDER BY `timestamp` ASC",
|
||||
variable{":timestamp_start", duration_cast<milliseconds>(begin.time_since_epoch() - timeout).count()},
|
||||
variable{":timestamp_end", duration_cast<milliseconds>(end.time_since_epoch()).count()}
|
||||
).query([&server_statistics](int columns, std::string* values, std::string* names){
|
||||
size_t key_id = 0;
|
||||
std::string unique_id;
|
||||
auto info = make_unique<LicenseManager::GlobalVersionsStatistic>();
|
||||
auto info = make_unique<DatabaseHandler::GlobalVersionsStatistic>();
|
||||
for(int index = 0; index < columns; index++) {
|
||||
try {
|
||||
if(names[index] == "keyId")
|
||||
@@ -411,7 +478,7 @@ std::deque<std::unique_ptr<LicenseManager::GlobalVersionsStatistic>> LicenseMana
|
||||
else if(names[index] == "version")
|
||||
info->versions[values[index]] = 1;
|
||||
} catch (std::exception& ex) {
|
||||
logError("Failed to parse column " + names[index] + " => " + ex.what() + " (Value: " + values[index] + ")");
|
||||
logError(LOG_GENERAL, "Failed to parse column " + names[index] + " => " + ex.what() + " (Value: " + values[index] + ")");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -422,14 +489,14 @@ std::deque<std::unique_ptr<LicenseManager::GlobalVersionsStatistic>> LicenseMana
|
||||
});
|
||||
|
||||
if(!state) {
|
||||
logError("Could not read license statistics (" + state.fmtStr() + ")");
|
||||
logError(LOG_GENERAL, "Could not read license statistics (" + state.fmtStr() + ")");
|
||||
return {};
|
||||
}
|
||||
|
||||
std::deque<std::unique_ptr<LicenseManager::GlobalVersionsStatistic>> result;
|
||||
std::deque<std::unique_ptr<DatabaseHandler::GlobalVersionsStatistic>> result;
|
||||
system_clock::time_point current_timestamp = begin;
|
||||
while(current_timestamp <= end) {
|
||||
auto info = make_unique<LicenseManager::GlobalVersionsStatistic>();
|
||||
auto info = make_unique<DatabaseHandler::GlobalVersionsStatistic>();
|
||||
info->timestamp = current_timestamp;
|
||||
|
||||
for(auto& server : server_statistics) {
|
||||
@@ -460,4 +527,87 @@ std::deque<std::unique_ptr<LicenseManager::GlobalVersionsStatistic>> LicenseMana
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DatabaseHandler::register_license_upgrade(license_key_id_t old_key_id, license_key_id_t new_key_id,
|
||||
const std::chrono::system_clock::time_point &begin_timestamp, const std::chrono::system_clock::time_point &end_timestamp, const std::string &license_key) {
|
||||
auto upgrade_id = std::chrono::system_clock::now().time_since_epoch().count();
|
||||
auto sql_result = sql::command(this->sql(), "INSERT INTO `license_upgrades` (`upgrade_id`, `old_key_id`, `new_key_id`, `timestamp_begin`, `timestamp_end`, `valid`, `use_count`, `license`) VALUES"
|
||||
"(:upgrade_id, :old_key_id, :new_key_id, :timestamp_begin, :timestamp_end, 1, 0, :license)",
|
||||
variable{":upgrade_id", upgrade_id},
|
||||
variable{":old_key_id", old_key_id},
|
||||
variable{":new_key_id", new_key_id},
|
||||
variable{":timestamp_begin", std::chrono::duration_cast<std::chrono::milliseconds>(begin_timestamp.time_since_epoch()).count()},
|
||||
variable{":timestamp_end", std::chrono::duration_cast<std::chrono::milliseconds>(end_timestamp.time_since_epoch()).count()},
|
||||
variable{":license", base64::decode(license_key)}).execute();
|
||||
if(!sql_result) {
|
||||
logError(LOG_GENERAL, "Failed to insert license upgrade: {}", sql_result.fmtStr());
|
||||
return false;
|
||||
}
|
||||
|
||||
sql_result = sql::command(this->sql(), "UPDATE `license` SET `upgrade_id` = :upgrade_id WHERE `keyId` = :key_id",
|
||||
variable{":upgrade_id", upgrade_id},
|
||||
variable{":key_id", old_key_id}).execute();
|
||||
if(!sql_result) {
|
||||
logError(LOG_GENERAL, "Failed to set license upgrade: {}", sql_result.fmtStr());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<LicenseUpgrade> DatabaseHandler::query_license_upgrade(upgrade_id_t id) {
|
||||
std::unique_ptr<LicenseUpgrade> result{};
|
||||
auto sql_result = sql::command(this->sql(), "SELECT `upgrade_id`, `old_key_id`, `new_key_id`, `timestamp_begin`, `timestamp_end`, `valid`, `use_count`, `license` FROM `license_upgrades` WHERE `upgrade_id` = :upgrade_id LIMIT 1",
|
||||
variable{":upgrade_id", id}).query([&](int length, std::string* values, std::string* names) {
|
||||
result = std::make_unique<LicenseUpgrade>();
|
||||
for(size_t index = 0; index < length; index++) {
|
||||
try {
|
||||
if(names[index] == "upgrade_id")
|
||||
result->upgrade_id = std::stoull(values[index]);
|
||||
else if(names[index] == "old_key_id")
|
||||
result->old_license_key_id = std::stoull(values[index]);
|
||||
else if(names[index] == "new_key_id")
|
||||
result->new_license_key_id = std::stoull(values[index]);
|
||||
else if(names[index] == "timestamp_begin")
|
||||
result->begin_timestamp = std::chrono::system_clock::time_point{} + std::chrono::milliseconds{std::stoull(values[index])};
|
||||
else if(names[index] == "timestamp_end")
|
||||
result->end_timestamp = std::chrono::system_clock::time_point{} + std::chrono::milliseconds{std::stoull(values[index])};
|
||||
else if(names[index] == "use_count")
|
||||
result->update_count = std::stoull(values[index]);
|
||||
else if(names[index] == "valid")
|
||||
result->valid = std::stoull(values[index]) > 0;
|
||||
else if(names[index] == "license")
|
||||
result->license_key = base64::encode(values[index]);
|
||||
} catch(std::exception& ex) {
|
||||
result = nullptr;
|
||||
logWarning(LOG_GENERAL, "Failed to parse column {} for upgrade id {}. (Value: {})", names[index], id, values[index]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
if(!sql_result) {
|
||||
logWarning(LOG_GENERAL, "Failed to query license upgrade info for upgrade {}: {}", id, sql_result.fmtStr());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void DatabaseHandler::log_license_upgrade_attempt(upgrade_id_t upgrade_id, bool succeeded, const std::string &unique_id, const std::string &ip) {
|
||||
auto result = sql::command(this->sql(), "INSERT INTO `license_upgrade_log` (`upgrade_id`, `timestamp`, `unique_id`, `server_ip`, `succeeded`) VALUES (:upgrade_id, :timestamp, :unique_id, :server_ip, :succeeded);",
|
||||
variable{":upgrade_id", upgrade_id},
|
||||
variable{":timestamp", std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()},
|
||||
variable{":unique_id", unique_id},
|
||||
variable{":server_ip", ip},
|
||||
variable{":succeeded", succeeded}).execute();
|
||||
if(!result)
|
||||
logWarning(LOG_GENERAL, "Failed to insert upgrade log into database ({})", result.fmtStr());
|
||||
|
||||
if(succeeded) {
|
||||
result = sql::command(this->sql(), "UPDATE `license_upgrades` SET `use_count` = `use_count` + 1 WHERE `upgrade_id` = :upgrade_id",
|
||||
variable{":upgrade_id", upgrade_id}).execute();
|
||||
if(!result)
|
||||
logWarning(LOG_GENERAL, "Failed to increase upgrade use count MySQL ({})", result.fmtStr());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
#pragma once
|
||||
|
||||
#include <sql/SqlQuery.h>
|
||||
#include <shared/include/license/license.h>
|
||||
#include <LicenseRequest.pb.h>
|
||||
|
||||
namespace license::server::database {
|
||||
typedef size_t license_key_id_t;
|
||||
typedef size_t upgrade_id_t;
|
||||
|
||||
class DatabaseHandler;
|
||||
class KeyIdCache {
|
||||
public:
|
||||
explicit KeyIdCache(DatabaseHandler*);
|
||||
|
||||
std::string get_key_from_id(license_key_id_t keyId);
|
||||
size_t get_key_id_from_key(const std::string &key);
|
||||
|
||||
void clear_cache();
|
||||
private:
|
||||
struct CacheEntry {
|
||||
std::string key;
|
||||
size_t keyId;
|
||||
std::chrono::system_clock::time_point age;
|
||||
};
|
||||
|
||||
int insert_entry(int, std::string*, std::string*);
|
||||
|
||||
DatabaseHandler* handle;
|
||||
|
||||
std::mutex entry_lock{};
|
||||
std::deque<std::unique_ptr<CacheEntry>> entries;
|
||||
};
|
||||
|
||||
struct LicenseUpgrade {
|
||||
upgrade_id_t upgrade_id{0};
|
||||
|
||||
license_key_id_t old_license_key_id{0};
|
||||
license_key_id_t new_license_key_id{0};
|
||||
|
||||
std::chrono::system_clock::time_point begin_timestamp{};
|
||||
std::chrono::system_clock::time_point end_timestamp{};
|
||||
|
||||
bool valid{false};
|
||||
size_t update_count{0};
|
||||
|
||||
std::string license_key{};
|
||||
|
||||
[[nodiscard]] inline bool not_yet_available() const {
|
||||
return std::chrono::system_clock::now() < this->begin_timestamp && this->begin_timestamp.time_since_epoch().count() != 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool is_expired() const {
|
||||
return std::chrono::system_clock::now() > this->end_timestamp && this->end_timestamp.time_since_epoch().count() != 0;
|
||||
}
|
||||
};
|
||||
|
||||
class DatabaseHandler {
|
||||
public:
|
||||
struct UserStatistics {
|
||||
uint64_t clients_online = 0;
|
||||
uint64_t web_clients_online = 0;
|
||||
uint64_t bots_online = 0;
|
||||
uint64_t queries_online = 0;
|
||||
uint64_t servers_online = 0;
|
||||
};
|
||||
|
||||
struct ExtendedUserStatistics : public UserStatistics {
|
||||
std::string ip_address;
|
||||
};
|
||||
|
||||
struct GlobalUserStatistics : public UserStatistics {
|
||||
uint64_t instance_online = 0;
|
||||
};
|
||||
|
||||
struct DatabaseUserStatistics : public UserStatistics {
|
||||
std::chrono::system_clock::time_point timestamp{};
|
||||
};
|
||||
|
||||
struct GlobalVersionsStatistic {
|
||||
std::chrono::system_clock::time_point timestamp;
|
||||
std::map<std::string, uint32_t> versions;
|
||||
};
|
||||
|
||||
struct UserHistory {
|
||||
std::chrono::system_clock::time_point begin{};
|
||||
std::chrono::system_clock::time_point end{};
|
||||
std::chrono::milliseconds interval{0};
|
||||
|
||||
size_t record_count = 0;
|
||||
GlobalUserStatistics history[0];
|
||||
};
|
||||
static_assert(sizeof(UserHistory) == 32);
|
||||
|
||||
public:
|
||||
explicit DatabaseHandler(sql::SqlManager* database);
|
||||
~DatabaseHandler();
|
||||
|
||||
bool setup(std::string&);
|
||||
|
||||
[[nodiscard]] inline std::shared_ptr<KeyIdCache> key_id_cache() { return this->id_cache; }
|
||||
|
||||
bool validLicenseKey(const std::string& /* key */);
|
||||
std::shared_ptr<LicenseInfo> query_license_info(const std::string&);
|
||||
std::map<std::string, std::shared_ptr<LicenseInfo>> list_licenses(int offset = 0, int limit = -1);
|
||||
|
||||
bool register_license_upgrade(license_key_id_t /* old key */, license_key_id_t /* new key */, const std::chrono::system_clock::time_point& /* begin */, const std::chrono::system_clock::time_point& /* end */, const std::string& /* key */);
|
||||
std::unique_ptr<LicenseUpgrade> query_license_upgrade(upgrade_id_t /* upgrade id */);
|
||||
void log_license_upgrade_attempt(upgrade_id_t /* upgrade id */, bool /* succeeded */, const std::string& /* server unique id */, const std::string& /* ip address */);
|
||||
|
||||
bool register_license(const std::string& /* key */, const std::shared_ptr<LicenseInfo>& /* info */, const std::string& /* issuer */);
|
||||
bool delete_license(const std::string& /* key */, bool /* full */ = false);
|
||||
|
||||
bool logRequest(const std::string& /* key */, const std::string& /* unique_id */, const std::string& /* ip */, const std::string& /* version */, int /* result */);
|
||||
bool logStatistic(const std::string& /* key */, const std::string& /* unique_id */, const std::string& /* ip */, const ts::proto::license::PropertyUpdateRequest&);
|
||||
//std::deque<std::unique_ptr<ExtendedUserStatistics>> list_statistics_user(const std::string& key, const std::chrono::system_clock::time_point& begin, const std::chrono::system_clock::time_point& end);
|
||||
std::shared_ptr<UserHistory> list_statistics_user(const std::chrono::system_clock::time_point& begin, const std::chrono::system_clock::time_point& end, const std::chrono::milliseconds& /* interval */);
|
||||
std::deque<std::unique_ptr<GlobalVersionsStatistic>> list_statistics_version(const std::chrono::system_clock::time_point& begin, const std::chrono::system_clock::time_point& end, const std::chrono::milliseconds& /* interval */);
|
||||
|
||||
inline sql::SqlManager* sql() { return this->database; }
|
||||
private:
|
||||
std::shared_ptr<KeyIdCache> id_cache;
|
||||
sql::SqlManager* database;
|
||||
};
|
||||
}
|
||||
@@ -1,26 +1,30 @@
|
||||
#include "log/LogUtils.h"
|
||||
#include "LicenseManager.h"
|
||||
#include "DatabaseHandler.h"
|
||||
|
||||
using namespace license;
|
||||
using namespace license::server;
|
||||
using namespace license::server::database;
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
using KeyIdCache = LicenseManager::KeyIdCache;
|
||||
|
||||
KeyIdCache::KeyIdCache(license::server::LicenseManager *handle) : handle(handle) {}
|
||||
KeyIdCache::KeyIdCache(DatabaseHandler *handle) : handle(handle) {}
|
||||
|
||||
std::string KeyIdCache::getKey(size_t keyId) {
|
||||
void KeyIdCache::clear_cache() {
|
||||
std::lock_guard elock{this->entry_lock};
|
||||
this->entries.clear();
|
||||
}
|
||||
|
||||
std::string KeyIdCache::get_key_from_id(size_t keyId) {
|
||||
{
|
||||
threads::MutexLock lock(this->entry_lock);
|
||||
std::lock_guard elock{this->entry_lock};
|
||||
|
||||
for(const auto& entry : this->entries)
|
||||
if(entry->keyId == keyId) return entry->key;
|
||||
}
|
||||
|
||||
sql::command(this->handle->database, "SELECT `key`, `keyId` FROM `license` WHERE `keyId` = :key", variable{":key", keyId})
|
||||
sql::command(this->handle->sql(), "SELECT `key`, `keyId` FROM `license` WHERE `keyId` = :key", variable{":key", keyId})
|
||||
.query(&KeyIdCache::insert_entry, this);
|
||||
{
|
||||
threads::MutexLock lock(this->entry_lock);
|
||||
std::lock_guard elock{this->entry_lock};
|
||||
|
||||
for(const auto& entry : this->entries)
|
||||
if(entry->keyId == keyId) return entry->key;
|
||||
@@ -28,20 +32,20 @@ std::string KeyIdCache::getKey(size_t keyId) {
|
||||
}
|
||||
}
|
||||
|
||||
size_t KeyIdCache::getKeyId(const std::string &key) {
|
||||
size_t KeyIdCache::get_key_id_from_key(const std::string &key) {
|
||||
{
|
||||
threads::MutexLock lock(this->entry_lock);
|
||||
std::lock_guard elock{this->entry_lock};
|
||||
|
||||
for(const auto& entry : this->entries)
|
||||
if(entry->key == key) return entry->keyId;
|
||||
}
|
||||
|
||||
auto result = sql::command(this->handle->database, "SELECT `key`, `keyId` FROM `license` WHERE `key` = :key", variable{":key", key})
|
||||
auto result = sql::command(this->handle->sql(), "SELECT `key`, `keyId` FROM `license` WHERE `key` = :key", variable{":key", key})
|
||||
.query(&KeyIdCache::insert_entry, this);
|
||||
if(!result)
|
||||
logError(LOG_GENERAL, "Failed to query key id for license. Query resulted in {}", result.fmtStr());
|
||||
{
|
||||
threads::MutexLock lock(this->entry_lock);
|
||||
std::lock_guard elock{this->entry_lock};
|
||||
|
||||
for(const auto& entry : this->entries)
|
||||
if(entry->key == key)
|
||||
@@ -52,16 +56,24 @@ size_t KeyIdCache::getKeyId(const std::string &key) {
|
||||
}
|
||||
|
||||
int KeyIdCache::insert_entry(int length, std::string *value, std::string *names) {
|
||||
string key;
|
||||
size_t keyId = 0;
|
||||
for(int index = 0; index < length; index++)
|
||||
string key{"unknown"};
|
||||
size_t keyId{0};
|
||||
|
||||
for(int index = 0; index < length; index++) {
|
||||
if(names[index] == "key")
|
||||
key = value[index];
|
||||
else if(names[index] == "keyId")
|
||||
keyId = stoll(value[index]);
|
||||
keyId = std::strtoll(value[index].c_str(), nullptr, 10);
|
||||
}
|
||||
if(!keyId) {
|
||||
logWarning(LOG_GENERAL, "Failed to parse key id for key {}", key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
{
|
||||
threads::MutexLock lock(this->entry_lock);
|
||||
this->entries.push_back(new KeyIdCache::CacheEntry{key, keyId, system_clock::now()});
|
||||
auto entry = new KeyIdCache::CacheEntry{key, keyId, system_clock::now()};
|
||||
std::lock_guard elock{this->entry_lock};
|
||||
this->entries.emplace_back(entry);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <sql/SqlQuery.h>
|
||||
#include <shared/License.h>
|
||||
#include <LicenseRequest.pb.h>
|
||||
|
||||
namespace license {
|
||||
namespace server {
|
||||
class LicenseManager {
|
||||
public:
|
||||
class KeyIdCache {
|
||||
struct CacheEntry {
|
||||
std::string key;
|
||||
size_t keyId;
|
||||
std::chrono::system_clock::time_point age;
|
||||
};
|
||||
|
||||
public:
|
||||
KeyIdCache(LicenseManager*);
|
||||
|
||||
void cache_keys(const std::deque<std::string>& /* keys */);
|
||||
std::string getKey(size_t keyId);
|
||||
size_t getKeyId(const std::string&);
|
||||
private:
|
||||
int insert_entry(int, std::string*, std::string*);
|
||||
|
||||
LicenseManager* handle;
|
||||
threads::Mutex entry_lock;
|
||||
threads::Mutex entry_update_lock;
|
||||
std::deque<CacheEntry*> entries;
|
||||
};
|
||||
struct UserStatistics {
|
||||
std::chrono::system_clock::time_point timestamp;
|
||||
uint64_t clients_online;
|
||||
uint64_t web_clients_online;
|
||||
uint64_t bots_online;
|
||||
uint64_t queries_online;
|
||||
uint64_t servers_online;
|
||||
};
|
||||
|
||||
struct ExtendedUserStatistics : public UserStatistics{
|
||||
std::string ip_address;
|
||||
};
|
||||
|
||||
struct GlobalUserStatistics : public UserStatistics {
|
||||
uint64_t instance_online;
|
||||
};
|
||||
|
||||
struct GlobalVersionsStatistic {
|
||||
std::chrono::system_clock::time_point timestamp;
|
||||
std::map<std::string, uint32_t> versions;
|
||||
};
|
||||
public:
|
||||
LicenseManager(sql::SqlManager* database);
|
||||
~LicenseManager();
|
||||
|
||||
bool setup(std::string&);
|
||||
|
||||
bool validLicenseKey(const std::string& /* key */);
|
||||
std::shared_ptr<LicenseInfo> licenseInfo(const std::string&);
|
||||
|
||||
std::map<std::string, std::shared_ptr<LicenseInfo>> listLicenses(int offset = 0, int limit = -1);
|
||||
|
||||
bool registerLicense(const std::string& /* key */, const std::shared_ptr<LicenseInfo>& /* info */, const std::string& /* issuer */);
|
||||
bool updateLicenseInfo(const std::string&, const std::shared_ptr<LicenseInfo>&);
|
||||
bool deleteLicense(const std::string& /* key */, bool /* full */ = false);
|
||||
|
||||
bool logRequest(const std::string& /* key */, const std::string& /* unique_id */, const std::string& /* ip */, const std::string& /* version */, int /* result */);
|
||||
bool logStatistic(const std::string& /* key */, const std::string& /* unique_id */, const std::string& /* ip */, const ts::proto::license::PropertyUpdateRequest&);
|
||||
//std::deque<std::unique_ptr<ExtendedUserStatistics>> list_statistics_user(const std::string& key, const std::chrono::system_clock::time_point& begin, const std::chrono::system_clock::time_point& end);
|
||||
std::deque<std::unique_ptr<GlobalUserStatistics>> list_statistics_user(const std::chrono::system_clock::time_point& begin, const std::chrono::system_clock::time_point& end, const std::chrono::milliseconds& /* interval */);
|
||||
std::deque<std::unique_ptr<GlobalVersionsStatistic>> list_statistics_version(const std::chrono::system_clock::time_point& begin, const std::chrono::system_clock::time_point& end, const std::chrono::milliseconds& /* interval */);
|
||||
|
||||
inline sql::SqlManager* sql() { return this->database; }
|
||||
private:
|
||||
std::shared_ptr<KeyIdCache> id_cache;
|
||||
sql::SqlManager* database;
|
||||
};
|
||||
}
|
||||
}
|
||||
+133
-104
@@ -1,16 +1,17 @@
|
||||
#include <unistd.h>
|
||||
#include <csignal>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <arpa/inet.h>
|
||||
#include <log/LogUtils.h>
|
||||
#include <misc/endianness.h>
|
||||
#include <LicenseRequest.pb.h>
|
||||
#include <shared/License.h>
|
||||
#include <shared/crypt.h>
|
||||
#include <misc/base64.h>
|
||||
#include <shared/include/license/license.h>
|
||||
#include <shared/src/crypt.h>
|
||||
#include <ThreadPool/ThreadHelper.h>
|
||||
#include "LicenseServer.h"
|
||||
#include "crypt.h"
|
||||
#include "UserManager.h"
|
||||
|
||||
using namespace std;
|
||||
@@ -19,98 +20,100 @@ using namespace license;
|
||||
using namespace ts;
|
||||
|
||||
LicenseServer::LicenseServer(const sockaddr_in& addr,
|
||||
const std::shared_ptr<server::LicenseManager>& manager,
|
||||
const shared_ptr<license::stats::StatisticManager> &stats,
|
||||
const shared_ptr<license::web::WebStatistics> &wstats,
|
||||
const std::shared_ptr<UserManager>& user_manager) : manager(manager), statistics(stats), web_statistics(wstats), user_manager(user_manager) {
|
||||
this->localAddr = new sockaddr_in{};
|
||||
memcpy(this->localAddr, &addr, sizeof(addr));
|
||||
std::shared_ptr<server::database::DatabaseHandler> manager,
|
||||
shared_ptr<license::stats::StatisticManager> stats,
|
||||
shared_ptr<license::web::WebStatistics> wstats,
|
||||
std::shared_ptr<UserManager> user_manager) : manager{std::move(manager)}, statistics{std::move(stats)}, web_statistics{std::move(wstats)}, user_manager{std::move(user_manager)} {
|
||||
memcpy(&this->localAddr, &addr, sizeof(addr));
|
||||
}
|
||||
|
||||
LicenseServer::~LicenseServer() {
|
||||
this->stopServer();
|
||||
delete this->localAddr;
|
||||
this->stop();
|
||||
}
|
||||
|
||||
#define SFAIL(message) \
|
||||
do { \
|
||||
logError(lstream << (message) << " Message: " << errno << "/" << strerror(errno)); \
|
||||
this->stopServer(); \
|
||||
logError(LOG_GENERAL, " Message: {} ({}/{})", message, errno, strerror(errno)); \
|
||||
this->stop(); \
|
||||
return false; \
|
||||
} while(0)
|
||||
|
||||
static int enabled = 1;
|
||||
static int disabled = 0;
|
||||
bool LicenseServer::startServer() {
|
||||
bool LicenseServer::start() {
|
||||
{
|
||||
lock_guard lock(this->lock);
|
||||
lock_guard lock(this->client_lock);
|
||||
if(this->running) return false;
|
||||
this->running = true;
|
||||
}
|
||||
|
||||
fileDescriptor = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fileDescriptor < 0) SFAIL("Could not create new socket");
|
||||
server_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (server_socket < 0) SFAIL("Could not create new socket");
|
||||
|
||||
if(setsockopt(this->fileDescriptor, SOL_SOCKET, SO_REUSEADDR, &enabled, sizeof(enabled)) < 0) SFAIL("could not set reuse address");
|
||||
if(setsockopt(this->fileDescriptor, IPPROTO_TCP, TCP_CORK, &disabled, sizeof(disabled)) < 0) SFAIL("could not set no push");
|
||||
if(bind(this->fileDescriptor, (struct sockaddr *) this->localAddr, sizeof(sockaddr_in)) < 0) SFAIL("Could not bind socket on " + string(inet_ntoa(this->localAddr->sin_addr)));
|
||||
if(setsockopt(this->server_socket, SOL_SOCKET, SO_REUSEADDR, &enabled, sizeof(enabled)) < 0) SFAIL("could not set reuse address");
|
||||
if(setsockopt(this->server_socket, IPPROTO_TCP, TCP_CORK, &disabled, sizeof(disabled)) < 0) SFAIL("could not set no push");
|
||||
if(bind(this->server_socket, (struct sockaddr *) &this->localAddr, sizeof(sockaddr_in)) < 0) SFAIL("Could not bind socket on " + string(inet_ntoa(this->localAddr.sin_addr)));
|
||||
|
||||
if(listen(this->fileDescriptor, 32) < 0) SFAIL("Could not listen on socket");
|
||||
if(listen(this->server_socket, 32) < 0) SFAIL("Could not listen on socket");
|
||||
|
||||
this->evBase = event_base_new();
|
||||
this->acceptEvent = event_new(this->evBase, this->fileDescriptor, EV_READ | EV_PERSIST, LicenseServer::handleEventAccept, this);
|
||||
this->client_cleanup = evtimer_new(this->evBase, LicenseServer::handleEventCleanup, this);
|
||||
this->event_accept = event_new(this->evBase, this->server_socket, EV_READ | EV_PERSIST, LicenseServer::handleEventAccept, this);
|
||||
this->event_cleanup = evtimer_new(this->evBase, LicenseServer::handleEventCleanup, this);
|
||||
|
||||
event_add(this->acceptEvent, nullptr);
|
||||
event_add(this->event_accept, nullptr);
|
||||
{
|
||||
timeval now{1, 0};
|
||||
evtimer_add(this->client_cleanup, &now);
|
||||
evtimer_add(this->event_cleanup, &now);
|
||||
}
|
||||
evBaseDispatch = new threads::Thread(THREAD_SAVE_OPERATIONS, [&](){
|
||||
|
||||
event_base_dispatch = std::thread([&]{
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
event_base_dispatch(this->evBase);
|
||||
::event_base_dispatch(this->evBase);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
void LicenseServer::stopServer() {
|
||||
void LicenseServer::stop() {
|
||||
{
|
||||
lock_guard lock(this->lock);
|
||||
lock_guard lock(this->client_lock);
|
||||
if(!this->running) return;
|
||||
this->running = false;
|
||||
}
|
||||
|
||||
/* first unregister the accept event so we don't get new clients */
|
||||
if(this->event_accept) {
|
||||
event_del(this->event_accept);
|
||||
event_free(this->event_accept);
|
||||
}
|
||||
this->event_accept = nullptr;
|
||||
|
||||
/* disconnect all clients */
|
||||
for(const auto& client : this->getClients())
|
||||
this->closeConnection(client);
|
||||
|
||||
if(this->acceptEvent) {
|
||||
event_del(this->acceptEvent);
|
||||
event_free(this->acceptEvent);
|
||||
}
|
||||
this->acceptEvent = nullptr;
|
||||
|
||||
if(this->client_cleanup) {
|
||||
event_del_block(this->client_cleanup);
|
||||
event_free(this->client_cleanup);
|
||||
this->client_cleanup = nullptr;
|
||||
}
|
||||
|
||||
if(this->evBase)
|
||||
event_base_loopbreak(this->evBase);
|
||||
|
||||
if(this->evBaseDispatch)
|
||||
this->evBaseDispatch->join();
|
||||
delete this->evBaseDispatch;
|
||||
this->evBaseDispatch = nullptr;
|
||||
if(this->evBase) {
|
||||
event_base_loopbreak(this->evBase); /* again for some reason */
|
||||
if(!threads::timed_join(this->event_base_dispatch, std::chrono::seconds{2})) {
|
||||
this->event_base_dispatch.detach();
|
||||
logCritical(LOG_GENERAL, "Failed to join event base dispatch thread. This will cause memory leaks.");
|
||||
}
|
||||
|
||||
/* Needs to be cleaned up after event loop has been destroyed. Because its used within the event loop. */
|
||||
if(this->event_cleanup) {
|
||||
event_del_block(this->event_cleanup);
|
||||
event_free(this->event_cleanup);
|
||||
this->event_cleanup = nullptr;
|
||||
}
|
||||
|
||||
if(this->evBase)
|
||||
event_base_free(this->evBase);
|
||||
}
|
||||
this->evBase = nullptr;
|
||||
|
||||
if(this->fileDescriptor != 0) {
|
||||
shutdown(this->fileDescriptor, SHUT_RDWR);
|
||||
close(this->fileDescriptor);
|
||||
this->fileDescriptor = 0;
|
||||
if(this->server_socket != 0) {
|
||||
shutdown(this->server_socket, SHUT_RDWR);
|
||||
close(this->server_socket);
|
||||
this->server_socket = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,8 +123,8 @@ void LicenseServer::handleEventCleanup(int, short, void* ptrServer) {
|
||||
server->cleanup_clients();
|
||||
timeval next{1, 0};
|
||||
|
||||
if(server->client_cleanup)
|
||||
event_add(server->client_cleanup, &next);
|
||||
if(server->event_cleanup)
|
||||
event_add(server->event_cleanup, &next);
|
||||
}
|
||||
|
||||
//Basic IO
|
||||
@@ -129,20 +132,27 @@ void LicenseServer::handleEventWrite(int fd, short, void* ptrServer) {
|
||||
auto server = static_cast<LicenseServer *>(ptrServer);
|
||||
auto client = server->findClient(fd);
|
||||
if(!client) return;
|
||||
buffer::RawBuffer* buffer = nullptr;
|
||||
{
|
||||
threads::MutexLock lock(client->network.lock);
|
||||
buffer = TAILQ_FIRST(&client->network.writeQueue);
|
||||
if(!buffer) return;
|
||||
|
||||
auto writtenBytes = send(fd, &buffer->buffer[buffer->index], buffer->length - buffer->index, 0);
|
||||
buffer->index += writtenBytes;
|
||||
buffer::RawBuffer* write_buffer{nullptr};
|
||||
while(true) { //TODO: May add some kind of timeout?
|
||||
std::lock_guard lock(client->network.write_queue_lock);
|
||||
write_buffer = TAILQ_FIRST(&client->network.write_queue);
|
||||
if(!write_buffer) return;
|
||||
|
||||
if(buffer->index >= buffer->length) {
|
||||
TAILQ_REMOVE(&client->network.writeQueue, buffer, tail);
|
||||
delete buffer;
|
||||
auto writtenBytes = send(fd, &write_buffer->buffer[write_buffer->index], write_buffer->length - write_buffer->index, 0);
|
||||
if(writtenBytes <= 0) {
|
||||
if(writtenBytes == -1 && errno == EAGAIN)
|
||||
return;
|
||||
logError(LOG_LICENSE_CONTROLL, "Invalid write. Disconnecting remote client. Message: {}/{}", errno, strerror(errno));
|
||||
} else {
|
||||
write_buffer->index += writtenBytes;
|
||||
}
|
||||
if(!TAILQ_EMPTY(&client->network.writeQueue))
|
||||
|
||||
if(write_buffer->index >= write_buffer->length) {
|
||||
TAILQ_REMOVE(&client->network.write_queue, write_buffer, tail);
|
||||
delete write_buffer;
|
||||
}
|
||||
if(!TAILQ_EMPTY(&client->network.write_queue))
|
||||
event_add(client->network.writeEvent, nullptr);
|
||||
}
|
||||
}
|
||||
@@ -158,23 +168,31 @@ void ConnectedClient::sendPacket(const protocol::packet& packet) {
|
||||
xorBuffer(&buffer->buffer[sizeof(packet.header)], packet.data.length(), this->protocol.cryptKey.data(), this->protocol.cryptKey.length());
|
||||
|
||||
{
|
||||
threads::MutexLock lock(this->network.lock);
|
||||
TAILQ_INSERT_TAIL(&this->network.writeQueue, buffer, tail);
|
||||
lock_guard queue_lock{this->network.write_queue_lock};
|
||||
TAILQ_INSERT_TAIL(&this->network.write_queue, buffer, tail);
|
||||
}
|
||||
event_add(this->network.writeEvent, nullptr);
|
||||
{
|
||||
lock_guard state_lock{this->protocol.state_lock};
|
||||
if(this->protocol.state == protocol::UNCONNECTED) goto error_cleanup;
|
||||
|
||||
event_add(this->network.writeEvent, nullptr);
|
||||
return;
|
||||
}
|
||||
error_cleanup:
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
void ConnectedClient::init() {
|
||||
protocol.last_read = std::chrono::system_clock::now();
|
||||
TAILQ_INIT(&network.writeQueue);
|
||||
TAILQ_INIT(&network.write_queue);
|
||||
}
|
||||
|
||||
void ConnectedClient::uninit() {
|
||||
{
|
||||
threads::MutexLock lock(this->network.lock);
|
||||
lock_guard queue_lock{this->network.write_queue_lock};
|
||||
ts::buffer::RawBuffer* buffer;
|
||||
while ((buffer = TAILQ_FIRST(&this->network.writeQueue))) {
|
||||
TAILQ_REMOVE(&this->network.writeQueue, buffer, tail);
|
||||
while ((buffer = TAILQ_FIRST(&this->network.write_queue))) {
|
||||
TAILQ_REMOVE(&this->network.write_queue, buffer, tail);
|
||||
delete buffer;
|
||||
}
|
||||
}
|
||||
@@ -202,12 +220,12 @@ void LicenseServer::handleEventRead(int fd, short, void* ptrServer) {
|
||||
|
||||
if(read < 0){
|
||||
if(errno == EWOULDBLOCK) return;
|
||||
logError(LOG_LICENSE_CONTROLL, "Invalid read. Disconnecting remote manager. Message: {}/{}", errno, strerror(errno));
|
||||
logError(LOG_LICENSE_CONTROLL, "Invalid read. Disconnecting remote client. Message: {}/{}", errno, strerror(errno));
|
||||
event_del_noblock(client->network.readEvent);
|
||||
server->closeConnection(client);
|
||||
return;
|
||||
} else if(read == 0) {
|
||||
logError(LOG_LICENSE_CONTROLL, "Invalid read. Disconnecting remote client");
|
||||
logMessage(LOG_LICENSE_CONTROLL, "[CLIENT][" + client->address() + "] Received EOF for client. Removing client.");
|
||||
event_del_noblock(client->network.readEvent);
|
||||
server->closeConnection(client);
|
||||
return;
|
||||
@@ -230,21 +248,21 @@ void LicenseServer::handleEventAccept(int fd, short, void* ptrServer) {
|
||||
if(setsockopt(client->network.fileDescriptor, IPPROTO_TCP, TCP_CORK, &disabled, sizeof(disabled)) < 0);// CERR("could not set no push");
|
||||
|
||||
if (client->network.fileDescriptor < 0) {
|
||||
logCritical("Could not accept new client! (" + to_string(client->network.fileDescriptor) + "|" + to_string(errno) + "|" + strerror(errno) + ")");
|
||||
logCritical(LOG_GENERAL, "Could not accept new client! (" + to_string(client->network.fileDescriptor) + "|" + to_string(errno) + "|" + strerror(errno) + ")");
|
||||
return;
|
||||
}
|
||||
|
||||
client->protocol.state = protocol::HANDSCAKE;
|
||||
client->protocol.state = protocol::HANDSCHAKE;
|
||||
{
|
||||
lock_guard lock(server->lock);
|
||||
server->currentClients.push_back(client);
|
||||
lock_guard lock(server->client_lock);
|
||||
server->clients.push_back(client);
|
||||
}
|
||||
|
||||
client->network.readEvent = event_new(server->evBase, client->network.fileDescriptor, EV_READ | EV_PERSIST, LicenseServer::handleEventRead, server);
|
||||
client->network.writeEvent = event_new(server->evBase, client->network.fileDescriptor, EV_WRITE, LicenseServer::handleEventWrite, server);
|
||||
event_add(client->network.readEvent, nullptr);
|
||||
|
||||
logMessage(lstream << "Got new client from " << inet_ntoa(client->network.remoteAddr.sin_addr));
|
||||
logMessage(LOG_GENERAL, "Accepted new client from {}", inet_ntoa(client->network.remoteAddr.sin_addr));
|
||||
}
|
||||
|
||||
void LicenseServer::disconnectClient(const std::shared_ptr<ConnectedClient>& client, const std::string &reason) {
|
||||
@@ -252,15 +270,15 @@ void LicenseServer::disconnectClient(const std::shared_ptr<ConnectedClient>& cli
|
||||
}
|
||||
|
||||
void LicenseServer::closeConnection(const std::shared_ptr<ConnectedClient> &client, bool blocking) {
|
||||
if(this->evBaseDispatch && threads::self::id() == *this->evBaseDispatch) {
|
||||
if(this_thread::get_id() == this->event_base_dispatch.get_id()) {
|
||||
std::thread(std::bind(&LicenseServer::closeConnection, this, client, true)).detach();
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
unique_lock lock(client->network.lock);
|
||||
if(!TAILQ_EMPTY(&client->network.writeQueue)) {
|
||||
unique_lock lock(client->network.write_queue_lock);
|
||||
if(!TAILQ_EMPTY(&client->network.write_queue)) {
|
||||
lock.unlock();
|
||||
|
||||
if(!blocking) {
|
||||
@@ -271,7 +289,7 @@ void LicenseServer::closeConnection(const std::shared_ptr<ConnectedClient> &clie
|
||||
while(system_clock::now() - start < seconds(5)){
|
||||
{
|
||||
lock.lock();
|
||||
if(TAILQ_EMPTY(&client->network.writeQueue)) break;
|
||||
if(TAILQ_EMPTY(&client->network.write_queue)) break;
|
||||
lock.unlock();
|
||||
}
|
||||
threads::self::sleep_for(milliseconds(5));
|
||||
@@ -283,49 +301,57 @@ void LicenseServer::closeConnection(const std::shared_ptr<ConnectedClient> &clie
|
||||
|
||||
void LicenseServer::unregisterClient(const std::shared_ptr<ConnectedClient> &client) {
|
||||
{
|
||||
lock_guard lock(this->lock);
|
||||
lock_guard lock(this->client_lock);
|
||||
|
||||
auto it = find(this->currentClients.begin(), this->currentClients.end(), client);
|
||||
if(it != this->currentClients.end())
|
||||
this->currentClients.erase(it);
|
||||
auto it = find(this->clients.begin(), this->clients.end(), client);
|
||||
if(it != this->clients.end())
|
||||
this->clients.erase(it);
|
||||
}
|
||||
|
||||
client->protocol.state = protocol::UNCONNECTED;
|
||||
{
|
||||
std::lock_guard state_lock{client->protocol.state_lock};
|
||||
client->protocol.state = protocol::UNCONNECTED;
|
||||
}
|
||||
client->uninit();
|
||||
}
|
||||
|
||||
void LicenseServer::cleanup_clients() {
|
||||
unique_lock lock(this->lock);
|
||||
auto clients = this->currentClients;
|
||||
unique_lock lock(this->client_lock);
|
||||
auto clients = this->clients;
|
||||
lock.unlock();
|
||||
|
||||
size_t cleanup_count{0};
|
||||
for(const auto& client : clients) {
|
||||
if(client->protocol.last_read + minutes(1) < system_clock::now()) {
|
||||
cleanup_count++;
|
||||
if(client->protocol.state != protocol::DISCONNECTING && client->protocol.state != protocol::UNCONNECTED) {
|
||||
this->disconnectClient(client, "timeout");
|
||||
this->closeConnection(client);
|
||||
client->protocol.state = protocol::DISCONNECTING;
|
||||
|
||||
std::lock_guard state_lock{client->protocol.state_lock};
|
||||
client->protocol.state = protocol::UNCONNECTED;
|
||||
} else {
|
||||
auto it = find(this->currentClients.begin(), this->currentClients.end(), client);
|
||||
if(it != this->currentClients.end())
|
||||
this->currentClients.erase(it);
|
||||
auto it = find(this->clients.begin(), this->clients.end(), client);
|
||||
if(it != this->clients.end())
|
||||
this->clients.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
debugMessage("Client's cleaned up");
|
||||
if(cleanup_count)
|
||||
debugMessage(LOG_GENERAL, "{} clients have been cleaned up due to a read timeout.", cleanup_count);
|
||||
}
|
||||
|
||||
std::shared_ptr<ConnectedClient> LicenseServer::findClient(int fileDescriptor) {
|
||||
lock_guard lock(this->lock);
|
||||
for(const auto& cl : this->currentClients)
|
||||
if(cl->network.fileDescriptor == fileDescriptor)
|
||||
std::shared_ptr<ConnectedClient> LicenseServer::findClient(int fd) {
|
||||
lock_guard lock(this->client_lock);
|
||||
for(const auto& cl : this->clients)
|
||||
if(cl->network.fileDescriptor == fd)
|
||||
return cl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#define ERR(message) \
|
||||
do { \
|
||||
logError(lstream << message); \
|
||||
logError(LOG_GENERAL, message); \
|
||||
this->closeConnection(client); \
|
||||
return; \
|
||||
} while(0)
|
||||
@@ -337,10 +363,11 @@ void LicenseServer::handleMessage(shared_ptr<ConnectedClient>& client, const std
|
||||
memcpy(&packet.header, message.data(), sizeof(protocol::packet::header));
|
||||
packet.data = message.substr(sizeof(protocol::packet::header), packet.header.length);
|
||||
|
||||
if(!client->protocol.cryptKey.empty())
|
||||
if(!client->protocol.cryptKey.empty()) {
|
||||
xorBuffer((char*) packet.data.data(), packet.data.length(), client->protocol.cryptKey.data(), client->protocol.cryptKey.length());
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
bool success{false};
|
||||
string error;
|
||||
try {
|
||||
if(packet.header.packetId == protocol::PACKET_CLIENT_HANDSHAKE) {
|
||||
@@ -351,6 +378,8 @@ void LicenseServer::handleMessage(shared_ptr<ConnectedClient>& client, const std
|
||||
success = this->handleServerValidation(client, packet, error);
|
||||
} else if(packet.header.packetId == protocol::PACKET_CLIENT_PROPERTY_ADJUSTMENT) {
|
||||
success = this->handlePacketPropertyUpdate(client, packet, error);
|
||||
} else if(packet.header.packetId == protocol::PACKET_CLIENT_LICENSE_UPGRADE) {
|
||||
success = this->handlePacketLicenseUpgrade(client, packet, error);
|
||||
} else if(packet.header.packetId == protocol::PACKET_CLIENT_AUTH_REQUEST) {
|
||||
success = this->handlePacketAuth(client, packet, error);
|
||||
} else if(packet.header.packetId == protocol::PACKET_CLIENT_LICENSE_CREATE_REQUEST) {
|
||||
@@ -368,7 +397,7 @@ void LicenseServer::handleMessage(shared_ptr<ConnectedClient>& client, const std
|
||||
}
|
||||
|
||||
if(!success) {
|
||||
logError("[CLIENT][" + client->address() + "] Failed to handle packet. message: " + error);
|
||||
logError(LOG_GENERAL, "[CLIENT][" + client->address() + "] Failed to handle packet. message: " + error);
|
||||
this->disconnectClient(client, error);
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,9 @@
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <ThreadPool/Thread.h>
|
||||
#include <shared/License.h>
|
||||
#include <shared/include/license/license.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "LicenseManager.h"
|
||||
#include "DatabaseHandler.h"
|
||||
|
||||
namespace license {
|
||||
namespace web {
|
||||
@@ -31,24 +31,31 @@ namespace license {
|
||||
struct {
|
||||
sockaddr_in remoteAddr;
|
||||
int fileDescriptor = 0;
|
||||
event* readEvent = nullptr;
|
||||
event* readEvent = nullptr; /* protected via state_lock (check state and the use these variables) */
|
||||
event* writeEvent = nullptr;
|
||||
|
||||
threads::Mutex lock;
|
||||
TAILQ_HEAD(, ts::buffer::RawBuffer) writeQueue;
|
||||
std::mutex write_queue_lock{};
|
||||
TAILQ_HEAD(, ts::buffer::RawBuffer) write_queue;
|
||||
} network;
|
||||
|
||||
struct {
|
||||
std::mutex state_lock{};
|
||||
protocol::RequestState state = protocol::UNCONNECTED;
|
||||
|
||||
std::chrono::system_clock::time_point last_read;
|
||||
std::string cryptKey = "";
|
||||
|
||||
int version{2}; /* current version is 3 */
|
||||
} protocol;
|
||||
|
||||
ClientType type = ClientType::SERVER;
|
||||
std::string username;
|
||||
std::string key;
|
||||
uint64_t key_pending_upgrade{0};
|
||||
std::string unique_identifier;
|
||||
|
||||
bool invalid_license = false;
|
||||
|
||||
void init();
|
||||
void uninit();
|
||||
void sendPacket(const protocol::packet&);
|
||||
@@ -56,44 +63,52 @@ namespace license {
|
||||
inline std::string address() { return inet_ntoa(network.remoteAddr.sin_addr); }
|
||||
};
|
||||
|
||||
struct WebCertificate {
|
||||
std::string revision;
|
||||
std::string key;
|
||||
std::string certificate;
|
||||
};
|
||||
|
||||
class LicenseServer {
|
||||
public:
|
||||
explicit LicenseServer(const sockaddr_in&, const std::shared_ptr<server::LicenseManager>&, const std::shared_ptr<stats::StatisticManager>& /* stats */, const std::shared_ptr<web::WebStatistics>& /* web stats */, const std::shared_ptr<UserManager>& /* user manager */);
|
||||
explicit LicenseServer(const sockaddr_in&, std::shared_ptr<server::database::DatabaseHandler> , std::shared_ptr<stats::StatisticManager> /* stats */, std::shared_ptr<web::WebStatistics> /* web stats */, std::shared_ptr<UserManager> /* user manager */);
|
||||
~LicenseServer();
|
||||
|
||||
bool startServer();
|
||||
bool start();
|
||||
bool isRunning(){ return this->running; }
|
||||
void stopServer();
|
||||
void stop();
|
||||
|
||||
std::shared_ptr<ConnectedClient> findClient(int fileDescriptor);
|
||||
void disconnectClient(const std::shared_ptr<ConnectedClient>&, const std::string& reason);
|
||||
void closeConnection(const std::shared_ptr<ConnectedClient>&, bool blocking = false);
|
||||
|
||||
std::deque<std::shared_ptr<ConnectedClient>> getClients() {
|
||||
std::lock_guard lock(this->lock);
|
||||
return currentClients;
|
||||
std::lock_guard lock(this->client_lock);
|
||||
return clients;
|
||||
}
|
||||
|
||||
std::shared_ptr<WebCertificate> web_certificate{nullptr};
|
||||
private:
|
||||
void unregisterClient(const std::shared_ptr<ConnectedClient>&);
|
||||
void cleanup_clients();
|
||||
|
||||
std::shared_ptr<web::WebStatistics> web_statistics;
|
||||
std::shared_ptr<stats::StatisticManager> statistics;
|
||||
std::shared_ptr<server::LicenseManager> manager;
|
||||
std::shared_ptr<server::database::DatabaseHandler> manager;
|
||||
std::shared_ptr<UserManager> user_manager;
|
||||
|
||||
bool running = false;
|
||||
std::mutex client_lock;
|
||||
std::deque<std::shared_ptr<ConnectedClient>> clients;
|
||||
|
||||
std::mutex lock;
|
||||
std::deque<std::shared_ptr<ConnectedClient>> currentClients;
|
||||
bool running = false; /* also secured by client_lock */
|
||||
|
||||
sockaddr_in* localAddr = nullptr;
|
||||
int fileDescriptor = 0;
|
||||
sockaddr_in localAddr{};
|
||||
int server_socket = 0;
|
||||
event_base* evBase = nullptr;
|
||||
event* acceptEvent = nullptr;
|
||||
event* client_cleanup = nullptr;
|
||||
event* event_accept = nullptr;
|
||||
event* event_cleanup = nullptr;
|
||||
|
||||
threads::Thread* evBaseDispatch = nullptr;
|
||||
std::thread event_base_dispatch{};
|
||||
|
||||
static void handleEventCleanup(int, short, void*);
|
||||
static void handleEventAccept(int, short, void*);
|
||||
@@ -105,6 +120,7 @@ namespace license {
|
||||
bool handleDisconnect(std::shared_ptr<ConnectedClient>&, protocol::packet&, std::string& error);
|
||||
bool handleHandshake(std::shared_ptr<ConnectedClient>&, protocol::packet&, std::string& error);
|
||||
bool handleServerValidation(std::shared_ptr<ConnectedClient> &, protocol::packet &, std::string &error);
|
||||
bool handlePacketLicenseUpgrade(std::shared_ptr<ConnectedClient> &client, protocol::packet &packet, std::string &error);
|
||||
bool handlePacketPropertyUpdate(std::shared_ptr<ConnectedClient> &, protocol::packet &, std::string &error);
|
||||
|
||||
bool handlePacketAuth(std::shared_ptr<ConnectedClient> &, protocol::packet &, std::string &error);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#include <misc/endianness.h>
|
||||
#include <misc/base64.h>
|
||||
#include <misc/hex.h>
|
||||
#include <log/LogUtils.h>
|
||||
#include <LicenseManager.pb.h>
|
||||
#include <shared/License.h>
|
||||
#include <shared/include/license/license.h>
|
||||
#include "LicenseRequest.pb.h"
|
||||
#include "shared/License.h"
|
||||
#include "shared/include/license/license.h"
|
||||
#include "LicenseServer.h"
|
||||
#include "WebAPI.h"
|
||||
#include "StatisticManager.h"
|
||||
@@ -21,6 +22,8 @@ inline void generate(char* buffer, size_t length){
|
||||
buffer[index] = rand();
|
||||
}
|
||||
|
||||
#define _str(x) #x
|
||||
|
||||
#define TEST_PROTOCOL_STATE(expected) \
|
||||
if(client->protocol.state != protocol::expected) { \
|
||||
error = "invalid protocol state"; \
|
||||
@@ -36,21 +39,23 @@ if(packet.data.length() < (expected)) { \
|
||||
#define PARSE_PROTO(class, var) \
|
||||
ts::proto::license::class var; \
|
||||
if(!var.ParseFromString(packet.data)) { \
|
||||
error = "invalid data!"; \
|
||||
error = "invalid data (" _str(class) ")!"; \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define CRYPT_KEY_LENGTH 32
|
||||
bool LicenseServer::handleHandshake(shared_ptr<ConnectedClient>& client, protocol::packet& packet, std::string &error) {
|
||||
TEST_PROTOCOL_STATE(HANDSCAKE);
|
||||
TEST_PROTOCOL_STATE(HANDSCHAKE);
|
||||
ENSURE_PACKET_SIZE(4);
|
||||
if((uint8_t) packet.data[0] != 0xC0 || (uint8_t) packet.data[1] != 0xFF || (uint8_t) packet.data[2] != 0xEE) {
|
||||
error = "invalid magic!";
|
||||
return false;
|
||||
}
|
||||
if((uint8_t) packet.data[3] != LICENSE_PROT_VERSION) {
|
||||
error = "invalid version!";
|
||||
return false;
|
||||
|
||||
client->protocol.version = (uint8_t) packet.data[3];
|
||||
if(client->protocol.version < 2 || client->protocol.version > 3) {
|
||||
error = "unsupported version";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool manager = false;
|
||||
@@ -66,7 +71,7 @@ bool LicenseServer::handleHandshake(shared_ptr<ConnectedClient>& client, protoco
|
||||
size_t buffer_index = 0;
|
||||
buffer[buffer_index++] = 0xAF;
|
||||
buffer[buffer_index++] = 0xFE;
|
||||
buffer[buffer_index++] = LICENSE_PROT_VERSION;
|
||||
buffer[buffer_index++] = client->protocol.version;
|
||||
le2be16(CRYPT_KEY_LENGTH, buffer, buffer_index, &buffer_index);
|
||||
memcpy(&buffer[buffer_index], buffer_cryptkey, CRYPT_KEY_LENGTH);
|
||||
buffer_index += CRYPT_KEY_LENGTH;
|
||||
@@ -88,21 +93,32 @@ bool LicenseServer::handleHandshake(shared_ptr<ConnectedClient>& client, protoco
|
||||
}
|
||||
|
||||
bool LicenseServer::handleDisconnect(shared_ptr<ConnectedClient>& client, protocol::packet& packet, std::string &error) {
|
||||
logMessage("[CLIENT][" + client->address() + "] Remote disconnect. Reason: " + packet.data);
|
||||
logMessage(LOG_GENERAL, "[CLIENT][" + client->address() + "] Remote disconnect. Reason: " + packet.data);
|
||||
this->closeConnection(client);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void fill_info(proto::license::LicenseInfo* proto, const shared_ptr<LicenseInfo>& info, const std::string& key) {
|
||||
proto->set_key(key);
|
||||
proto->set_username(info->username);
|
||||
proto->set_first_name(info->first_name);
|
||||
proto->set_last_name(info->last_name);
|
||||
proto->set_email(info->email);
|
||||
proto->set_type(info->type);
|
||||
proto->set_created(duration_cast<milliseconds>(info->creation.time_since_epoch()).count());
|
||||
proto->set_begin(duration_cast<milliseconds>(info->start.time_since_epoch()).count());
|
||||
proto->set_end(duration_cast<milliseconds>(info->end.time_since_epoch()).count());
|
||||
if(info) {
|
||||
proto->set_username(info->username);
|
||||
proto->set_first_name(info->first_name);
|
||||
proto->set_last_name(info->last_name);
|
||||
proto->set_email(info->email);
|
||||
proto->set_type(info->type);
|
||||
proto->set_created(duration_cast<milliseconds>(info->creation.time_since_epoch()).count());
|
||||
proto->set_begin(duration_cast<milliseconds>(info->start.time_since_epoch()).count());
|
||||
proto->set_end(duration_cast<milliseconds>(info->end.time_since_epoch()).count());
|
||||
} else {
|
||||
proto->set_username("invalid (null)");
|
||||
proto->set_first_name("invalid (null)");
|
||||
proto->set_last_name("invalid (null)");
|
||||
proto->set_email("invalid (null)");
|
||||
proto->set_type(0);
|
||||
proto->set_created(0);
|
||||
proto->set_begin(0);
|
||||
proto->set_end(0);
|
||||
}
|
||||
}
|
||||
|
||||
std::string string_to_hex(const std::string& input)
|
||||
@@ -122,109 +138,183 @@ std::string string_to_hex(const std::string& input)
|
||||
}
|
||||
|
||||
bool LicenseServer::handleServerValidation(shared_ptr<ConnectedClient> &client, protocol::packet &packet, std::string &error) {
|
||||
TEST_PROTOCOL_STATE(SERVER_VALIDATION);
|
||||
if(client->protocol.state != protocol::LICENSE_UPGRADE) /* server may wants to verify new license */
|
||||
TEST_PROTOCOL_STATE(SERVER_VALIDATION);
|
||||
|
||||
PARSE_PROTO(ServerValidation, pkt);
|
||||
|
||||
shared_ptr<License> remoteLicense = nullptr;
|
||||
if(pkt.licensed() && !pkt.has_license()) {
|
||||
//TODO shutdown server
|
||||
std::shared_ptr<License> remote_license{nullptr};
|
||||
if(pkt.licensed() && (!pkt.has_license() || !pkt.has_license_info())) {
|
||||
error = "invalid/missing license data";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!pkt.has_info()) {
|
||||
error = "invalid data or missing data";
|
||||
return false;
|
||||
}
|
||||
if(pkt.has_license()){ //Client has license
|
||||
remoteLicense = readLocalLicence(pkt.license(), error);
|
||||
if(!remoteLicense) {
|
||||
error = "Could not read remote key: " + error;
|
||||
|
||||
if(pkt.licensed()){ //Client has license
|
||||
remote_license = readLocalLicence(pkt.license(), error);
|
||||
if(!remote_license) {
|
||||
error = "could not parse license (" + error + ")";
|
||||
return false;
|
||||
};
|
||||
logMessage(LOG_GENERAL, "[CLIENT][{}] Got remote license. Registered to {}. Key: {} (0x{})", client->address(), remoteLicense->owner(), base64::encode(remoteLicense->key()), string_to_hex(remoteLicense->key()));
|
||||
client->key = remoteLicense->key();
|
||||
} else { }
|
||||
if(pkt.licensed() && !pkt.has_license_info()) {
|
||||
error = "Invalid content!";
|
||||
return false;
|
||||
}
|
||||
|
||||
logMessage(LOG_GENERAL, "[CLIENT][{}] Got remote license. Registered to {}. Key: {} (0x{})", client->address(), remote_license->owner(), base64::encode(remote_license->key()), string_to_hex(remote_license->key()));
|
||||
client->key = remote_license->key();
|
||||
}
|
||||
|
||||
logMessage(LOG_GENERAL, "[CLIENT][{}] Got some server information. TeaSpeak-Version: {} uname: {}", client->address(), pkt.info().version(), pkt.info().uname());
|
||||
ts::proto::license::LicenseResponse response;
|
||||
|
||||
//Forces
|
||||
|
||||
ts::proto::license::LicenseResponse response{};
|
||||
client->unique_identifier = pkt.info().has_unique_id() ? pkt.info().unique_id() : client->address();
|
||||
if(remoteLicense && pkt.licensed()) {
|
||||
auto info = this->manager->licenseInfo(remoteLicense->key());
|
||||
if(!info) {
|
||||
response.set_valid(false);
|
||||
|
||||
/*
|
||||
logMessage(LOG_GENERAL, "[CLIENT][{}] Unknown license! Adding it to database!", client->address());
|
||||
auto db_info = make_shared<LicenseInfo>();
|
||||
db_info->start = system_clock::now();
|
||||
db_info->end = remoteLicense->end();
|
||||
db_info->last_name = "unknown";
|
||||
db_info->first_name = "unknown";
|
||||
db_info->username = remoteLicense->owner();
|
||||
db_info->email = "unknonw@unknown";
|
||||
db_info->creation = system_clock::now();
|
||||
db_info->type = remoteLicense->data.type;
|
||||
this->manager->registerLicense(remoteLicense->key(), db_info, "teaforo-fix");
|
||||
info = this->manager->licenseInfo(remoteLicense->key());
|
||||
if(!info) {
|
||||
error = "could not insert key!";
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
if(remote_license) {
|
||||
auto info = this->manager->query_license_info(remote_license->key());
|
||||
|
||||
if(!info) {
|
||||
response.set_invalid_reason("license has not been found");
|
||||
response.set_valid(false);
|
||||
|
||||
logMessage(LOG_GENERAL, "[CLIENT][{}] Remote license hasn't been found in database. Shutting down server!", client->address());
|
||||
} else {
|
||||
response.set_update_pending(info->upgrade_id > 0);
|
||||
client->key_pending_upgrade = info->upgrade_id;
|
||||
if(info->deleted) {
|
||||
response.set_invalid_reason("license has been deleted");
|
||||
response.set_valid(false);
|
||||
logMessage(LOG_GENERAL, "[CLIENT][{}] Remote license has been deleted! Shutting down server!", client->address());
|
||||
} else {
|
||||
fill_info(response.mutable_license_info(), info, remoteLicense->data.licenceKey);
|
||||
response.set_valid(info->isValid());
|
||||
fill_info(response.mutable_license_info(), info, remote_license->data.licenceKey);
|
||||
auto is_invalid = !info->isValid();
|
||||
if(is_invalid) {
|
||||
response.set_invalid_reason("license is invalid");
|
||||
response.set_valid(false);
|
||||
} else {
|
||||
response.set_valid(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
this->manager->logRequest(remoteLicense->key(), client->unique_identifier, client->address(), pkt.info().version(), response.valid());
|
||||
this->manager->logRequest(remote_license->key(), client->unique_identifier, client->address(), pkt.info().version(), response.valid());
|
||||
} else {
|
||||
response.set_valid(true);
|
||||
}
|
||||
|
||||
response.mutable_blacklist()->set_state(ts::proto::license::VALID);
|
||||
if(client->protocol.version == 2) {
|
||||
if(response.valid())
|
||||
response.mutable_blacklist()->set_state(ts::proto::license::VALID);
|
||||
else {
|
||||
response.mutable_blacklist()->set_reason(response.invalid_reason());
|
||||
response.mutable_blacklist()->set_state(ts::proto::license::BLACKLISTED); /* "Hack" for all old clients */
|
||||
|
||||
if(!response.has_license_info()) fill_info(response.mutable_license_info(), nullptr, ""); /* "Hack" for old clients which require a license. Else the server would not be stopped */
|
||||
client->invalid_license = true;
|
||||
}
|
||||
} else {
|
||||
if(!response.has_blacklist())
|
||||
response.mutable_blacklist()->set_state(ts::proto::license::VALID);
|
||||
}
|
||||
client->invalid_license = !response.valid();
|
||||
|
||||
client->sendPacket(protocol::packet{protocol::PACKET_SERVER_VALIDATION_RESPONSE, response});
|
||||
client->protocol.state = protocol::PROPERTY_ADJUSTMENT;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LicenseServer::handlePacketLicenseUpgrade(shared_ptr<ConnectedClient> &client, license::protocol::packet &packet,
|
||||
std::string &error) {
|
||||
TEST_PROTOCOL_STATE(PROPERTY_ADJUSTMENT);
|
||||
PARSE_PROTO(RequestLicenseUpgrade, pkt);
|
||||
|
||||
if(!client->key_pending_upgrade) {
|
||||
error = "no update pending";
|
||||
return false;
|
||||
}
|
||||
ts::proto::license::LicenseUpgradeResponse response;
|
||||
auto license_upgrade = this->manager->query_license_upgrade(client->key_pending_upgrade);
|
||||
response.set_valid(false);
|
||||
if(license_upgrade) {
|
||||
if(!license_upgrade->valid) {
|
||||
response.set_error_message("upgrade has been invalidated");
|
||||
} else if(license_upgrade->is_expired()) {
|
||||
response.set_error_message("upgrade has been expired");
|
||||
} else if(license_upgrade->not_yet_available()) {
|
||||
response.set_error_message("upgrade is not yet active.");
|
||||
} else {
|
||||
response.set_valid(true);
|
||||
response.set_license_key(license_upgrade->license_key);
|
||||
|
||||
}
|
||||
this->manager->log_license_upgrade_attempt(license_upgrade->upgrade_id, response.valid(), client->unique_identifier, client->address());
|
||||
logMessage(LOG_GENERAL, "[CLIENT][{}] Client requested license upgrade {}. Result: {}", client->key_pending_upgrade, response.valid() ? "granted" : "denied (" + response.error_message() + ")");
|
||||
} else {
|
||||
response.set_error_message("failed to find upgrade");
|
||||
}
|
||||
|
||||
client->sendPacket(protocol::packet{protocol::PACKET_SERVER_LICENSE_UPGRADE_RESPONSE, response});
|
||||
client->protocol.state = protocol::LICENSE_UPGRADE;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LicenseServer::handlePacketPropertyUpdate(shared_ptr<ConnectedClient> &client, protocol::packet &packet, std::string &error) {
|
||||
TEST_PROTOCOL_STATE(PROPERTY_ADJUSTMENT);
|
||||
if(client->protocol.state != protocol::LICENSE_UPGRADE) /* LICENSE_UPGRADE could be skipped */
|
||||
TEST_PROTOCOL_STATE(PROPERTY_ADJUSTMENT);
|
||||
if(client->invalid_license) {
|
||||
ts::proto::license::PropertyUpdateResponse response;
|
||||
response.set_accepted(true);
|
||||
response.set_reset_speach(false);
|
||||
response.set_speach_total_remote(0);
|
||||
response.set_speach_varianz_corrector(0);
|
||||
client->sendPacket(protocol::packet{protocol::PACKET_SERVER_PROPERTY_ADJUSTMENT, response});
|
||||
this->disconnectClient(client, "finished");
|
||||
|
||||
/* Not sure if we really want here to log these data. May put a lvalid=false within the db? */
|
||||
return true;
|
||||
}
|
||||
PARSE_PROTO(PropertyUpdateRequest, pkt);
|
||||
|
||||
logMessage("[CLIENT][" + client->address() + "] Got server statistics:");
|
||||
logMessage("[CLIENT][" + client->address() + "] Spoken total : " + to_string(pkt.speach_total()));
|
||||
logMessage("[CLIENT][" + client->address() + "] Spoken dead : " + to_string(pkt.speach_dead()));
|
||||
logMessage("[CLIENT][" + client->address() + "] Spoken online : " + to_string(pkt.speach_online()));
|
||||
logMessage("[CLIENT][" + client->address() + "] Spoken varianz : " + to_string(pkt.speach_varianz()));
|
||||
logMessage("[CLIENT][" + client->address() + "] -------------------------------");
|
||||
logMessage("[CLIENT][" + client->address() + "] Users online : " + to_string(pkt.clients_online()));
|
||||
logMessage("[CLIENT][" + client->address() + "] Web Users online : " + to_string(pkt.web_clients_online()));
|
||||
logMessage("[CLIENT][" + client->address() + "] Queries online : " + to_string(pkt.queries_online()));
|
||||
logMessage("[CLIENT][" + client->address() + "] Bots online : " + to_string(pkt.bots_online()));
|
||||
logMessage("[CLIENT][" + client->address() + "] Servers : " + to_string(pkt.servers_online()));
|
||||
logMessage(LOG_GENERAL, "[CLIENT][" + client->address() + "] Got server statistics:");
|
||||
logMessage(LOG_GENERAL, "[CLIENT][" + client->address() + "] Spoken total : " + to_string(pkt.speach_total()));
|
||||
logMessage(LOG_GENERAL, "[CLIENT][" + client->address() + "] Spoken dead : " + to_string(pkt.speach_dead()));
|
||||
logMessage(LOG_GENERAL, "[CLIENT][" + client->address() + "] Spoken online : " + to_string(pkt.speach_online()));
|
||||
logMessage(LOG_GENERAL, "[CLIENT][" + client->address() + "] Spoken varianz : " + to_string(pkt.speach_varianz()));
|
||||
logMessage(LOG_GENERAL, "[CLIENT][" + client->address() + "] -------------------------------");
|
||||
logMessage(LOG_GENERAL, "[CLIENT][" + client->address() + "] Users online : " + to_string(pkt.clients_online()));
|
||||
logMessage(LOG_GENERAL, "[CLIENT][" + client->address() + "] Web Users online : " + to_string(pkt.web_clients_online()));
|
||||
logMessage(LOG_GENERAL, "[CLIENT][" + client->address() + "] Queries online : " + to_string(pkt.queries_online()));
|
||||
logMessage(LOG_GENERAL, "[CLIENT][" + client->address() + "] Bots online : " + to_string(pkt.bots_online()));
|
||||
logMessage(LOG_GENERAL, "[CLIENT][" + client->address() + "] Servers : " + to_string(pkt.servers_online()));
|
||||
this->manager->logStatistic(client->key, client->unique_identifier, client->address(), pkt);
|
||||
//TODO test stuff!
|
||||
//TODO test stuff if its possible!
|
||||
|
||||
ts::proto::license::WebCertificate* web_certificate{nullptr};
|
||||
if(pkt.has_web_cert_revision()) {
|
||||
logMessage(LOG_GENERAL, "[CLIENT][" + client->address() + "] -------------------------------");
|
||||
logMessage(LOG_GENERAL, "[CLIENT][" + client->address() + "] Web cert revision : " + hex::hex(pkt.web_cert_revision()));
|
||||
|
||||
auto cert = this->web_certificate;
|
||||
if(cert && cert->revision != pkt.web_cert_revision()) {
|
||||
web_certificate = new ts::proto::license::WebCertificate{};
|
||||
web_certificate->set_key(cert->key);
|
||||
web_certificate->set_certificate(cert->certificate);
|
||||
web_certificate->set_revision(cert->revision);
|
||||
}
|
||||
}
|
||||
|
||||
ts::proto::license::PropertyUpdateResponse response;
|
||||
response.set_accepted(true);
|
||||
response.set_reset_speach(pkt.speach_total() < 0);
|
||||
response.set_speach_total_remote(pkt.speach_total());
|
||||
response.set_speach_varianz_corrector(0);
|
||||
response.set_allocated_web_certificate(web_certificate);
|
||||
client->sendPacket(protocol::packet{protocol::PACKET_SERVER_PROPERTY_ADJUSTMENT, response});
|
||||
this->disconnectClient(client, "finished");
|
||||
|
||||
if(this->statistics)
|
||||
this->statistics->reset_cache_general();
|
||||
|
||||
if(this->web_statistics)
|
||||
this->web_statistics->async_broadcast_notify_general_update();
|
||||
return true;
|
||||
@@ -234,7 +324,7 @@ bool LicenseServer::handlePacketAuth(shared_ptr<ConnectedClient> &client, protoc
|
||||
TEST_PROTOCOL_STATE(MANAGER_AUTHORIZATION);
|
||||
PARSE_PROTO(AuthorizationRequest, pkt);
|
||||
|
||||
logMessage("[MANAGER][" + client->address() + "] Got login. User: " + pkt.username() + " Password: " + pkt.password());
|
||||
logMessage(LOG_GENERAL, "[MANAGER][" + client->address() + "] Got login. User: " + pkt.username() + " Password: " + pkt.password());
|
||||
|
||||
ts::proto::license::AuthorizationResponse response;
|
||||
response.set_success(false);
|
||||
@@ -265,11 +355,11 @@ bool LicenseServer::handlePacketAuth(shared_ptr<ConnectedClient> &client, protoc
|
||||
response.set_message("username or password mismatch");
|
||||
|
||||
if(response.success()) {
|
||||
logMessage("[MANAGER][" + client->address() + "] Got succeeded user login. User: " + pkt.username() + " Password: " + pkt.password());
|
||||
logMessage(LOG_GENERAL, "[MANAGER][" + client->address() + "] Got succeeded user login. User: " + pkt.username() + " Password: " + pkt.password());
|
||||
client->username = pkt.username();
|
||||
client->protocol.state = protocol::MANAGER_CONNECTED;
|
||||
} else
|
||||
logMessage("[MANAGER][" + client->address() + "] Got failed user login. User: " + pkt.username() + " Password: " + pkt.password());
|
||||
logMessage(LOG_GENERAL, "[MANAGER][" + client->address() + "] Got failed user login. User: " + pkt.username() + " Password: " + pkt.password());
|
||||
|
||||
client->sendPacket(protocol::packet{protocol::PACKET_SERVER_AUTH_RESPONSE, response});
|
||||
return true;
|
||||
@@ -279,33 +369,58 @@ bool LicenseServer::handlePacketLicenseCreate(shared_ptr<ConnectedClient> &clien
|
||||
TEST_PROTOCOL_STATE(MANAGER_CONNECTED);
|
||||
PARSE_PROTO(LicenseCreateRequest, pkt);
|
||||
|
||||
logMessage(LOG_GENERAL, "[MANAGER][" + client->address() + "] Register new license to {} {} ({}). E-Mail: {}", pkt.issuer_first_name(), pkt.issuer_last_name(), pkt.issuer_username(), pkt.issuer_email());
|
||||
auto old_license = pkt.has_old_key() ? hex::hex(pkt.old_key()) : "none";
|
||||
logMessage(LOG_GENERAL, "[MANAGER][" + client->address() + "] Register new license to {} {} ({}). E-Mail: {}. Old license: {}", pkt.issuer_first_name(), pkt.issuer_last_name(), pkt.issuer_username(), pkt.issuer_email(), old_license);
|
||||
|
||||
ts::proto::license::LicenseCreateResponse response;
|
||||
auto old_key_id{0};
|
||||
ts::proto::license::LicenseCreateResponse response{};
|
||||
if(pkt.has_old_key()) {
|
||||
old_key_id = this->manager->key_id_cache()->get_key_id_from_key(pkt.old_key());
|
||||
if(old_key_id == 0) {
|
||||
response.set_error("failed to find old license key in database");
|
||||
goto _send_response;
|
||||
}
|
||||
}
|
||||
|
||||
auto db_info = make_shared<LicenseInfo>();
|
||||
db_info->start = system_clock::time_point() + milliseconds(pkt.begin());
|
||||
db_info->end = system_clock::time_point() + milliseconds(pkt.end());
|
||||
db_info->last_name = pkt.issuer_last_name();
|
||||
db_info->first_name = pkt.issuer_first_name();
|
||||
db_info->username = pkt.issuer_username();
|
||||
db_info->email = pkt.issuer_email();
|
||||
db_info->creation = system_clock::now();
|
||||
db_info->type = static_cast<LicenseType>(pkt.type());
|
||||
{
|
||||
auto db_info = make_shared<LicenseInfo>();
|
||||
db_info->start = system_clock::time_point() + milliseconds(pkt.begin());
|
||||
db_info->end = system_clock::time_point() + milliseconds(pkt.end());
|
||||
db_info->last_name = pkt.issuer_last_name();
|
||||
db_info->first_name = pkt.issuer_first_name();
|
||||
db_info->username = pkt.issuer_username();
|
||||
db_info->email = pkt.issuer_email();
|
||||
db_info->creation = system_clock::now();
|
||||
db_info->type = static_cast<LicenseType>(pkt.type());
|
||||
|
||||
auto license = license::createLocalLicence(db_info->type, db_info->end, db_info->first_name + db_info->last_name);
|
||||
auto parsed_license = license::readLocalLicence(license, error);
|
||||
if(!parsed_license) {
|
||||
response.set_error("failed to register license (parse)");
|
||||
} else {
|
||||
auto license = license::createLocalLicence(db_info->type, db_info->end, db_info->first_name + db_info->last_name);
|
||||
auto parsed_license = license::readLocalLicence(license, error);
|
||||
if(!parsed_license) {
|
||||
response.set_error("failed to register license (parse)");
|
||||
} else {
|
||||
if(!this->manager->register_license(parsed_license->key(), db_info, client->username)) {
|
||||
response.set_error("failed to register license");
|
||||
goto _send_response;
|
||||
}
|
||||
|
||||
if(!this->manager->registerLicense(parsed_license->key(), db_info, client->username)) {
|
||||
response.set_error("failed to register license");
|
||||
} else {
|
||||
fill_info(response.mutable_license(), db_info, parsed_license->key());
|
||||
response.set_exported_key(license);
|
||||
}
|
||||
}
|
||||
if(old_key_id) {
|
||||
auto new_key_id = this->manager->key_id_cache()->get_key_id_from_key(parsed_license->key());
|
||||
if(!new_key_id) {
|
||||
response.set_error("failed to find new license in database");
|
||||
goto _send_response;
|
||||
}
|
||||
|
||||
if(!this->manager->register_license_upgrade(old_key_id, new_key_id, std::chrono::system_clock::now(), db_info->end, license)) {
|
||||
response.set_error("failed to register license upgrade");
|
||||
goto _send_response;
|
||||
}
|
||||
}
|
||||
fill_info(response.mutable_license(), db_info, parsed_license->key());
|
||||
response.set_exported_key(license);
|
||||
}
|
||||
}
|
||||
|
||||
_send_response:
|
||||
client->sendPacket(protocol::packet{protocol::PACKET_SERVER_LICENSE_CREATE_RESPONSE, response});
|
||||
return true;
|
||||
}
|
||||
@@ -317,7 +432,7 @@ bool LicenseServer::handlePacketLicenseList(shared_ptr<ConnectedClient> &client,
|
||||
proto::license::LicenseListResponse response;
|
||||
response.set_end(false);
|
||||
|
||||
for(const auto& info : this->manager->listLicenses(pkt.offset(), pkt.count())) {
|
||||
for(const auto& info : this->manager->list_licenses(pkt.offset(), pkt.count())) {
|
||||
auto entry = response.add_entries();
|
||||
fill_info(entry, info.second, info.first);
|
||||
}
|
||||
@@ -331,7 +446,7 @@ bool LicenseServer::handlePacketLicenseDelete(shared_ptr<ConnectedClient> &clien
|
||||
PARSE_PROTO(LicenseDeleteRequest, pkt);
|
||||
|
||||
proto::license::LicenseDeleteResponse response;
|
||||
response.set_succeed(this->manager->deleteLicense(pkt.key(), pkt.full()));
|
||||
response.set_succeed(this->manager->delete_license(pkt.key(), pkt.full()));
|
||||
client->sendPacket(protocol::packet{protocol::PACKET_CLIENT_DELETE_RESPONSE, response});
|
||||
|
||||
return true;
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
|
||||
#include <sql/SqlQuery.h>
|
||||
#include <misc/std_unique_ptr.h>
|
||||
|
||||
#include <utility>
|
||||
#include "StatisticManager.h"
|
||||
#include "LicenseManager.h"
|
||||
#include "DatabaseHandler.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
@@ -76,16 +78,16 @@ system_clock::time_point HistoryStatistics::align_type(license::stats::HistorySt
|
||||
}
|
||||
}
|
||||
|
||||
StatisticManager::StatisticManager(const std::shared_ptr<license::server::LicenseManager> &manager) : license_manager(manager) {}
|
||||
StatisticManager::~StatisticManager() {}
|
||||
StatisticManager::StatisticManager(std::shared_ptr<license::server::database::DatabaseHandler> manager) : license_manager{std::move(manager)} {}
|
||||
StatisticManager::~StatisticManager() = default;
|
||||
|
||||
struct GeneralStatisticEntry {
|
||||
std::chrono::system_clock::time_point age;
|
||||
string unique_id = "";
|
||||
uint64_t key_id = 0;
|
||||
uint64_t servers = 0;
|
||||
uint64_t clients = 0;
|
||||
uint64_t bots = 0;
|
||||
string unique_id{""};
|
||||
uint64_t key_id{0};
|
||||
uint64_t servers{0};
|
||||
uint64_t clients{0};
|
||||
uint64_t bots{0};
|
||||
};
|
||||
|
||||
void StatisticManager::reset_cache_general() {
|
||||
@@ -93,7 +95,7 @@ void StatisticManager::reset_cache_general() {
|
||||
this->_general_statistics = nullptr;
|
||||
}
|
||||
|
||||
void parse_general_entry(deque<unique_ptr<GeneralStatisticEntry>>& entries, bool unique, int length, string* values, string* names) {
|
||||
void parse_general_entry(std::deque<std::unique_ptr<GeneralStatisticEntry>>& entries, bool unique, int length, string* values, string* names) {
|
||||
auto entry = make_unique<GeneralStatisticEntry>();
|
||||
for(int index = 0; index < length; index++) {
|
||||
if(names[index] == "keyId") {
|
||||
@@ -139,7 +141,7 @@ std::shared_ptr<GeneralStatistics> StatisticManager::general_statistics() {
|
||||
|
||||
auto result = sql::command(this->license_manager->sql(), "SELECT `keyId`, `unique_id`, `timestamp`,`server`,`clients`,`music` FROM `history_online` WHERE `timestamp` > :time ORDER BY `timestamp` ASC",
|
||||
variable{":time", duration_cast<milliseconds>(system_clock::now().time_since_epoch() - hours(2) - minutes(10)).count()}) //10min as buffer
|
||||
.query(std::function<decltype(parse_general_entry)>(parse_general_entry), entries, true);
|
||||
.query(std::function<decltype(parse_general_entry)>{parse_general_entry}, entries, true);
|
||||
|
||||
auto stats = make_shared<GeneralStatistics>();
|
||||
for(auto& entry : entries) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
#include "LicenseManager.h"
|
||||
#include "DatabaseHandler.h"
|
||||
|
||||
namespace license {
|
||||
namespace stats {
|
||||
@@ -17,6 +17,19 @@ namespace license {
|
||||
};
|
||||
|
||||
struct HistoryStatistics {
|
||||
enum HistoryPeriod {
|
||||
DAY,
|
||||
WEEK,
|
||||
MONTH,
|
||||
HALF_YEAR,
|
||||
YEAR
|
||||
};
|
||||
enum HistoryOffset {
|
||||
NOW,
|
||||
ONE_BEFORE,
|
||||
SEVEN_BEFORE,
|
||||
TWELVE_BEFORE
|
||||
};
|
||||
enum HistoryType {
|
||||
LAST_DAY,
|
||||
DAY_YESTERDAY,
|
||||
@@ -34,21 +47,21 @@ namespace license {
|
||||
std::chrono::system_clock::time_point begin;
|
||||
std::chrono::system_clock::time_point end;
|
||||
std::chrono::milliseconds period;
|
||||
HistoryType type;
|
||||
HistoryType type;
|
||||
|
||||
std::deque<std::unique_ptr<server::LicenseManager::GlobalUserStatistics>> statistics;
|
||||
std::shared_ptr<server::database::DatabaseHandler::UserHistory> statistics;
|
||||
};
|
||||
|
||||
class StatisticManager {
|
||||
public:
|
||||
explicit StatisticManager(const std::shared_ptr<server::LicenseManager>& /* manager */);
|
||||
explicit StatisticManager(std::shared_ptr<server::database::DatabaseHandler> /* manager */);
|
||||
virtual ~StatisticManager();
|
||||
|
||||
void reset_cache_general();
|
||||
std::shared_ptr<GeneralStatistics> general_statistics();
|
||||
std::shared_ptr<HistoryStatistics> history(HistoryStatistics::HistoryType);
|
||||
private:
|
||||
std::shared_ptr<server::LicenseManager> license_manager;
|
||||
std::shared_ptr<server::database::DatabaseHandler> license_manager;
|
||||
|
||||
std::recursive_mutex _general_statistics_lock;
|
||||
std::recursive_mutex _general_statistics_generate_lock;
|
||||
|
||||
+82
-30
@@ -17,7 +17,7 @@ using namespace ts::ssl;
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
|
||||
WebStatistics::WebStatistics(const shared_ptr<LicenseManager> &manager, const std::shared_ptr<stats::StatisticManager>& stats) : license_manager(manager), statistics_manager(stats) {}
|
||||
WebStatistics::WebStatistics(const shared_ptr<database::DatabaseHandler> &manager, const std::shared_ptr<stats::StatisticManager>& stats) : license_manager(manager), statistics_manager(stats) {}
|
||||
WebStatistics::~WebStatistics() {}
|
||||
|
||||
#define SFAIL(message) \
|
||||
@@ -38,11 +38,10 @@ bool WebStatistics::start(std::string &error, uint16_t port, const std::shared_p
|
||||
this->ssl = ssl;
|
||||
|
||||
{
|
||||
this->socket.local_address = make_unique<sockaddr_in>();
|
||||
memset(this->socket.local_address.get(), 0, sizeof(sockaddr_in));
|
||||
this->socket.local_address->sin_family = AF_INET;
|
||||
this->socket.local_address->sin_addr.s_addr = INADDR_ANY;
|
||||
this->socket.local_address->sin_port = htons(port);
|
||||
memset(&this->socket.address, 0, sizeof(sockaddr_in));
|
||||
this->socket.address.sin_family = AF_INET;
|
||||
this->socket.address.sin_addr.s_addr = INADDR_ANY;
|
||||
this->socket.address.sin_port = htons(port);
|
||||
}
|
||||
|
||||
this->socket.file_descriptor = ::socket(AF_INET, SOCK_STREAM, 0);
|
||||
@@ -50,7 +49,7 @@ bool WebStatistics::start(std::string &error, uint16_t port, const std::shared_p
|
||||
|
||||
if(setsockopt(this->socket.file_descriptor, SOL_SOCKET, SO_REUSEADDR, &enabled, sizeof(enabled)) < 0) SFAIL("could not set reuse address");
|
||||
if(setsockopt(this->socket.file_descriptor, IPPROTO_TCP, TCP_CORK, &disabled, sizeof(disabled)) < 0) SFAIL("could not set no push");
|
||||
if(bind(this->socket.file_descriptor, (struct sockaddr *) this->socket.local_address.get(), sizeof(sockaddr_in)) < 0) SFAIL("Could not bind socket on " + string(inet_ntoa(this->socket.local_address->sin_addr)));
|
||||
if(bind(this->socket.file_descriptor, (struct sockaddr *) &this->socket.address, sizeof(sockaddr_in)) < 0) SFAIL("Could not bind socket on " + string(inet_ntoa(this->socket.address.sin_addr)));
|
||||
|
||||
if(listen(this->socket.file_descriptor, 32) < 0) SFAIL("Could not listen on socket");
|
||||
|
||||
@@ -162,13 +161,11 @@ void WebStatistics::initialize_client(const std::shared_ptr<license::web::WebSta
|
||||
|
||||
auto lmethod = request.method;
|
||||
transform(lmethod.begin(), lmethod.end(), lmethod.begin(), ::tolower);
|
||||
if(lmethod == "get" && !request.parameters["type"].empty())
|
||||
if(lmethod == "get" && request.parameters.count("type") && !request.parameters.at("type").empty())
|
||||
this->handle_request(_client, request, response);
|
||||
};
|
||||
|
||||
client->pipe_websocket->initialize();
|
||||
|
||||
//FIXME Setup ssl
|
||||
}
|
||||
|
||||
{
|
||||
@@ -369,6 +366,15 @@ std::shared_ptr<WebStatistics::Client> WebStatistics::find_client_by_fd(int file
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool WebStatistics::send_message(const std::shared_ptr<Client> &client, const pipes::buffer_view &buffer) {
|
||||
lock_guard<recursive_mutex> lock(client->execute_lock);
|
||||
if(client->pipe_websocket) {
|
||||
client->pipe_websocket->send({pipes::TEXT, buffer.own_buffer()});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#define HERR(message, ...) \
|
||||
do {\
|
||||
logError(LOG_LICENSE_WEB, "[{}] " message, client->client_prefix(), ##__VA_ARGS__); \
|
||||
@@ -382,9 +388,6 @@ inline pipes::buffer json_dump(const Json::Value& value) {
|
||||
return pipes::buffer((void*) json.c_str(), json.length());
|
||||
}
|
||||
|
||||
Json::Value::Value(long value) : Value(to_string(value)) {}
|
||||
Json::Value::Value(unsigned long value) : Value(to_string(value)) {}
|
||||
|
||||
bool WebStatistics::handle_message(const std::shared_ptr<license::web::WebStatistics::Client> &client, const pipes::WSMessage &raw_message) {
|
||||
if(this->update_flood(client, 10)) {
|
||||
static pipes::buffer _response;
|
||||
@@ -396,7 +399,7 @@ bool WebStatistics::handle_message(const std::shared_ptr<license::web::WebStatis
|
||||
_response = json_dump(response);
|
||||
}
|
||||
|
||||
client->pipe_websocket->send({pipes::TEXT, _response});
|
||||
this->send_message(client, _response);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -429,9 +432,9 @@ bool WebStatistics::handle_message(const std::shared_ptr<license::web::WebStatis
|
||||
response["statistics"]["clients"] = to_string(stats->clients);
|
||||
response["statistics"]["music"] = to_string(stats->bots);
|
||||
|
||||
client->pipe_websocket->send({pipes::TEXT, json_dump(response)});
|
||||
this->send_message(client, json_dump(response));
|
||||
return true;
|
||||
} else if(message["request_type"].asString() == "history") {
|
||||
} else if(message["request_type"].asString() == "history" ) {
|
||||
auto type = message["history_type"].asInt();
|
||||
if(type < 0 || type > stats::HistoryStatistics::LAST_HALF_YEAR)
|
||||
__throw_range_error("invalid range!");
|
||||
@@ -450,6 +453,7 @@ bool WebStatistics::handle_message(const std::shared_ptr<license::web::WebStatis
|
||||
this->update_flood(client, 80);
|
||||
|
||||
|
||||
//TODO: Some kind of handle else this could crash the server on shutdown
|
||||
std::thread([&, client, type, message]() {
|
||||
auto history = this->statistics_manager->history((stats::HistoryStatistics::HistoryType) type);
|
||||
|
||||
@@ -462,20 +466,68 @@ bool WebStatistics::handle_message(const std::shared_ptr<license::web::WebStatis
|
||||
response["history"]["end"] = duration_cast<milliseconds>(history->end.time_since_epoch()).count();
|
||||
response["history"]["interval"] = duration_cast<milliseconds>(history->period).count();
|
||||
|
||||
int index = 0;
|
||||
for(auto& element : history->statistics) {
|
||||
response["history"]["data"][index]["instances"] = element->instance_online;
|
||||
response["history"]["data"][index]["servers"] = element->servers_online;
|
||||
response["history"]["data"][index]["clients"] = element->clients_online;
|
||||
response["history"]["data"][index]["music"] = element->bots_online;
|
||||
index++;
|
||||
}
|
||||
|
||||
lock_guard lock(client->execute_lock);
|
||||
if(client->pipe_websocket)
|
||||
client->pipe_websocket->send({pipes::TEXT, json_dump(response)});
|
||||
int index;
|
||||
auto stats = history->statistics;
|
||||
auto& history_data = response["history"]["data"];
|
||||
for(index = 0; index < stats->record_count; index++) {
|
||||
auto& indexed_data = history_data[index];
|
||||
indexed_data["instances"] = stats->history[index].instance_online;
|
||||
indexed_data["servers"] = stats->history[index].servers_online;
|
||||
indexed_data["clients"] = stats->history[index].clients_online;
|
||||
indexed_data["music"] = stats->history[index].bots_online;
|
||||
}
|
||||
|
||||
this->send_message(client, json_dump(response));
|
||||
}).detach();
|
||||
return true;
|
||||
} else if(message["request_type"].asString() == "history_custom") {
|
||||
auto begin = std::chrono::milliseconds{message["history_begin"].asInt64()};
|
||||
auto end = std::chrono::milliseconds{message["history_end"].asInt64()};
|
||||
auto interval = std::chrono::milliseconds{message["history_interval"].asInt64()};
|
||||
auto code = message["code"].asString();
|
||||
|
||||
auto token = message["token"].asString();
|
||||
if(token != "blubalutsch") {
|
||||
Json::Value response;
|
||||
response["type"] = "error";
|
||||
response["code"] = code;
|
||||
response["message"] = "invalid token";
|
||||
this->send_message(client, json_dump(response));
|
||||
return true;
|
||||
}
|
||||
|
||||
//TODO: Some kind of handle else this could crash the server on shutdown
|
||||
std::thread([&, client, begin, end, interval, code]{
|
||||
auto data = this->license_manager->list_statistics_user(
|
||||
std::chrono::system_clock::time_point{} + begin,
|
||||
std::chrono::system_clock::time_point{} + end,
|
||||
interval
|
||||
);
|
||||
|
||||
Json::Value response;
|
||||
response["type"] = "response";
|
||||
response["code"] = code;
|
||||
|
||||
response["history"]["timestamp"] = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||
response["history"]["begin"] = duration_cast<milliseconds>(begin).count();
|
||||
response["history"]["end"] = duration_cast<milliseconds>(end).count();
|
||||
response["history"]["interval"] = duration_cast<milliseconds>(interval).count();
|
||||
|
||||
|
||||
int index;
|
||||
auto& history_data = response["history"]["data"];
|
||||
for(index = 0; index < data->record_count; index++) {
|
||||
auto& indexed_data = history_data[index];
|
||||
indexed_data["instances"] = data->history[index].instance_online;
|
||||
indexed_data["servers"] = data->history[index].servers_online;
|
||||
indexed_data["clients"] = data->history[index].clients_online;
|
||||
indexed_data["music"] = data->history[index].bots_online;
|
||||
}
|
||||
|
||||
this->send_message(client, json_dump(response));
|
||||
}).detach();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
@@ -484,8 +536,8 @@ bool WebStatistics::handle_message(const std::shared_ptr<license::web::WebStatis
|
||||
Json::Value response;
|
||||
response["type"] = "error";
|
||||
response["code"] = message["code"];
|
||||
response["message"] = "could not assign action";
|
||||
client->pipe_websocket->send({pipes::TEXT, json_dump(response)});
|
||||
response["message"] = "could not execute action";
|
||||
this->send_message(client, json_dump(response));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -494,7 +546,7 @@ bool WebStatistics::handle_message(const std::shared_ptr<license::web::WebStatis
|
||||
response["type"] = "error";
|
||||
response["code"] = message["code"];
|
||||
response["message"] = "could not assign action";
|
||||
client->pipe_websocket->send({pipes::TEXT, json_dump(response)});
|
||||
this->send_message(client, json_dump(response));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
+10
-8
@@ -9,7 +9,7 @@
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <ThreadPool/Thread.h>
|
||||
#include <shared/License.h>
|
||||
#include <shared/include/license/license.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <misc/net.h>
|
||||
#include <json/json.h>
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
namespace license {
|
||||
namespace server {
|
||||
class LicenseManager;
|
||||
class DatabaseHandler;
|
||||
}
|
||||
namespace stats {
|
||||
class StatisticManager;
|
||||
@@ -31,6 +31,7 @@ namespace license {
|
||||
struct Client {
|
||||
std::unique_ptr<sockaddr_in> peer_address;
|
||||
int file_descriptor = 0;
|
||||
|
||||
event* event_read = nullptr;
|
||||
event* event_write = nullptr;
|
||||
|
||||
@@ -46,7 +47,7 @@ namespace license {
|
||||
inline std::string client_prefix() { return peer_address ? net::to_string(peer_address->sin_addr) : "unconnected"; }
|
||||
};
|
||||
public:
|
||||
WebStatistics(const std::shared_ptr<server::LicenseManager>& /* license manager */, const std::shared_ptr<stats::StatisticManager>& /* stats manager */);
|
||||
WebStatistics(const std::shared_ptr<server::database::DatabaseHandler>& /* license manager */, const std::shared_ptr<stats::StatisticManager>& /* stats manager */);
|
||||
virtual ~WebStatistics();
|
||||
|
||||
bool start(std::string& /* error */, uint16_t /* port */, const std::shared_ptr<ts::ssl::SSLContext>& /* ssl */);
|
||||
@@ -63,6 +64,7 @@ namespace license {
|
||||
|
||||
void close_connection(const std::shared_ptr<Client>& /* client */);
|
||||
std::shared_ptr<Client> find_client_by_fd(int /* file descriptor */);
|
||||
bool send_message(const std::shared_ptr<Client>& /* client */, const pipes::buffer_view& /* data */);
|
||||
|
||||
void broadcast_message(const Json::Value& /* message */);
|
||||
|
||||
@@ -73,14 +75,14 @@ namespace license {
|
||||
bool _running = false;
|
||||
std::recursive_mutex running_lock;
|
||||
|
||||
std::shared_ptr<server::LicenseManager> license_manager;
|
||||
std::shared_ptr<server::database::DatabaseHandler> license_manager;
|
||||
std::shared_ptr<stats::StatisticManager> statistics_manager;
|
||||
|
||||
struct {
|
||||
std::unique_ptr<sockaddr_in> local_address;
|
||||
int file_descriptor = 0;
|
||||
event* event_accept = nullptr;
|
||||
event_base* event_base = nullptr;
|
||||
sockaddr_in address{};
|
||||
int file_descriptor{0};
|
||||
event* event_accept{nullptr};
|
||||
struct event_base* event_base{nullptr};
|
||||
std::unique_ptr<threads::Thread> event_base_dispatch;
|
||||
} socket;
|
||||
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
#include <google/protobuf/message.h>
|
||||
#include <misc/base64.h>
|
||||
|
||||
//#define NO_OPEN_SSL
|
||||
#include <misc/digest.h>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include "crypt.h"
|
||||
#include "License.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
|
||||
inline void generate(char* buffer, size_t length){
|
||||
for(int index = 0; index < length; index++)
|
||||
buffer[index] = rand();
|
||||
}
|
||||
|
||||
namespace license {
|
||||
std::string LicenseTypeNames[] = LT_NAMES;
|
||||
|
||||
std::shared_ptr<License> readLocalLicence(const std::string& buffer, std::string& error){
|
||||
string bbuffer = base64::decode(buffer);
|
||||
if(bbuffer.length() < sizeof(License)) {
|
||||
error = "Invalid license size";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto license = static_cast<License *>(malloc(sizeof(License)));
|
||||
memcpy(license, bbuffer.data(), sizeof(License));
|
||||
|
||||
if(license->header.version != LICENSE_VERSION){
|
||||
error = "Invalid license version (" + to_string(license->header.version) + ")";
|
||||
return nullptr;
|
||||
}
|
||||
xorBuffer(&((char*) license)[sizeof(License::header)], sizeof(License::data), license->header.cryptKey, sizeof(license->header.cryptKey));
|
||||
|
||||
auto hash = digest::sha1(reinterpret_cast<const char *>(&license->data), sizeof(license->data));
|
||||
|
||||
uint64_t checkSum = 0;
|
||||
for(int i = 0; i < SHA_DIGEST_LENGTH; i++)
|
||||
checkSum += (uint8_t) hash[i] << (i % 8);
|
||||
|
||||
if((checkSum ^ *(uint64_t*) &license->header.cryptKey) != MAGIC_NUMER) {
|
||||
error = "invalid check sum";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return shared_ptr<License>(license, [](License* l){
|
||||
if(l) free(l);
|
||||
});
|
||||
}
|
||||
|
||||
std::string exportLocalLicense(const std::shared_ptr<License>& ref){
|
||||
auto copy = static_cast<License *>(malloc(sizeof(License)));
|
||||
memcpy(copy, ref.get(), sizeof(License));
|
||||
|
||||
auto hash = digest::sha1(reinterpret_cast<const char *>(©->data), sizeof(copy->data));
|
||||
|
||||
uint64_t checkSum = 0;
|
||||
for(int i = 0; i < SHA_DIGEST_LENGTH; i++)
|
||||
checkSum += (uint8_t) hash[i] << (i % 8);
|
||||
checkSum ^= MAGIC_NUMER;
|
||||
|
||||
generate(const_cast<char *>(copy->header.cryptKey), sizeof(copy->header.cryptKey));
|
||||
*(uint64_t*) ©->header.cryptKey = checkSum;
|
||||
|
||||
|
||||
xorBuffer(&((char*) copy)[sizeof(License::header)], sizeof(License::data), copy->header.cryptKey, sizeof(copy->header.cryptKey));
|
||||
auto result = base64_encode((const char*) copy, sizeof(License));
|
||||
free(copy);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string createLocalLicence(LicenseType type, std::chrono::system_clock::time_point until, std::string licenseOwner){
|
||||
auto license = shared_ptr<License>(static_cast<License *>(malloc(sizeof(License))), [](License* l) { if(l) free(l); });
|
||||
assert(licenseOwner.length() < sizeof(license->data.licenceOwner));
|
||||
|
||||
license->header.version = LICENSE_VERSION;
|
||||
generate(const_cast<char *>(license->data.licenceKey), sizeof(license->data.licenceKey));
|
||||
generate(const_cast<char *>(license->data.licenceOwner), sizeof(license->data.licenceOwner)); //Crap data :)
|
||||
license->data.type = type;
|
||||
license->data.endTimestamp = duration_cast<milliseconds>(until.time_since_epoch()).count();
|
||||
memcpy((void *) license->data.licenceOwner, licenseOwner.c_str(), strlen(licenseOwner.c_str()) + 1); //Copy the string into it
|
||||
|
||||
return exportLocalLicense(license);
|
||||
}
|
||||
|
||||
const char *exceptions::LicenseException::what() const throw() {
|
||||
return this->errorMessage.c_str();
|
||||
}
|
||||
|
||||
protocol::packet::packet(PacketType packetId, const ::google::protobuf::Message& message) {
|
||||
this->header.packetId = packetId;
|
||||
this->data = message.SerializeAsString();
|
||||
}
|
||||
|
||||
protocol::packet::packet(license::protocol::PacketType packetId, nullptr_t) {
|
||||
this->header.packetId = packetId;
|
||||
this->data = "";
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <ThreadPool/Mutex.h>
|
||||
#include <ThreadPool/Future.h>
|
||||
#include <Variable.h>
|
||||
|
||||
#define LICENSE_VERSION 1
|
||||
#define LICENSE_PROT_VERSION 2
|
||||
#define MAGIC_NUMER 0xBADC0DED
|
||||
|
||||
namespace license {
|
||||
namespace exceptions {
|
||||
class LicenseException : public std::exception {
|
||||
public:
|
||||
LicenseException() = delete;
|
||||
LicenseException(std::string message) : errorMessage(std::move(message)) {}
|
||||
LicenseException(const LicenseException& ref) : errorMessage(ref.errorMessage) {}
|
||||
LicenseException(LicenseException&& ref) : errorMessage(std::move(ref.errorMessage)) {}
|
||||
|
||||
const char* what() const noexcept override;
|
||||
private:
|
||||
std::string errorMessage;
|
||||
};
|
||||
}
|
||||
|
||||
struct LicenseHeader {
|
||||
uint16_t version;
|
||||
const char cryptKey[64]; //The dummy key for data de/encryption
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
/*
|
||||
namespace v2 {
|
||||
namespace data {
|
||||
struct ChainHead {
|
||||
uint32_t chain_version;
|
||||
uint32_t chain_magic;
|
||||
uint8_t sign[32];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct ChainEntryHead {
|
||||
uint8_t entry_type; //sign bit = contains private
|
||||
int64_t entry_begin;
|
||||
int32_t entry_length;
|
||||
uint8_t key[32];
|
||||
} __attribute__ ((__packed__));
|
||||
}
|
||||
|
||||
struct LicenseIssuer {
|
||||
std::string name;
|
||||
std::string email;
|
||||
};
|
||||
|
||||
struct LicenseChainEntry {
|
||||
data::ChainEntryHead head;
|
||||
struct {
|
||||
bool contains;
|
||||
uint8_t key[32];
|
||||
} prv_key;
|
||||
LicenseIssuer issuer;
|
||||
};
|
||||
|
||||
struct LicenseChain {
|
||||
public:
|
||||
data::ChainHead head;
|
||||
std::deque<LicenseChainEntry> entries;
|
||||
|
||||
private:
|
||||
};
|
||||
}
|
||||
*/
|
||||
|
||||
enum LicenseType : uint8_t {
|
||||
INVALID,
|
||||
DEMO,
|
||||
PREMIUM,
|
||||
HOSTER,
|
||||
PRIVATE,
|
||||
};
|
||||
|
||||
inline bool isPremiumLicense(LicenseType type){ return type == HOSTER || type == PREMIUM || type == PRIVATE; }
|
||||
|
||||
#define LT_NAMES {"Invalid", "Demo", "Premium", "Hoster", "Private"};
|
||||
extern std::string LicenseTypeNames[5];
|
||||
|
||||
struct License {
|
||||
LicenseHeader header;
|
||||
|
||||
//Crypted part
|
||||
struct {
|
||||
LicenseType type;
|
||||
int64_t endTimestamp;
|
||||
|
||||
const char licenceKey[64]; //The actual key
|
||||
const char licenceOwner[64];
|
||||
|
||||
} __attribute__ ((__packed__)) data;
|
||||
|
||||
inline std::string key() { return std::string(data.licenceKey, 64); }
|
||||
inline std::chrono::time_point<std::chrono::system_clock> end() { return std::chrono::system_clock::time_point() + std::chrono::milliseconds(this->data.endTimestamp); }
|
||||
inline std::string owner() { return std::string(this->data.licenceOwner); }
|
||||
inline bool isValid() { return data.endTimestamp == 0 || std::chrono::system_clock::now() < this->end(); }
|
||||
inline bool isPremium(){ return isPremiumLicense(data.type); }
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct LicenseInfo {
|
||||
LicenseType type;
|
||||
std::string username;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
std::string email;
|
||||
std::chrono::system_clock::time_point start;
|
||||
std::chrono::system_clock::time_point end;
|
||||
std::chrono::system_clock::time_point creation;
|
||||
|
||||
bool deleted = false;
|
||||
|
||||
inline bool isValid() { return (end.time_since_epoch().count() == 0 || std::chrono::system_clock::now() < this->end); }
|
||||
};
|
||||
|
||||
extern std::shared_ptr<License> readLocalLicence(const std::string &, std::string &);
|
||||
extern std::string exportLocalLicense(const std::shared_ptr<License>&);
|
||||
extern std::string createLocalLicence(LicenseType type, std::chrono::time_point<std::chrono::system_clock> until, std::string licenseOwner);
|
||||
|
||||
namespace protocol {
|
||||
enum RequestState {
|
||||
UNCONNECTED,
|
||||
CONNECTING,
|
||||
|
||||
HANDSCAKE,
|
||||
SERVER_VALIDATION,
|
||||
LICENSE_INFO,
|
||||
PROPERTY_ADJUSTMENT,
|
||||
MANAGER_AUTHORIZATION,
|
||||
MANAGER_CONNECTED,
|
||||
|
||||
DISCONNECTING
|
||||
};
|
||||
|
||||
enum PacketType : uint8_t {
|
||||
PACKET_CLIENT_HANDSHAKE,
|
||||
PACKET_SERVER_HANDSHAKE,
|
||||
PACKET_CLIENT_SERVER_VALIDATION,
|
||||
PACKET_SERVER_VALIDATION_RESPONSE,
|
||||
PACKET_CLIENT_PROPERTY_ADJUSTMENT,
|
||||
PACKET_SERVER_PROPERTY_ADJUSTMENT,
|
||||
|
||||
PACKET_CLIENT_AUTH_REQUEST,
|
||||
PACKET_SERVER_AUTH_RESPONSE,
|
||||
PACKET_CLIENT_LICENSE_CREATE_REQUEST,
|
||||
PACKET_SERVER_LICENSE_CREATE_RESPONSE,
|
||||
|
||||
PACKET_CLIENT_LIST_REQUEST,
|
||||
PACKET_SERVER_LIST_RESPONSE,
|
||||
|
||||
PACKET_CLIENT_DELETE_REQUEST,
|
||||
PACKET_CLIENT_DELETE_RESPONSE,
|
||||
|
||||
PACKET_PING = 0xF0,
|
||||
PACKET_DISCONNECT = 0xFF
|
||||
};
|
||||
|
||||
struct packet {
|
||||
struct {
|
||||
PacketType packetId;
|
||||
mutable uint16_t length;
|
||||
} header;
|
||||
std::string data;
|
||||
|
||||
inline void prepare() const {
|
||||
this->header.length = (uint16_t) data.length();
|
||||
}
|
||||
|
||||
packet(PacketType packetId, std::string data) : data(std::move(data)), header({packetId, 0}) {}
|
||||
|
||||
#ifdef GOOGLE_PROTOBUF_MESSAGE_H__
|
||||
packet(PacketType packetId, const ::google::protobuf::Message&);
|
||||
#endif
|
||||
packet(PacketType packetId, nullptr_t);
|
||||
};
|
||||
}
|
||||
}
|
||||
//DEFINE_TRANSFORMS(license::LicenseType, uint8_t);
|
||||
@@ -1,301 +0,0 @@
|
||||
#include <netinet/tcp.h>
|
||||
#include <log/LogUtils.h>
|
||||
#include <misc/memtracker.h>
|
||||
#include "crypt.h"
|
||||
#define DEFINE_HELPER
|
||||
#include "LicenseRequest.h"
|
||||
#include "License.h"
|
||||
#include <csignal>
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
using namespace ts;
|
||||
using namespace license;
|
||||
|
||||
#define DEBUG_LICENSE_CLIENT
|
||||
#define CERR(message) LICENSE_FERR(this, CouldNotConnectException, message)
|
||||
|
||||
|
||||
LicenceRequest::LicenceRequest(const std::shared_ptr<LicenseRequestData> & license, const sockaddr_in& remoteAddr) : data(license) {
|
||||
#ifdef DEBUG_LICENSE_CLIENT
|
||||
memtrack::allocated<LicenceRequest>(this);
|
||||
#endif
|
||||
memcpy(&this->remote_address, &remoteAddr, sizeof(remoteAddr));
|
||||
|
||||
assert(license->info);
|
||||
}
|
||||
|
||||
LicenceRequest::~LicenceRequest() {
|
||||
#ifdef DEBUG_LICENSE_CLIENT
|
||||
memtrack::freed<LicenceRequest>(this);
|
||||
#endif
|
||||
this->abortRequest();
|
||||
|
||||
if(this->closeThread) {
|
||||
this->closeThread->join();
|
||||
delete this->closeThread;
|
||||
this->closeThread = nullptr;
|
||||
}
|
||||
|
||||
|
||||
delete this->currentFuture;
|
||||
this->currentFuture = nullptr;
|
||||
}
|
||||
|
||||
threads::Future<std::shared_ptr<LicenseRequestResponse>> LicenceRequest::requestInfo() {
|
||||
{
|
||||
lock_guard lock(this->lock);
|
||||
if(this->currentFuture) return *this->currentFuture;
|
||||
this->currentFuture = new threads::Future<std::shared_ptr<LicenseRequestResponse>>();
|
||||
}
|
||||
|
||||
this->beginRequest();
|
||||
return *this->currentFuture;
|
||||
}
|
||||
|
||||
|
||||
//Basic IO
|
||||
void LicenceRequest::handleEventWrite(int fd, short event, void* ptrClient) {
|
||||
auto* client = static_cast<LicenceRequest *>(ptrClient);
|
||||
|
||||
buffer::RawBuffer* buffer = nullptr;
|
||||
{
|
||||
lock_guard lock(client->lock);
|
||||
if((event & EV_TIMEOUT) > 0) { //Connect timeout
|
||||
LICENSE_FERR(client, ConnectionException, "Connect timeout");
|
||||
return;
|
||||
}
|
||||
|
||||
if(client->state == protocol::CONNECTING){
|
||||
client->handleConnected();
|
||||
}
|
||||
|
||||
if(client->state == protocol::UNCONNECTED || !client->event_write)
|
||||
return;
|
||||
|
||||
buffer = TAILQ_FIRST(&client->writeQueue);
|
||||
if(!buffer) return;
|
||||
|
||||
auto writtenBytes = send(fd, &buffer->buffer[buffer->index], buffer->length - buffer->index, MSG_NOSIGNAL | MSG_DONTWAIT);
|
||||
buffer->index += writtenBytes;
|
||||
|
||||
if(buffer->index >= buffer->length) {
|
||||
TAILQ_REMOVE(&client->writeQueue, buffer, tail);
|
||||
delete buffer;
|
||||
}
|
||||
if(!TAILQ_EMPTY(&client->writeQueue))
|
||||
event_add(client->event_write, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void LicenceRequest::sendPacket(const protocol::packet& packet) {
|
||||
if(this->state == protocol::UNCONNECTED || this->state == protocol::DISCONNECTING) {
|
||||
if(this->verbose)
|
||||
logError("Tried to send a packet to an unconnected remote!");
|
||||
return;
|
||||
}
|
||||
packet.prepare();
|
||||
|
||||
auto buffer = new buffer::RawBuffer(packet.data.length() + sizeof(packet.header));
|
||||
memcpy(buffer->buffer, &packet.header, sizeof(packet.header));
|
||||
memcpy(&buffer->buffer[sizeof(packet.header)], packet.data.data(), packet.data.length());
|
||||
|
||||
if(!this->cryptKey.empty())
|
||||
xorBuffer(&buffer->buffer[sizeof(packet.header)], packet.data.length(), this->cryptKey.data(), this->cryptKey.length());
|
||||
|
||||
{
|
||||
lock_guard lock(this->lock);
|
||||
TAILQ_INSERT_TAIL(&this->writeQueue, buffer, tail);
|
||||
if(this->event_write)
|
||||
event_add(this->event_write, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void LicenceRequest::handleEventRead(int fd, short, void* ptrClient) {
|
||||
auto* client = static_cast<LicenceRequest *>(ptrClient);
|
||||
|
||||
auto buffer = std::unique_ptr<void, decltype(free)*>{malloc(1024), free};
|
||||
sockaddr_in remoteAddr{};
|
||||
socklen_t remoteAddrSize = sizeof(remoteAddr);
|
||||
|
||||
auto read = recvfrom(fd, buffer.get(), 1024, MSG_NOSIGNAL | MSG_DONTWAIT, reinterpret_cast<sockaddr *>(&remoteAddr), &remoteAddrSize);
|
||||
|
||||
if(read < 0){
|
||||
if(errno == EWOULDBLOCK) return;
|
||||
if(client->event_read)
|
||||
event_del_noblock(client->event_read);
|
||||
LICENSE_FERR(client, ConnectionException, "Invalid read: " + string(strerror(errno)) + "/" + to_string(errno));
|
||||
return;
|
||||
} else if(read == 0) {
|
||||
if(client->event_read)
|
||||
event_del_noblock(client->event_read);
|
||||
LICENSE_FERR(client, ConnectionException, "IO error (" + to_string(errno) + "): " + string(strerror(errno)));
|
||||
return;
|
||||
}
|
||||
|
||||
client->handleMessage(string((char*) buffer.get(), read));
|
||||
}
|
||||
|
||||
|
||||
static int enabled = 1;
|
||||
static int disabled = 0;
|
||||
void LicenceRequest::beginRequest() {
|
||||
lock_guard lock(this->lock);
|
||||
TAILQ_INIT(&this->writeQueue);
|
||||
|
||||
this->file_descriptor = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
||||
if(this->file_descriptor < 0) CERR("Socket setup failed");
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
auto state = ::connect(this->file_descriptor, reinterpret_cast<const sockaddr *>(&this->remote_address), sizeof(this->remote_address));
|
||||
if(state < 0 && errno != EINPROGRESS) CERR("connect() failed (" + string(strerror(errno)) + ")");
|
||||
|
||||
if(setsockopt(this->file_descriptor, SOL_SOCKET, SO_REUSEADDR, &enabled, sizeof(enabled)) < 0) CERR("could not set reuse addr");
|
||||
if(setsockopt(this->file_descriptor, IPPROTO_TCP, TCP_CORK, &disabled, sizeof(disabled)) < 0) CERR("could not set no push");
|
||||
|
||||
if(fcntl(this->file_descriptor, F_SETFD, fcntl(this->file_descriptor, F_GETFL, 0) | FD_CLOEXEC | O_NONBLOCK) < 0) CERR("Failed to set FD_CLOEXEC and O_NONBLOCK");
|
||||
|
||||
this->event_base = event_base_new();
|
||||
this->event_read = event_new(this->event_base, this->file_descriptor, EV_READ | EV_PERSIST, LicenceRequest::handleEventRead, this);
|
||||
this->event_write = event_new(this->event_base, this->file_descriptor, EV_WRITE, LicenceRequest::handleEventWrite, this);
|
||||
|
||||
this->state = protocol::CONNECTING; //First set connected, then we could enable the event loop
|
||||
|
||||
event_dispatch = std::thread([&]() {
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
{ /* now we could start listening */
|
||||
lock_guard _lock(this->lock);
|
||||
if(!this->event_read || !this->event_write) return;
|
||||
|
||||
event_add(this->event_read, nullptr);
|
||||
timeval connect_timeout{5, 0};
|
||||
event_add(this->event_write, &connect_timeout);
|
||||
}
|
||||
|
||||
event_base_dispatch(this->event_base);
|
||||
});
|
||||
}
|
||||
|
||||
void LicenceRequest::handleConnected() {
|
||||
this->state = protocol::HANDSCAKE;
|
||||
|
||||
uint8_t handshakeBuffer[4];
|
||||
handshakeBuffer[0] = 0xC0;
|
||||
handshakeBuffer[1] = 0xFF;
|
||||
handshakeBuffer[2] = 0xEE;
|
||||
handshakeBuffer[3] = LICENSE_PROT_VERSION;
|
||||
this->sendPacket(protocol::packet{protocol::PACKET_CLIENT_HANDSHAKE, string((const char*) handshakeBuffer, 4)}); //Initialise packet
|
||||
}
|
||||
|
||||
void LicenceRequest::handleMessage(const std::string& message) {
|
||||
if(message.length() < sizeof(protocol::packet::header)) LICENSE_FERR(this, ConnectionException, "Invalid packet size");
|
||||
protocol::packet packet{protocol::PACKET_DISCONNECT, ""};
|
||||
memcpy(&packet.header, message.data(), sizeof(protocol::packet::header));
|
||||
packet.data = message.substr(sizeof(protocol::packet::header));
|
||||
|
||||
if(!this->cryptKey.empty()) {
|
||||
xorBuffer((char*) packet.data.data(), packet.data.length(), this->cryptKey.data(), this->cryptKey.length());
|
||||
}
|
||||
|
||||
if(packet.header.packetId == protocol::PACKET_SERVER_HANDSHAKE) {
|
||||
this->handlePacketHandshake(packet.data);
|
||||
} else if(packet.header.packetId == protocol::PACKET_DISCONNECT) {
|
||||
this->handlePacketDisconnect(packet.data);
|
||||
} else if(packet.header.packetId == protocol::PACKET_SERVER_VALIDATION_RESPONSE) {
|
||||
this->handlePacketLicenseInfo(packet.data);
|
||||
} else if(packet.header.packetId == protocol::PACKET_SERVER_PROPERTY_ADJUSTMENT) {
|
||||
this->handlePacketInfoAdjustment(packet.data);
|
||||
} else
|
||||
LICENSE_FERR(this, ConnectionException, "Invalid packet id (" + to_string(packet.header.packetId) + ")");
|
||||
}
|
||||
|
||||
void LicenceRequest::disconnect(const std::string& message) {
|
||||
if(this->state != protocol::UNCONNECTED && this->state != protocol::DISCONNECTING)
|
||||
this->sendPacket({protocol::PACKET_DISCONNECT, message});
|
||||
this->closeConnection();
|
||||
//TODO flush?
|
||||
}
|
||||
|
||||
void LicenceRequest::closeConnection() {
|
||||
event *event_read, *event_write;
|
||||
{
|
||||
lock_guard lock(this->lock);
|
||||
if(this->state == protocol::UNCONNECTED) return;
|
||||
|
||||
if(this->event_dispatch.get_id() == this_thread::get_id()) { //We could not close in the same thread as we read/write (we're joining it later)
|
||||
if(this->state == protocol::DISCONNECTING) return;
|
||||
|
||||
this->state = protocol::DISCONNECTING;
|
||||
this->closeThread = new threads::Thread(THREAD_SAVE_OPERATIONS, [&]() { this->closeConnection(); });
|
||||
|
||||
#ifdef DEBUG_LICENSE_CLIENT
|
||||
if(this->verbose) {
|
||||
debugMessage("Running close in a new thread");
|
||||
this->closeThread->name("License request close");
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
this->state = protocol::UNCONNECTED;
|
||||
|
||||
event_read = this->event_read;
|
||||
event_write = this->event_write;
|
||||
|
||||
this->event_write = nullptr;
|
||||
this->event_read = nullptr;
|
||||
}
|
||||
|
||||
if(event_read) {
|
||||
event_del_block(event_read);
|
||||
event_free(event_read);
|
||||
}
|
||||
|
||||
if(event_write) {
|
||||
event_del_block(event_write);
|
||||
event_free(event_write);
|
||||
}
|
||||
|
||||
/* close before base shutdown (else epoll hangup) */
|
||||
if(this->file_descriptor > 0) {
|
||||
shutdown(this->file_descriptor, SHUT_RDWR);
|
||||
close(this->file_descriptor);
|
||||
}
|
||||
this->file_descriptor = 0;
|
||||
|
||||
{
|
||||
lock_guard lock(this->lock);
|
||||
ts::buffer::RawBuffer* buffer;
|
||||
while ((buffer = TAILQ_FIRST(&this->writeQueue))) {
|
||||
TAILQ_REMOVE(&this->writeQueue, buffer, tail);
|
||||
delete buffer;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if(this->event_base) {
|
||||
timeval seconds{1, 0};
|
||||
event_base_loopexit(this->event_base, &seconds);
|
||||
event_base_loopexit(this->event_base, nullptr);
|
||||
}
|
||||
|
||||
if(this->event_dispatch.joinable()) {
|
||||
this->event_dispatch.join();
|
||||
}
|
||||
|
||||
if(this->event_base) {
|
||||
event_base_free(this->event_base);
|
||||
this->event_base = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LICENSE_CLIENT
|
||||
if(this->verbose)
|
||||
debugMessage("Executing close done");
|
||||
#endif
|
||||
}
|
||||
|
||||
void LicenceRequest::abortRequest(const std::chrono::system_clock::time_point &timeout) {
|
||||
this->closeConnection();
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <protocol/buffers.h>
|
||||
#include <ThreadPool/Mutex.h>
|
||||
#include <ThreadPool/Thread.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <event.h>
|
||||
#include "License.h"
|
||||
|
||||
#ifdef DEFINE_HELPER
|
||||
#define LICENSE_FERR(this, class, message) \
|
||||
do { \
|
||||
this->currentException = std::make_shared<exceptions::class>(message); \
|
||||
if(this->currentFuture && this->currentFuture->state() == threads::FutureState::WORKING) this->currentFuture->executionFailed(); \
|
||||
this->disconnect("internal error"); \
|
||||
return; \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
namespace license {
|
||||
namespace exceptions {
|
||||
class CouldNotConnectException : public LicenseException {
|
||||
public:
|
||||
explicit CouldNotConnectException(const std::string &message) : LicenseException(message) {}
|
||||
};
|
||||
|
||||
class ConnectionException : public LicenseException {
|
||||
public:
|
||||
explicit ConnectionException(const std::string &message) : LicenseException(message) {}
|
||||
};
|
||||
|
||||
class UnexcpectedDisconnectException : public LicenseException {
|
||||
public:
|
||||
explicit UnexcpectedDisconnectException(const std::string &message) : LicenseException(message) {}
|
||||
};
|
||||
|
||||
class InvalidResponseException : public LicenseException {
|
||||
public:
|
||||
explicit InvalidResponseException(const std::string &message) : LicenseException(message) {}
|
||||
};
|
||||
}
|
||||
|
||||
struct ServerInfo {
|
||||
std::string unique_identifier;
|
||||
int64_t timestamp;
|
||||
std::string uname;
|
||||
std::string version;
|
||||
};
|
||||
|
||||
struct LicenseRequestResponse {
|
||||
std::shared_ptr<LicenseInfo> license;
|
||||
bool license_valid;
|
||||
|
||||
int64_t speach_varianz_adjustment;
|
||||
bool speach_reset;
|
||||
bool properties_valid;
|
||||
|
||||
std::chrono::system_clock::time_point age;
|
||||
};
|
||||
|
||||
struct LicenseRequestData {
|
||||
std::shared_ptr<License> license = nullptr;
|
||||
std::shared_ptr<ServerInfo> info = nullptr;
|
||||
|
||||
int64_t speach_total = 0;
|
||||
int64_t speach_dead = 0;
|
||||
int64_t speach_online = 0;
|
||||
int64_t speach_varianz = 0;
|
||||
|
||||
int64_t client_online = 0;
|
||||
int64_t web_clients_online = 0;
|
||||
int64_t bots_online = 0;
|
||||
int64_t queries_online = 0;
|
||||
int64_t servers_online = 0;
|
||||
};
|
||||
|
||||
class LicenceRequest {
|
||||
public:
|
||||
typedef threads::Future<std::shared_ptr<LicenseRequestResponse>> ResponseFuture;
|
||||
LicenceRequest(const std::shared_ptr<LicenseRequestData>&, const sockaddr_in&);
|
||||
~LicenceRequest();
|
||||
|
||||
std::shared_ptr<exceptions::LicenseException> exception(){ return this->currentException; }
|
||||
void clearExceptions(){ this->currentException = nullptr; }
|
||||
ResponseFuture requestInfo();
|
||||
void abortRequest(const std::chrono::system_clock::time_point& timeout = std::chrono::system_clock::time_point());
|
||||
|
||||
void sendPacket(const protocol::packet&);
|
||||
|
||||
bool verbose = true;
|
||||
private:
|
||||
std::shared_ptr<LicenseRequestData> data;
|
||||
threads::Future<std::shared_ptr<LicenseRequestResponse>>* currentFuture = nullptr;
|
||||
std::shared_ptr<LicenseRequestResponse> response = nullptr;
|
||||
std::shared_ptr<exceptions::LicenseException> currentException;
|
||||
|
||||
std::recursive_mutex lock;
|
||||
protocol::RequestState state = protocol::UNCONNECTED;
|
||||
|
||||
sockaddr_in remote_address;
|
||||
|
||||
int file_descriptor = 0;
|
||||
std::thread event_dispatch;
|
||||
threads::Thread* closeThread = nullptr;
|
||||
struct event_base* event_base = nullptr;
|
||||
event* event_read = nullptr;
|
||||
event* event_write = nullptr;
|
||||
|
||||
TAILQ_HEAD(, ts::buffer::RawBuffer) writeQueue;
|
||||
|
||||
std::string cryptKey = "";
|
||||
|
||||
void beginRequest();
|
||||
void handleConnected();
|
||||
|
||||
static void handleEventRead(int, short, void*);
|
||||
static void handleEventWrite(int, short, void*);
|
||||
|
||||
void handleMessage(const std::string&);
|
||||
void disconnect(const std::string&);
|
||||
void closeConnection();
|
||||
|
||||
void handlePacketHandshake(const std::string&);
|
||||
void handlePacketDisconnect(const std::string&);
|
||||
void handlePacketLicenseInfo(const std::string&);
|
||||
void handlePacketInfoAdjustment(const std::string&);
|
||||
};
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
#include <misc/endianness.h>
|
||||
#include <LicenseRequest.pb.h>
|
||||
|
||||
#define DEFINE_HELPER
|
||||
#include "LicenseRequest.h"
|
||||
|
||||
using namespace license;
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
|
||||
void LicenceRequest::handlePacketDisconnect(const std::string& message) {
|
||||
if(this->state != protocol::DISCONNECTING)
|
||||
LICENSE_FERR(this, UnexcpectedDisconnectException, "Remote side closed the connection (" + message + ")");
|
||||
}
|
||||
|
||||
void LicenceRequest::handlePacketHandshake(const std::string& data) {
|
||||
if(this->state != protocol::HANDSCAKE) LICENSE_FERR(this, InvalidResponseException, "Protocol state mismatch");
|
||||
if(data.length() < 3) LICENSE_FERR(this, InvalidResponseException, "Invalid packet size");
|
||||
|
||||
if((uint8_t) data[0] != 0xAF || (uint8_t) data[1] != 0xFE) LICENSE_FERR(this, InvalidResponseException, "Invalid handshake");
|
||||
if((uint8_t) data[2] != LICENSE_PROT_VERSION) LICENSE_FERR(this, InvalidResponseException, "Invalid license protocol version. Please update TeaSpeak!");
|
||||
|
||||
auto key_length = be2le16(data.data(), 3);
|
||||
if(data.length() < key_length + 3) LICENSE_FERR(this, InvalidResponseException, "Invalid packet size");
|
||||
this->cryptKey = data.substr(5, key_length);
|
||||
|
||||
ts::proto::license::ServerValidation request;
|
||||
if(this->data->license) {
|
||||
request.set_licensed(true);
|
||||
request.set_license_info(true);
|
||||
request.set_license(exportLocalLicense(this->data->license));
|
||||
} else {
|
||||
request.set_licensed(false);
|
||||
request.set_license_info(false);
|
||||
}
|
||||
request.mutable_info()->set_uname(this->data->info->uname);
|
||||
request.mutable_info()->set_version(this->data->info->version);
|
||||
request.mutable_info()->set_timestamp(this->data->info->timestamp);
|
||||
request.mutable_info()->set_unique_id(this->data->info->unique_identifier);
|
||||
|
||||
this->sendPacket(protocol::packet{protocol::PACKET_CLIENT_SERVER_VALIDATION, request});
|
||||
this->state = protocol::LICENSE_INFO;
|
||||
}
|
||||
|
||||
void LicenceRequest::handlePacketLicenseInfo(const std::string& message) {
|
||||
ts::proto::license::LicenseResponse response;
|
||||
if(!response.ParseFromString(message)) LICENSE_FERR(this, InvalidResponseException, "Could not parse response");
|
||||
|
||||
auto result = make_shared<LicenseRequestResponse>();
|
||||
auto licenseInfo = make_shared<LicenseInfo>();
|
||||
if(!response.has_license_info() && this->data->license) LICENSE_FERR(this, InvalidResponseException, "Missing license info");
|
||||
|
||||
if(this->data->license) {
|
||||
licenseInfo->type = (LicenseType) response.license_info().type();
|
||||
licenseInfo->email = response.license_info().email();
|
||||
licenseInfo->username = response.license_info().username();
|
||||
licenseInfo->first_name = response.license_info().first_name();
|
||||
licenseInfo->last_name = response.license_info().last_name();
|
||||
licenseInfo->creation = system_clock::time_point() + milliseconds(response.license_info().created());
|
||||
licenseInfo->start = system_clock::time_point() + milliseconds(response.license_info().begin());
|
||||
licenseInfo->end = system_clock::time_point() + milliseconds(response.license_info().end());
|
||||
} else {
|
||||
licenseInfo->type = LicenseType::DEMO;
|
||||
licenseInfo->email = "license@teaspeak.de";
|
||||
licenseInfo->username = "WolverinDEV";
|
||||
licenseInfo->first_name = "Max";
|
||||
licenseInfo->last_name = "Musterman";
|
||||
licenseInfo->creation = system_clock::now();
|
||||
licenseInfo->start = system_clock::now();
|
||||
licenseInfo->end = system_clock::time_point();
|
||||
}
|
||||
result->license_valid = response.blacklist().state() == ts::proto::license::VALID; //TODO more detailed
|
||||
result->age = system_clock::now();
|
||||
|
||||
result->license = licenseInfo;
|
||||
this->response = result;
|
||||
|
||||
|
||||
ts::proto::license::PropertyUpdateRequest infos;
|
||||
infos.set_speach_total(this->data->speach_total);
|
||||
infos.set_speach_dead(this->data->speach_dead);
|
||||
infos.set_speach_online(this->data->speach_online);
|
||||
infos.set_speach_varianz(this->data->speach_varianz);
|
||||
|
||||
infos.set_clients_online(this->data->client_online);
|
||||
infos.set_bots_online(this->data->bots_online);
|
||||
infos.set_queries_online(this->data->queries_online);
|
||||
infos.set_servers_online(this->data->servers_online);
|
||||
infos.set_web_clients_online(this->data->web_clients_online);
|
||||
this->sendPacket({protocol::PACKET_CLIENT_PROPERTY_ADJUSTMENT, infos});
|
||||
this->state = protocol::PROPERTY_ADJUSTMENT;
|
||||
}
|
||||
|
||||
void LicenceRequest::handlePacketInfoAdjustment(const std::string& message) {
|
||||
ts::proto::license::PropertyUpdateResponse response;
|
||||
if(!response.ParseFromString(message)) LICENSE_FERR(this, InvalidResponseException, "Could not parse response");
|
||||
|
||||
this->response->properties_valid = response.accepted();
|
||||
this->response->speach_varianz_adjustment = response.speach_varianz_corrector();
|
||||
this->response->speach_reset = response.reset_speach();
|
||||
this->currentFuture->executionSucceed(this->response);
|
||||
this->response = nullptr;
|
||||
|
||||
this->disconnect("query succeeded!");
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
|
||||
#include <protocol/buffers.h>
|
||||
#include <netinet/in.h>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
|
||||
#include "license.h"
|
||||
|
||||
namespace license::client {
|
||||
class LicenseServerClient {
|
||||
public:
|
||||
enum ConnectionState {
|
||||
CONNECTING,
|
||||
INITIALIZING,
|
||||
CONNECTED,
|
||||
DISCONNECTING,
|
||||
|
||||
UNCONNECTED
|
||||
};
|
||||
typedef std::function<void()> callback_connected_t;
|
||||
typedef std::function<void(protocol::PacketType /* type */, const void* /* payload */, size_t /* length */)> callback_message_t;
|
||||
typedef std::function<void(bool /* expected */, const std::string& /* reason */)> callback_disconnect_t;
|
||||
|
||||
explicit LicenseServerClient(const sockaddr_in&, int /* protocol version */);
|
||||
virtual ~LicenseServerClient();
|
||||
|
||||
bool start_connection(std::string& /* error */);
|
||||
void send_message(protocol::PacketType /* type */, const void* /* buffer */, size_t /* length */);
|
||||
void close_connection();
|
||||
|
||||
void disconnect(const std::string& /* reason */, std::chrono::system_clock::time_point /* timeout */);
|
||||
bool await_disconnect();
|
||||
|
||||
|
||||
/*
|
||||
* Events will be called within the event loop.
|
||||
* All methods are save to call.
|
||||
* When close_connection or await_disconnect has been called these methods will not be called anymore.
|
||||
*/
|
||||
callback_message_t callback_message{nullptr};
|
||||
callback_connected_t callback_connected{nullptr};
|
||||
callback_disconnect_t callback_disconnected{nullptr};
|
||||
|
||||
const int protocol_version;
|
||||
private:
|
||||
std::mutex connection_lock{};
|
||||
ConnectionState connection_state{ConnectionState::UNCONNECTED};
|
||||
std::chrono::system_clock::time_point disconnect_timeout{};
|
||||
|
||||
struct Buffer {
|
||||
static Buffer* allocate(size_t /* capacity */);
|
||||
static void free(Buffer* /* ptr */);
|
||||
|
||||
void* data;
|
||||
size_t capacity;
|
||||
size_t fill;
|
||||
size_t offset;
|
||||
|
||||
TAILQ_ENTRY(Buffer) tail;
|
||||
};
|
||||
|
||||
/* modify everything here only within the event base, or when exited when connection_lock is locked */
|
||||
struct {
|
||||
sockaddr_in address{};
|
||||
int file_descriptor{0};
|
||||
|
||||
std::thread event_dispatch{};
|
||||
struct event_base* event_base{nullptr}; /* will be cleaned up by the event loop! */
|
||||
struct event* event_read{nullptr};
|
||||
struct event* event_write{nullptr};
|
||||
} network;
|
||||
|
||||
struct {
|
||||
std::mutex lock{};
|
||||
std::condition_variable notify_empty{};
|
||||
|
||||
Buffer* read{nullptr}; /* must noch be accessed via lock because only the event loop uses it */
|
||||
TAILQ_HEAD(, Buffer) write;
|
||||
} buffers;
|
||||
|
||||
struct {
|
||||
bool initialized{false};
|
||||
std::string crypt_key{};
|
||||
} communication;
|
||||
|
||||
void callback_read(short /* events */);
|
||||
void callback_write(short /* events */);
|
||||
void callback_socket_connected();
|
||||
|
||||
void cleanup_network_resources();
|
||||
|
||||
void handle_data(void*, size_t);
|
||||
void handle_raw_packet(protocol::PacketType /* type */, void* /* payload */, size_t /* length */);
|
||||
void handle_handshake_packet(void* /* payload */, size_t /* length */);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,429 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <ThreadPool/Mutex.h>
|
||||
#include <ThreadPool/Future.h>
|
||||
#include <Variable.h>
|
||||
|
||||
#define LICENSE_VERSION 1
|
||||
#define LICENSE_PROT_VERSION 3
|
||||
#define MAGIC_NUMER 0xBADC0DED
|
||||
|
||||
namespace license {
|
||||
namespace exceptions {
|
||||
class LicenseException : public std::exception {
|
||||
public:
|
||||
LicenseException() = delete;
|
||||
explicit LicenseException(std::string message) : errorMessage(std::move(message)) {}
|
||||
LicenseException(const LicenseException& ref) : errorMessage(ref.errorMessage) {}
|
||||
explicit LicenseException(LicenseException&& ref) : errorMessage(std::move(ref.errorMessage)) {}
|
||||
|
||||
[[nodiscard]] const char* what() const noexcept override;
|
||||
private:
|
||||
std::string errorMessage;
|
||||
};
|
||||
}
|
||||
|
||||
struct LicenseHeader {
|
||||
uint16_t version;
|
||||
const char cryptKey[64]; //The dummy key for data de/encryption
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
namespace v2 {
|
||||
struct LicenseHeader {
|
||||
uint16_t version; /* first 16 bytes const version */
|
||||
uint64_t crypt_key_seed; /* the seed */
|
||||
uint8_t crypt_key_verify_offset; /* the first 8 bits determine how much generations (n * 3) and the rest what value is expected. Due to the loss of 8 bits does the highest 8 bits get xored with the lowerst and 56 bits get compared */
|
||||
uint8_t crypt_key_verify[5];
|
||||
} __attribute__ ((__packed__));
|
||||
static_assert(sizeof(LicenseHeader) == 16);
|
||||
|
||||
struct BodyHeader {
|
||||
uint16_t length_private_data;
|
||||
uint16_t length_hierarchy; /* contains all public data */
|
||||
|
||||
uint8_t checksum_hierarchy[20]; /* SHA1 */
|
||||
uint8_t private_data_sign[64]; /* ed sign from the hierarchy created public key */
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
extern std::array<uint8_t, 32> public_root_key;
|
||||
|
||||
struct HierarchyEntry;
|
||||
struct LicensePrivate;
|
||||
struct LicensePrivateWriteOptions;
|
||||
struct License {
|
||||
public:
|
||||
static std::shared_ptr<License> read(const uint8_t* /* buffer */, size_t /* max size */, uint8_t& /* error */);
|
||||
static std::shared_ptr<License> create(const std::vector<std::shared_ptr<const HierarchyEntry>>& hierarchy, const std::array<uint8_t, 32>& /* precalculated last entry */);
|
||||
/* Note for the write method: Make the private version index configurable, so we could "export" the license */
|
||||
/* Note for the write method: Write "private_buffer" if we're not able to resign the private data. As well enfore (assert) that we have a private buffer (e.g. by the read method) */
|
||||
|
||||
~License();
|
||||
[[nodiscard]] std::vector<std::shared_ptr<const HierarchyEntry>> hierarchy() const { return this->_hierarchy; }
|
||||
bool push_entry(const std::shared_ptr<const HierarchyEntry>& /* entry */, size_t* /* index */ = nullptr);
|
||||
|
||||
bool hierarchy_timestamps_valid();
|
||||
|
||||
template <typename I, typename... Args>
|
||||
bool push_entry(Args&&... args) {
|
||||
std::array<uint8_t, 32> key_private{}, key_public{};
|
||||
if(!this->generate_keypair(key_private.data(), key_public.data())) return false;
|
||||
|
||||
auto entry = I::create(key_public.data(), std::forward<Args>(args)...);
|
||||
if(!entry) return false;
|
||||
|
||||
size_t index;
|
||||
if(!this->push_entry(entry, &index)) return false;
|
||||
|
||||
this->_register_raw_private_key(index, key_private.data());
|
||||
return true;
|
||||
}
|
||||
|
||||
std::array<uint8_t, 32> generate_public_key(const uint8_t* /* public key root */, int /* length */ = -1) const;
|
||||
|
||||
std::string write(uint8_t& /* error */);
|
||||
|
||||
[[nodiscard]] bool private_data_editable() const;
|
||||
bool write_private_data(const LicensePrivateWriteOptions& /* write options */);
|
||||
|
||||
[[nodiscard]] inline uint16_t version() const { return this->_version; }
|
||||
private:
|
||||
License() = default;
|
||||
|
||||
uint16_t _version = 0;
|
||||
|
||||
std::array<uint8_t, 64> private_buffer_sign{};
|
||||
uint8_t* private_buffer = nullptr;
|
||||
size_t private_buffer_length = 0;
|
||||
std::shared_ptr<LicensePrivate> private_data{};
|
||||
|
||||
uint64_t crypt_seed = 0;
|
||||
std::vector<std::shared_ptr<const HierarchyEntry>> _hierarchy{};
|
||||
|
||||
bool generate_keypair(uint8_t* /* private key */, uint8_t* /* public key */);
|
||||
void _register_raw_private_key(size_t /* index */, uint8_t* /* key */);
|
||||
};
|
||||
|
||||
struct LicensePrivateWriteOptions {
|
||||
int precalculated_key_index = -2; /* -2 => Do not write any private keys; -1 => Write everything */
|
||||
};
|
||||
|
||||
struct LicensePrivate {
|
||||
public:
|
||||
static std::shared_ptr<LicensePrivate> read(const std::shared_ptr<License>& /* handle */, uint8_t /* version */, const uint8_t* /* buffer */, size_t /* length */, uint8_t& /* error */);
|
||||
static std::shared_ptr<LicensePrivate> create(const std::shared_ptr<License>& /* handle */, int /* precalculated private key index */, const uint8_t* /* precalculated key */);
|
||||
|
||||
bool private_key_chain_valid();
|
||||
|
||||
[[nodiscard]] bool has_meta(const std::string& key) const { return this->meta_data.count(key) > 0; }
|
||||
[[nodiscard]] std::string get_meta(const std::string& key) const { return this->meta_data.at(key); }
|
||||
void set_meta(const std::string& key, const std::string& value) { this->meta_data[key] = value; }
|
||||
|
||||
/* if target is null just increase the offset! */
|
||||
bool write(uint8_t* /* target */, size_t& /* offset */, size_t /* length */, const LicensePrivateWriteOptions& /* options */);
|
||||
|
||||
void register_raw_private_key(uint8_t /* index */, const uint8_t* /* key */);
|
||||
[[nodiscard]] bool has_raw_private_key(uint8_t /* index */) const;
|
||||
|
||||
[[nodiscard]] bool private_key_calculable(int /* index */) const;
|
||||
bool calculate_private_key(uint8_t* /* response */, uint8_t /* index */) const;
|
||||
private:
|
||||
std::weak_ptr<License> _handle;
|
||||
LicensePrivate() = default;
|
||||
|
||||
int precalculated_private_key_index = -2; /* -2 means not set, -1 means root key */
|
||||
std::array<uint8_t, 32> precalculated_private_key{};
|
||||
std::map<uint8_t, std::array<uint8_t, 32>> private_keys{};
|
||||
std::map<std::string, std::string> meta_data{};
|
||||
};
|
||||
|
||||
namespace hierarchy {
|
||||
struct BodyInterpreter;
|
||||
}
|
||||
|
||||
struct HierarchyEntry {
|
||||
friend struct hierarchy::BodyInterpreter;
|
||||
public:
|
||||
~HierarchyEntry();
|
||||
|
||||
static std::shared_ptr<const HierarchyEntry> read(const uint8_t* /* buffer */, size_t& /* offset */, size_t /* max size */);
|
||||
bool write(uint8_t* /* buffer */, size_t& /* offset */, size_t /* max size */) const;
|
||||
inline size_t write_length() const { return 43 + this->read_body_length; }
|
||||
|
||||
inline uint8_t entry_type() const { return this->_entry_type; }
|
||||
|
||||
template <typename T = std::chrono::system_clock>
|
||||
inline typename T::time_point begin_timestamp() const { return typename T::time_point{} + std::chrono::minutes(this->_timestamp_begin); }
|
||||
|
||||
template <typename T = std::chrono::system_clock>
|
||||
inline typename T::time_point end_timestamp() const { return typename T::time_point{} + std::chrono::minutes(this->_timestamp_end); }
|
||||
|
||||
inline const std::array<uint8_t, 32>& public_key() const { return this->_public_key; }
|
||||
inline std::array<uint8_t, 32>& public_key() {
|
||||
this->_hash_set = false;
|
||||
return this->_public_key;
|
||||
}
|
||||
|
||||
inline const uint8_t* body() const { return this->read_body; }
|
||||
inline size_t body_length() const { return this->read_body_length; }
|
||||
|
||||
template <typename I>
|
||||
inline I interpret_as() const {
|
||||
assert(this->interpretable_as<I>());
|
||||
return I{this->read_body, this->read_body_length};
|
||||
}
|
||||
|
||||
template <typename I>
|
||||
inline bool interpretable_as() const { return I::_type == this->_entry_type; }
|
||||
|
||||
inline bool hash(uint8_t* /* hash result [64] */) const;
|
||||
protected:
|
||||
template <typename T = std::chrono::system_clock>
|
||||
HierarchyEntry(uint8_t type, const uint8_t* public_key, const typename T::time_point& begin, const typename T::time_point& end) {
|
||||
this->_entry_type = type;
|
||||
memcpy(this->_public_key.data(), public_key, this->_public_key.size());
|
||||
this->_timestamp_begin = std::chrono::floor<std::chrono::minutes>(begin.time_since_epoch()).count();
|
||||
this->_timestamp_end = std::chrono::floor<std::chrono::minutes>(end.time_since_epoch()).count();
|
||||
}
|
||||
private:
|
||||
HierarchyEntry() = default;
|
||||
|
||||
mutable std::array<uint8_t, 64> _hash{};
|
||||
mutable bool _hash_set = false;
|
||||
|
||||
uint8_t _entry_type = 0;
|
||||
std::array<uint8_t, 32> _public_key{};
|
||||
|
||||
uint32_t _timestamp_begin = 0; /* Minutes since epoch! */
|
||||
uint32_t _timestamp_end = 0; /* Minutes since epoch! */
|
||||
|
||||
uint8_t* read_body = nullptr;
|
||||
size_t read_body_length = 0;
|
||||
|
||||
bool allocate_read_body(size_t);
|
||||
};
|
||||
|
||||
namespace hierarchy {
|
||||
struct type {
|
||||
enum value : uint8_t {
|
||||
Intermediate = 1,
|
||||
Server = 2,
|
||||
Ephemeral = 8
|
||||
};
|
||||
|
||||
static constexpr const char* name(const value& value) {
|
||||
switch (value) {
|
||||
case Intermediate:
|
||||
return "Intermediate";
|
||||
case Server:
|
||||
return "Server";
|
||||
case Ephemeral:
|
||||
return "Ephemeral";
|
||||
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
};
|
||||
struct BodyInterpreter {
|
||||
public:
|
||||
BodyInterpreter() = delete;
|
||||
|
||||
protected:
|
||||
template <typename T>
|
||||
static std::shared_ptr<HierarchyEntry> _create(
|
||||
const uint8_t *pub_key,
|
||||
const std::chrono::system_clock::time_point &begin,
|
||||
const std::chrono::system_clock::time_point &end,
|
||||
size_t buffer_size, uint8_t*& buffer_ptr
|
||||
) {
|
||||
auto result = std::make_shared<HierarchyEntry>(HierarchyEntry{T::_type, pub_key, begin, end});
|
||||
if(!result || !result->allocate_read_body(buffer_size)) return nullptr;
|
||||
result->read_body_length = buffer_size;
|
||||
buffer_ptr = result->read_body;
|
||||
return result;
|
||||
}
|
||||
|
||||
BodyInterpreter(const uint8_t* memory, size_t length) { this->_memory = memory; this->_length = length; }
|
||||
const uint8_t* _memory = nullptr;
|
||||
size_t _length = 0;
|
||||
};
|
||||
|
||||
struct Intermediate : public BodyInterpreter {
|
||||
public:
|
||||
static constexpr uint8_t _type = type::Intermediate;
|
||||
static std::shared_ptr<const HierarchyEntry> create(
|
||||
const uint8_t* /* public key */,
|
||||
const std::chrono::system_clock::time_point& /* begin */,
|
||||
const std::chrono::system_clock::time_point& /* end */,
|
||||
const std::string& /* description */
|
||||
);
|
||||
|
||||
std::string_view description();
|
||||
private:
|
||||
Intermediate(const uint8_t* memory, size_t length) : BodyInterpreter(memory, length) {}
|
||||
};
|
||||
|
||||
struct Server : public BodyInterpreter {
|
||||
public:
|
||||
static constexpr uint8_t _type = type::Server;
|
||||
static std::shared_ptr<const HierarchyEntry> create(
|
||||
const uint8_t* /* public key */,
|
||||
const std::chrono::system_clock::time_point& /* begin */,
|
||||
const std::chrono::system_clock::time_point& /* end */,
|
||||
|
||||
const std::string& /* email */,
|
||||
const std::optional<std::string>& /* value */
|
||||
);
|
||||
|
||||
std::string_view contact_email();
|
||||
|
||||
bool has_username();
|
||||
std::string_view username();
|
||||
private:
|
||||
Server(const uint8_t* memory, size_t length) : BodyInterpreter(memory, length) {}
|
||||
};
|
||||
|
||||
struct Ephemeral : public BodyInterpreter {
|
||||
public:
|
||||
static constexpr uint8_t _type = type::Ephemeral;
|
||||
static std::shared_ptr<const HierarchyEntry> create(
|
||||
const uint8_t* /* public key */,
|
||||
const std::chrono::system_clock::time_point& /* begin */,
|
||||
const std::chrono::system_clock::time_point& /* end */
|
||||
);
|
||||
private:
|
||||
Ephemeral(const uint8_t* memory, size_t length) : BodyInterpreter(memory, length) {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
enum LicenseType : uint8_t {
|
||||
INVALID,
|
||||
DEMO,
|
||||
PREMIUM,
|
||||
HOSTER,
|
||||
PRIVATE,
|
||||
};
|
||||
|
||||
inline bool isPremiumLicense(LicenseType type){ return type == HOSTER || type == PREMIUM || type == PRIVATE; }
|
||||
|
||||
#define LT_NAMES {"Invalid", "Demo", "Premium", "Hoster", "Private"};
|
||||
extern std::string LicenseTypeNames[5];
|
||||
|
||||
struct License {
|
||||
LicenseHeader header;
|
||||
|
||||
//Crypted part
|
||||
struct {
|
||||
LicenseType type;
|
||||
int64_t endTimestamp;
|
||||
|
||||
const char licenceKey[64]; //The actual key
|
||||
const char licenceOwner[64];
|
||||
|
||||
} __attribute__ ((__packed__)) data;
|
||||
|
||||
inline std::string key() { return std::string(data.licenceKey, 64); }
|
||||
inline std::chrono::time_point<std::chrono::system_clock> end() { return std::chrono::system_clock::time_point() + std::chrono::milliseconds(this->data.endTimestamp); }
|
||||
inline std::string owner() { return std::string(this->data.licenceOwner); } //Scopetita
|
||||
inline bool isValid() { return data.endTimestamp == 0 || std::chrono::system_clock::now() < this->end(); }
|
||||
inline bool isPremium(){ return isPremiumLicense(data.type); }
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct LicenseInfo {
|
||||
LicenseType type;
|
||||
std::string username;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
std::string email;
|
||||
std::chrono::system_clock::time_point start;
|
||||
std::chrono::system_clock::time_point end;
|
||||
std::chrono::system_clock::time_point creation;
|
||||
|
||||
bool deleted{false};
|
||||
uint32_t upgrade_id{0};
|
||||
|
||||
inline bool isValid() { return (end.time_since_epoch().count() == 0 || std::chrono::system_clock::now() < this->end); }
|
||||
};
|
||||
|
||||
extern std::shared_ptr<License> readLocalLicence(const std::string &, std::string &);
|
||||
extern std::string exportLocalLicense(const std::shared_ptr<License>&);
|
||||
extern std::string createLocalLicence(LicenseType type, std::chrono::time_point<std::chrono::system_clock> until, std::string licenseOwner);
|
||||
|
||||
namespace protocol {
|
||||
enum RequestState {
|
||||
UNCONNECTED,
|
||||
CONNECTING,
|
||||
|
||||
HANDSCHAKE,
|
||||
SERVER_VALIDATION,
|
||||
LICENSE_INFO,
|
||||
|
||||
PROPERTY_ADJUSTMENT,
|
||||
LICENSE_UPGRADE,
|
||||
|
||||
MANAGER_AUTHORIZATION,
|
||||
MANAGER_CONNECTED,
|
||||
|
||||
DISCONNECTING
|
||||
};
|
||||
|
||||
enum PacketType : uint8_t {
|
||||
PACKET_CLIENT_HANDSHAKE,
|
||||
PACKET_SERVER_HANDSHAKE,
|
||||
|
||||
PACKET_CLIENT_SERVER_VALIDATION,
|
||||
PACKET_SERVER_VALIDATION_RESPONSE,
|
||||
|
||||
PACKET_CLIENT_PROPERTY_ADJUSTMENT,
|
||||
PACKET_SERVER_PROPERTY_ADJUSTMENT,
|
||||
|
||||
PACKET_CLIENT_AUTH_REQUEST,
|
||||
PACKET_SERVER_AUTH_RESPONSE,
|
||||
PACKET_CLIENT_LICENSE_CREATE_REQUEST,
|
||||
PACKET_SERVER_LICENSE_CREATE_RESPONSE,
|
||||
|
||||
PACKET_CLIENT_LIST_REQUEST,
|
||||
PACKET_SERVER_LIST_RESPONSE,
|
||||
|
||||
PACKET_CLIENT_DELETE_REQUEST,
|
||||
PACKET_CLIENT_DELETE_RESPONSE,
|
||||
|
||||
PACKET_CLIENT_LICENSE_UPGRADE,
|
||||
PACKET_SERVER_LICENSE_UPGRADE_RESPONSE,
|
||||
|
||||
PACKET_PING = 0xF0,
|
||||
PACKET_DISCONNECT = 0xFF
|
||||
};
|
||||
|
||||
struct packet_header {
|
||||
PacketType packetId{0};
|
||||
uint16_t length{0};
|
||||
};
|
||||
|
||||
struct packet {
|
||||
struct {
|
||||
PacketType packetId{0};
|
||||
mutable uint16_t length{0};
|
||||
} header;
|
||||
std::string data;
|
||||
|
||||
inline void prepare() const {
|
||||
this->header.length = (uint16_t) data.length();
|
||||
}
|
||||
|
||||
packet(PacketType packetId, std::string data) : data(std::move(data)), header({packetId, 0}) {}
|
||||
|
||||
#ifdef GOOGLE_PROTOBUF_MESSAGE_H__
|
||||
packet(PacketType packetId, const ::google::protobuf::Message&);
|
||||
#endif
|
||||
packet(PacketType packetId, nullptr_t);
|
||||
};
|
||||
}
|
||||
}
|
||||
//DEFINE_TRANSFORMS(license::LicenseType, uint8_t);
|
||||
@@ -32,6 +32,9 @@ message LicenseCreateRequest {
|
||||
required int64 type = 5;
|
||||
required int64 begin = 6;
|
||||
required int64 end = 7;
|
||||
|
||||
/* if set the license will upgrade automatically */
|
||||
optional bytes old_key = 8;
|
||||
}
|
||||
message LicenseCreateResponse {
|
||||
oneof result {
|
||||
@@ -13,7 +13,6 @@ message Blacklist {
|
||||
optional string reason = 2;
|
||||
}
|
||||
|
||||
|
||||
message LicenseInfo {
|
||||
required bytes key = 1;
|
||||
required string username = 2;
|
||||
@@ -41,13 +40,16 @@ message ServerValidation {
|
||||
required bool licensed = 1;
|
||||
required bool license_info = 2;
|
||||
optional bytes license = 3;
|
||||
optional ServerInfo info = 4; //Change somewhen to required but its currently for lagacy support
|
||||
optional ServerInfo info = 4; //Change somewhere to required but its currently for legacy support
|
||||
}
|
||||
|
||||
message LicenseResponse {
|
||||
required bool valid = 1;
|
||||
optional string invalid_reason = 5; /* in protocol version 2 the blacklist.reason field will contain the message */
|
||||
|
||||
required Blacklist blacklist = 2;
|
||||
optional LicenseInfo license_info = 3; //Only availible when ServerValidation::license_info = true
|
||||
optional LicenseInfo license_info = 3; //Only available when ServerValidation::license_info = true
|
||||
optional bool update_pending = 4; /* if an update is pending */
|
||||
}
|
||||
|
||||
message PropertyUpdateRequest {
|
||||
@@ -61,6 +63,23 @@ message PropertyUpdateRequest {
|
||||
required int64 bots_online = 9;
|
||||
required int64 queries_online = 10;
|
||||
required int64 servers_online = 11;
|
||||
|
||||
optional bytes web_cert_revision = 12;
|
||||
}
|
||||
|
||||
message RequestLicenseUpgrade { }
|
||||
message LicenseUpgradeResponse {
|
||||
required bool valid = 1;
|
||||
oneof result {
|
||||
bytes license_key = 2;
|
||||
string error_message = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message WebCertificate {
|
||||
required bytes revision = 1;
|
||||
required string key = 2;
|
||||
required string certificate = 3;
|
||||
}
|
||||
|
||||
message PropertyUpdateResponse {
|
||||
@@ -69,4 +88,5 @@ message PropertyUpdateResponse {
|
||||
required int64 speach_varianz_corrector = 3;
|
||||
|
||||
optional bool reset_speach = 4;
|
||||
optional WebCertificate web_certificate = 5;
|
||||
}
|
||||
@@ -0,0 +1,527 @@
|
||||
//
|
||||
// Created by WolverinDEV on 23/02/2020.
|
||||
//
|
||||
|
||||
#include <csignal>
|
||||
#include <netinet/tcp.h>
|
||||
#include <event.h>
|
||||
#include <ThreadPool/ThreadHelper.h>
|
||||
#include <misc/endianness.h>
|
||||
#include "shared/include/license/client.h"
|
||||
#include "crypt.h"
|
||||
|
||||
using namespace license::client;
|
||||
|
||||
LicenseServerClient::Buffer* LicenseServerClient::Buffer::allocate(size_t capacity) {
|
||||
static_assert(std::is_trivially_constructible<Buffer>::value);
|
||||
|
||||
const auto allocated_bytes = sizeof(LicenseServerClient::Buffer) + capacity;
|
||||
auto result = malloc(allocated_bytes);
|
||||
if(!result) return nullptr;
|
||||
|
||||
auto buffer = reinterpret_cast<LicenseServerClient::Buffer*>(result);
|
||||
buffer->capacity = capacity;
|
||||
buffer->fill = 0;
|
||||
buffer->offset = 0;
|
||||
buffer->data = (char*) result + sizeof(LicenseServerClient::Buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void LicenseServerClient::Buffer::free(Buffer *ptr) {
|
||||
static_assert(std::is_trivially_destructible<Buffer>::value);
|
||||
|
||||
::free(ptr);
|
||||
}
|
||||
|
||||
LicenseServerClient::LicenseServerClient(const sockaddr_in &address, int pversion) : protocol_version{pversion} {
|
||||
memcpy(&this->network.address, &address, sizeof(address));
|
||||
TAILQ_INIT(&this->buffers.write);
|
||||
|
||||
if(!this->buffers.read)
|
||||
this->buffers.read = Buffer::allocate(1024 * 8);
|
||||
}
|
||||
|
||||
LicenseServerClient::~LicenseServerClient() {
|
||||
this->close_connection();
|
||||
|
||||
if(this->buffers.read)
|
||||
Buffer::free(this->buffers.read);
|
||||
threads::save_join(this->network.event_dispatch, false);
|
||||
}
|
||||
|
||||
bool LicenseServerClient::start_connection(std::string &error) {
|
||||
bool event_dispatch_spawned{false};
|
||||
|
||||
std::unique_lock slock{this->connection_lock};
|
||||
if(this->connection_state != ConnectionState::UNCONNECTED) {
|
||||
error = "invalid connection state";
|
||||
return false;
|
||||
}
|
||||
|
||||
this->connection_state = ConnectionState::CONNECTING;
|
||||
this->communication.initialized = false;
|
||||
|
||||
this->network.file_descriptor = socket(this->network.address.sin_family, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
||||
if(this->network.file_descriptor < 0) {
|
||||
error = "failed to allocate socket";
|
||||
goto error_cleanup;
|
||||
}
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
{
|
||||
auto connect_state = ::connect(this->network.file_descriptor, reinterpret_cast<const sockaddr *>(&this->network.address), sizeof(this->network.address));
|
||||
if(connect_state < 0 && errno != EINPROGRESS) {
|
||||
error = "connect() failed (" + std::string{strerror(errno)} + ")";
|
||||
goto error_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int enabled{1}, disabled{0};
|
||||
if(setsockopt(this->network.file_descriptor, SOL_SOCKET, SO_REUSEADDR, &enabled, sizeof(enabled)) < 0); //CERR("could not set reuse addr");
|
||||
if(setsockopt(this->network.file_descriptor, IPPROTO_TCP, TCP_CORK, &disabled, sizeof(disabled)) < 0); // CERR("could not set no push");
|
||||
|
||||
if(fcntl(this->network.file_descriptor, F_SETFD, fcntl(this->network.file_descriptor, F_GETFL, 0) | FD_CLOEXEC | O_NONBLOCK) < 0); // CERR("Failed to set FD_CLOEXEC and O_NONBLOCK (" + std::to_string(errno) + ")");
|
||||
}
|
||||
|
||||
this->network.event_base = event_base_new();
|
||||
this->network.event_read = event_new(this->network.event_base, this->network.file_descriptor, EV_READ | EV_PERSIST, [](int, short e, void* _this) {
|
||||
auto client = reinterpret_cast<LicenseServerClient*>(_this);
|
||||
client->callback_read(e);
|
||||
}, this);
|
||||
this->network.event_write = event_new(this->network.event_base, this->network.file_descriptor, EV_WRITE, [](int, short e, void* _this) {
|
||||
auto client = reinterpret_cast<LicenseServerClient*>(_this);
|
||||
client->callback_write(e);
|
||||
}, this);
|
||||
|
||||
event_dispatch_spawned = true;
|
||||
this->network.event_dispatch = std::thread([&] {
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
event_add(this->network.event_read, nullptr);
|
||||
|
||||
timeval connect_timeout{5, 0};
|
||||
event_add(this->network.event_write, &connect_timeout);
|
||||
|
||||
auto event_base{this->network.event_base};
|
||||
event_base_loop(event_base, EVLOOP_NO_EXIT_ON_EMPTY);
|
||||
event_base_free(event_base);
|
||||
|
||||
//this ptr might be dangling
|
||||
});
|
||||
|
||||
return true;
|
||||
error_cleanup:
|
||||
this->cleanup_network_resources();
|
||||
if(!event_dispatch_spawned) {
|
||||
event_base_free(this->network.event_base);
|
||||
this->network.event_base = nullptr;
|
||||
}
|
||||
this->connection_state = ConnectionState::UNCONNECTED;
|
||||
return false;
|
||||
}
|
||||
|
||||
void LicenseServerClient::close_connection() {
|
||||
std::unique_lock slock{this->connection_lock};
|
||||
if(this->connection_state == ConnectionState::UNCONNECTED) return;
|
||||
this->connection_state = ConnectionState::UNCONNECTED;
|
||||
|
||||
this->cleanup_network_resources();
|
||||
}
|
||||
|
||||
void LicenseServerClient::cleanup_network_resources() {
|
||||
const auto is_event_loop = this->network.event_dispatch.get_id() == std::this_thread::get_id();
|
||||
|
||||
if(this->network.event_read) {
|
||||
if(is_event_loop) event_del_noblock(this->network.event_read);
|
||||
else event_del_block(this->network.event_read);
|
||||
event_free(this->network.event_read);
|
||||
this->network.event_read = nullptr;
|
||||
}
|
||||
|
||||
if(this->network.event_write) {
|
||||
if(is_event_loop) event_del_noblock(this->network.event_write);
|
||||
else event_del_block(this->network.event_write);
|
||||
event_free(this->network.event_write);
|
||||
this->network.event_write = nullptr;
|
||||
}
|
||||
|
||||
if(this->network.event_base) {
|
||||
event_base_loopexit(this->network.event_base, nullptr);
|
||||
if(!is_event_loop)
|
||||
threads::save_join(this->network.event_dispatch, false);
|
||||
this->network.event_base = nullptr; /* event base has been saved by the event dispatcher and will be freed there */
|
||||
}
|
||||
|
||||
if(this->network.file_descriptor) {
|
||||
::close(this->network.file_descriptor);
|
||||
this->network.file_descriptor = 0;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard block{this->buffers.lock};
|
||||
auto buffer = TAILQ_FIRST(&this->buffers.write);
|
||||
while(buffer) {
|
||||
auto next = TAILQ_NEXT(buffer, tail);
|
||||
Buffer::free(next);
|
||||
buffer = next;
|
||||
}
|
||||
TAILQ_INIT(&this->buffers.write);
|
||||
this->buffers.notify_empty.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
void LicenseServerClient::callback_read(short events) {
|
||||
constexpr static auto buffer_size{1024};
|
||||
|
||||
ssize_t read_bytes{0};
|
||||
char buffer[buffer_size];
|
||||
|
||||
read_bytes = recv(this->network.file_descriptor, buffer, buffer_size, MSG_DONTWAIT);
|
||||
if(read_bytes <= 0) {
|
||||
if(errno == EAGAIN) return;
|
||||
std::unique_lock slock{this->connection_lock};
|
||||
|
||||
std::string disconnect_reason{};
|
||||
bool disconnect_expected{false};
|
||||
switch (this->connection_state) {
|
||||
case ConnectionState::CONNECTING:
|
||||
disconnect_reason = "connect error (" + std::string{strerror(errno)} + ")";
|
||||
disconnect_expected = false;
|
||||
break;
|
||||
case ConnectionState::INITIALIZING:
|
||||
case ConnectionState::CONNECTED:
|
||||
disconnect_reason = "read error (" + std::string{strerror(errno)} + ")";
|
||||
disconnect_expected = false;
|
||||
break;
|
||||
case ConnectionState::DISCONNECTING:
|
||||
disconnect_expected = true;
|
||||
break;
|
||||
case ConnectionState::UNCONNECTED:
|
||||
return; /* we're obsolete */
|
||||
}
|
||||
|
||||
if(auto callback{this->callback_disconnected}; callback) {
|
||||
slock.unlock();
|
||||
callback(disconnect_expected, disconnect_reason);
|
||||
slock.lock();
|
||||
}
|
||||
|
||||
if(this->connection_state != ConnectionState::UNCONNECTED) {
|
||||
this->cleanup_network_resources();
|
||||
this->connection_state = ConnectionState::UNCONNECTED;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this->handle_data(buffer, (size_t) read_bytes);
|
||||
}
|
||||
|
||||
void LicenseServerClient::callback_write(short events) {
|
||||
bool add_write_event{this->connection_state == ConnectionState::DISCONNECTING};
|
||||
if(events & EV_TIMEOUT) {
|
||||
std::unique_lock slock{this->connection_lock};
|
||||
if(this->connection_state == ConnectionState::CONNECTING || this->connection_state == ConnectionState::INITIALIZING) {
|
||||
/* connect timeout */
|
||||
if(auto callback{this->callback_disconnected}; callback) {
|
||||
slock.unlock();
|
||||
callback(false, "connect timeout");
|
||||
slock.lock();
|
||||
}
|
||||
|
||||
if(this->connection_state != ConnectionState::UNCONNECTED) {
|
||||
this->cleanup_network_resources();
|
||||
this->connection_state = ConnectionState::UNCONNECTED;
|
||||
}
|
||||
} else if(this->connection_state == ConnectionState::DISCONNECTING) {
|
||||
/* disconnect timeout */
|
||||
this->cleanup_network_resources();
|
||||
this->connection_state = ConnectionState::UNCONNECTED;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(events & EV_WRITE) {
|
||||
if(this->connection_state == ConnectionState::CONNECTING)
|
||||
this->callback_socket_connected();
|
||||
|
||||
ssize_t written_bytes{0};
|
||||
|
||||
std::unique_lock block{this->buffers.lock};
|
||||
auto buffer = TAILQ_FIRST(&this->buffers.write);
|
||||
if(!buffer) {
|
||||
this->buffers.notify_empty.notify_all();
|
||||
return;
|
||||
}
|
||||
block.unlock();
|
||||
written_bytes = send(this->network.file_descriptor, (char*) buffer->data + buffer->offset, buffer->fill - buffer->offset, MSG_DONTWAIT);
|
||||
|
||||
if(written_bytes <= 0) {
|
||||
if(errno == EAGAIN) goto readd_event;
|
||||
std::unique_lock slock{this->connection_lock};
|
||||
|
||||
std::string disconnect_reason{};
|
||||
bool disconnect_expected{false};
|
||||
switch (this->connection_state) {
|
||||
case ConnectionState::CONNECTING:
|
||||
case ConnectionState::INITIALIZING:
|
||||
case ConnectionState::CONNECTED:
|
||||
disconnect_reason = "write error (" + std::string{strerror(errno)} + ")";
|
||||
disconnect_expected = false;
|
||||
break;
|
||||
case ConnectionState::DISCONNECTING:
|
||||
disconnect_expected = true;
|
||||
break;
|
||||
case ConnectionState::UNCONNECTED:
|
||||
return; /* we're obsolete */
|
||||
}
|
||||
if(auto callback{this->callback_disconnected}; callback) {
|
||||
slock.unlock();
|
||||
callback(disconnect_expected, disconnect_reason);
|
||||
slock.lock();
|
||||
}
|
||||
|
||||
if(this->connection_state != ConnectionState::UNCONNECTED) {
|
||||
this->cleanup_network_resources();
|
||||
this->connection_state = ConnectionState::UNCONNECTED;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
buffer->offset += (size_t) written_bytes;
|
||||
if(buffer->offset >= buffer->fill) {
|
||||
assert(buffer->offset == buffer->fill);
|
||||
block.lock();
|
||||
TAILQ_REMOVE(&this->buffers.write, buffer, tail);
|
||||
if(!TAILQ_FIRST(&this->buffers.write)) {
|
||||
this->buffers.notify_empty.notify_all();
|
||||
} else {
|
||||
add_write_event = true;
|
||||
}
|
||||
block.unlock();
|
||||
Buffer::free(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if(this->network.event_write && add_write_event) {
|
||||
readd_event:
|
||||
auto timeout = this->disconnect_timeout;
|
||||
if(timeout.time_since_epoch().count() == 0)
|
||||
event_add(this->network.event_write, nullptr);
|
||||
else {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
struct timeval t{0, 1};
|
||||
if(now > timeout) {
|
||||
this->callback_write(EV_TIMEOUT);
|
||||
return;
|
||||
} else {
|
||||
auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(timeout - now);
|
||||
auto seconds = std::chrono::duration_cast<std::chrono::seconds>(microseconds);
|
||||
microseconds -= seconds;
|
||||
|
||||
t.tv_usec = microseconds.count();
|
||||
t.tv_sec = seconds.count();
|
||||
}
|
||||
event_add(this->network.event_write, &t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LicenseServerClient::handle_data(void *recv_buffer, size_t length) {
|
||||
auto& buffer = this->buffers.read;
|
||||
assert(buffer);
|
||||
|
||||
if(buffer->capacity - buffer->offset - buffer->fill < length) {
|
||||
if(buffer->capacity - buffer->fill > length) {
|
||||
memcpy(buffer->data, (char*) buffer->data + buffer->offset, buffer->fill);
|
||||
buffer->offset = 0;
|
||||
} else {
|
||||
auto new_buffer = Buffer::allocate(buffer->fill + length);
|
||||
memcpy(new_buffer->data, (char*) buffer->data + buffer->offset, buffer->fill);
|
||||
new_buffer->fill = buffer->fill;
|
||||
Buffer::free(buffer);
|
||||
buffer = new_buffer;
|
||||
}
|
||||
}
|
||||
auto buffer_ptr = (char*) buffer->data;
|
||||
auto& buffer_offset = buffer->offset;
|
||||
auto& buffer_length = buffer->fill;
|
||||
|
||||
memcpy((char*) buffer_ptr + buffer_offset + buffer_length, recv_buffer, length);
|
||||
buffer_length += length;
|
||||
|
||||
while(true) {
|
||||
if(buffer_length < sizeof(protocol::packet_header)) return;
|
||||
|
||||
auto header = reinterpret_cast<protocol::packet_header*>(buffer_ptr + buffer_offset);
|
||||
if(header->length > 1024 * 8) {
|
||||
if(auto callback{this->callback_disconnected}; callback)
|
||||
callback(false, "received a too large message");
|
||||
this->disconnect("received too large message", std::chrono::system_clock::time_point{});
|
||||
return;
|
||||
}
|
||||
|
||||
if(buffer_length < header->length + sizeof(protocol::packet_header)) return;
|
||||
|
||||
this->handle_raw_packet(header->packetId, buffer_ptr + buffer_offset + sizeof(protocol::packet_header), header->length);
|
||||
buffer_offset += header->length + sizeof(protocol::packet_header);
|
||||
buffer_length -= header->length + sizeof(protocol::packet_header);
|
||||
}
|
||||
}
|
||||
|
||||
void LicenseServerClient::send_message(protocol::PacketType type, const void *payload, size_t size) {
|
||||
const auto packet_size = size + sizeof(protocol::packet_header);
|
||||
auto buffer = Buffer::allocate(packet_size);
|
||||
buffer->fill = packet_size;
|
||||
|
||||
auto header = (protocol::packet_header*) buffer->data;
|
||||
header->length = packet_size;
|
||||
header->packetId = type;
|
||||
memcpy((char*) buffer->data + sizeof(protocol::packet_header), payload, size);
|
||||
if(this->communication.initialized)
|
||||
xorBuffer((char*) buffer->data + sizeof(protocol::packet_header), size, this->communication.crypt_key.data(), this->communication.crypt_key.length());
|
||||
|
||||
std::lock_guard clock{this->connection_lock};
|
||||
if(this->connection_state == ConnectionState::UNCONNECTED || !this->network.event_write) {
|
||||
Buffer::free(buffer);
|
||||
return;
|
||||
}
|
||||
{
|
||||
std::lock_guard block{this->buffers.lock};
|
||||
TAILQ_INSERT_TAIL(&this->buffers.write, buffer, tail);
|
||||
}
|
||||
event_add(this->network.event_write, nullptr);
|
||||
}
|
||||
|
||||
void LicenseServerClient::disconnect(const std::string &message, std::chrono::system_clock::time_point timeout) {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
if(now > timeout)
|
||||
timeout = now + std::chrono::seconds{timeout.time_since_epoch().count() ? 1 : 0};
|
||||
|
||||
std::unique_lock clock{this->connection_lock};
|
||||
if(this->connection_state == ConnectionState::DISCONNECTING) {
|
||||
this->disconnect_timeout = std::min(this->disconnect_timeout, timeout);
|
||||
if(this->network.event_write)
|
||||
event_add(this->network.event_write, nullptr); /* let the write update the timeout */
|
||||
return;
|
||||
}
|
||||
this->disconnect_timeout = timeout;
|
||||
|
||||
if(this->connection_state != ConnectionState::INITIALIZING && this->connection_state != ConnectionState::CONNECTED) {
|
||||
clock.unlock();
|
||||
this->close_connection();
|
||||
return;
|
||||
}
|
||||
|
||||
this->connection_state = ConnectionState::DISCONNECTING;
|
||||
if(this->network.event_read)
|
||||
event_del_noblock(this->network.event_read);
|
||||
clock.unlock();
|
||||
|
||||
this->send_message(protocol::PACKET_DISCONNECT, message.data(), message.length());
|
||||
}
|
||||
|
||||
bool LicenseServerClient::await_disconnect() {
|
||||
{
|
||||
std::lock_guard clock{this->connection_lock};
|
||||
if(this->connection_state != ConnectionState::DISCONNECTING)
|
||||
return this->connection_state == ConnectionState::UNCONNECTED;
|
||||
}
|
||||
/* state might change here, but when we're disconnected the write buffer will be empty */
|
||||
std::unique_lock block{this->buffers.lock};
|
||||
while(TAILQ_FIRST(&this->buffers.write))
|
||||
this->buffers.notify_empty.wait(block);
|
||||
|
||||
return std::chrono::system_clock::now() <= this->disconnect_timeout;
|
||||
}
|
||||
|
||||
void LicenseServerClient::callback_socket_connected() {
|
||||
{
|
||||
std::lock_guard clock{this->connection_lock};
|
||||
if(this->connection_state != ConnectionState::CONNECTING) return;
|
||||
this->connection_state = ConnectionState::INITIALIZING;
|
||||
}
|
||||
|
||||
uint8_t handshakeBuffer[4];
|
||||
handshakeBuffer[0] = 0xC0;
|
||||
handshakeBuffer[1] = 0xFF;
|
||||
handshakeBuffer[2] = 0xEE;
|
||||
handshakeBuffer[3] = this->protocol_version;
|
||||
|
||||
this->send_message(protocol::PACKET_CLIENT_HANDSHAKE, handshakeBuffer, 4);
|
||||
}
|
||||
|
||||
void LicenseServerClient::handle_raw_packet(license::protocol::PacketType type, void * buffer, size_t length) {
|
||||
/* decrypt packet */
|
||||
if(this->communication.initialized)
|
||||
xorBuffer((char*) buffer, length, this->communication.crypt_key.data(), this->communication.crypt_key.length());
|
||||
|
||||
if(type == protocol::PACKET_DISCONNECT) {
|
||||
if(auto callback{this->callback_disconnected}; callback)
|
||||
callback(false, std::string{(const char*) buffer, length});
|
||||
this->close_connection();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this->communication.initialized) {
|
||||
if(type != protocol::PACKET_SERVER_HANDSHAKE) {
|
||||
if(auto callback{this->callback_disconnected}; callback)
|
||||
callback(false, "expected handshake packet");
|
||||
this->disconnect("expected handshake packet", std::chrono::system_clock::time_point{});
|
||||
return;
|
||||
}
|
||||
|
||||
this->handle_handshake_packet(buffer, length);
|
||||
this->communication.initialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if(auto callback{this->callback_message}; callback)
|
||||
callback(type, buffer, length);
|
||||
else
|
||||
; //TODO: Print error?
|
||||
}
|
||||
|
||||
void LicenseServerClient::handle_handshake_packet(void *buffer, size_t length) {
|
||||
const auto data_ptr = (const char*) buffer;
|
||||
|
||||
std::string error{};
|
||||
if(this->connection_state != ConnectionState::INITIALIZING) {
|
||||
error = "invalid protocol state";
|
||||
goto handle_error;
|
||||
}
|
||||
|
||||
if(length < 5) {
|
||||
error = "invalid packet size";
|
||||
goto handle_error;
|
||||
}
|
||||
|
||||
if((uint8_t) data_ptr[0] != 0xAF || (uint8_t) data_ptr[1] != 0xFE) {
|
||||
error = "invalid handshake signature";
|
||||
goto handle_error;
|
||||
}
|
||||
if((uint8_t) data_ptr[2] != this->protocol_version) {
|
||||
error = "Invalid license protocol version. Please update TeaSpeak!";
|
||||
goto handle_error;
|
||||
}
|
||||
|
||||
{
|
||||
auto key_length = be2le16(data_ptr, 3);
|
||||
if(length < key_length + 5) {
|
||||
error = "invalid packet size";
|
||||
goto handle_error;
|
||||
}
|
||||
this->communication.crypt_key = std::string(data_ptr + 5, key_length);
|
||||
this->communication.initialized = true;
|
||||
}
|
||||
|
||||
if(auto callback{this->callback_connected}; callback)
|
||||
callback();
|
||||
return;
|
||||
|
||||
handle_error:
|
||||
if(auto callback{this->callback_disconnected}; callback)
|
||||
callback(false, error);
|
||||
this->disconnect(error, std::chrono::system_clock::time_point{});
|
||||
}
|
||||
@@ -0,0 +1,860 @@
|
||||
#include <google/protobuf/message.h>
|
||||
#include <misc/base64.h>
|
||||
#include <random>
|
||||
#include <ed25519/ed25519.h>
|
||||
|
||||
#define NO_OPEN_SSL
|
||||
#include <misc/digest.h>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <ed25519/ge.h>
|
||||
#include <ed25519/sc.h>
|
||||
#include "crypt.h"
|
||||
#include "shared/include/license/license.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
|
||||
inline void generate(char* buffer, size_t length){
|
||||
for(int index = 0; index < length; index++)
|
||||
buffer[index] = (uint8_t) rand();
|
||||
}
|
||||
|
||||
namespace license {
|
||||
std::string LicenseTypeNames[] = LT_NAMES;
|
||||
|
||||
std::shared_ptr<License> readLocalLicence(const std::string& buffer, std::string& error){
|
||||
string bbuffer = base64::decode(buffer);
|
||||
if(bbuffer.length() < sizeof(License)) {
|
||||
error = "invalid size";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto license = static_cast<License *>(malloc(sizeof(License)));
|
||||
memcpy(license, bbuffer.data(), sizeof(License));
|
||||
|
||||
if(license->header.version != LICENSE_VERSION){
|
||||
error = "invalid version (" + to_string(license->header.version) + ")";
|
||||
return nullptr;
|
||||
}
|
||||
xorBuffer(&((char*) license)[sizeof(License::header)], sizeof(License::data), license->header.cryptKey, sizeof(license->header.cryptKey));
|
||||
|
||||
auto hash = digest::sha1(reinterpret_cast<const char *>(&license->data), sizeof(license->data));
|
||||
|
||||
uint64_t checkSum = 0;
|
||||
for(int i = 0; i < SHA_DIGEST_LENGTH; i++)
|
||||
checkSum += (uint8_t) hash[i] << (i % 8);
|
||||
|
||||
if((checkSum ^ *(uint64_t*) &license->header.cryptKey) != MAGIC_NUMER) {
|
||||
error = "invalid check sum";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return shared_ptr<License>(license, [](License* l){
|
||||
if(l) free(l);
|
||||
});
|
||||
}
|
||||
|
||||
std::string exportLocalLicense(const std::shared_ptr<License>& ref){
|
||||
auto copy = static_cast<License *>(malloc(sizeof(License)));
|
||||
memcpy(copy, ref.get(), sizeof(License));
|
||||
|
||||
auto hash = digest::sha1(reinterpret_cast<const char *>(©->data), sizeof(copy->data));
|
||||
|
||||
uint64_t checkSum = 0;
|
||||
for(int i = 0; i < SHA_DIGEST_LENGTH; i++)
|
||||
checkSum += (uint8_t) hash[i] << (i % 8);
|
||||
checkSum ^= MAGIC_NUMER;
|
||||
|
||||
generate(const_cast<char *>(copy->header.cryptKey), sizeof(copy->header.cryptKey));
|
||||
*(uint64_t*) ©->header.cryptKey = checkSum;
|
||||
|
||||
|
||||
xorBuffer(&((char*) copy)[sizeof(License::header)], sizeof(License::data), copy->header.cryptKey, sizeof(copy->header.cryptKey));
|
||||
auto result = base64_encode((const char*) copy, sizeof(License));
|
||||
free(copy);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string createLocalLicence(LicenseType type, std::chrono::system_clock::time_point until, std::string licenseOwner){
|
||||
auto license = shared_ptr<License>(static_cast<License *>(malloc(sizeof(License))), [](License* l) { if(l) free(l); });
|
||||
assert(licenseOwner.length() < sizeof(license->data.licenceOwner));
|
||||
|
||||
license->header.version = LICENSE_VERSION;
|
||||
generate(const_cast<char *>(license->data.licenceKey), sizeof(license->data.licenceKey));
|
||||
generate(const_cast<char *>(license->data.licenceOwner), sizeof(license->data.licenceOwner)); //Crap data :)
|
||||
license->data.type = type;
|
||||
license->data.endTimestamp = duration_cast<milliseconds>(until.time_since_epoch()).count();
|
||||
memcpy((void *) license->data.licenceOwner, licenseOwner.c_str(), strlen(licenseOwner.c_str()) + 1); //Copy the string into it
|
||||
|
||||
return exportLocalLicense(license);
|
||||
}
|
||||
|
||||
const char *exceptions::LicenseException::what() const throw() {
|
||||
return this->errorMessage.c_str();
|
||||
}
|
||||
|
||||
protocol::packet::packet(PacketType packetId, const ::google::protobuf::Message& message) {
|
||||
this->header.packetId = packetId;
|
||||
this->data = message.SerializeAsString();
|
||||
}
|
||||
|
||||
protocol::packet::packet(license::protocol::PacketType packetId, nullptr_t) {
|
||||
this->header.packetId = packetId;
|
||||
this->data = "";
|
||||
}
|
||||
}
|
||||
|
||||
std::array<uint8_t, 32> license::v2::public_root_key = {
|
||||
0x84, 0x54, 0x2c, 0x2b, 0x46, 0x19, 0x05, 0x6c,
|
||||
0x01, 0xd8, 0x61, 0x49, 0x4e, 0x48, 0x47, 0x1e,
|
||||
0x6c, 0x61, 0xfa, 0x6a, 0xde, 0x6b, 0x1c, 0x76,
|
||||
0x3a, 0xeb, 0x2f, 0x39, 0x49, 0x3d, 0x71, 0x35
|
||||
};
|
||||
|
||||
namespace license::v2 {
|
||||
License::~License() {
|
||||
if(this->private_buffer)
|
||||
::free(this->private_buffer);
|
||||
}
|
||||
|
||||
std::shared_ptr<License> License::create(const std::vector<std::shared_ptr<const license::v2::HierarchyEntry>> &hierarchy, const std::array<uint8_t, 32> &prv_key) {
|
||||
auto result = shared_ptr<License>(new License{});
|
||||
|
||||
result->_version = 2;
|
||||
result->crypt_seed = std::mt19937_64{std::random_device{}()}();
|
||||
result->_hierarchy = hierarchy;
|
||||
result->private_data = LicensePrivate::create(result, (int) hierarchy.size() - 1, prv_key.data());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<License> License::read(const uint8_t *buffer, size_t length, uint8_t &error) {
|
||||
auto result = shared_ptr<License>(new License{});
|
||||
|
||||
LicenseHeader header{};
|
||||
BodyHeader body_header{};
|
||||
if(length < sizeof(header) + sizeof(body_header)) {
|
||||
error = 2; /* buffer too small */
|
||||
return nullptr;
|
||||
}
|
||||
memcpy(&header, buffer, sizeof(header));
|
||||
|
||||
if(header.version != 2) {
|
||||
error = 3; /* invalid version */
|
||||
return nullptr;
|
||||
}
|
||||
result->_version = header.version;
|
||||
|
||||
std::mt19937_64 crypt_key_gen{header.crypt_key_seed};
|
||||
|
||||
/* verify the crypt key gen */
|
||||
{
|
||||
crypt_key_gen.discard(header.crypt_key_verify_offset);
|
||||
uint64_t expected = 0;
|
||||
memcpy(&expected, header.crypt_key_verify, 5);
|
||||
|
||||
uint64_t received = crypt_key_gen();
|
||||
received = received ^ (received >> 40UL);
|
||||
received &= 0xFFFFFFFFFFULL;
|
||||
|
||||
if(expected != received) {
|
||||
error = 4; /* invalid key sequence */
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
crypt_key_gen.seed(header.crypt_key_seed);
|
||||
auto decoded_buffer_length = length - sizeof(header);
|
||||
auto decoded_buffer = unique_ptr<uint8_t, decltype(::free)*>{(uint8_t*) malloc(decoded_buffer_length), ::free};
|
||||
if(!decoded_buffer) {
|
||||
error = 1; /* out of memory */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* "decode" the data */
|
||||
{
|
||||
auto index = sizeof(header);
|
||||
auto index_decoded = 0;
|
||||
while(index + 4 < length) {
|
||||
auto& memory = *(uint32_t*) (&*decoded_buffer + index_decoded);
|
||||
memory = *(uint32_t*) (buffer + index);
|
||||
memory ^= (uint32_t) crypt_key_gen();
|
||||
index += 4;
|
||||
index_decoded += 4;
|
||||
}
|
||||
while(index < length) {
|
||||
auto& memory = *(uint8_t*) (&*decoded_buffer + index_decoded);
|
||||
memory = *(uint8_t*) (buffer + index);
|
||||
memory ^= (uint8_t) crypt_key_gen();
|
||||
index++;
|
||||
index_decoded++;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&body_header, &*decoded_buffer, sizeof(body_header));
|
||||
if(decoded_buffer_length < sizeof(body_header) + body_header.length_hierarchy + body_header.length_private_data) {
|
||||
error = 2; /* buffer too small */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto hierarchy_buffer = &*decoded_buffer + sizeof(body_header) + body_header.length_private_data;
|
||||
/* test the checksum for the hierarchy (license data indirectly verified via data_sign) */
|
||||
{
|
||||
uint8_t sha_buffer[20];
|
||||
digest::sha1((char*) hierarchy_buffer, body_header.length_hierarchy, sha_buffer);
|
||||
if(memcmp(sha_buffer, body_header.checksum_hierarchy, 20) != 0) {
|
||||
error = 5; /* checksum does not match */
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* now lets read the hierarchy data */
|
||||
{
|
||||
size_t offset = 0, length = body_header.length_hierarchy;
|
||||
while(offset < length) {
|
||||
auto entry = HierarchyEntry::read(hierarchy_buffer, offset, length);
|
||||
if(!entry) {
|
||||
error = 6; /* failed to read an entry */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
result->_hierarchy.push_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/* verify the given data */
|
||||
auto public_key = result->generate_public_key(public_root_key.data());
|
||||
if(!ed25519_verify(body_header.private_data_sign, &*decoded_buffer + sizeof(body_header), body_header.length_private_data, public_key.data())) {
|
||||
error = 7; /* failed to verify private data */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
memcpy(result->private_buffer_sign.data(), body_header.private_data_sign, 64);
|
||||
|
||||
/* copy the private data */
|
||||
result->private_buffer = (uint8_t*) malloc(body_header.length_private_data);
|
||||
result->private_buffer_length = body_header.length_private_data;
|
||||
memcpy(result->private_buffer, &*decoded_buffer + sizeof(body_header), body_header.length_private_data);
|
||||
|
||||
/* let parse the private data */
|
||||
result->private_data = LicensePrivate::read(result, result->_version, result->private_buffer, result->private_buffer_length, error);
|
||||
if(!result->private_data) {
|
||||
error = 7; /* failed to parse private data */
|
||||
return nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string License::write(uint8_t &error) {
|
||||
if(!this->private_data || !this->private_buffer_length) {
|
||||
error = 2; /* missing private data */
|
||||
return "";
|
||||
}
|
||||
|
||||
/* lets estimate a buffer size */
|
||||
auto buffer_size = sizeof(LicenseHeader) + sizeof(BodyHeader) + this->private_buffer_length;
|
||||
|
||||
for(auto& he : this->_hierarchy)
|
||||
if(!he->write(nullptr, buffer_size, 0)) {
|
||||
error = 3; /* failed to estimate buffer size */
|
||||
return "";
|
||||
}
|
||||
|
||||
auto buffer = unique_ptr<uint8_t, decltype(::free)*>{(uint8_t*) malloc(buffer_size), ::free};
|
||||
LicenseHeader license_header{};
|
||||
BodyHeader body_header{};
|
||||
|
||||
/* first copy the private data */
|
||||
{
|
||||
memcpy(body_header.private_data_sign, this->private_buffer_sign.data(), this->private_buffer_sign.size());
|
||||
memcpy(&*buffer + sizeof(license_header) + sizeof(body_header), this->private_buffer, this->private_buffer_length);
|
||||
body_header.length_private_data = this->private_buffer_length;
|
||||
}
|
||||
|
||||
/* lets write the hierarchy */
|
||||
{
|
||||
auto offset = sizeof(license_header) + sizeof(body_header) + this->private_buffer_length;
|
||||
const auto begin_offset = offset;
|
||||
for(auto& he : this->_hierarchy)
|
||||
if(!he->write(&*buffer, offset, buffer_size)) {
|
||||
error = 3; /* failed to write hierarchy */
|
||||
return "";
|
||||
}
|
||||
|
||||
body_header.length_hierarchy = offset - begin_offset;
|
||||
digest::sha1((char*) &*buffer + begin_offset, body_header.length_hierarchy, body_header.checksum_hierarchy);
|
||||
}
|
||||
|
||||
/* write the body header */
|
||||
memcpy(&*buffer + sizeof(license_header), &body_header, sizeof(body_header));
|
||||
|
||||
/* lets generate the license header */
|
||||
{
|
||||
std::mt19937_64 rnd{std::random_device{}()};
|
||||
|
||||
license_header.version = 2;
|
||||
license_header.crypt_key_seed = rnd();
|
||||
license_header.crypt_key_verify_offset = std::uniform_int_distribution<uint8_t>{}(rnd);
|
||||
|
||||
{
|
||||
rnd.seed(license_header.crypt_key_seed);
|
||||
rnd.discard(license_header.crypt_key_verify_offset);
|
||||
|
||||
uint64_t expected = rnd();
|
||||
expected = expected ^ (expected >> 40UL);
|
||||
expected &= 0xFFFFFFFFFFULL;
|
||||
|
||||
memcpy(license_header.crypt_key_verify, &expected, 5);
|
||||
}
|
||||
}
|
||||
|
||||
/* now lets "encrypt" the body */
|
||||
{
|
||||
std::mt19937_64 crypt_key_gen{license_header.crypt_key_seed};
|
||||
|
||||
auto index = sizeof(license_header);
|
||||
while(index + 4 < buffer_size) {
|
||||
auto& memory = *(uint32_t*) (&*buffer + index);
|
||||
memory = *(uint32_t*) (&*buffer + index);
|
||||
memory ^= (uint32_t) crypt_key_gen();
|
||||
index += 4;
|
||||
}
|
||||
while(index < buffer_size) {
|
||||
auto& memory = *(uint8_t*) (&*buffer + index);
|
||||
memory = *(uint8_t*) (&*buffer + index);
|
||||
memory ^= (uint8_t) crypt_key_gen();
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
/* write the license header */
|
||||
memcpy(&*buffer, &license_header, sizeof(license_header));
|
||||
return std::string((char*) &*buffer, buffer_size);
|
||||
}
|
||||
|
||||
bool License::private_data_editable() const {
|
||||
return this->private_data->private_key_calculable(this->_hierarchy.size() - 1);
|
||||
}
|
||||
|
||||
bool License::write_private_data(const LicensePrivateWriteOptions& write_options) {
|
||||
if(this->_hierarchy.empty()) return false;
|
||||
|
||||
uint8_t private_key[64]; //ed25519_sign requires 64 bytes (may it expects a public key in front?)
|
||||
if(!this->private_data->calculate_private_key(private_key, this->_hierarchy.size() - 1))
|
||||
return false;
|
||||
memcpy(private_key + 32, private_key, 32);
|
||||
|
||||
auto public_key = this->generate_public_key(public_root_key.data());
|
||||
|
||||
size_t length = 0, offset = 0;
|
||||
if(!this->private_data->write(nullptr, length, 65536, write_options))
|
||||
return false;
|
||||
|
||||
if(this->private_buffer)
|
||||
::free(this->private_buffer);
|
||||
this->private_buffer_length = length;
|
||||
this->private_buffer = (uint8_t*) malloc(length);
|
||||
if(!this->private_buffer) return false;
|
||||
|
||||
if(!this->private_data->write(this->private_buffer, offset, length, write_options))
|
||||
return false;
|
||||
|
||||
ed25519_sign(this->private_buffer_sign.data(), this->private_buffer, length, public_key.data(), private_key);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::array<uint8_t, 32> License::generate_public_key(const uint8_t* root_key, int length) const {
|
||||
uint8_t hash_buffer[64];
|
||||
|
||||
ge_p3 parent_key{};
|
||||
ge_cached parent_cached{};
|
||||
|
||||
/* import the main parent key */
|
||||
ge_frombytes_negate_vartime(&parent_key, root_key);
|
||||
|
||||
/* undo the negate */
|
||||
fe_neg(parent_key.X, parent_key.X);
|
||||
fe_neg(parent_key.T, parent_key.T);
|
||||
|
||||
for(const auto& entry : this->_hierarchy) {
|
||||
if(length-- == 0) continue;
|
||||
|
||||
ge_p3 e_pub_key{};
|
||||
ge_frombytes_negate_vartime(&e_pub_key, entry->public_key().data());
|
||||
|
||||
ge_p3_to_cached(&parent_cached, &parent_key);
|
||||
|
||||
/* malloc could fail, but we ignore this for now */
|
||||
if(!entry->hash(hash_buffer)) /* */;
|
||||
|
||||
/* import hash (convert to a valid coordinate) */
|
||||
memset(hash_buffer + 32, 0, 32); /* yes, we have to drop half of the SHA512 hash :( */
|
||||
hash_buffer[0] &= 0xF8U;
|
||||
hash_buffer[31] &= 0x3FU;
|
||||
hash_buffer[31] |= 0x40U;
|
||||
sc_reduce(hash_buffer);
|
||||
|
||||
/* import the clamp data */
|
||||
ge_p3 p3_clamp_mul_pKey{};
|
||||
ge_p2 p2_clamp_mul_pKey{};
|
||||
ge_scalarmult_vartime(&p2_clamp_mul_pKey, hash_buffer, &e_pub_key);
|
||||
ge_p2_to_p3(&p3_clamp_mul_pKey, &p2_clamp_mul_pKey);
|
||||
|
||||
/* add parent with the clamp data */
|
||||
ge_p1p1 a{};
|
||||
ge_add(&a, &p3_clamp_mul_pKey, &parent_cached);
|
||||
|
||||
/* convert stuff back */
|
||||
ge_p3 r2{};
|
||||
ge_p1p1_to_p3(&r2, &a);
|
||||
|
||||
parent_key = r2;
|
||||
}
|
||||
|
||||
std::array<uint8_t, 32> result{};
|
||||
ge_p3_tobytes((uint8_t*) result.data(), &parent_key);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool License::push_entry(const std::shared_ptr<const HierarchyEntry> &entry, size_t* index) {
|
||||
assert(this->private_data);
|
||||
|
||||
auto idx = this->_hierarchy.size();
|
||||
if(idx > 0 && !this->private_data->private_key_calculable(idx - 1))
|
||||
return false;
|
||||
|
||||
if(index)
|
||||
*index = idx;
|
||||
this->_hierarchy.push_back(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef duration<int64_t, ratio<hours::period::num * 24, hours::period::den>> days;
|
||||
typedef duration<int64_t, ratio<days::period::num * 365, days::period::den>> years;
|
||||
|
||||
bool License::hierarchy_timestamps_valid() {
|
||||
system_clock::time_point time_begin{};
|
||||
system_clock::time_point time_end = system_clock::time_point{} + years{5000};
|
||||
|
||||
for(const auto& entry : this->_hierarchy) {
|
||||
auto end = entry->end_timestamp();
|
||||
auto begin = entry->begin_timestamp();
|
||||
if(begin < time_begin)
|
||||
return false;
|
||||
if(end > time_end)
|
||||
return false;
|
||||
|
||||
time_begin = begin;
|
||||
if(end.time_since_epoch().count() != 0) time_end = end;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void License::_register_raw_private_key(size_t index, uint8_t *data) {
|
||||
assert(this->private_data);
|
||||
this->private_data->register_raw_private_key(index, data);
|
||||
}
|
||||
|
||||
bool License::generate_keypair(uint8_t *prv, uint8_t *pbl) {
|
||||
std::random_device rd;
|
||||
std::uniform_int_distribution<uint8_t> d;
|
||||
|
||||
uint8_t root_seed[64];
|
||||
for(auto& e : root_seed)
|
||||
e = d(rd);
|
||||
|
||||
ed25519_create_keypair(pbl, prv, root_seed);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<LicensePrivate> LicensePrivate::create(const std::shared_ptr<license::v2::License> &handle, int key_index, const uint8_t *key) {
|
||||
auto result = shared_ptr<LicensePrivate>(new LicensePrivate{});
|
||||
result->_handle = handle;
|
||||
result->precalculated_private_key_index = key_index;
|
||||
if(key) {
|
||||
memcpy(result->precalculated_private_key.data(), key, result->precalculated_private_key.size());
|
||||
} else {
|
||||
assert(key_index < -1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<LicensePrivate> LicensePrivate::read(const std::shared_ptr<License>& handle, uint8_t version, const uint8_t *buffer, size_t length, uint8_t& error) {
|
||||
if(version != 2) {
|
||||
error = 2; /* invalid version */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto result = LicensePrivate::create(handle, -2, nullptr);
|
||||
|
||||
size_t offset = 0;
|
||||
if((offset + 1) > length)
|
||||
return nullptr;
|
||||
|
||||
/* read the precalculated private key */
|
||||
if(*(buffer + offset++)) {
|
||||
if((offset + 1 + result->precalculated_private_key.size()) > length)
|
||||
return nullptr;
|
||||
|
||||
result->precalculated_private_key_index = *(buffer + offset++);
|
||||
memcpy(result->precalculated_private_key.data(), buffer + offset, result->precalculated_private_key.size());
|
||||
offset += result->precalculated_private_key.size();
|
||||
}
|
||||
|
||||
/* read raw private keys */
|
||||
{
|
||||
if((offset + 1) > length)
|
||||
return nullptr;
|
||||
|
||||
auto private_key_count = *(buffer + offset++);
|
||||
|
||||
if((offset + private_key_count * 33) > length)
|
||||
return nullptr;
|
||||
while(private_key_count-- > 0) {
|
||||
auto index = *(buffer + offset++);
|
||||
result->register_raw_private_key(index, buffer + offset);
|
||||
offset += 32;
|
||||
}
|
||||
}
|
||||
|
||||
/* read the metadata */
|
||||
{
|
||||
if((offset + 4) > length)
|
||||
return nullptr;
|
||||
|
||||
auto meta_data_length = *(uint32_t*) (buffer + offset);
|
||||
offset += 4;
|
||||
|
||||
while(meta_data_length-- > 0) {
|
||||
if((offset + 3) > length)
|
||||
return nullptr;
|
||||
auto key_length = *(buffer + offset++);
|
||||
auto value_length = *(uint16_t*) (buffer + offset);
|
||||
offset += 2;
|
||||
|
||||
if((offset + key_length + value_length) > length)
|
||||
return nullptr;
|
||||
|
||||
result->meta_data[{(char*) buffer + offset, key_length}] = {(char*) buffer + offset + key_length, value_length};
|
||||
offset += key_length;
|
||||
offset += value_length;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LicensePrivate::write(uint8_t *buffer, size_t &offset, size_t length, const LicensePrivateWriteOptions& options) {
|
||||
if(options.precalculated_key_index < -1) {
|
||||
if(buffer) {
|
||||
if((offset + 2) > length) return false;
|
||||
*(buffer + offset++) = 0; /* no precalculated private key */
|
||||
*(buffer + offset++) = 0; /* no raw private keys */
|
||||
} else {
|
||||
offset += 2;
|
||||
}
|
||||
} else {
|
||||
auto index = options.precalculated_key_index == -1 ? this->precalculated_private_key_index : options.precalculated_key_index;
|
||||
if(index < 0) return false; /* we will NEVER write the root key */
|
||||
|
||||
if(buffer) {
|
||||
if((offset + 2 + 32) > length) return false;
|
||||
*(buffer + offset++) = 1;
|
||||
{
|
||||
*(buffer + offset++) = index;
|
||||
|
||||
if(!this->calculate_private_key(buffer + offset, index))
|
||||
return false;
|
||||
offset += 32;
|
||||
}
|
||||
|
||||
if((offset + 1) > length) return false;
|
||||
auto& private_key_count = *(buffer + offset++);
|
||||
private_key_count = 0;
|
||||
for(auto& [key_index, key] : this->private_keys) {
|
||||
if(key_index <= index)
|
||||
continue;
|
||||
|
||||
if((offset + 1 + key.size()) > length) return false;
|
||||
*(buffer + offset++) = key_index;
|
||||
memcpy(buffer + offset, key.data(), key.size());
|
||||
|
||||
private_key_count++;
|
||||
offset += key.size();
|
||||
}
|
||||
} else {
|
||||
/* private precalc key */
|
||||
offset += 2 + 32;
|
||||
|
||||
/* raw keys */
|
||||
offset += 1;
|
||||
for(auto& [key_index, key] : this->private_keys) {
|
||||
if(key_index <= index)
|
||||
continue;
|
||||
|
||||
offset += 1 + key.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(buffer) {
|
||||
if((offset + 4) > length) return false;
|
||||
*(uint32_t*) (buffer + offset) = this->meta_data.size();
|
||||
offset += 4;
|
||||
|
||||
for(auto& [key, value] : this->meta_data) {
|
||||
if((offset + 3 + key.length() + value.length()) > length) return false;
|
||||
|
||||
*(buffer + offset++) = key.length();
|
||||
*(uint16_t*)(buffer + offset) = value.length();
|
||||
offset += 2;
|
||||
|
||||
memcpy(buffer + offset, key.data(), key.length());
|
||||
offset += key.length();
|
||||
|
||||
memcpy(buffer + offset, value.data(), value.length());
|
||||
offset += value.length();
|
||||
}
|
||||
} else {
|
||||
offset += 4;
|
||||
for(auto& [key, value] : this->meta_data)
|
||||
offset += 3 + key.length() + value.length();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LicensePrivate::private_key_chain_valid() {
|
||||
auto handle = this->_handle.lock();
|
||||
if(!handle) return false;
|
||||
|
||||
auto hierarchy = handle->hierarchy();
|
||||
|
||||
auto base_index = this->precalculated_private_key_index;
|
||||
if(base_index >= (int64_t) hierarchy.size()) return false;
|
||||
if(base_index < -1) return true; /* means we don't have a private key */
|
||||
|
||||
while(base_index < hierarchy.size()) {
|
||||
if(!this->has_raw_private_key(base_index++))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LicensePrivate::private_key_calculable(int index) const {
|
||||
auto handle = this->_handle.lock();
|
||||
if(!handle) return false;
|
||||
|
||||
auto hierarchy = handle->hierarchy();
|
||||
if(index >= (int64_t) hierarchy.size()) return false;
|
||||
|
||||
|
||||
auto base_index = this->precalculated_private_key_index;
|
||||
if(base_index > index) return false;
|
||||
if(base_index < -1) return false;
|
||||
|
||||
while(base_index < index) {
|
||||
base_index++;
|
||||
if(this->private_keys.count(base_index) < 1)
|
||||
return false; /* we're missing a private key here, how is this even possible? */
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LicensePrivate::calculate_private_key(uint8_t *buffer, uint8_t index) const {
|
||||
auto handle = this->_handle.lock();
|
||||
if(!handle) return false;
|
||||
|
||||
auto hierarchy = handle->hierarchy();
|
||||
if(index >= hierarchy.size()) return false;
|
||||
|
||||
auto base_index = this->precalculated_private_key_index;
|
||||
if(base_index > index) return false;
|
||||
if(base_index < -1) return false;
|
||||
|
||||
uint8_t hash_buffer[64];
|
||||
memcpy(buffer, this->precalculated_private_key.data(), this->precalculated_private_key.size());
|
||||
while(base_index < index) {
|
||||
base_index++;
|
||||
if(this->private_keys.count(base_index) < 1)
|
||||
return false; /* we're missing a private key here, how is this even possible? */
|
||||
|
||||
if(!hierarchy[index]->hash(hash_buffer)) return false;
|
||||
|
||||
/* import hash (convert to a valid coordinate) */
|
||||
memset(hash_buffer + 32, 0, 32); /* yes, we have to drop half of the SHA512 hash :( */
|
||||
hash_buffer[0] &= 0xF8U;
|
||||
hash_buffer[31] &= 0x3FU;
|
||||
hash_buffer[31] |= 0x40U;
|
||||
sc_reduce(hash_buffer);
|
||||
|
||||
sc_muladd(buffer, this->private_keys.at(base_index).data(), hash_buffer, buffer);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LicensePrivate::register_raw_private_key(uint8_t index, const uint8_t *buffer) {
|
||||
auto& target = this->private_keys[index];
|
||||
memcpy(target.data(), buffer, target.size());
|
||||
}
|
||||
|
||||
bool LicensePrivate::has_raw_private_key(uint8_t index) const {
|
||||
return this->private_keys.count(index) > 0;
|
||||
}
|
||||
|
||||
HierarchyEntry::~HierarchyEntry() {
|
||||
this->allocate_read_body(0);
|
||||
}
|
||||
|
||||
std::shared_ptr<const HierarchyEntry> HierarchyEntry::read(const uint8_t *buffer, size_t &offset, size_t length) {
|
||||
auto result = shared_ptr<HierarchyEntry>(new HierarchyEntry{});
|
||||
if((offset + 43) > length) return nullptr;
|
||||
|
||||
result->_entry_type = *(buffer + offset);
|
||||
offset++;
|
||||
|
||||
memcpy(result->_public_key.data(), buffer + offset, 32);
|
||||
offset += 32;
|
||||
|
||||
memcpy(&result->_timestamp_begin, buffer + offset, 4);
|
||||
offset += 4;
|
||||
|
||||
memcpy(&result->_timestamp_end, buffer + offset, 4);
|
||||
offset += 4;
|
||||
|
||||
uint16_t body_length;
|
||||
memcpy(&body_length, buffer + offset, 2);
|
||||
offset += 2;
|
||||
|
||||
if(body_length > length) return nullptr;
|
||||
if(!result->allocate_read_body(body_length)) return nullptr;
|
||||
|
||||
if(body_length > 0) {
|
||||
result->allocate_read_body(body_length);
|
||||
if(!result->read_body) return nullptr;
|
||||
result->read_body_length = body_length;
|
||||
memcpy(result->read_body, buffer + offset, body_length);
|
||||
offset += body_length;
|
||||
}
|
||||
|
||||
result->_hash_set = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool HierarchyEntry::write(uint8_t *buffer, size_t &offset, size_t length) const {
|
||||
if(buffer && (offset + 43 + this->read_body_length) > length) return false;
|
||||
|
||||
if(buffer) *(buffer + offset) = this->_entry_type;
|
||||
offset++;
|
||||
|
||||
if(buffer) memcpy(buffer + offset, this->_public_key.data(), 32);
|
||||
offset += 32;
|
||||
|
||||
if(buffer) memcpy(buffer + offset, &this->_timestamp_begin, 4);
|
||||
offset += 4;
|
||||
|
||||
if(buffer) memcpy(buffer + offset, &this->_timestamp_end, 4);
|
||||
offset += 4;
|
||||
|
||||
if(buffer) memcpy(buffer + offset, &this->read_body_length, 2);
|
||||
offset += 2;
|
||||
|
||||
if(this->read_body_length > 0) {
|
||||
if(buffer) memcpy(buffer + offset, this->read_body, this->read_body_length);
|
||||
offset += this->read_body_length;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HierarchyEntry::allocate_read_body(size_t size) {
|
||||
if(this->read_body) {
|
||||
::free(this->read_body);
|
||||
this->read_body = nullptr;
|
||||
}
|
||||
|
||||
if(size > 0) {
|
||||
this->read_body = (uint8_t*) malloc(size);
|
||||
if(!this->read_body) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HierarchyEntry::hash(uint8_t *target_buffer) const {
|
||||
if(this->_hash_set) {
|
||||
memcpy(target_buffer, this->_hash.data(), this->_hash.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t length = 43 + this->read_body_length, offset = 0;
|
||||
auto buffer = unique_ptr<uint8_t, decltype(::free)*>((uint8_t*) malloc(length), ::free);
|
||||
if(!buffer) return false;
|
||||
if(this->write(&*buffer, offset, length)) {
|
||||
digest::sha512((char*) &*buffer, length, this->_hash.data());
|
||||
this->_hash_set = true;
|
||||
}
|
||||
|
||||
return this->_hash_set ? this->hash(target_buffer) : false;
|
||||
}
|
||||
|
||||
namespace hierarchy {
|
||||
std::string_view Intermediate::description() {
|
||||
if(this->_length == 0)
|
||||
return {};
|
||||
|
||||
return std::string_view{(const char*) this->_memory + 1, (size_t) *this->_memory};
|
||||
}
|
||||
|
||||
std::shared_ptr<const HierarchyEntry> Intermediate::create(const uint8_t *pub_key, const std::chrono::system_clock::time_point &begin, const std::chrono::system_clock::time_point & end, const std::string &description) {
|
||||
assert(description.size() < 256);
|
||||
auto buffer_length = description.size() + 1;
|
||||
|
||||
uint8_t* buffer;
|
||||
auto result = BodyInterpreter::_create<Intermediate>(pub_key, begin, end, buffer_length, buffer);
|
||||
if(!result) return nullptr;
|
||||
|
||||
memcpy(buffer + 1, description.data(), description.length());
|
||||
*buffer = (uint8_t) description.length();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Server::has_username() {
|
||||
return *(this->_memory + 1) > 0;
|
||||
}
|
||||
|
||||
std::string_view Server::contact_email() {
|
||||
return {(const char*) this->_memory + 2, *this->_memory};
|
||||
}
|
||||
|
||||
std::string_view Server::username() {
|
||||
return {(const char*) this->_memory + 2 + *this->_memory, *(this->_memory + 1)};
|
||||
}
|
||||
|
||||
std::shared_ptr<const HierarchyEntry> Server::create(const uint8_t *pub_key, const std::chrono::system_clock::time_point &begin, const std::chrono::system_clock::time_point & end, const std::string &email, const std::optional<std::string> &username) {
|
||||
assert(email.size() < 256);
|
||||
assert(!username.has_value() || username->size() < 256);
|
||||
auto buffer_length = 2 + email.size() + (username.has_value() ? username->length() : 0);
|
||||
|
||||
uint8_t* buffer;
|
||||
auto result = BodyInterpreter::_create<Intermediate>(pub_key, begin, end, buffer_length, buffer);
|
||||
if(!result) return nullptr;
|
||||
|
||||
memcpy(buffer + 2, email.data(), email.length());
|
||||
*buffer = (uint8_t) email.length();
|
||||
|
||||
if(username.has_value())
|
||||
memcpy(buffer + 2 + email.length(), username->data(), username->length());
|
||||
*(buffer + 1) = (uint8_t) (username.has_value() ? username->length() : 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<const HierarchyEntry> Ephemeral::create(const uint8_t *pub_key, const std::chrono::system_clock::time_point &begin, const std::chrono::system_clock::time_point & end) {
|
||||
uint8_t* buffer;
|
||||
return BodyInterpreter::_create<Ephemeral>(pub_key, begin, end, 0, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
Submodule music updated: af7918a243...ae7f8c7f3d
+214
-218
@@ -3,7 +3,7 @@ project(TeaSpeak-Server)
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
#--allow-multiple-definition
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -Wall -Wno-reorder -Wno-sign-compare -static-libgcc -static-libstdc++ -g -Wl,-no-whole-archive,--no-undefined -pthread ${MEMORY_DEBUG_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -Wall -Wno-reorder -Wno-sign-compare -static-libgcc -static-libstdc++ -g -Wl,--no-whole-archive -pthread ${MEMORY_DEBUG_FLAGS} -Werror=return-type")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3")
|
||||
|
||||
@@ -13,14 +13,14 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/environment/)
|
||||
|
||||
#disable for debug
|
||||
#add_definitions(-DRELEASE_MODE)
|
||||
find_event(ON)
|
||||
|
||||
include_directories(../music/include/)
|
||||
include_directories(../shared/src)
|
||||
include_directories(../license/src)
|
||||
include_directories(../MusicBot/src)
|
||||
include_directories(/usr/local/include/breakpad)
|
||||
include_directories(${LIBRARY_PATH}/tomcrypt/src/headers)
|
||||
include_directories(${LIBRARY_PATH}/spdlog/include)
|
||||
# include_directories(/usr/local/include/breakpad)
|
||||
# include_directories(${LIBRARY_PATH}/tomcrypt/src/headers)
|
||||
|
||||
add_definitions(-DLTM_DESC)
|
||||
add_definitions(-DMUSIC_BOT)
|
||||
@@ -33,281 +33,277 @@ add_definitions(-DUSE_BORINGSSL)
|
||||
option(BUILD_TYPE "Sets the build type" OFF)
|
||||
option(BUILD_TYPE_NAME "Sets the build type name" OFF)
|
||||
option(COMPILE_WEB_CLIENT "Enable/Disable the web cleint future" OFF)
|
||||
set(COMPILE_WEB_CLIENT "ON")
|
||||
#set(COMPILE_WEB_CLIENT "ON")
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
set(SERVER_SOURCE_FILES
|
||||
main.cpp
|
||||
src/client/ConnectedClient.cpp
|
||||
src/client/voice/PrecomputedPuzzles.cpp
|
||||
src/client/voice/VoiceClient.cpp
|
||||
src/client/voice/VoiceClientHandschake.cpp
|
||||
src/client/voice/VoiceClientCommandHandler.cpp
|
||||
src/client/voice/VoiceClientPacketHandler.cpp
|
||||
src/client/voice/VoiceClientView.cpp
|
||||
src/TS3ServerClientManager.cpp
|
||||
src/TSServer.cpp
|
||||
src/TS3ServerHeartbeat.cpp
|
||||
src/SignalHandler.cpp
|
||||
src/server/VoiceServer.cpp
|
||||
src/server/POWHandler.cpp
|
||||
src/client/voice/VoiceClientConnection.cpp
|
||||
src/client/ConnectedClientCommandHandler.cpp
|
||||
src/client/ConnectedClientNotifyHandler.cpp
|
||||
src/ServerManager.cpp
|
||||
src/server/file/FileServer.cpp
|
||||
main.cpp
|
||||
tomcryptTest.cpp
|
||||
MySQLLibSSLFix.c
|
||||
|
||||
src/client/ConnectedClient.cpp
|
||||
src/client/voice/PrecomputedPuzzles.cpp
|
||||
src/client/voice/VoiceClient.cpp
|
||||
src/client/voice/VoiceClientHandschake.cpp
|
||||
src/client/voice/VoiceClientCommandHandler.cpp
|
||||
src/client/voice/VoiceClientPacketHandler.cpp
|
||||
src/client/voice/VoiceClientView.cpp
|
||||
src/TS3ServerClientManager.cpp
|
||||
src/VirtualServer.cpp
|
||||
src/TS3ServerHeartbeat.cpp
|
||||
src/SignalHandler.cpp
|
||||
src/server/VoiceServer.cpp
|
||||
src/server/POWHandler.cpp
|
||||
src/client/voice/VoiceClientConnection.cpp
|
||||
#src/client/ConnectedClientCommandHandler.cpp
|
||||
src/client/command_handler/channel.cpp
|
||||
src/client/command_handler/client.cpp
|
||||
src/client/command_handler/server.cpp
|
||||
src/client/command_handler/misc.cpp
|
||||
|
||||
src/client/ConnectedClientNotifyHandler.cpp
|
||||
src/VirtualServerManager.cpp
|
||||
src/server/file/FileServer.cpp
|
||||
src/channel/ServerChannel.cpp
|
||||
src/channel/ClientChannelView.cpp
|
||||
src/client/file/FileClient.cpp
|
||||
src/client/file/FileClientIO.cpp
|
||||
src/Group.cpp
|
||||
src/manager/BanManager.cpp
|
||||
src/client/InternalClient.cpp
|
||||
#src/weblist/WeblistClient.cpp
|
||||
#src/weblist/WebList.cpp
|
||||
src/client/file/FileClient.cpp
|
||||
src/client/file/FileClientIO.cpp
|
||||
src/Group.cpp
|
||||
src/manager/BanManager.cpp
|
||||
src/client/InternalClient.cpp
|
||||
#src/weblist/WeblistClient.cpp
|
||||
#src/weblist/WebList.cpp
|
||||
|
||||
src/client/DataClient.cpp
|
||||
src/server/QueryServer.cpp
|
||||
src/client/query/QueryClient.cpp
|
||||
src/client/query/QueryClientCommands.cpp
|
||||
src/client/query/QueryClientNotify.cpp
|
||||
src/client/DataClient.cpp
|
||||
src/server/QueryServer.cpp
|
||||
src/client/query/QueryClient.cpp
|
||||
src/client/query/QueryClientCommands.cpp
|
||||
src/client/query/QueryClientNotify.cpp
|
||||
|
||||
|
||||
src/manager/IpListManager.cpp
|
||||
src/manager/IpListManager.cpp
|
||||
|
||||
src/ConnectionStatistics.cpp
|
||||
src/ConnectionStatistics.cpp
|
||||
|
||||
src/manager/TokeManager.cpp
|
||||
src/manager/TokeManager.cpp
|
||||
|
||||
src/terminal/CommandHandler.cpp
|
||||
src/terminal/CommandHandler.cpp
|
||||
|
||||
src/manager/ComplainManager.cpp
|
||||
src/DatabaseHelper.cpp
|
||||
src/manager/ComplainManager.cpp
|
||||
src/DatabaseHelper.cpp
|
||||
|
||||
src/manager/LetterManager.cpp
|
||||
src/manager/PermissionNameManager.cpp
|
||||
src/manager/LetterManager.cpp
|
||||
src/manager/PermissionNameManager.cpp
|
||||
|
||||
tomcryptTest.cpp
|
||||
src/pinteraction/ApplicationInteraction.cpp
|
||||
src/ServerManagerSnapshot.cpp
|
||||
src/ServerManagerSnapshotDeploy.cpp
|
||||
src/client/music/Song.cpp
|
||||
src/music/PlayablePlaylist.cpp
|
||||
src/InstanceHandler.cpp
|
||||
src/InstanceHandlerSetup.cpp
|
||||
|
||||
src/pinteraction/ApplicationInteraction.cpp
|
||||
src/ServerManagerSnapshot.cpp
|
||||
src/ServerManagerSnapshotDeploy.cpp
|
||||
src/client/music/Song.cpp
|
||||
src/music/PlayablePlaylist.cpp
|
||||
src/InstanceHandler.cpp
|
||||
src/InstanceHandlerSetup.cpp
|
||||
src/Configuration.cpp
|
||||
|
||||
src/Configuration.cpp
|
||||
src/build.cpp
|
||||
|
||||
src/build.cpp
|
||||
src/music/MusicPlaylist.cpp
|
||||
src/client/music/MusicClient.cpp
|
||||
src/client/music/MusicClientPlayer.cpp
|
||||
src/client/ConnectedClientTextCommandHandler.cpp
|
||||
src/music/MusicBotManager.cpp
|
||||
src/client/music/internal_provider/channel_replay/ChannelProvider.cpp
|
||||
|
||||
src/music/MusicPlaylist.cpp
|
||||
src/client/music/MusicClient.cpp
|
||||
src/client/music/MusicClientPlayer.cpp
|
||||
src/client/ConnectedClientTextCommandHandler.cpp
|
||||
src/music/MusicBotManager.cpp
|
||||
src/client/music/internal_provider/channel_replay/ChannelProvider.cpp
|
||||
src/geo/GeoLocation.cpp
|
||||
src/geo/IP2Location.cpp
|
||||
src/geo/VPNBlocker.cpp
|
||||
|
||||
src/geo/GeoLocation.cpp
|
||||
src/geo/IP2Location.cpp
|
||||
src/geo/VPNBlocker.cpp
|
||||
src/client/query/XMacroEventTypes.h
|
||||
|
||||
src/client/query/XMacroEventTypes.h
|
||||
src/server/VoiceIOManager.cpp
|
||||
src/server/WebIoManager.cpp
|
||||
src/client/SpeakingClient.cpp
|
||||
|
||||
src/server/VoiceIOManager.cpp
|
||||
src/server/WebIoManager.cpp
|
||||
src/client/SpeakingClient.cpp
|
||||
../shared/src/ssl/SSLManager.cpp
|
||||
|
||||
src/lincense/LicenseHelper.cpp
|
||||
../shared/src/ssl/SSLManager.cpp
|
||||
src/manager/SqlDataManager.cpp
|
||||
|
||||
src/manager/SqlDataManager.cpp
|
||||
src/ShutdownHelper.cpp
|
||||
src/client/music/MusicQueue.cpp
|
||||
src/lincense/TeamSpeakLicense.cpp
|
||||
|
||||
src/ShutdownHelper.cpp
|
||||
src/client/music/MusicQueue.cpp
|
||||
src/lincense/TeamSpeakLicense.cpp
|
||||
src/weblist/WebListManager.cpp
|
||||
src/weblist/TeamSpeakWebClient.cpp
|
||||
|
||||
src/weblist/WebListManager.cpp
|
||||
src/weblist/TeamSpeakWebClient.cpp
|
||||
)
|
||||
if(COMPILE_WEB_CLIENT)
|
||||
add_definitions(-DCOMPILE_WEB_CLIENT)
|
||||
src/manager/ConversationManager.cpp
|
||||
src/client/SpeakingClientHandshake.cpp
|
||||
src/client/command_handler/music.cpp src/client/command_handler/file.cpp)
|
||||
if (COMPILE_WEB_CLIENT)
|
||||
add_definitions(-DCOMPILE_WEB_CLIENT)
|
||||
|
||||
set(SERVER_SOURCE_FILES
|
||||
${SERVER_SOURCE_FILES}
|
||||
set(SERVER_SOURCE_FILES
|
||||
${SERVER_SOURCE_FILES}
|
||||
|
||||
src/server/WebServer.cpp
|
||||
src/client/web/WebClient.cpp
|
||||
# src/server/web/WebRTCServer.cpp
|
||||
src/client/web/WSWebClient.cpp
|
||||
src/client/web/SampleHandler.cpp
|
||||
src/client/SpeakingClientHandshake.cpp
|
||||
src/client/web/VoiceBridge.cpp
|
||||
)
|
||||
endif()
|
||||
src/server/WebServer.cpp
|
||||
src/client/web/WebClient.cpp
|
||||
# src/server/web/WebRTCServer.cpp
|
||||
src/client/web/WSWebClient.cpp
|
||||
src/client/web/SampleHandler.cpp
|
||||
src/client/web/VoiceBridge.cpp
|
||||
src/client/command_handler/helpers.h src/music/PlaylistPermissions.cpp src/music/PlaylistPermissions.h src/lincense/LicenseService.cpp src/lincense/LicenseService.h)
|
||||
endif ()
|
||||
|
||||
add_executable(PermHelper helpers/permgen.cpp)
|
||||
target_link_libraries(PermHelper
|
||||
${LIBRARY_PATH_ED255}
|
||||
${LIBRARY_PATH_ED255}
|
||||
|
||||
TeaSpeak #Static
|
||||
TeaLicenseHelper #Static
|
||||
TeaMusic #Static
|
||||
${LIBRARY_PATH_THREAD_POOL} #Static
|
||||
${LIBRARY_PATH_TERMINAL} #Static
|
||||
${LIBRARY_PATH_VARIBALES}
|
||||
${LIBRARY_PATH_YAML}
|
||||
pthread
|
||||
stdc++fs
|
||||
${LIBEVENT_PATH}/libevent.a
|
||||
${LIBEVENT_PATH}/libevent_pthreads.a
|
||||
${LIBRARY_PATH_OPUS}
|
||||
${LIBRARY_PATH_JSON}
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
TeaSpeak #Static
|
||||
TeaLicenseHelper #Static
|
||||
TeaMusic #Static
|
||||
${LIBRARY_PATH_THREAD_POOL} #Static
|
||||
${LIBRARY_PATH_TERMINAL} #Static
|
||||
${LIBRARY_PATH_VARIBALES}
|
||||
${LIBRARY_PATH_YAML}
|
||||
pthread
|
||||
stdc++fs
|
||||
${LIBEVENT_PATH}/libevent.a
|
||||
${LIBEVENT_PATH}/libevent_pthreads.a
|
||||
${LIBRARY_PATH_OPUS}
|
||||
${LIBRARY_PATH_JSON}
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
|
||||
#${LIBWEBRTC_LIBRARIES} #ATTENTIAN! WebRTC does not work with crypto! (Already contains a crypto version)
|
||||
${LIBRARY_TOM_CRYPT}
|
||||
${LIBRARY_TOM_MATH}
|
||||
#${LIBWEBRTC_LIBRARIES} #ATTENTIAN! WebRTC does not work with crypto! (Already contains a crypto version)
|
||||
${LIBRARY_TOM_CRYPT}
|
||||
${LIBRARY_TOM_MATH}
|
||||
|
||||
#We're forsed to use boringssl caused by the fact that boringssl is already within webrtc!
|
||||
#We're forsed to use boringssl caused by the fact that boringssl is already within webrtc!
|
||||
|
||||
#Require a so
|
||||
sqlite3
|
||||
#Require a so
|
||||
sqlite3
|
||||
|
||||
${LIBRARY_PATH_BREAKPAD}
|
||||
${LIBRARY_PATH_JDBC}
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
${LIBRARY_PATH_BREAKPAD}
|
||||
${LIBRARY_PATH_JDBC}
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
|
||||
${LIBRARY_PATH_DATA_PIPES}
|
||||
${LIBRARY_PATH_BORINGSSL_SSL}
|
||||
${LIBRARY_PATH_BORINGSSL_CRYPTO}
|
||||
dl
|
||||
jemalloc
|
||||
)
|
||||
${LIBRARY_PATH_DATA_PIPES}
|
||||
${LIBRARY_PATH_BORINGSSL_SSL}
|
||||
${LIBRARY_PATH_BORINGSSL_CRYPTO}
|
||||
dl
|
||||
jemalloc
|
||||
)
|
||||
|
||||
add_executable(PermMapHelper helpers/PermMapGen.cpp)
|
||||
target_link_libraries(PermMapHelper
|
||||
${LIBRARY_PATH_ED255}
|
||||
${LIBRARY_PATH_ED255}
|
||||
|
||||
TeaSpeak #Static
|
||||
TeaLicenseHelper #Static
|
||||
TeaMusic #Static
|
||||
${LIBRARY_PATH_THREAD_POOL} #Static
|
||||
${LIBRARY_PATH_TERMINAL} #Static
|
||||
${LIBRARY_PATH_VARIBALES}
|
||||
${LIBRARY_PATH_YAML}
|
||||
pthread
|
||||
stdc++fs
|
||||
${LIBEVENT_PATH}/libevent.a
|
||||
${LIBEVENT_PATH}/libevent_pthreads.a
|
||||
${LIBRARY_PATH_OPUS}
|
||||
${LIBRARY_PATH_JSON}
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
TeaSpeak #Static
|
||||
TeaLicenseHelper #Static
|
||||
TeaMusic #Static
|
||||
${LIBRARY_PATH_THREAD_POOL} #Static
|
||||
${LIBRARY_PATH_TERMINAL} #Static
|
||||
${LIBRARY_PATH_VARIBALES}
|
||||
${LIBRARY_PATH_YAML}
|
||||
pthread
|
||||
stdc++fs
|
||||
${LIBEVENT_PATH}/libevent.a
|
||||
${LIBEVENT_PATH}/libevent_pthreads.a
|
||||
${LIBRARY_PATH_OPUS}
|
||||
${LIBRARY_PATH_JSON}
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
|
||||
#${LIBWEBRTC_LIBRARIES} #ATTENTIAN! WebRTC does not work with crypto! (Already contains a crypto version)
|
||||
${LIBRARY_TOM_CRYPT}
|
||||
${LIBRARY_TOM_MATH}
|
||||
#${LIBWEBRTC_LIBRARIES} #ATTENTIAN! WebRTC does not work with crypto! (Already contains a crypto version)
|
||||
${LIBRARY_TOM_CRYPT}
|
||||
${LIBRARY_TOM_MATH}
|
||||
|
||||
#We're forsed to use boringssl caused by the fact that boringssl is already within webrtc!
|
||||
#We're forsed to use boringssl caused by the fact that boringssl is already within webrtc!
|
||||
|
||||
#Require a so
|
||||
sqlite3
|
||||
#Require a so
|
||||
sqlite3
|
||||
|
||||
${LIBRARY_PATH_BREAKPAD}
|
||||
${LIBRARY_PATH_JDBC}
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
${LIBRARY_PATH_BREAKPAD}
|
||||
${LIBRARY_PATH_JDBC}
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
|
||||
${LIBRARY_PATH_DATA_PIPES}
|
||||
${LIBRARY_PATH_BORINGSSL_SSL}
|
||||
${LIBRARY_PATH_BORINGSSL_CRYPTO}
|
||||
dl
|
||||
jemalloc
|
||||
)
|
||||
${LIBRARY_PATH_DATA_PIPES}
|
||||
${LIBRARY_PATH_BORINGSSL_SSL}
|
||||
${LIBRARY_PATH_BORINGSSL_CRYPTO}
|
||||
dl
|
||||
jemalloc
|
||||
)
|
||||
|
||||
|
||||
SET(CPACK_PACKAGE_VERSION_MAJOR "1")
|
||||
SET(CPACK_PACKAGE_VERSION_MINOR "3")
|
||||
SET(CPACK_PACKAGE_VERSION_PATCH "26")
|
||||
if(BUILD_TYPE_NAME EQUAL OFF)
|
||||
SET(CPACK_PACKAGE_VERSION_DATA "beta")
|
||||
elseif(BUILD_TYPE_NAME STREQUAL "")
|
||||
SET(CPACK_PACKAGE_VERSION_DATA "")
|
||||
else()
|
||||
SET(CPACK_PACKAGE_VERSION_DATA "-${BUILD_TYPE_NAME}")
|
||||
endif()
|
||||
if(BUILD_TYPE EQUAL OFF)
|
||||
SET(BUILD_TYPE "1")
|
||||
endif()
|
||||
SET(CPACK_PACKAGE_VERSION_MINOR "4")
|
||||
SET(CPACK_PACKAGE_VERSION_PATCH "10")
|
||||
if (BUILD_TYPE_NAME EQUAL OFF)
|
||||
SET(CPACK_PACKAGE_VERSION_DATA "beta")
|
||||
elseif (BUILD_TYPE_NAME STREQUAL "")
|
||||
SET(CPACK_PACKAGE_VERSION_DATA "")
|
||||
else ()
|
||||
SET(CPACK_PACKAGE_VERSION_DATA "-${BUILD_TYPE_NAME}")
|
||||
endif ()
|
||||
if (NOT BUILD_TYPE AND NOT BUILD_TYPE STREQUAL "0")
|
||||
SET(BUILD_TYPE "3")
|
||||
endif ()
|
||||
set_source_files_properties(src/build.cpp PROPERTIES
|
||||
COMPILE_FLAGS "-DBUILD_MAJOR=${CPACK_PACKAGE_VERSION_MAJOR} -DBUILD_MINOR=${CPACK_PACKAGE_VERSION_MINOR} -DBUILD_PATCH=${CPACK_PACKAGE_VERSION_PATCH} -DBUILD_DATA=\"${CPACK_PACKAGE_VERSION_DATA}\" -DBUILD_TYPE=${BUILD_TYPE} -DBUILD_COUNT=0")
|
||||
COMPILE_FLAGS "-DBUILD_MAJOR=${CPACK_PACKAGE_VERSION_MAJOR} -DBUILD_MINOR=${CPACK_PACKAGE_VERSION_MINOR} -DBUILD_PATCH=${CPACK_PACKAGE_VERSION_PATCH} -DBUILD_DATA=\"${CPACK_PACKAGE_VERSION_DATA}\" -DBUILD_TYPE=${BUILD_TYPE} -DBUILD_COUNT=0")
|
||||
file(WRITE repro/env/buildVersion.txt "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}${CPACK_PACKAGE_VERSION_DATA}")
|
||||
|
||||
add_executable(TeaSpeakServer ${SERVER_SOURCE_FILES})
|
||||
target_link_libraries(TeaSpeakServer
|
||||
${LIBRARY_PATH_THREAD_POOL} #Static
|
||||
TeaSpeak #Static
|
||||
TeaLicenseHelper #Static
|
||||
TeaMusic #Static
|
||||
${LIBRARY_PATH_TERMINAL} #Static
|
||||
${LIBRARY_PATH_VARIBALES}
|
||||
${LIBRARY_PATH_YAML}
|
||||
pthread
|
||||
stdc++fs
|
||||
${LIBEVENT_PATH}/libevent.a
|
||||
${LIBEVENT_PATH}/libevent_pthreads.a
|
||||
${LIBRARY_PATH_OPUS}
|
||||
${LIBRARY_PATH_JSON}
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
threadpool::static #Static
|
||||
TeaSpeak #Static
|
||||
TeaLicenseHelper #Static
|
||||
TeaMusic #Static
|
||||
CXXTerminal::static #Static
|
||||
${StringVariable_LIBRARIES_STATIC}
|
||||
${YAML_CPP_LIBRARIES}
|
||||
pthread
|
||||
stdc++fs
|
||||
libevent::core libevent::pthreads
|
||||
opus::static
|
||||
yaml-cpp
|
||||
|
||||
#We're forsed to use boringssl caused by the fact that boringssl is already within webrtc!
|
||||
#Require a so
|
||||
sqlite3
|
||||
DataPipes::rtc::shared
|
||||
|
||||
#Require a so
|
||||
sqlite3
|
||||
breakpad::static
|
||||
protobuf::libprotobuf
|
||||
jemalloc::shared
|
||||
|
||||
${LIBRARY_PATH_BREAKPAD}
|
||||
${LIBRARY_PATH_PROTOBUF}
|
||||
tomcrypt::static
|
||||
tommath::static
|
||||
|
||||
#${LIBWEBRTC_LIBRARIES} #ATTENTIAN! WebRTC does not work with crypto! (Already contains a crypto version)
|
||||
${LIBRARY_TOM_CRYPT}
|
||||
${LIBRARY_TOM_MATH}
|
||||
|
||||
mysqlclient.a
|
||||
z
|
||||
|
||||
${LIBRARY_PATH_ED255}
|
||||
jsoncpp_lib
|
||||
${ed25519_LIBRARIES_STATIC}
|
||||
)
|
||||
|
||||
if(${COMPILE_WEB_CLIENT})
|
||||
find_package(LibNice REQUIRED)
|
||||
find_package(UsrSCTP REQUIRED)
|
||||
target_link_libraries(TeaSpeakServer
|
||||
LibNice::LibNice
|
||||
${LIBRARY_PATH_DATA_PIPES}
|
||||
)
|
||||
endif()
|
||||
if (COMPILE_WEB_CLIENT)
|
||||
target_link_libraries(TeaSpeakServer ${glib20_DIR}/lib/x86_64-linux-gnu/libffi.so.7 ${nice_DIR}/lib/libnice.so.10)
|
||||
endif ()
|
||||
|
||||
include_directories(${LIBRARY_PATH}/boringssl/include/)
|
||||
target_link_libraries(TeaSpeakServer
|
||||
${LIBRARY_PATH_BORINGSSL_SSL}
|
||||
${LIBRARY_PATH_BORINGSSL_CRYPTO}
|
||||
dl
|
||||
openssl::ssl::shared
|
||||
openssl::crypto::shared
|
||||
dl
|
||||
z
|
||||
rt # For clock_gettime
|
||||
)
|
||||
|
||||
#check_include_file(mysql.h HAVE_MYSQL_MYSQL_H)
|
||||
#if (NOT HAVE_MYSQL_MYSQL_H)
|
||||
# check_include_file(mysql.h HAVE_MYSQL_H)
|
||||
# if (NOT HAVE_MYSQL_H)
|
||||
# message(FATAL_ERROR "Missing MySQL header")
|
||||
# endif ()
|
||||
#endif ()
|
||||
|
||||
set(DISABLE_JEMALLOC ON)
|
||||
if(NOT DISABLE_JEMALLOC)
|
||||
target_link_libraries(TeaSpeakServer
|
||||
jemalloc
|
||||
)
|
||||
add_definitions(-DHAVE_JEMALLOC)
|
||||
endif()
|
||||
|
||||
#Fix RPATH
|
||||
#patchelf --set-rpath ./libs/ TeaSpeakServer
|
||||
#patchelf --remove-rpath TeaSpeakServer
|
||||
|
||||
#add_custom_command(
|
||||
# TARGET TeaSpeakServer
|
||||
## COMMAND bash -c "patchelf --set-rpath ./libs/ ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}TeaSpeakServer"
|
||||
# COMMAND bash -c "patchelf --remove-rpath ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}TeaSpeakServer"
|
||||
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
# COMMENT "Cleaning RPATH"
|
||||
#)
|
||||
if (NOT DISABLE_JEMALLOC)
|
||||
target_link_libraries(TeaSpeakServer
|
||||
jemalloc
|
||||
)
|
||||
add_definitions(-DHAVE_JEMALLOC)
|
||||
endif ()
|
||||
@@ -3,3 +3,8 @@ Build opus:
|
||||
|
||||
Build libevent 2.1.8 (with -fPIC)
|
||||
|
||||
|
||||
|
||||
Local licenses test:
|
||||
Base: AQDm4ty6AAAAACnNuqvy++NGfMJU+Bvo5412Wi5jM5/JmmYyDbcxWKNaJV0FF1jpXtSrss3Gm7RUEQ6CdEEhPdyH5OLcugAAAAAp9cb+t1r6P5zGt9fi+QbAOroWM7LqY0B+iy055XrZxX+r8bfP50esuU9qypU9DUtnE9+qJ2gZmOgHcVkHJ4JhN4Db2ZmOkA4dpjGWfY2L6QJanPCy6HsVOm1/1LasZv9Om1/4uWHYLfab0n2+FNajxbcyDY3FAI6+rLBlQzGErtE=
|
||||
New: AQCJON26AAAAACnNuqvy++NGfMJU+Bvo5412Wi5jM5/JmmYyDbcxWKNaJV0FF1jpXtSrss3Gm7RUEQ6CdEEhPdyHizjdugAAAAAp6d+xUgRteE54jqv3OXoRS946xsWKUtJBFkB4pPMT1+pIrXhM3/CTWjpXG8KDLoa1DEjwguolTXJ+RCvySR7Bd4Db2ZmOkA4dpjGWfY2L6QJ3bxZH8OTPFlV/1lU9x1r5QPPOpFmZt68h6VZDz4y9AVNXO+JZPHu24Pre7hTnyhg=
|
||||
@@ -0,0 +1,108 @@
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/cipher.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const EVP_CIPHER *EVP_aes_128_cfb1(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_192_cfb1(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_256_cfb1(void){ return 0; }
|
||||
|
||||
const EVP_CIPHER *EVP_aes_128_cfb8(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_192_cfb8(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_256_cfb8(void){ return 0; }
|
||||
|
||||
const EVP_CIPHER *EVP_aes_128_cfb128(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_192_cfb128(void){ return 0; }
|
||||
const EVP_CIPHER *EVP_aes_256_cfb128(void){ return 0; }
|
||||
|
||||
int EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) {
|
||||
return EVP_EncryptFinal_ex(ctx, out, out_len);
|
||||
}
|
||||
|
||||
int EVP_DecryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) {
|
||||
return EVP_DecryptFinal_ex(ctx, out, out_len);
|
||||
}
|
||||
|
||||
int SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DTLSv1_get_timeout DTLSv1_get_timeout
|
||||
#define DTLSv1_handle_timeout DTLSv1_handle_timeout
|
||||
#define SSL_CTX_add0_chain_cert SSL_CTX_add0_chain_cert
|
||||
#define SSL_CTX_add1_chain_cert SSL_CTX_add1_chain_cert
|
||||
#define SSL_CTX_add_extra_chain_cert SSL_CTX_add_extra_chain_cert
|
||||
#define SSL_CTX_clear_extra_chain_certs SSL_CTX_clear_extra_chain_certs
|
||||
#define SSL_CTX_clear_chain_certs SSL_CTX_clear_chain_certs
|
||||
#define SSL_CTX_clear_mode SSL_CTX_clear_mode
|
||||
#define SSL_CTX_clear_options SSL_CTX_clear_options
|
||||
#define SSL_CTX_get0_chain_certs SSL_CTX_get0_chain_certs
|
||||
#define SSL_CTX_get_extra_chain_certs SSL_CTX_get_extra_chain_certs
|
||||
#define SSL_CTX_get_max_cert_list SSL_CTX_get_max_cert_list
|
||||
#define SSL_CTX_get_mode SSL_CTX_get_mode
|
||||
#define SSL_CTX_get_options SSL_CTX_get_options
|
||||
#define SSL_CTX_get_read_ahead SSL_CTX_get_read_ahead
|
||||
#define SSL_CTX_get_session_cache_mode SSL_CTX_get_session_cache_mode
|
||||
#define SSL_CTX_get_tlsext_ticket_keys SSL_CTX_get_tlsext_ticket_keys
|
||||
#define SSL_CTX_need_tmp_RSA SSL_CTX_need_tmp_RSA
|
||||
#define SSL_CTX_sess_get_cache_size SSL_CTX_sess_get_cache_size
|
||||
#define SSL_CTX_sess_number SSL_CTX_sess_number
|
||||
#define SSL_CTX_sess_set_cache_size SSL_CTX_sess_set_cache_size
|
||||
#define SSL_CTX_set0_chain SSL_CTX_set0_chain
|
||||
#define SSL_CTX_set1_chain SSL_CTX_set1_chain
|
||||
#define SSL_CTX_set1_curves SSL_CTX_set1_curves
|
||||
#define SSL_CTX_set_max_cert_list SSL_CTX_set_max_cert_list
|
||||
#define SSL_CTX_set_max_send_fragment SSL_CTX_set_max_send_fragment
|
||||
#define SSL_CTX_set_mode SSL_CTX_set_mode
|
||||
#define SSL_CTX_set_msg_callback_arg SSL_CTX_set_msg_callback_arg
|
||||
#define SSL_CTX_set_options SSL_CTX_set_options
|
||||
#define SSL_CTX_set_read_ahead SSL_CTX_set_read_ahead
|
||||
#define SSL_CTX_set_session_cache_mode SSL_CTX_set_session_cache_mode
|
||||
#define SSL_CTX_set_tlsext_servername_arg SSL_CTX_set_tlsext_servername_arg
|
||||
#define SSL_CTX_set_tlsext_servername_callback \
|
||||
SSL_CTX_set_tlsext_servername_callback
|
||||
#define SSL_CTX_set_tlsext_ticket_key_cb SSL_CTX_set_tlsext_ticket_key_cb
|
||||
#define SSL_CTX_set_tlsext_ticket_keys SSL_CTX_set_tlsext_ticket_keys
|
||||
#define SSL_CTX_set_tmp_dh SSL_CTX_set_tmp_dh
|
||||
#define SSL_CTX_set_tmp_ecdh SSL_CTX_set_tmp_ecdh
|
||||
#define SSL_CTX_set_tmp_rsa SSL_CTX_set_tmp_rsa
|
||||
#define SSL_add0_chain_cert SSL_add0_chain_cert
|
||||
#define SSL_add1_chain_cert SSL_add1_chain_cert
|
||||
#define SSL_clear_chain_certs SSL_clear_chain_certs
|
||||
#define SSL_clear_mode SSL_clear_mode
|
||||
#define SSL_clear_options SSL_clear_options
|
||||
#define SSL_get0_certificate_types SSL_get0_certificate_types
|
||||
#define SSL_get0_chain_certs SSL_get0_chain_certs
|
||||
#define SSL_get_max_cert_list SSL_get_max_cert_list
|
||||
#define SSL_get_mode SSL_get_mode
|
||||
#define SSL_get_options SSL_get_options
|
||||
#define SSL_get_secure_renegotiation_support \
|
||||
SSL_get_secure_renegotiation_support
|
||||
#define SSL_need_tmp_RSA SSL_need_tmp_RSA
|
||||
#define SSL_num_renegotiations SSL_num_renegotiations
|
||||
#define SSL_session_reused SSL_session_reused
|
||||
#define SSL_set0_chain SSL_set0_chain
|
||||
#define SSL_set1_chain SSL_set1_chain
|
||||
#define SSL_set1_curves SSL_set1_curves
|
||||
#define SSL_set_max_cert_list SSL_set_max_cert_list
|
||||
#define SSL_set_max_send_fragment SSL_set_max_send_fragment
|
||||
#define SSL_set_mode SSL_set_mode
|
||||
#define SSL_set_msg_callback_arg SSL_set_msg_callback_arg
|
||||
#define SSL_set_mtu SSL_set_mtu
|
||||
#define SSL_set_options SSL_set_options
|
||||
#define SSL_set_tlsext_host_name SSL_set_tlsext_host_name
|
||||
#define SSL_set_tmp_dh SSL_set_tmp_dh
|
||||
#define SSL_set_tmp_ecdh SSL_set_tmp_ecdh
|
||||
#define SSL_set_tmp_rsa SSL_set_tmp_rsa
|
||||
#define SSL_total_renegotiations SSL_total_renegotiations
|
||||
|
||||
long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
@@ -1,11 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -e "build.data" ]; then
|
||||
echo "File exists"
|
||||
DATA=$(cat "build.data")
|
||||
echo "File exists"
|
||||
DATA=$(cat "build.data")
|
||||
else
|
||||
echo "Create new file"
|
||||
echo "0" > "build.data"
|
||||
echo "Create new file"
|
||||
echo "0" > "build.data"
|
||||
fi
|
||||
|
||||
DATA=$(($DATA+1))
|
||||
|
||||
Executable
+114
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#WARNING: Any spaces within the path will cause trouble!
|
||||
|
||||
#ldd -d
|
||||
if [[ ! -f "$1" ]]; then
|
||||
echo "Missing target file ($1)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# This is a multidimensional array
|
||||
# key /* library file */ => (library name; library file; dependencies ())
|
||||
declare -A collected_libraries
|
||||
|
||||
# This is a one dimensional array
|
||||
# key /* library file */ => use count
|
||||
declare -A collected_libraries_use_count
|
||||
|
||||
declare -A libraries_of_result
|
||||
function libraries_of {
|
||||
local buffer
|
||||
local index
|
||||
local data
|
||||
|
||||
buffer=$(ldd -d "$1")
|
||||
index=0
|
||||
|
||||
libraries_of_result=()
|
||||
|
||||
IFS=$'\n'
|
||||
for line in ${buffer}; do
|
||||
index=$(($index + 1))
|
||||
[[ ${index} == 1 ]] && continue
|
||||
IFS=$' ' data=(${line})
|
||||
|
||||
# We trim the leading and tailing white spaces
|
||||
_key=$(echo "${data[0]}" | sed -e 's/^[[:space:]]*//')
|
||||
_value=$(echo "${data[2]}" | sed -e 's/^[[:space:]]*//')
|
||||
libraries_of_result["${_key}"]="${_value}"
|
||||
done
|
||||
|
||||
[[ $? -ne 0 ]] && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
function print_lookup_stack {
|
||||
index_max=${#@}
|
||||
index_args="$@"
|
||||
|
||||
#echo -n -e "\r\033[K"
|
||||
echo ""
|
||||
for (( index = 0; index < $index_max; ++index )); do
|
||||
arg=$(eval echo \$$((${index} + 1)))
|
||||
echo -n $(basename ${arg})
|
||||
[[ $(($index + 1)) -lt ${index_max} ]] && echo -n " => "
|
||||
done
|
||||
#sleep 1
|
||||
}
|
||||
|
||||
declare -a libraries_of_deep_stack
|
||||
function libraries_of_deep {
|
||||
local IFS
|
||||
local valid_libraries
|
||||
local inner_array
|
||||
local result_array
|
||||
|
||||
libraries_of $1
|
||||
|
||||
valid_libraries=()
|
||||
#echo "Gathered libraries for $1:"
|
||||
for library_name in "${!libraries_of_result[@]}"; do
|
||||
[[ -z "${libraries_of_result[$library_name]}" ]] && {
|
||||
#echo " The dependency $library_name for $1 could not be resolved"
|
||||
continue
|
||||
}
|
||||
|
||||
#echo " $library_name at ${libraries_of_result[$library_name]}";
|
||||
valid_libraries+=("${libraries_of_result[$library_name]}")
|
||||
done
|
||||
|
||||
IFS=$';' inner_array="${valid_libraries[*]}"
|
||||
IFS=$' ' result_array=("$(basename $1)" "$1" "$inner_array")
|
||||
collected_libraries[$1]="${result_array[@]}"
|
||||
|
||||
libraries_of_deep_stack+=($1)
|
||||
print_lookup_stack ${libraries_of_deep_stack[@]}
|
||||
|
||||
for library_path in "${valid_libraries[@]}"; do
|
||||
# echo "Looking up library path $library_path"
|
||||
[[ ! -z "${collected_libraries[$library_path]}" ]] && {
|
||||
#echo "Library $library_path already resolved"
|
||||
collected_libraries_use_count[$library_path]=$((${collected_libraries_use_count[$library_path]} + 1))
|
||||
continue
|
||||
}
|
||||
#echo "Resolving libraries for path $library_path"
|
||||
collected_libraries_use_count[$library_path]=1
|
||||
libraries_of_deep ${library_path}
|
||||
#library_name
|
||||
done
|
||||
unset 'libraries_of_deep_stack[${#libraries_of_deep_stack[@]}-1]';
|
||||
}
|
||||
|
||||
libraries_of_deep $1
|
||||
echo -e -n "\r\033[K" #Clear the stack
|
||||
|
||||
for key in "${!collected_libraries[@]}"; do
|
||||
IFS=$' ' library_data=(${collected_libraries[$key]})
|
||||
IFS=$';' libraries=(${library_data[2]})
|
||||
|
||||
echo "Got library ${library_data[0]} (${library_data[1]}) directly used ${collected_libraries_use_count[$key]} times:"
|
||||
for library in "${libraries[@]}"; do
|
||||
echo " $library"
|
||||
done
|
||||
done
|
||||
@@ -1,80 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="general">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>General</string>
|
||||
</attribute>
|
||||
<widget class="QPushButton" name="pushButton_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>260</x>
|
||||
<y>180</y>
|
||||
<width>181</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Stop Instance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="ts::gui::ServerTabWidget" name="servers">
|
||||
<attribute name="title">
|
||||
<string>Servers</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Log</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>19</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ts::gui::ServerTabWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>src/ServerTabWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 8.6 KiB |
@@ -57,18 +57,18 @@ struct Group {
|
||||
deque<permission::update::UpdatePermission> permissions;
|
||||
};
|
||||
|
||||
map<Target, map<string, string>> property_mapping = {
|
||||
map<Target, map<string, vector<string>>> property_mapping = {
|
||||
{TARGET_QUERY, {
|
||||
{"Guest Server Query", "serverinstance_guest_serverquery_group"},
|
||||
{"Admin Server Query", "serverinstance_admin_serverquery_group"}
|
||||
{"Guest Server Query", {"serverinstance_guest_serverquery_group"}},
|
||||
{"Admin Server Query", {"serverinstance_admin_serverquery_group"}}
|
||||
}},
|
||||
{TARGET_SERVER, {
|
||||
{"Server Admin", "serverinstance_template_serveradmin_group"},
|
||||
{"Guest", "serverinstance_template_serverdefault_group"}
|
||||
{"Server Admin", {"serverinstance_template_serveradmin_group"}},
|
||||
{"Guest", {"serverinstance_template_serverdefault_group", "serverinstance_template_musicdefault_group"}}
|
||||
}},
|
||||
{TARGET_CHANNEL, {
|
||||
{"Channel Admin", "serverinstance_template_channeladmin_group"},
|
||||
{"Guest", "serverinstance_template_channeldefault_group"}
|
||||
{"Channel Admin", {"serverinstance_template_channeladmin_group"}},
|
||||
{"Guest", {"serverinstance_template_channeldefault_group"}}
|
||||
}},
|
||||
};
|
||||
|
||||
@@ -125,7 +125,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
deque<Group> groups;
|
||||
{
|
||||
ifstream file("../helpers/server_groups_new"); /* the new file is already mapped! */
|
||||
ifstream file("../helpers/server_groups"); /* the new file is already mapped! */
|
||||
string line;
|
||||
while (read_line(file, line))
|
||||
{
|
||||
@@ -242,7 +242,8 @@ int main(int argc, char** argv) {
|
||||
of << "--start" << endl;
|
||||
of << "name:" << group.name << endl;
|
||||
of << "target:" << group.target << endl;
|
||||
of << "property:" << property_mapping[group.target][group.name] << endl;
|
||||
for(const auto& property : property_mapping[group.target][group.name])
|
||||
of << "property:" << property << endl;
|
||||
for(const auto& perm : group.permissions) {
|
||||
of << "permission:" << perm.name << "=" << perm.value << "," << perm.granted << "," << perm.skipped << "," << perm.negated << endl;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
+208
-219
@@ -1,13 +1,13 @@
|
||||
#include <client/linux/handler/exception_handler.h>
|
||||
#include <iostream>
|
||||
#include <misc/endianness.h>
|
||||
#include <misc/strobf.h>
|
||||
#include <CXXTerminal/QuickTerminal.h>
|
||||
#include <event2/thread.h>
|
||||
#include <log/LogUtils.h>
|
||||
#include <ThreadPool/Timer.h>
|
||||
|
||||
#include "src/Configuration.h"
|
||||
#include "src/TSServer.h"
|
||||
#include "src/VirtualServer.h"
|
||||
#include "src/InstanceHandler.h"
|
||||
#include "src/server/QueryServer.h"
|
||||
#include "src/server/file/FileServer.h"
|
||||
@@ -55,29 +55,29 @@ class CLIParser{
|
||||
this->tokens.emplace_back(argv[i]);
|
||||
}
|
||||
|
||||
std::deque<std::string> getCmdOptions(const std::string &option) const {
|
||||
std::deque<std::string> result;
|
||||
std::deque<std::string> getCmdOptions(const std::string &option) const {
|
||||
std::deque<std::string> result;
|
||||
|
||||
auto itr = this->tokens.begin();
|
||||
while(true) {
|
||||
itr = std::find(itr, this->tokens.end(), option);
|
||||
if (itr != this->tokens.end() && ++itr != this->tokens.end()){
|
||||
result.push_back(*itr);
|
||||
itr++;
|
||||
} else break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
auto itr = this->tokens.begin();
|
||||
while(true) {
|
||||
itr = std::find(itr, this->tokens.end(), option);
|
||||
if (itr != this->tokens.end() && ++itr != this->tokens.end()){
|
||||
result.push_back(*itr);
|
||||
itr++;
|
||||
} else break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::deque<std::string> getCmdOptionsBegins(const std::string &option) const {
|
||||
std::deque<std::string> result;
|
||||
std::deque<std::string> getCmdOptionsBegins(const std::string &option) const {
|
||||
std::deque<std::string> result;
|
||||
|
||||
for(const auto& token : this->tokens)
|
||||
if(token.find(option) == 0)
|
||||
result.push_back(token);
|
||||
for(const auto& token : this->tokens)
|
||||
if(token.find(option) == 0)
|
||||
result.push_back(token);
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::string& get_option(const std::string &option) const {
|
||||
auto itr = std::find(this->tokens.begin(), this->tokens.end(), option);
|
||||
@@ -102,36 +102,33 @@ void __raise_exception (void **addr, void *id);
|
||||
#define T(address) \
|
||||
std::cout << "Testing: " << address << " => "; \
|
||||
{\
|
||||
sockaddr_storage storage;\
|
||||
net::resolve_address(address, storage);\
|
||||
std::cout << manager.contains(storage) << std::endl;\
|
||||
sockaddr_storage storage;\
|
||||
net::resolve_address(address, storage);\
|
||||
std::cout << manager.contains(storage) << std::endl;\
|
||||
}
|
||||
|
||||
#define CONFIG_NAME "config.yml"
|
||||
const char *malloc_conf = ""; //retain:false"; //,dirty_decay_ms:0";
|
||||
int main(int argc, char** argv) {
|
||||
#ifdef HAVE_JEMALLOC
|
||||
(void*) malloc_conf;
|
||||
(void*) malloc_conf;
|
||||
#endif
|
||||
|
||||
CLIParser arguments(argc, argv);
|
||||
SSL_load_error_strings();
|
||||
OpenSSL_add_ssl_algorithms();
|
||||
ts::permission::setup_permission_resolve();
|
||||
ts::permission::setup_permission_resolve();
|
||||
|
||||
{
|
||||
u_char buffer[SHA512_DIGEST_LENGTH];
|
||||
SHA512_CTX md{};
|
||||
SHA512_Init(&md);
|
||||
SHA512_Update(&md, "Hello World", 11);
|
||||
SHA512_Final(buffer,&md);
|
||||
}
|
||||
{
|
||||
auto evthread_use_pthreads_result = evthread_use_pthreads();
|
||||
assert(evthread_use_pthreads_result == 0);
|
||||
}
|
||||
terminal::install();
|
||||
if(!terminal::active()){ cerr << "could not setup terminal!" << endl; return -1; }
|
||||
{
|
||||
auto evthread_use_pthreads_result = evthread_use_pthreads();
|
||||
assert(evthread_use_pthreads_result == 0);
|
||||
(void) evthread_use_pthreads_result;
|
||||
}
|
||||
|
||||
if(!arguments.cmdOptionExists("--no-terminal")) {
|
||||
terminal::install();
|
||||
if(!terminal::active()){ cerr << "could not setup terminal!" << endl; return -1; }
|
||||
}
|
||||
assert(ts::property::impl::validateUnique());
|
||||
|
||||
if(arguments.cmdOptionExists("--help") || arguments.cmdOptionExists("-h")) {
|
||||
@@ -139,87 +136,87 @@ int main(int argc, char** argv) {
|
||||
logMessageFmt(true, LOG_GENERAL, "Available command line parameters:");
|
||||
logMessageFmt(true, LOG_GENERAL, HELP_FMT, "-h", "--help", "Shows this page");
|
||||
logMessageFmt(true, LOG_GENERAL, HELP_FMT, "-q", "--set_query_password", "Changed the server admin query password");
|
||||
logMessageFmt(true, LOG_GENERAL, HELP_FMT, "-P<property>=<value>", "--property:<property>=<value>", "Override a config value manual");
|
||||
logMessageFmt(true, LOG_GENERAL, HELP_FMT, "-l", "--property-list", "List all available properties");
|
||||
logMessageFmt(true, LOG_GENERAL, HELP_FMT, "-P<property>=<value>", "--property:<property>=<value>", "Override a config value manual");
|
||||
logMessageFmt(true, LOG_GENERAL, HELP_FMT, "-l", "--property-list", "List all available properties");
|
||||
terminal::uninstall();
|
||||
return 0;
|
||||
}
|
||||
if(arguments.cmdOptionExists("--property-list") || arguments.cmdOptionExists("-l")) {
|
||||
logMessageFmt(true, LOG_GENERAL, "Available properties:");
|
||||
auto properties = ts::config::create_bindings();
|
||||
for(const auto& property : properties) {
|
||||
logMessageFmt(true, LOG_GENERAL, " " + property->key);
|
||||
for(const auto& entry : property->description) {
|
||||
if(entry.first.empty()) {
|
||||
for(const auto& line : entry.second)
|
||||
logMessageFmt(true, LOG_GENERAL, " " + line);
|
||||
} else {
|
||||
logMessageFmt(true, LOG_GENERAL, " " + entry.first + ":");
|
||||
for(const auto& line : entry.second)
|
||||
logMessageFmt(true, LOG_GENERAL, " " + line);
|
||||
}
|
||||
}
|
||||
logMessageFmt(true, LOG_GENERAL, " " + property->value_description());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if(arguments.cmdOptionExists("--property-list") || arguments.cmdOptionExists("-l")) {
|
||||
logMessageFmt(true, LOG_GENERAL, "Available properties:");
|
||||
auto properties = ts::config::create_bindings();
|
||||
for(const auto& property : properties) {
|
||||
logMessageFmt(true, LOG_GENERAL, " " + property->key);
|
||||
for(const auto& entry : property->description) {
|
||||
if(entry.first.empty()) {
|
||||
for(const auto& line : entry.second)
|
||||
logMessageFmt(true, LOG_GENERAL, " " + line);
|
||||
} else {
|
||||
logMessageFmt(true, LOG_GENERAL, " " + entry.first + ":");
|
||||
for(const auto& line : entry.second)
|
||||
logMessageFmt(true, LOG_GENERAL, " " + line);
|
||||
}
|
||||
}
|
||||
logMessageFmt(true, LOG_GENERAL, " " + property->value_description());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!arguments.cmdOptionExists("--valgrind")) {
|
||||
ts::syssignal::setup();
|
||||
}
|
||||
ts::syssignal::setup_threads();
|
||||
if(!arguments.cmdOptionExists("--valgrind")) {
|
||||
ts::syssignal::setup();
|
||||
}
|
||||
ts::syssignal::setup_threads();
|
||||
|
||||
map<string, string> override_settings;
|
||||
{
|
||||
auto short_override = arguments.getCmdOptionsBegins("-P");
|
||||
for(const auto& entry : short_override) {
|
||||
if(entry.length() < 2) continue;
|
||||
auto ei = entry.find('=');
|
||||
if(ei == string::npos || ei == 2) {
|
||||
logErrorFmt(true, LOG_GENERAL, "Invalid command line parameter. (\"" + entry + "\")");
|
||||
return 1;
|
||||
}
|
||||
map<string, string> override_settings;
|
||||
{
|
||||
auto short_override = arguments.getCmdOptionsBegins("-P");
|
||||
for(const auto& entry : short_override) {
|
||||
if(entry.length() < 2) continue;
|
||||
auto ei = entry.find('=');
|
||||
if(ei == string::npos || ei == 2) {
|
||||
logErrorFmt(true, LOG_GENERAL, "Invalid command line parameter. (\"" + entry + "\")");
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto key = entry.substr(2, ei - 2);
|
||||
auto value = entry.substr(ei + 1);
|
||||
override_settings[key] = value;
|
||||
}
|
||||
}
|
||||
{
|
||||
auto short_override = arguments.getCmdOptionsBegins("--property:");
|
||||
for(const auto& entry : short_override) {
|
||||
if(entry.length() < 11) continue;
|
||||
auto ei = entry.find('=');
|
||||
if(ei == string::npos || ei == 11) {
|
||||
logErrorFmt(true, LOG_GENERAL, "Invalid command line parameter. (\"" + entry + "\")");
|
||||
return 1;
|
||||
}
|
||||
auto key = entry.substr(2, ei - 2);
|
||||
auto value = entry.substr(ei + 1);
|
||||
override_settings[key] = value;
|
||||
}
|
||||
}
|
||||
{
|
||||
auto short_override = arguments.getCmdOptionsBegins("--property:");
|
||||
for(const auto& entry : short_override) {
|
||||
if(entry.length() < 11) continue;
|
||||
auto ei = entry.find('=');
|
||||
if(ei == string::npos || ei == 11) {
|
||||
logErrorFmt(true, LOG_GENERAL, "Invalid command line parameter. (\"" + entry + "\")");
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto key = entry.substr(11, ei - 11);
|
||||
auto value = entry.substr(ei + 1);
|
||||
override_settings[key] = value;
|
||||
}
|
||||
}
|
||||
auto key = entry.substr(11, ei - 11);
|
||||
auto value = entry.substr(ei + 1);
|
||||
override_settings[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto bindings = ts::config::create_bindings();
|
||||
for(const auto& setting : bindings) {
|
||||
for(auto it = override_settings.begin(); it != override_settings.end(); it++) {
|
||||
if(it->first == setting->key) {
|
||||
try {
|
||||
setting->read_argument(it->second);
|
||||
} catch(const std::exception& ex) {
|
||||
logErrorFmt(true, LOG_GENERAL, "Failed to apply value for given property '" + it->first + "': " + ex.what());
|
||||
}
|
||||
override_settings.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(const auto& entry : override_settings) {
|
||||
logMessageFmt(true, LOG_GENERAL, "Missing property " + entry.first + ". Value unused!");
|
||||
}
|
||||
}
|
||||
{
|
||||
auto bindings = ts::config::create_bindings();
|
||||
for(const auto& setting : bindings) {
|
||||
for(auto it = override_settings.begin(); it != override_settings.end(); it++) {
|
||||
if(it->first == setting->key) {
|
||||
try {
|
||||
setting->read_argument(it->second);
|
||||
} catch(const std::exception& ex) {
|
||||
logErrorFmt(true, LOG_GENERAL, "Failed to apply value for given property '" + it->first + "': " + ex.what());
|
||||
}
|
||||
override_settings.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(const auto& entry : override_settings) {
|
||||
logMessageFmt(true, LOG_GENERAL, "Missing property " + entry.first + ". Value unused!");
|
||||
}
|
||||
}
|
||||
/*
|
||||
std::string error;
|
||||
if(!interaction::waitForAttach(error)){
|
||||
@@ -241,85 +238,87 @@ int main(int argc, char** argv) {
|
||||
std::string descriptors = "LTGE";
|
||||
bool crypt_init = false;
|
||||
for(const auto& c : descriptors)
|
||||
if(crypt_init |= crypt_mp_init(&c))
|
||||
if((crypt_init |= crypt_mp_init(&c)))
|
||||
break;
|
||||
if(!crypt_init) {
|
||||
logCritical(LOG_GENERAL, "Could not initialise libtomcrypt mp descriptors!");
|
||||
return 1;
|
||||
}
|
||||
if(register_prng(&sprng_desc) == -1) {
|
||||
cerr << "could not setup prng" << endl;
|
||||
logCritical(LOG_GENERAL, "could not setup prng");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (register_cipher(&rijndael_desc) == -1) {
|
||||
cerr << "could not setup rijndael" << endl;
|
||||
logCritical(LOG_GENERAL, "could not setup rijndael");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
testTomMath();
|
||||
}
|
||||
|
||||
ts::server::SqlDataManager* sql = nullptr;
|
||||
std::string errorMessage;
|
||||
ts::server::SqlDataManager* sql = nullptr;
|
||||
std::string errorMessage;
|
||||
shared_ptr<logger::LoggerConfig> logConfig = nullptr;
|
||||
std::string line;
|
||||
std::string line;
|
||||
|
||||
logMessage("Loading configuration");
|
||||
terminal::instance()->writeMessage("Loading configuration");
|
||||
logMessageFmt(true, LOG_GENERAL, "Loading configuration");
|
||||
auto cfgErrors = ts::config::parseConfig(CONFIG_NAME);
|
||||
if(!cfgErrors.empty()){
|
||||
logError("Could not load configuration. Errors: (" + to_string(cfgErrors.size()) + ")");
|
||||
logErrorFmt(true, LOG_GENERAL, "Could not load configuration. Errors: (" + to_string(cfgErrors.size()) + ")");
|
||||
for(const auto& entry : cfgErrors)
|
||||
logError(" - " + entry);
|
||||
logError("Stopping server...");
|
||||
logError(true, LOG_GENERAL, " - {}", entry);
|
||||
logErrorFmt(true, LOG_GENERAL, "Stopping server...");
|
||||
goto stopApp;
|
||||
}
|
||||
|
||||
logMessage("Setting up log");
|
||||
logMessage(LOG_GENERAL, "Setting up logging");
|
||||
logConfig = make_shared<logger::LoggerConfig>();
|
||||
logConfig->logfileLevel = (spdlog::level::level_enum) ts::config::log::logfileLevel;
|
||||
logConfig->terminalLevel = (spdlog::level::level_enum) ts::config::log::terminalLevel;
|
||||
logConfig->file_colored = ts::config::log::logfileColored;
|
||||
logConfig->logPath = ts::config::log::path;
|
||||
logConfig->vs_group_size = ts::config::log::vs_size;
|
||||
logConfig->sync = !terminal::instance();
|
||||
|
||||
logger::setup(logConfig);
|
||||
threads::timer::function_log = [](const std::string& message, bool debug) {
|
||||
if(debug)
|
||||
debugMessage(LOG_GENERAL, message);
|
||||
else
|
||||
logWarning(LOG_GENERAL, message);
|
||||
};
|
||||
threads::timer::function_log = [](const std::string& message, bool debug) {
|
||||
auto msg = message.find('\n') == std::string::npos ? message : message.substr(0, message.find('\n'));
|
||||
if(debug)
|
||||
debugMessage(LOG_GENERAL, msg);
|
||||
else
|
||||
logWarning(LOG_GENERAL, msg);
|
||||
};
|
||||
|
||||
logger::updateLogLevels();
|
||||
if(ts::config::license_original && ts::config::license_original->data.type != license::LicenseType::DEMO){
|
||||
logMessageFmt(true, LOG_GENERAL, "[]---------------------------------------------------------[]");
|
||||
logMessageFmt(true, LOG_GENERAL, " §aThank you for buying the TeaSpeak-§lPremium-§aSoftware! ");
|
||||
logMessageFmt(true, LOG_GENERAL, " §aLicense information:");
|
||||
logMessageFmt(true, LOG_GENERAL, " §aLicense owner : §e" + ts::config::license_original->owner());
|
||||
logMessageFmt(true, LOG_GENERAL, " §aLicense type : §e" + license::LicenseTypeNames[ts::config::license_original->data.type]);
|
||||
if(ts::config::license_original && ts::config::license_original->data.type != license::LicenseType::DEMO){
|
||||
logMessageFmt(true, LOG_GENERAL, strobf("[]---------------------------------------------------------[]").string());
|
||||
logMessageFmt(true, LOG_GENERAL, strobf(" §aThank you for buying the TeaSpeak-§lPremium-§aSoftware! ").string());
|
||||
logMessageFmt(true, LOG_GENERAL, strobf(" §aLicense information:").string());
|
||||
logMessageFmt(true, LOG_GENERAL, strobf(" §aLicense owner : §e").string() + ts::config::license_original->owner());
|
||||
logMessageFmt(true, LOG_GENERAL, strobf(" §aLicense type : §e").string() + license::LicenseTypeNames[ts::config::license_original->data.type]);
|
||||
|
||||
if(ts::config::license_original->end().time_since_epoch().count() == 0){
|
||||
logMessageFmt(true, LOG_GENERAL, " §aLicense expires: §enever");
|
||||
} else {
|
||||
char timeBuffer[32];
|
||||
time_t t = duration_cast<seconds>(ts::config::license_original->end().time_since_epoch()).count();
|
||||
tm* stime = localtime(&t);
|
||||
strftime(timeBuffer, 32, "%c", stime);
|
||||
logMessageFmt(true, LOG_GENERAL, " §aLicense expires: §e" + string(timeBuffer));
|
||||
}
|
||||
logMessage(string() + " §aLicense valid : " + (ts::config::license_original->isValid() ? "§ayes" : "§cno"));
|
||||
logMessageFmt(true, LOG_GENERAL, "[]---------------------------------------------------------[]");
|
||||
}
|
||||
if(ts::config::license_original->end().time_since_epoch().count() == 0){
|
||||
logMessageFmt(true, LOG_GENERAL, strobf(" §aLicense expires: §enever").string());
|
||||
} else {
|
||||
char timeBuffer[32];
|
||||
time_t t = duration_cast<seconds>(ts::config::license_original->end().time_since_epoch()).count();
|
||||
tm* stime = localtime(&t);
|
||||
strftime(timeBuffer, 32, "%c", stime);
|
||||
logMessageFmt(true, LOG_GENERAL, strobf(" §aLicense expires: §e").string() + string(timeBuffer));
|
||||
}
|
||||
logMessageFmt(true, LOG_GENERAL, string() + strobf(" §aLicense valid : ").string() + (ts::config::license_original->isValid() ? strobf("§ayes").string() : strobf("§cno").string()));
|
||||
logMessageFmt(true, LOG_GENERAL, strobf("[]---------------------------------------------------------[]").string());
|
||||
}
|
||||
|
||||
logMessage(LOG_GENERAL, "Starting TeaSpeak-Server v{}", build::version()->string(true));
|
||||
logMessage(LOG_GENERAL, "Starting music providers");
|
||||
logMessage(LOG_GENERAL, "Starting music providers");
|
||||
|
||||
terminal::instance()->setPrompt("§aStarting server. §7[§aloading music§7]");
|
||||
if(ts::config::music::enabled && !arguments.cmdOptionExists("--valgrind")) {
|
||||
::music::manager::loadProviders("providers");
|
||||
::music::manager::register_provider(::music::provider::ChannelProvider::create_provider());
|
||||
}
|
||||
if(terminal::instance()) terminal::instance()->setPrompt("§aStarting server. §7[§aloading music§7]");
|
||||
if(ts::config::music::enabled && !arguments.cmdOptionExists("--no-providers")) {
|
||||
::music::manager::loadProviders("providers");
|
||||
::music::manager::register_provider(::music::provider::ChannelProvider::create_provider());
|
||||
}
|
||||
|
||||
terminal::instance()->setPrompt("§aStarting server. §7[§aloading geoloc§7]");
|
||||
if(terminal::instance()) terminal::instance()->setPrompt("§aStarting server. §7[§aloading geoloc§7]");
|
||||
|
||||
if(!ts::config::geo::staticFlag) {
|
||||
if(ts::config::geo::type == geoloc::PROVIDER_SOFTWARE77)
|
||||
@@ -327,108 +326,98 @@ int main(int argc, char** argv) {
|
||||
else if(ts::config::geo::type == geoloc::PROVIDER_IP2LOCATION)
|
||||
geoloc::provider = new geoloc::IP2LocationProvider(ts::config::geo::mappingFile);
|
||||
else {
|
||||
logCritical("Invalid geo resolver type!");
|
||||
logCritical(LOG_GENERAL,"Invalid geo resolver type!");
|
||||
}
|
||||
if(geoloc::provider && !geoloc::provider->load(errorMessage)) {
|
||||
logCritical("Could not setup geoloc! Fallback to default flag!");
|
||||
logCritical("Message: " + errorMessage);
|
||||
logCritical(LOG_GENERAL,"Could not setup geoloc! Fallback to default flag!");
|
||||
logCritical(LOG_GENERAL,"Message: {}", errorMessage);
|
||||
geoloc::provider = nullptr;
|
||||
errorMessage = "";
|
||||
errorMessage = "";
|
||||
}
|
||||
}
|
||||
if(ts::config::geo::vpn_block) {
|
||||
geoloc::provider_vpn = new geoloc::IPCatBlocker(ts::config::geo::vpn_file);
|
||||
|
||||
if(geoloc::provider_vpn && !geoloc::provider_vpn->load(errorMessage)) {
|
||||
logCritical("Could not setup vpn detector!");
|
||||
logCritical("Message: " + errorMessage);
|
||||
logCritical(LOG_GENERAL,"Could not setup vpn detector!");
|
||||
logCritical(LOG_GENERAL,"Message: {}", errorMessage);
|
||||
geoloc::provider_vpn = nullptr;
|
||||
errorMessage = "";
|
||||
}
|
||||
}
|
||||
terminal::instance()->setPrompt("§aStarting server. §7[§aloading sql§7]");
|
||||
if(terminal::instance()) terminal::instance()->setPrompt("§aStarting server. §7[§aloading sql§7]");
|
||||
|
||||
sql = new ts::server::SqlDataManager();
|
||||
if(!sql->initialize(errorMessage)) {
|
||||
logCritical("Could not initialize SQL!");
|
||||
if(errorMessage.find("database is locked") != string::npos) {
|
||||
logCriticalFmt(true, LOG_GENERAL, "----------------------------[ ATTENTION ]----------------------------");
|
||||
sql = new ts::server::SqlDataManager();
|
||||
if(!sql->initialize(errorMessage)) {
|
||||
logCriticalFmt(true, LOG_GENERAL, "Could not initialize SQL!");
|
||||
if(errorMessage.find("database is locked") != string::npos) {
|
||||
logCriticalFmt(true, LOG_GENERAL, "----------------------------[ ATTENTION ]----------------------------");
|
||||
logCriticalFmt(true, LOG_GENERAL, "{:^69}", "You're database is already in use!");
|
||||
logCriticalFmt(true, LOG_GENERAL, "{:^69}", "Stop the other instance first!");
|
||||
logCriticalFmt(true, LOG_GENERAL, "----------------------------[ ATTENTION ]----------------------------");
|
||||
} else {
|
||||
logCriticalFmt(true, LOG_GENERAL, "{:^69}", "Stop the other instance first!");
|
||||
logCriticalFmt(true, LOG_GENERAL, "----------------------------[ ATTENTION ]----------------------------");
|
||||
} else {
|
||||
logCriticalFmt(true, LOG_GENERAL, errorMessage);
|
||||
}
|
||||
goto stopApp;
|
||||
}
|
||||
}
|
||||
goto stopApp;
|
||||
}
|
||||
|
||||
terminal::instance()->setPrompt("§aStarting server. §7[§astarting instance§7]");
|
||||
if(terminal::instance()) terminal::instance()->setPrompt("§aStarting server. §7[§astarting instance§7]");
|
||||
|
||||
serverInstance = new ts::server::InstanceHandler(sql); //if error than mainThreadActive = false
|
||||
if(!mainThreadActive || !serverInstance->startInstance())
|
||||
goto stopApp;
|
||||
|
||||
if(arguments.cmdOptionExists("-q") || arguments.cmdOptionExists("--set_query_password")) {
|
||||
auto password = arguments.cmdOptionExists("-q") ? arguments.get_option("-q") : arguments.get_option("--set_query_password");
|
||||
if(!password.empty()) {
|
||||
logMessageFmt(true, LOG_GENERAL, "Updating server admin query password to \"{}\"", password);
|
||||
auto accounts = serverInstance->getQueryServer()->find_query_accounts_by_unique_id(serverInstance->getInitalServerAdmin()->getUid());
|
||||
bool found = false;
|
||||
for(const auto& account : accounts) {
|
||||
if(account->bound_server != 0) continue;
|
||||
if(!serverInstance->getQueryServer()->change_query_password(account, password)) {
|
||||
logErrorFmt(true, LOG_GENERAL, "Failed to update server admin query password! (Internal error)");
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if(!found) {
|
||||
logErrorFmt(true, LOG_GENERAL, "Failed to update server admin query password! Login does not exists!");
|
||||
}
|
||||
}
|
||||
auto password = arguments.cmdOptionExists("-q") ? arguments.get_option("-q") : arguments.get_option("--set_query_password");
|
||||
if(!password.empty()) {
|
||||
logMessageFmt(true, LOG_GENERAL, "Updating server admin query password to \"{}\"", password);
|
||||
auto accounts = serverInstance->getQueryServer()->find_query_accounts_by_unique_id(serverInstance->getInitialServerAdmin()->getUid());
|
||||
bool found = false;
|
||||
for(const auto& account : accounts) {
|
||||
if(account->bound_server != 0) continue;
|
||||
if(!serverInstance->getQueryServer()->change_query_password(account, password)) {
|
||||
logErrorFmt(true, LOG_GENERAL, "Failed to update server admin query password! (Internal error)");
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if(!found) {
|
||||
logErrorFmt(true, LOG_GENERAL, "Failed to update server admin query password! Login does not exists!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
terminal::instance()->setPrompt("§7> §f");
|
||||
if(terminal::instance()) terminal::instance()->setPrompt("§7> §f");
|
||||
while(mainThreadActive) {
|
||||
usleep(5 * 1000);
|
||||
|
||||
if(terminal::instance()->linesAvailable() > 0){
|
||||
while(!(line = terminal::instance()->readLine("§7> §f")).empty())
|
||||
threads::Thread(THREAD_DETACHED, [line](){ terminal::chandler::handleCommand(line); });
|
||||
if(terminal::instance()) {
|
||||
if(terminal::instance()->linesAvailable() > 0){
|
||||
while(!(line = terminal::instance()->readLine("§7> §f")).empty())
|
||||
threads::Thread(THREAD_DETACHED, [line](){ terminal::chandler::handleCommand(line); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
stopApp:
|
||||
logMessage("Stopping application");
|
||||
logMessageFmt(true, LOG_GENERAL, "Stopping application");
|
||||
::music::manager::finalizeProviders();
|
||||
|
||||
if(serverInstance)
|
||||
serverInstance->stopInstance();
|
||||
delete serverInstance;
|
||||
serverInstance = nullptr;
|
||||
|
||||
serverInstance = nullptr;
|
||||
|
||||
ts::music::MusicBotManager::shutdown();
|
||||
if(sql)
|
||||
sql->finalize();
|
||||
delete sql;
|
||||
logMessage("Application suspend successful!");
|
||||
sql->finalize();
|
||||
delete sql;
|
||||
logMessageFmt(true, LOG_GENERAL, "Application suspend successful!");
|
||||
|
||||
logger::uninstall();
|
||||
terminal::uninstall();
|
||||
mainThreadDone = true;
|
||||
if(terminal::active())
|
||||
terminal::uninstall();
|
||||
mainThreadDone = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 2][OUT] (188.225.34.225:9988) ftinitdownload clientftfid=4096 name=\/icon_166694597 cid=0 cpw seekpos=0 proto=1 return_code=
|
||||
[02][OUT] (188.225.34.225:9988) ftinitdownload clientftfid=4095 name=\/icon_4113966246 cid=0 cpw seekpos=0 proto=1 return_code=
|
||||
[02][OUT] (188.225.34.225:9988) ftinitdownload clientftfid=4094 name=\/icon_3002705295 cid=0 cpw seekpos=0 proto=1 return_code=
|
||||
[02][OUT] (188.225.34.225:9988) ftinitdownload clientftfid=4093 name=\/icon_494035633 cid=0 cpw seekpos=0 proto=1 return_code=
|
||||
[02][OUT] (188.225.34.225:9988) ftinitdownload clientftfid=4092 name=\/icon_847789427 cid=0 cpw seekpos=0 proto=1 return_code=
|
||||
[02][ IN] (188.225.34.225:9988) notifyclientupdated clid=5 client_version=3.2.0\s[Build:\s1533739581] client_platform=Linux client_login_name=WolverinDEV client_created=1536521950 client_lastconnected=1536522252 client_totalconnections=2 client_month_bytes_uploaded=0 client_month_bytes_downloaded=0 client_total_bytes_uploaded=0 client_total_bytes_downloaded=0 client_icon_id=0 client_country=DE
|
||||
[02][ IN] (188.225.34.225:9988) notifystartdownload clientftfid=4096 proto=1 serverftfid=1 ftkey=R0Vcnx4fNdrXuMFg port=30303 size=1086
|
||||
[02][ IN] (188.225.34.225:9988) notifystartdownload clientftfid=4095 proto=1 serverftfid=1 ftkey=3eYwsuviQvTWme42 port=30303 size=822
|
||||
[02][ IN] (188.225.34.225:9988) notifystartdownload clientftfid=4094 proto=1 serverftfid=1 ftkey=dM5oaVuLYLwia2me port=30303 size=852
|
||||
[02][ IN] (188.225.34.225:9988) notifystartdownload clientftfid=4093 proto=1 serverftfid=1 ftkey=60BltUu8fbUqgLhj port=30303 size=3441
|
||||
[02][ IN] (188.225.34.225:9988) notifystartdownload clientftfid=4092 proto=1 serverftfid=1 ftkey=a0wmURVHqhNE71H2 port=30303 size=1452
|
||||
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
env/libs/
|
||||
+16
-14
@@ -1,25 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
|
||||
BUILD_PATH=$1
|
||||
if [ -z ${BUILD_PATH} ]; then
|
||||
if [[ -z "${BUILD_PATH}" ]]; then
|
||||
echo "Missing versions path!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
./generate_version.sh ${BUILD_PATH}
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to generate version!"
|
||||
./generate_version.sh "${BUILD_PATH}" || {
|
||||
echo "Failed to generate version! ($?)"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
./package_server.sh ${BUILD_PATH}
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to package server!"
|
||||
./generate_libraries.sh || {
|
||||
echo "Failed to generate libraries! ($?)"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
./deploy_build.sh ${BUILD_PATH}
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to deploy package!"
|
||||
./package_server.sh "${BUILD_PATH}" || {
|
||||
echo "Failed to package server! ($?)"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
./deploy_build.sh "${BUILD_PATH}" || {
|
||||
echo "Failed to deploy package! ($?)"
|
||||
exit 1
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
BUILD_PATH=$1
|
||||
if [[ -z ${BUILD_PATH} ]]; then
|
||||
echo "Missing versions path!"
|
||||
#exit 1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BUILD_INFO=($(cat build_version.txt))
|
||||
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
../../../git-teaspeak/default_files/install_libnice.sh
|
||||
-1
@@ -1 +0,0 @@
|
||||
../../../../../libraries/DataPipes/build/libDataPipes.so
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
../../../../MusicBot/libs/libTeaMusic.so
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
../../../../../libraries/boringssl/build/crypto/libcrypto.so
|
||||
-1
@@ -1 +0,0 @@
|
||||
../../../../../libraries/jemalloc/out/libjemalloc.so.2
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
/usr/local/lib/libopus.so.0
|
||||
-1
@@ -1 +0,0 @@
|
||||
/usr/lib/x86_64-linux-gnu/libsqlite3.so.0
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
../../../../../libraries/boringssl/build/ssl/libssl.so
|
||||
Executable
+100
@@ -0,0 +1,100 @@
|
||||
#!/bin/bash
|
||||
|
||||
#Required libraries:
|
||||
# "libssl.so"
|
||||
# "libcrypto.so"
|
||||
# "libDataPipes.so"
|
||||
# "libjemalloc.so.2"
|
||||
# "libsqlite3.so.0"
|
||||
# "libTeaMusic.so"
|
||||
# "libnice.so.10"
|
||||
# "libpcre.so.3" (only for web)
|
||||
# "libgobject-2.0.so.0" (only for web)
|
||||
# "libglib-2.0.so.0" (only for web)
|
||||
# "libffi.so.7"
|
||||
|
||||
[[ -z "${build_os_type}" ]] && { echo "missing build os type"; exit 1; }
|
||||
[[ -z "${build_os_arch}" ]] && { echo "missing build os arch"; exit 1; }
|
||||
build_path="out/${build_os_type}_${build_os_arch}/"
|
||||
|
||||
function query_system_link() {
|
||||
local _binary="$2"
|
||||
[[ -z "$_binary" ]] && _binary="../../../environment/TeaSpeakServer"
|
||||
data=$(ldd "$_binary" | grep "$1")
|
||||
# shellcheck disable=SC2206
|
||||
data=($data)
|
||||
library_path=${data[2]}
|
||||
|
||||
[[ -z "${library_path}" ]] && { echo "failed to resolve library path for $1 in $_binary"; exit 1; }
|
||||
[[ "${library_path}" == "not" ]] && { echo "failed to resolve library path for $1 in $_binary"; exit 1; }
|
||||
}
|
||||
|
||||
cd $(dirname $0) || exit 1
|
||||
cd env || { echo "failed to enter env"; exit 1; }
|
||||
|
||||
[[ -d libs ]] && {
|
||||
rm -r libs || { echo "failed to delete old lib folder"; exit 1; }
|
||||
}
|
||||
mkdir libs || { echo "failed to create lib directory"; exit 1; }
|
||||
cd libs || { echo "failed to enter lib directory"; exit 1; }
|
||||
|
||||
# Creating copied
|
||||
library_base=$(realpath ../../../../../libraries)
|
||||
|
||||
# Setting up ssl
|
||||
library_path=$(realpath "${library_base}/boringssl/${build_path}/ssl/libssl.so")
|
||||
cp "$library_path" . || { echo "failed to copy libssl.so"; exit 1; }
|
||||
|
||||
# Setting up crypto
|
||||
library_path=$(realpath "${library_base}/boringssl/${build_path}/crypto/libcrypto.so")
|
||||
cp "$library_path" . || { echo "failed to copy libcrypto.so"; exit 1; }
|
||||
|
||||
# Setting up DataPipes
|
||||
library_path=$(realpath "${library_base}/DataPipes/${build_path}/lib/libDataPipes-RTC.so")
|
||||
cp "$library_path" . || { echo "failed to copy libDataPipes-RTC.so"; exit 1; }
|
||||
_dp_path="$library_path"
|
||||
|
||||
# Setting up Sqlite3
|
||||
query_system_link "libsqlite3.so.0"
|
||||
cp "${library_path}" . || { echo "failed to copy libsqlite3.so.0"; exit 1; }
|
||||
|
||||
# Setting up jemalloc
|
||||
query_system_link "libjemalloc.so.2"
|
||||
cp "${library_path}" . || { echo "failed to copy libjemalloc.so.2"; exit 1; }
|
||||
|
||||
# Setting up TeaMusic
|
||||
library_path=$(realpath "../../../../MusicBot/libs/libTeaMusic.so")
|
||||
cp "$library_path" . || { echo "failed to copy libTeaMusic.so"; exit 1; }
|
||||
|
||||
if ldd "../../../environment/TeaSpeakServer" | grep -q "libnice.so.10"; then
|
||||
echo "Adding web libraries"
|
||||
|
||||
# Setting up libnice
|
||||
library_path=$(realpath "${library_base}/libnice/${build_os_type}_${build_os_arch}/lib/libnice.so.10")
|
||||
cp "$library_path" libnice.so.10 || { echo "failed to copy libnice.so.10"; exit 1; }
|
||||
|
||||
|
||||
glib_libs=$(realpath "${library_base}//glibc/${build_os_type}_${build_os_arch}/lib/"*"/")
|
||||
cp "$glib_libs/libgobject-2.0.so.0" . || { echo "failed to copy libgobject-2.0.so.0"; exit 1; }
|
||||
cp "$glib_libs/libgmodule-2.0.so.0" . || { echo "failed to copy libgmodule-2.0.so.0"; exit 1; }
|
||||
cp "$glib_libs/libglib-2.0.so.0" . || { echo "failed to copy libglib-2.0.so.0"; exit 1; }
|
||||
cp "$glib_libs/libgio-2.0.so.0" . || { echo "failed to copy libgio-2.0.so.0"; exit 1; }
|
||||
cp "$glib_libs/libffi.so.7" . || { echo "failed to copy libffi.so.7"; exit 1; }
|
||||
|
||||
# "libgobject-2.0.so.0" (only for web)
|
||||
# "libglib-2.0.so.0" (only for web)
|
||||
|
||||
# Setting up libpcre
|
||||
query_system_link "libpcre.so.3" "$_dp_path"
|
||||
cp "${library_path}" . || { echo "failed to copy libpcre.so.3"; exit 1; }
|
||||
fi
|
||||
|
||||
# Doing some prostprocessing
|
||||
chmod 755 *
|
||||
for file in *.so*; do
|
||||
echo "Editing rpath for $file"
|
||||
strip -s "$file"
|
||||
patchelf --set-rpath "./libs/:./" "$file"
|
||||
done
|
||||
|
||||
echo "All libraries have been copied successfully"
|
||||
@@ -17,13 +17,13 @@ if [[ -z ${BUILD_PATH} ]]; then
|
||||
#exit 1
|
||||
fi
|
||||
|
||||
CURRENT_VERSION=`cat env/buildVersion.txt`
|
||||
CURRENT_VERSION=$(cat env/buildVersion.txt)
|
||||
CURRENT_VERSION_ESCAPED=$(echo "${CURRENT_VERSION}" | sed -e 's/[\/&\.\-]/\\&/g')
|
||||
AVAILABLE_VERSIONS=`ssh -i build_private_key TeaSpeak-Jenkins@mcgalaxy.de "
|
||||
AVAILABLE_VERSIONS=$(ssh -i build_private_key TeaSpeak-Jenkins@mcgalaxy.de "
|
||||
if [ -d versions/${BUILD_PATH} ]; then
|
||||
ls versions/${BUILD_PATH} | grep -E '^${CURRENT_VERSION_ESCAPED}(\-[0-9]+)?$'
|
||||
fi
|
||||
"`
|
||||
")
|
||||
debug "${AVAILABLE_VERSIONS}"
|
||||
|
||||
TARGET_VERSION=""
|
||||
|
||||
@@ -6,7 +6,7 @@ TMP_FILE="temp"
|
||||
|
||||
function mkdir_not_exists() {
|
||||
if [[ ! -d $1 ]]; then
|
||||
mkdir $1
|
||||
mkdir "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -15,7 +15,10 @@ function create_dump() {
|
||||
local BINARY_NAME=${2}
|
||||
|
||||
echo "Creating dump file for ${BINARY_NAME} (${BINARY_PATH}/${BINARY_NAME})"
|
||||
dump_syms ${BINARY_PATH}/${BINARY_NAME} > ${TMP_FILE}
|
||||
dump_syms "${BINARY_PATH}/${BINARY_NAME}" > ${TMP_FILE} || {
|
||||
echo "Failed to generate dump."
|
||||
exit 1
|
||||
}
|
||||
SYM_INFO=$(head -n1 < ${TMP_FILE})
|
||||
SYM_INFO=($SYM_INFO)
|
||||
DUMP_ID=${SYM_INFO[3]}
|
||||
@@ -26,7 +29,10 @@ function create_dump() {
|
||||
mkdir_not_exists ${SYMBOL_ROOT}/${BINARY_NAME}/${DUMP_ID}
|
||||
|
||||
DUMP_PATH=${SYMBOL_ROOT}/${BINARY_NAME}/${DUMP_ID}/${BINARY_NAME}.sym
|
||||
mv ${TMP_FILE} ${DUMP_PATH}
|
||||
mv "$TMP_FILE" "$DUMP_PATH" || {
|
||||
echo "Failed to move dump."
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
create_dump "env" "TeaSpeakServer"
|
||||
|
||||
@@ -8,21 +8,30 @@ BUILD_FILENAME=${BUILD_INFO[3]}
|
||||
|
||||
echo "Creating TeaSpeak ${BUILD_NAME} Build index ${BUILD_VERSION}"
|
||||
|
||||
if [[ -d finalenv ]]; then
|
||||
rm -r finalenv
|
||||
fi
|
||||
cp -r env finalenv
|
||||
cd finalenv
|
||||
cd finalenv || {
|
||||
echo "failed to enter dir"
|
||||
exit 1
|
||||
}
|
||||
echo -e "# Version: ${BUILD_FULL_NAME}
|
||||
# TeaSpeak version: ${BUILD_NAME}
|
||||
# Build version: ${BUILD_VERSION}
|
||||
|
||||
{build_name: \"${BUILD_FULL_NAME}\", build_version: \"${BUILD_NAME}\", build_index: ${BUILD_VERSION}}" > buildVersion.txt
|
||||
{\"build_name\": \"${BUILD_FULL_NAME}\", \"build_version\": \"${BUILD_NAME}\", \"build_index\": ${BUILD_VERSION}}" > buildVersion.txt
|
||||
|
||||
#Create a copy and save unstripped
|
||||
cp TeaSpeakServer TeaSpeakServerTmp
|
||||
rm TeaSpeakServer
|
||||
mv TeaSpeakServerTmp TeaSpeakServer
|
||||
|
||||
strip -s -p -v TeaSpeakServer
|
||||
tar --dereference -czvf "../${BUILD_FILENAME}" *
|
||||
strip -s -p -v TeaSpeakServer || { echo "failed to strip symbols!"; exit 1; }
|
||||
patchelf --set-rpath ./libs/ TeaSpeakServer || { echo "failed to set rpath!"; exit 1; }
|
||||
tar --dereference -cvf - * | gzip -f -9 > "../${BUILD_FILENAME}"
|
||||
[[ $? -ne 0 ]] && { echo "failed to package server"; exit 1; }
|
||||
|
||||
cd ..
|
||||
rm -r finalenv
|
||||
./make_symbol.sh
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
BVERSION="$(cat env/buildVersion.txt)"
|
||||
FBUILD=0
|
||||
|
||||
# shellcheck disable=SC2120
|
||||
function buildName() {
|
||||
if [ ! -z "$1" ]; then
|
||||
if [ -n "$1" ]; then
|
||||
L_FBUILD="$1"
|
||||
else
|
||||
L_FBUILD="${FBUILD}"
|
||||
|
||||
+878
-709
File diff suppressed because it is too large
Load Diff
+174
-167
@@ -8,212 +8,219 @@
|
||||
#endif
|
||||
#include <spdlog/common.h>
|
||||
#include "geo/GeoLocation.h"
|
||||
#include "../../license/shared/License.h"
|
||||
#include "../../license/shared/include/license/license.h"
|
||||
|
||||
namespace YAML {
|
||||
class Node;
|
||||
class Node;
|
||||
}
|
||||
namespace ts {
|
||||
namespace config {
|
||||
struct EntryBinding {
|
||||
std::string key;
|
||||
std::map<std::string, std::deque<std::string>> description;
|
||||
uint8_t flags = 0;
|
||||
namespace ts::config {
|
||||
struct EntryBinding {
|
||||
std::string key;
|
||||
std::map<std::string, std::deque<std::string>> description;
|
||||
uint8_t flags = 0;
|
||||
|
||||
int type = 0; /* 0 = unbound | 1 = string | 2 = number | 3 = boolean | 4 = user defined */
|
||||
int bounded_by = 0; /* 0 = unbound | 1 = config | 2 = command line */
|
||||
int type = 0; /* 0 = unbound | 1 = string | 2 = number | 3 = boolean | 4 = user defined */
|
||||
int bounded_by = 0; /* 0 = unbound | 1 = config | 2 = command line */
|
||||
|
||||
std::function<std::deque<std::string>()> default_value;
|
||||
std::function<std::string()> value_description;
|
||||
std::function<void(YAML::Node&)> set_default;
|
||||
std::function<void(YAML::Node&)> read_config;
|
||||
std::function<void(const std::string&)> read_argument;
|
||||
};
|
||||
std::function<std::deque<std::string>()> default_value;
|
||||
std::function<std::string()> value_description;
|
||||
std::function<void(YAML::Node&)> set_default;
|
||||
std::function<void(YAML::Node&)> read_config;
|
||||
std::function<void(const std::string&)> read_argument;
|
||||
};
|
||||
|
||||
extern std::vector<std::string> parseConfig(const std::string& /* path */);
|
||||
extern std::deque<std::shared_ptr<EntryBinding>> create_bindings();
|
||||
extern bool update_license(std::string& /* error */, const std::string& /* new license */);
|
||||
extern std::vector<std::string> parseConfig(const std::string& /* path */);
|
||||
extern std::vector<std::string> reload();
|
||||
extern std::deque<std::shared_ptr<EntryBinding>> create_bindings();
|
||||
|
||||
namespace database {
|
||||
extern std::string url;
|
||||
namespace sqlite {
|
||||
extern std::string journal_mode;
|
||||
extern std::string locking_mode;
|
||||
extern std::string sync_mode;
|
||||
}
|
||||
namespace database {
|
||||
extern std::string url;
|
||||
namespace sqlite {
|
||||
extern std::string journal_mode;
|
||||
extern std::string locking_mode;
|
||||
extern std::string sync_mode;
|
||||
}
|
||||
}
|
||||
|
||||
extern std::shared_ptr<license::License> license;
|
||||
extern std::shared_ptr<license::License> license_original;
|
||||
|
||||
extern bool experimental_31;
|
||||
extern std::string permission_mapping_file;
|
||||
|
||||
namespace binding {
|
||||
extern bool enforce_default_voice_host;
|
||||
extern std::string DefaultVoiceHost;
|
||||
extern std::string DefaultWebHost;
|
||||
extern std::string DefaultQueryHost;
|
||||
extern std::string DefaultFileHost;
|
||||
|
||||
extern uint16_t DefaultQueryPort;
|
||||
extern uint16_t DefaultFilePort;
|
||||
}
|
||||
|
||||
namespace server {
|
||||
extern std::string DefaultServerVersion;
|
||||
extern std::string DefaultServerPlatform;
|
||||
|
||||
extern bool delete_old_bans;
|
||||
extern bool delete_missing_icon_permissions;
|
||||
|
||||
extern LicenseType DefaultServerLicense;
|
||||
|
||||
extern bool strict_ut8_mode;
|
||||
|
||||
extern bool enable_teamspeak_weblist;
|
||||
extern bool show_invisible_clients_as_online;
|
||||
extern bool disable_ip_saving;
|
||||
extern bool default_music_bot;
|
||||
|
||||
namespace badges {
|
||||
extern bool allow_overwolf;
|
||||
extern bool allow_badges;
|
||||
}
|
||||
|
||||
extern std::shared_ptr<license::License> license;
|
||||
extern std::shared_ptr<license::License> license_original;
|
||||
|
||||
extern bool experimental_31;
|
||||
extern std::string permission_mapping_file;
|
||||
|
||||
namespace binding {
|
||||
extern bool enforce_default_voice_host;
|
||||
extern std::string DefaultVoiceHost;
|
||||
extern std::string DefaultWebHost;
|
||||
extern std::string DefaultQueryHost;
|
||||
extern std::string DefaultFileHost;
|
||||
|
||||
extern uint16_t DefaultQueryPort;
|
||||
extern uint16_t DefaultFilePort;
|
||||
namespace authentication {
|
||||
extern bool name;
|
||||
}
|
||||
|
||||
namespace server {
|
||||
extern std::string DefaultServerVersion;
|
||||
extern std::string DefaultServerPlatform;
|
||||
|
||||
extern bool delete_old_bans;
|
||||
extern bool delete_missing_icon_permissions;
|
||||
|
||||
extern LicenseType DefaultServerLicense;
|
||||
|
||||
extern bool strict_ut8_mode;
|
||||
|
||||
extern bool enable_teamspeak_weblist;
|
||||
extern bool show_invisible_clients_as_online;
|
||||
extern bool disable_ip_saving;
|
||||
|
||||
namespace badges {
|
||||
extern bool allow_overwolf;
|
||||
extern bool allow_badges;
|
||||
}
|
||||
|
||||
namespace authentication {
|
||||
extern bool name;
|
||||
}
|
||||
|
||||
extern ssize_t max_virtual_server;
|
||||
namespace clients {
|
||||
extern bool teamspeak;
|
||||
extern bool teaspeak;
|
||||
extern bool teaweb;
|
||||
}
|
||||
|
||||
namespace voice {
|
||||
extern size_t DefaultPuzzlePrecomputeSize;
|
||||
extern int RsaPuzzleLevel;
|
||||
extern bool enforce_coocie_handshake;
|
||||
extern ssize_t max_virtual_server;
|
||||
}
|
||||
|
||||
namespace voice {
|
||||
extern size_t DefaultPuzzlePrecomputeSize;
|
||||
extern int RsaPuzzleLevel;
|
||||
extern bool enforce_coocie_handshake;
|
||||
|
||||
|
||||
extern bool notifyMuted;
|
||||
extern int connectLimit;
|
||||
extern int clientConnectLimit;
|
||||
extern bool notifyMuted;
|
||||
extern int connectLimit;
|
||||
extern int clientConnectLimit;
|
||||
|
||||
extern bool suppress_myts_warnings;
|
||||
extern uint16_t default_voice_port;
|
||||
extern bool suppress_myts_warnings;
|
||||
extern uint16_t default_voice_port;
|
||||
|
||||
extern bool warn_on_permission_editor;
|
||||
extern bool allow_session_reinitialize;
|
||||
extern bool warn_on_permission_editor;
|
||||
extern bool allow_session_reinitialize;
|
||||
}
|
||||
|
||||
namespace geo {
|
||||
extern std::string countryFlag;
|
||||
extern bool staticFlag;
|
||||
|
||||
extern std::string mappingFile;
|
||||
extern geoloc::ProviderType type;
|
||||
|
||||
extern bool vpn_block;
|
||||
extern std::string vpn_file;
|
||||
}
|
||||
|
||||
namespace query {
|
||||
extern std::string motd;
|
||||
extern std::string newlineCharacter;
|
||||
|
||||
extern int sslMode;
|
||||
namespace ssl {
|
||||
extern std::string keyFile;
|
||||
extern std::string certFile;
|
||||
}
|
||||
}
|
||||
|
||||
namespace geo {
|
||||
extern std::string countryFlag;
|
||||
extern bool staticFlag;
|
||||
namespace music {
|
||||
extern bool enabled;
|
||||
extern std::string command_prefix;
|
||||
}
|
||||
|
||||
extern std::string mappingFile;
|
||||
extern geoloc::ProviderType type;
|
||||
namespace messages {
|
||||
extern std::string serverStopped;
|
||||
extern std::string applicationStopped;
|
||||
extern std::string applicationCrashed;
|
||||
|
||||
extern bool vpn_block;
|
||||
extern std::string vpn_file;
|
||||
}
|
||||
extern std::string idle_time_exceeded;
|
||||
|
||||
namespace query {
|
||||
extern std::string motd;
|
||||
extern std::string newlineCharacter;
|
||||
extern std::string mute_notify_message;
|
||||
extern std::string unmute_notify_message;
|
||||
|
||||
extern int sslMode;
|
||||
namespace ssl {
|
||||
extern std::string keyFile;
|
||||
extern std::string certFile;
|
||||
}
|
||||
extern std::string kick_invalid_hardware_id;
|
||||
extern std::string kick_invalid_badges;
|
||||
extern std::string kick_invalid_command;
|
||||
|
||||
extern std::string kick_vpn;
|
||||
|
||||
extern std::string teamspeak_permission_editor;
|
||||
|
||||
namespace shutdown {
|
||||
extern std::string scheduled;
|
||||
extern std::string interval;
|
||||
extern std::string now;
|
||||
extern std::string canceled;
|
||||
|
||||
extern std::vector<std::pair<std::chrono::seconds, std::string>> intervals;
|
||||
}
|
||||
|
||||
namespace music {
|
||||
extern bool enabled;
|
||||
extern std::string command_prefix;
|
||||
extern std::string song_announcement;
|
||||
}
|
||||
|
||||
namespace messages {
|
||||
extern std::string serverStopped;
|
||||
extern std::string applicationStopped;
|
||||
extern std::string applicationCrashed;
|
||||
namespace timeout {
|
||||
extern std::string packet_resend_failed;
|
||||
extern std::string connection_reinitialized;
|
||||
}
|
||||
}
|
||||
|
||||
extern std::string idle_time_exceeded;
|
||||
namespace web {
|
||||
extern bool activated;
|
||||
|
||||
extern std::string mute_notify_message;
|
||||
extern std::string unmute_notify_message;
|
||||
namespace ssl {
|
||||
/* servername; private key file; public key file*/
|
||||
extern std::deque<std::tuple<std::string, std::string, std::string>> certificates;
|
||||
}
|
||||
|
||||
extern std::string kick_invalid_hardware_id;
|
||||
extern std::string kick_invalid_badges;
|
||||
extern std::string kick_invalid_command;
|
||||
extern uint16_t webrtc_port_min;
|
||||
extern uint16_t webrtc_port_max;
|
||||
extern std::deque<std::string> ice_servers;
|
||||
extern bool enable_upnp;
|
||||
}
|
||||
|
||||
extern std::string kick_vpn;
|
||||
namespace threads {
|
||||
extern size_t ticking;
|
||||
|
||||
extern std::string teamspeak_permission_editor;
|
||||
namespace voice {
|
||||
extern size_t execute_per_server;
|
||||
extern size_t execute_limit;
|
||||
|
||||
namespace shutdown {
|
||||
extern std::string scheduled;
|
||||
extern std::string interval;
|
||||
extern std::string now;
|
||||
extern std::string canceled;
|
||||
extern size_t events_per_server;
|
||||
extern size_t io_min;
|
||||
extern size_t io_per_server;
|
||||
extern size_t io_limit;
|
||||
|
||||
extern std::vector<std::pair<std::chrono::seconds, std::string>> intervals;
|
||||
}
|
||||
extern bool bind_io_thread_to_kernel_thread;
|
||||
}
|
||||
|
||||
namespace music {
|
||||
extern std::string song_announcement;
|
||||
}
|
||||
|
||||
namespace timeout {
|
||||
extern std::string packet_resend_failed;
|
||||
extern std::string connection_reinitialized;
|
||||
}
|
||||
namespace music {
|
||||
extern size_t execute_per_bot;
|
||||
extern size_t execute_limit;
|
||||
}
|
||||
|
||||
namespace web {
|
||||
extern bool activated;
|
||||
|
||||
namespace ssl {
|
||||
/* servername; private key file; public key file*/
|
||||
extern std::deque<std::tuple<std::string, std::string, std::string>> certificates;
|
||||
}
|
||||
|
||||
extern uint16_t webrtc_port_min;
|
||||
extern uint16_t webrtc_port_max;
|
||||
extern std::deque<std::string> ice_servers;
|
||||
extern bool enable_upnp;
|
||||
extern size_t io_loops;
|
||||
}
|
||||
|
||||
namespace threads {
|
||||
extern size_t ticking;
|
||||
|
||||
namespace voice {
|
||||
extern size_t execute_per_server;
|
||||
extern size_t execute_limit;
|
||||
|
||||
extern size_t events_per_server;
|
||||
extern size_t io_min;
|
||||
extern size_t io_per_server;
|
||||
extern size_t io_limit;
|
||||
|
||||
extern bool bind_io_thread_to_kernel_thread;
|
||||
}
|
||||
|
||||
namespace music {
|
||||
extern size_t execute_per_bot;
|
||||
extern size_t execute_limit;
|
||||
}
|
||||
|
||||
namespace web {
|
||||
extern size_t io_loops;
|
||||
}
|
||||
}
|
||||
|
||||
namespace log {
|
||||
extern std::string path;
|
||||
extern size_t vs_size;
|
||||
extern spdlog::level::level_enum logfileLevel;
|
||||
extern bool logfileColored;
|
||||
extern spdlog::level::level_enum terminalLevel;
|
||||
}
|
||||
|
||||
extern std::string crash_path;
|
||||
}
|
||||
|
||||
namespace log {
|
||||
extern std::string path;
|
||||
extern size_t vs_size;
|
||||
extern spdlog::level::level_enum logfileLevel;
|
||||
extern bool logfileColored;
|
||||
extern spdlog::level::level_enum terminalLevel;
|
||||
}
|
||||
|
||||
extern std::string crash_path;
|
||||
}
|
||||
+206
-195
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <misc/memtracker.h>
|
||||
#include "ConnectionStatistics.h"
|
||||
#include "TSServer.h"
|
||||
#include "VirtualServer.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
@@ -14,14 +14,14 @@ using namespace ts::stats;
|
||||
using namespace ts::protocol;
|
||||
|
||||
ConnectionStatistics::ConnectionStatistics(const shared_ptr<ConnectionStatistics>& handle, bool properties) : handle(handle) {
|
||||
memtrack::allocated<ConnectionStatistics>(this);
|
||||
memtrack::allocated<ConnectionStatistics>(this);
|
||||
|
||||
if(properties) {
|
||||
this->properties = make_shared<Properties>(); //TODO load etc?
|
||||
this->properties->register_property_type<property::ConnectionProperties>();
|
||||
}
|
||||
if(properties) {
|
||||
this->properties = make_shared<Properties>(); //TODO load etc?
|
||||
this->properties->register_property_type<property::ConnectionProperties>();
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
this->properties->registerProperty("connection_packets_sent_speech", 0, PROP_STATISTIC);
|
||||
this->properties->registerProperty("connection_bytes_sent_speech", 0, PROP_STATISTIC);
|
||||
this->properties->registerProperty("connection_packets_received_speech", 0, PROP_STATISTIC);
|
||||
@@ -47,280 +47,291 @@ ConnectionStatistics::ConnectionStatistics(const shared_ptr<ConnectionStatistics
|
||||
this->properties->registerProperty("connection_bandwidth_received_last_second_total", 0, PROP_STATISTIC);
|
||||
this->properties->registerProperty("connection_bandwidth_received_last_minute_total", 0, PROP_STATISTIC);
|
||||
|
||||
this->properties->registerProperty("connection_filetransfer_bandwidth_sent", 0, PROP_STATISTIC);
|
||||
this->properties->registerProperty("connection_filetransfer_bandwidth_received", 0, PROP_STATISTIC);
|
||||
this->properties->registerProperty("connection_filetransfer_bytes_sent_total", 0, PROP_STATISTIC);
|
||||
this->properties->registerProperty("connection_filetransfer_bytes_received_total", 0, PROP_STATISTIC);
|
||||
*/
|
||||
this->properties->registerProperty("connection_filetransfer_bandwidth_sent", 0, PROP_STATISTIC);
|
||||
this->properties->registerProperty("connection_filetransfer_bandwidth_received", 0, PROP_STATISTIC);
|
||||
this->properties->registerProperty("connection_filetransfer_bytes_sent_total", 0, PROP_STATISTIC);
|
||||
this->properties->registerProperty("connection_filetransfer_bytes_received_total", 0, PROP_STATISTIC);
|
||||
*/
|
||||
}
|
||||
|
||||
ConnectionStatistics::~ConnectionStatistics() {
|
||||
memtrack::freed<ConnectionStatistics>(this);
|
||||
memtrack::freed<ConnectionStatistics>(this);
|
||||
|
||||
{
|
||||
lock_guard lock(this->history_lock_incoming);
|
||||
{
|
||||
lock_guard lock(this->history_lock_incoming);
|
||||
|
||||
for(auto entry : this->history_incoming)
|
||||
if(entry->use_count.fetch_sub(1) == 1)
|
||||
delete entry;
|
||||
for(auto entry : this->history_file_incoming)
|
||||
if(entry->use_count.fetch_sub(1) == 1)
|
||||
delete entry;
|
||||
for(auto entry : this->history_incoming)
|
||||
if(entry->use_count.fetch_sub(1) == 1)
|
||||
delete entry;
|
||||
for(auto entry : this->history_file_incoming)
|
||||
if(entry->use_count.fetch_sub(1) == 1)
|
||||
delete entry;
|
||||
|
||||
this->history_incoming.clear();
|
||||
this->history_file_incoming.clear();
|
||||
}
|
||||
{
|
||||
lock_guard lock(this->history_lock_outgoing);
|
||||
this->history_incoming.clear();
|
||||
this->history_file_incoming.clear();
|
||||
}
|
||||
{
|
||||
lock_guard lock(this->history_lock_outgoing);
|
||||
|
||||
for(auto entry : this->history_outgoing)
|
||||
if(entry->use_count.fetch_sub(1) == 1)
|
||||
delete entry;
|
||||
for(auto entry : this->history_file_outgoing)
|
||||
if(entry->use_count.fetch_sub(1) == 1)
|
||||
delete entry;
|
||||
for(auto entry : this->history_outgoing)
|
||||
if(entry->use_count.fetch_sub(1) == 1)
|
||||
delete entry;
|
||||
for(auto entry : this->history_file_outgoing)
|
||||
if(entry->use_count.fetch_sub(1) == 1)
|
||||
delete entry;
|
||||
|
||||
this->history_outgoing.clear();
|
||||
this->history_file_outgoing.clear();
|
||||
}
|
||||
this->history_outgoing.clear();
|
||||
this->history_file_outgoing.clear();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Properties> ConnectionStatistics::statistics() {
|
||||
return this->properties;
|
||||
}
|
||||
|
||||
/* general statistics */
|
||||
inline int8_t typeIndex(const PacketTypeInfo& type){
|
||||
if(type == PacketTypeInfo::Command || type == PacketTypeInfo::CommandLow)
|
||||
return 1;
|
||||
else if(type == PacketTypeInfo::Ack || type == PacketTypeInfo::AckLow)
|
||||
return 2;
|
||||
else if(type == PacketTypeInfo::Voice || type == PacketTypeInfo::VoiceWhisper)
|
||||
return 3;
|
||||
return -1;
|
||||
}
|
||||
void ConnectionStatistics::logIncomingPacket(const category::value &category, size_t size) {
|
||||
auto info_entry = new StatisticEntry{};
|
||||
info_entry->timestamp = system_clock::now();
|
||||
info_entry->size = uint16_t(size);
|
||||
|
||||
void ConnectionStatistics::logIncomingPacket(const ClientPacket& pkt) {
|
||||
auto info_entry = new StatisticEntry{};
|
||||
info_entry->timestamp = system_clock::now();
|
||||
info_entry->size = uint16_t(pkt.data().length() + pkt.header().length() + pkt.mac().length());
|
||||
|
||||
auto index = typeIndex(pkt.type());
|
||||
this->_log_incoming_packet(info_entry, index);
|
||||
this->_log_incoming_packet(info_entry, category);
|
||||
}
|
||||
|
||||
void ConnectionStatistics::_log_incoming_packet(ts::stats::StatisticEntry *info_entry, int8_t index) {
|
||||
if(index >= 0 && index <= 3) {
|
||||
this->connection_packets_received[index] ++;
|
||||
this->connection_bytes_received[index] += info_entry->size;
|
||||
}
|
||||
this->connection_packets_received[0] ++;
|
||||
this->connection_bytes_received[0] += info_entry->size;
|
||||
if(index >= 0 && index <= 3) {
|
||||
this->connection_packets_received[index] ++;
|
||||
this->connection_bytes_received[index] += info_entry->size;
|
||||
}
|
||||
this->connection_packets_received[0] ++;
|
||||
this->connection_bytes_received[0] += info_entry->size;
|
||||
|
||||
if(this->_measure_bandwidths) {
|
||||
auto lock_count = info_entry->use_count++;
|
||||
assert(lock_count >= 0);
|
||||
if(this->_measure_bandwidths) {
|
||||
auto lock_count = info_entry->use_count++;
|
||||
assert(lock_count >= 0);
|
||||
(void) lock_count;
|
||||
|
||||
lock_guard lock(this->history_lock_incoming);
|
||||
this->history_incoming.push_back(info_entry);
|
||||
}
|
||||
if(this->handle)
|
||||
this->handle->_log_incoming_packet(info_entry, index);
|
||||
lock_guard lock(this->history_lock_incoming);
|
||||
this->history_incoming.push_back(info_entry);
|
||||
}
|
||||
if(this->handle)
|
||||
this->handle->_log_incoming_packet(info_entry, index);
|
||||
}
|
||||
|
||||
void ConnectionStatistics::logOutgoingPacket(const ServerPacket& pkt) {
|
||||
auto info_entry = new StatisticEntry{};
|
||||
info_entry->timestamp = system_clock::now();
|
||||
info_entry->size = uint16_t(pkt.data().length() + pkt.header().length() + pkt.mac().length());
|
||||
void ConnectionStatistics::logOutgoingPacket(const category::value &category, size_t size) {
|
||||
auto info_entry = new StatisticEntry{};
|
||||
info_entry->timestamp = system_clock::now();
|
||||
info_entry->size = uint16_t(size);
|
||||
|
||||
auto index = typeIndex(pkt.type());
|
||||
this->_log_outgoing_packet(info_entry, index);
|
||||
this->_log_outgoing_packet(info_entry, category);
|
||||
}
|
||||
|
||||
|
||||
void ConnectionStatistics::_log_outgoing_packet(ts::stats::StatisticEntry *info_entry, int8_t index) {
|
||||
if(index >= 0 && index <= 3) {
|
||||
this->connection_packets_sent[index] ++;
|
||||
this->connection_bytes_sent[index] += info_entry->size;
|
||||
}
|
||||
this->connection_packets_sent[0] ++;
|
||||
this->connection_bytes_sent[0] += info_entry->size;
|
||||
if(index >= 0 && index <= 3) {
|
||||
this->connection_packets_sent[index] ++;
|
||||
this->connection_bytes_sent[index] += info_entry->size;
|
||||
}
|
||||
this->connection_packets_sent[0] ++;
|
||||
this->connection_bytes_sent[0] += info_entry->size;
|
||||
|
||||
if(this->_measure_bandwidths) {
|
||||
auto lock_count = info_entry->use_count++;
|
||||
assert(lock_count >= 0);
|
||||
if(this->_measure_bandwidths) {
|
||||
auto lock_count = info_entry->use_count++;
|
||||
assert(lock_count >= 0);
|
||||
(void) lock_count;
|
||||
|
||||
lock_guard lock(this->history_lock_outgoing);
|
||||
this->history_outgoing.push_back(info_entry);
|
||||
}
|
||||
if(this->handle)
|
||||
this->handle->_log_outgoing_packet(info_entry, index);
|
||||
lock_guard lock(this->history_lock_outgoing);
|
||||
this->history_outgoing.push_back(info_entry);
|
||||
}
|
||||
if(this->handle)
|
||||
this->handle->_log_outgoing_packet(info_entry, index);
|
||||
}
|
||||
|
||||
/* file transfer */
|
||||
void ConnectionStatistics::logFileTransfareIn(uint64_t bytes) {
|
||||
auto info_entry = new StatisticEntry{};
|
||||
info_entry->timestamp = system_clock::now();
|
||||
info_entry->size = bytes;
|
||||
void ConnectionStatistics::logFileTransferIn(uint64_t bytes) {
|
||||
auto info_entry = new StatisticEntry{};
|
||||
info_entry->timestamp = system_clock::now();
|
||||
info_entry->size = bytes;
|
||||
|
||||
this->_log_incoming_file_packet(info_entry);
|
||||
this->_log_incoming_file_packet(info_entry);
|
||||
}
|
||||
|
||||
void ConnectionStatistics::_log_incoming_file_packet(ts::stats::StatisticEntry *info_entry) {
|
||||
this->file_bytes_received += info_entry->size;
|
||||
this->file_bytes_received += info_entry->size;
|
||||
|
||||
if(this->_measure_bandwidths) {
|
||||
auto lock_count = info_entry->use_count++;
|
||||
assert(lock_count >= 0);
|
||||
if(this->_measure_bandwidths) {
|
||||
auto lock_count = info_entry->use_count++;
|
||||
assert(lock_count >= 0);
|
||||
(void) lock_count;
|
||||
|
||||
lock_guard lock(this->history_lock_incoming);
|
||||
this->history_file_incoming.push_back(info_entry);
|
||||
}
|
||||
lock_guard lock(this->history_lock_incoming);
|
||||
this->history_file_incoming.push_back(info_entry);
|
||||
}
|
||||
|
||||
if(this->handle)
|
||||
this->handle->_log_incoming_file_packet(info_entry);
|
||||
if(this->handle)
|
||||
this->handle->_log_incoming_file_packet(info_entry);
|
||||
}
|
||||
|
||||
void ConnectionStatistics::logFileTransfareOut(uint64_t bytes) {
|
||||
auto info_entry = new StatisticEntry{};
|
||||
info_entry->timestamp = system_clock::now();
|
||||
info_entry->size = bytes;
|
||||
void ConnectionStatistics::logFileTransferOut(uint64_t bytes) {
|
||||
auto info_entry = new StatisticEntry{};
|
||||
info_entry->timestamp = system_clock::now();
|
||||
info_entry->size = bytes;
|
||||
|
||||
this->_log_outgoing_file_packet(info_entry);
|
||||
this->_log_outgoing_file_packet(info_entry);
|
||||
}
|
||||
|
||||
void ConnectionStatistics::_log_outgoing_file_packet(ts::stats::StatisticEntry *info_entry) {
|
||||
this->file_bytes_sent += info_entry->size;
|
||||
this->file_bytes_sent += info_entry->size;
|
||||
|
||||
if(this->_measure_bandwidths) {
|
||||
auto lock_count = info_entry->use_count++;
|
||||
assert(lock_count >= 0);
|
||||
if(this->_measure_bandwidths) {
|
||||
auto lock_count = info_entry->use_count++;
|
||||
assert(lock_count >= 0);
|
||||
(void) lock_count;
|
||||
|
||||
lock_guard lock(this->history_lock_outgoing);
|
||||
this->history_file_outgoing.push_back(info_entry);
|
||||
}
|
||||
lock_guard lock(this->history_lock_outgoing);
|
||||
this->history_file_outgoing.push_back(info_entry);
|
||||
}
|
||||
|
||||
if(this->handle)
|
||||
this->handle->_log_outgoing_file_packet(info_entry);
|
||||
if(this->handle)
|
||||
this->handle->_log_outgoing_file_packet(info_entry);
|
||||
}
|
||||
|
||||
void ConnectionStatistics::tick() {
|
||||
StatisticEntry* entry;
|
||||
{
|
||||
auto timeout_min = system_clock::now() - minutes(1);
|
||||
StatisticEntry* entry;
|
||||
{
|
||||
auto timeout_min = system_clock::now() - minutes(1);
|
||||
|
||||
lock_guard lock(this->history_lock_incoming);
|
||||
lock_guard lock(this->history_lock_incoming);
|
||||
|
||||
while(!this->history_incoming.empty() && (entry = this->history_incoming[0])->timestamp < timeout_min) {
|
||||
if(entry->use_count.fetch_sub(1) == 1)
|
||||
delete entry;
|
||||
while(!this->history_incoming.empty() && (entry = this->history_incoming[0])->timestamp < timeout_min) {
|
||||
if(entry->use_count.fetch_sub(1) == 1)
|
||||
delete entry;
|
||||
|
||||
this->history_incoming.pop_front();
|
||||
}
|
||||
this->history_incoming.pop_front();
|
||||
}
|
||||
|
||||
while(!this->history_file_incoming.empty() && (entry = this->history_file_incoming[0])->timestamp < timeout_min) {
|
||||
if(entry->use_count.fetch_sub(1) == 1)
|
||||
delete entry;
|
||||
while(!this->history_file_incoming.empty() && (entry = this->history_file_incoming[0])->timestamp < timeout_min) {
|
||||
if(entry->use_count.fetch_sub(1) == 1)
|
||||
delete entry;
|
||||
|
||||
this->history_file_incoming.pop_front();
|
||||
}
|
||||
}
|
||||
{
|
||||
auto timeout_min = system_clock::now() - minutes(1);
|
||||
lock_guard lock(this->history_lock_outgoing);
|
||||
this->history_file_incoming.pop_front();
|
||||
}
|
||||
}
|
||||
{
|
||||
auto timeout_min = system_clock::now() - minutes(1);
|
||||
lock_guard lock(this->history_lock_outgoing);
|
||||
|
||||
while(!this->history_outgoing.empty() && (entry = this->history_outgoing[0])->timestamp < timeout_min) {
|
||||
if(entry->use_count.fetch_sub(1) == 1)
|
||||
delete entry;
|
||||
while(!this->history_outgoing.empty() && (entry = this->history_outgoing[0])->timestamp < timeout_min) {
|
||||
if(entry->use_count.fetch_sub(1) == 1)
|
||||
delete entry;
|
||||
|
||||
this->history_outgoing.pop_front();
|
||||
}
|
||||
this->history_outgoing.pop_front();
|
||||
}
|
||||
|
||||
while(!this->history_file_outgoing.empty() && (entry = this->history_file_outgoing[0])->timestamp < timeout_min) {
|
||||
if(entry->use_count.fetch_sub(1) == 1)
|
||||
delete entry;
|
||||
while(!this->history_file_outgoing.empty() && (entry = this->history_file_outgoing[0])->timestamp < timeout_min) {
|
||||
if(entry->use_count.fetch_sub(1) == 1)
|
||||
delete entry;
|
||||
|
||||
this->history_file_outgoing.pop_front();
|
||||
}
|
||||
}
|
||||
this->history_file_outgoing.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
if(this->properties) {
|
||||
auto& _properties = *this->properties;
|
||||
if(this->properties) {
|
||||
auto& _properties = *this->properties;
|
||||
#define M(type, index) \
|
||||
_properties[property::CONNECTION_BYTES_SENT_ ##type] = (uint64_t) this->connection_bytes_sent[index]; \
|
||||
_properties[property::CONNECTION_PACKETS_SENT_ ##type] = (uint64_t) this->connection_packets_sent[index]; \
|
||||
_properties[property::CONNECTION_BYTES_RECEIVED_ ##type] = (uint64_t) this->connection_bytes_received[index]; \
|
||||
_properties[property::CONNECTION_PACKETS_RECEIVED_ ##type] = (uint64_t) this->connection_packets_received[index]; \
|
||||
_properties[property::CONNECTION_BYTES_SENT_ ##type] = (uint64_t) this->connection_bytes_sent[index]; \
|
||||
_properties[property::CONNECTION_PACKETS_SENT_ ##type] = (uint64_t) this->connection_packets_sent[index]; \
|
||||
_properties[property::CONNECTION_BYTES_RECEIVED_ ##type] = (uint64_t) this->connection_bytes_received[index]; \
|
||||
_properties[property::CONNECTION_PACKETS_RECEIVED_ ##type] = (uint64_t) this->connection_packets_received[index]; \
|
||||
|
||||
M(TOTAL, 0);
|
||||
M(CONTROL, 1);
|
||||
M(KEEPALIVE, 2);
|
||||
M(SPEECH, 3);
|
||||
M(TOTAL, 0);
|
||||
M(CONTROL, 1);
|
||||
M(KEEPALIVE, 2);
|
||||
M(SPEECH, 3);
|
||||
|
||||
_properties[property::CONNECTION_FILETRANSFER_BYTES_RECEIVED_TOTAL] = (uint64_t) this->file_bytes_received;
|
||||
_properties[property::CONNECTION_FILETRANSFER_BYTES_SENT_TOTAL] = (uint64_t) this->file_bytes_sent;
|
||||
}
|
||||
_properties[property::CONNECTION_FILETRANSFER_BYTES_RECEIVED_TOTAL] = (uint64_t) this->file_bytes_received;
|
||||
_properties[property::CONNECTION_FILETRANSFER_BYTES_SENT_TOTAL] = (uint64_t) this->file_bytes_sent;
|
||||
|
||||
_properties[property::CONNECTION_FILETRANSFER_BYTES_RECEIVED_TOTAL] = (uint64_t) this->file_bytes_received;
|
||||
_properties[property::CONNECTION_FILETRANSFER_BYTES_SENT_TOTAL] = (uint64_t) this->file_bytes_sent;
|
||||
}
|
||||
}
|
||||
|
||||
DataSummery ConnectionStatistics::dataReport() {
|
||||
DataSummery report{};
|
||||
auto minTimeout = system_clock::now() - seconds(1);
|
||||
auto minTimeout = system_clock::now() - seconds(1);
|
||||
|
||||
|
||||
{
|
||||
lock_guard lock(this->history_lock_incoming);
|
||||
{
|
||||
lock_guard lock(this->history_lock_incoming);
|
||||
|
||||
for(const auto& elm : this->history_incoming){
|
||||
if(elm->timestamp >= minTimeout) {
|
||||
report.recv_second += elm->size;
|
||||
}
|
||||
for(const auto& elm : this->history_incoming){
|
||||
if(elm->timestamp >= minTimeout) {
|
||||
report.recv_second += elm->size;
|
||||
}
|
||||
|
||||
report.recv_minute += elm->size;
|
||||
}
|
||||
report.recv_minute += elm->size;
|
||||
}
|
||||
|
||||
for(const auto& elm : this->history_file_incoming) {
|
||||
report.file_recv += elm->size;
|
||||
}
|
||||
}
|
||||
for(const auto& elm : this->history_file_incoming) {
|
||||
report.file_recv += elm->size;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
lock_guard lock(this->history_lock_outgoing);
|
||||
{
|
||||
lock_guard lock(this->history_lock_outgoing);
|
||||
|
||||
for(const auto& elm : this->history_outgoing){
|
||||
if(elm->timestamp >= minTimeout) {
|
||||
report.send_second += elm->size;
|
||||
}
|
||||
for(const auto& elm : this->history_outgoing){
|
||||
if(elm->timestamp >= minTimeout) {
|
||||
report.send_second += elm->size;
|
||||
}
|
||||
|
||||
report.send_minute += elm->size;
|
||||
}
|
||||
report.send_minute += elm->size;
|
||||
}
|
||||
|
||||
for(const auto& elm : this->history_file_outgoing) {
|
||||
report.file_send += elm->size;
|
||||
}
|
||||
}
|
||||
for(const auto& elm : this->history_file_outgoing) {
|
||||
report.file_send += elm->size;
|
||||
}
|
||||
}
|
||||
|
||||
report.recv_minute /= 60;
|
||||
report.send_minute /= 60;
|
||||
return report;
|
||||
}
|
||||
|
||||
FullReport ConnectionStatistics::full_report() {
|
||||
FullReport report{};
|
||||
|
||||
for(size_t index = 0 ; index < 4; index++) {
|
||||
report.connection_bytes_sent[index] = (uint64_t) this->connection_bytes_sent[index];
|
||||
report.connection_packets_sent[index] = (uint64_t) this->connection_packets_sent[index];
|
||||
report.connection_bytes_received[index] = (uint64_t) this->connection_bytes_received[index];
|
||||
report.connection_packets_received[index] = (uint64_t) this->connection_packets_received[index];
|
||||
}
|
||||
|
||||
report.file_bytes_sent = this->file_bytes_sent;
|
||||
report.file_bytes_received = this->file_bytes_received;
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
std::pair<uint64_t, uint64_t> ConnectionStatistics::mark_file_bytes() {
|
||||
std::pair<uint64_t, uint64_t> result;
|
||||
std::pair<uint64_t, uint64_t> result;
|
||||
|
||||
{
|
||||
lock_guard lock(this->history_lock_incoming);
|
||||
if(this->mark_file_bytes_received < this->file_bytes_received)
|
||||
result.second = this->file_bytes_received - this->mark_file_bytes_received;
|
||||
this->mark_file_bytes_received = (uint64_t) this->file_bytes_received;
|
||||
}
|
||||
{
|
||||
lock_guard lock(this->history_lock_incoming);
|
||||
if(this->mark_file_bytes_received < this->file_bytes_received)
|
||||
result.second = this->file_bytes_received - this->mark_file_bytes_received;
|
||||
this->mark_file_bytes_received = (uint64_t) this->file_bytes_received;
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
|
||||
lock_guard lock(this->history_lock_outgoing);
|
||||
lock_guard lock(this->history_lock_outgoing);
|
||||
|
||||
if(this->mark_file_bytes_sent < this->file_bytes_sent)
|
||||
result.first = this->file_bytes_sent - this->mark_file_bytes_sent;
|
||||
this->mark_file_bytes_sent = (uint64_t) this->file_bytes_sent;
|
||||
}
|
||||
if(this->mark_file_bytes_sent < this->file_bytes_sent)
|
||||
result.first = this->file_bytes_sent - this->mark_file_bytes_sent;
|
||||
this->mark_file_bytes_sent = (uint64_t) this->file_bytes_sent;
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
namespace ts {
|
||||
namespace server {
|
||||
class TSServer;
|
||||
class VirtualServer;
|
||||
}
|
||||
|
||||
namespace stats {
|
||||
@@ -28,51 +28,78 @@ namespace ts {
|
||||
uint32_t file_send;
|
||||
};
|
||||
|
||||
struct FullReport {
|
||||
uint64_t connection_packets_sent[4]{0, 0, 0, 0};
|
||||
uint64_t connection_bytes_sent[4]{0, 0, 0, 0};
|
||||
uint64_t connection_packets_received[4]{0, 0, 0, 0};
|
||||
uint64_t connection_bytes_received[4]{0, 0, 0, 0};
|
||||
|
||||
uint64_t file_bytes_sent = 0;
|
||||
uint64_t file_bytes_received = 0;
|
||||
};
|
||||
|
||||
class ConnectionStatistics {
|
||||
public:
|
||||
struct category {
|
||||
enum value {
|
||||
COMMAND,
|
||||
ACK,
|
||||
VOICE,
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
constexpr static std::array<category::value, 16> lookup_table{
|
||||
VOICE, /* Voice */
|
||||
VOICE, /* VoiceWhisper */
|
||||
COMMAND, /* Command */
|
||||
COMMAND, /* CommandLow */
|
||||
ACK, /* Ping */
|
||||
ACK, /* Pong */
|
||||
ACK, /* Ack */
|
||||
ACK, /* AckLow */
|
||||
COMMAND, /* */
|
||||
|
||||
UNKNOWN,
|
||||
UNKNOWN,
|
||||
UNKNOWN,
|
||||
UNKNOWN,
|
||||
UNKNOWN,
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
/* much faster than a switch */
|
||||
inline static category::value from_type(uint8_t type){
|
||||
return lookup_table[type & 0xFU];
|
||||
}
|
||||
|
||||
inline static category::value from_type(const protocol::PacketTypeInfo& type){
|
||||
return from_type(type.type());
|
||||
}
|
||||
};
|
||||
explicit ConnectionStatistics(const std::shared_ptr<ConnectionStatistics>& /* root */, bool /* spawn properties */);
|
||||
~ConnectionStatistics();
|
||||
|
||||
std::shared_ptr<Properties> statistics();
|
||||
|
||||
void logIncomingPacket(const protocol::ClientPacket&);
|
||||
void logOutgoingPacket(const protocol::ServerPacket&);
|
||||
void logFileTransfareIn(uint64_t);
|
||||
void logFileTransfareOut(uint64_t);
|
||||
inline void logIncomingPacket(const protocol::ClientPacket& packet) { this->logIncomingPacket(category::from_type(packet.type()), packet.length()); }
|
||||
void logIncomingPacket(const category::value& /* category */, size_t /* length */);
|
||||
inline void logOutgoingPacket(const protocol::ServerPacket& packet) { this->logOutgoingPacket(category::from_type(packet.type()), packet.length()); }
|
||||
void logOutgoingPacket(const category::value& /* category */, size_t /* length */);
|
||||
void logFileTransferIn(uint64_t);
|
||||
void logFileTransferOut(uint64_t);
|
||||
|
||||
void tick();
|
||||
|
||||
DataSummery dataReport();
|
||||
FullReport full_report();
|
||||
|
||||
std::pair<uint64_t, uint64_t> mark_file_bytes();
|
||||
|
||||
inline bool measure_bandwidths() { return this->_measure_bandwidths; }
|
||||
void measure_bandwidths(bool flag) { this->_measure_bandwidths = flag; }
|
||||
|
||||
inline bool has_properties() { return !!this->properties; }
|
||||
private:
|
||||
class spin_lock {
|
||||
std::atomic_flag locked = ATOMIC_FLAG_INIT;
|
||||
public:
|
||||
void lock() {
|
||||
uint8_t round = 0;
|
||||
while (locked.test_and_set(std::memory_order_acquire)) {
|
||||
//Yield when we're using this lock for a longer time, which we usually not doing
|
||||
if(round++ % 8 == 0)
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
|
||||
inline bool try_lock() {
|
||||
return !locked.test_and_set(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
locked.clear(std::memory_order_release);
|
||||
}
|
||||
};
|
||||
typedef spin_lock fast_lock_t;
|
||||
void measure_bandwidths(bool flag) { this->_measure_bandwidths = flag; }
|
||||
|
||||
inline bool has_properties() { return !!this->properties; }
|
||||
private:
|
||||
bool _measure_bandwidths = true;
|
||||
std::shared_ptr<ConnectionStatistics> handle;
|
||||
std::shared_ptr<Properties> properties;
|
||||
@@ -89,18 +116,18 @@ namespace ts {
|
||||
std::atomic<uint64_t> mark_file_bytes_sent = 0;
|
||||
std::atomic<uint64_t> mark_file_bytes_received = 0;
|
||||
|
||||
fast_lock_t history_lock_outgoing;
|
||||
fast_lock_t history_lock_incoming;
|
||||
std::deque<StatisticEntry*> history_file_incoming{};
|
||||
std::deque<StatisticEntry*> history_file_outgoing{};
|
||||
std::deque<StatisticEntry*> history_incoming{};
|
||||
std::deque<StatisticEntry*> history_outgoing{};
|
||||
spin_lock history_lock_outgoing;
|
||||
spin_lock history_lock_incoming;
|
||||
std::deque<StatisticEntry*> history_file_incoming{};
|
||||
std::deque<StatisticEntry*> history_file_outgoing{};
|
||||
std::deque<StatisticEntry*> history_incoming{};
|
||||
std::deque<StatisticEntry*> history_outgoing{};
|
||||
|
||||
void _log_incoming_packet(StatisticEntry */* statistics */, int8_t /* type index */);
|
||||
void _log_outgoing_packet(StatisticEntry* /* statistics */, int8_t /* type index */);
|
||||
void _log_incoming_packet(StatisticEntry */* statistics */, int8_t /* type index */);
|
||||
void _log_outgoing_packet(StatisticEntry* /* statistics */, int8_t /* type index */);
|
||||
|
||||
void _log_incoming_file_packet(StatisticEntry */* statistics */);
|
||||
void _log_outgoing_file_packet(StatisticEntry* /* statistics */);
|
||||
void _log_incoming_file_packet(StatisticEntry */* statistics */);
|
||||
void _log_outgoing_file_packet(StatisticEntry* /* statistics */);
|
||||
};
|
||||
}
|
||||
}
|
||||
+650
-813
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user