Merge branch 'master-develop' of gitee.com:shenzhen-jiuyilian/ipc into master-develop
This commit is contained in:
commit
18c0123ea9
6
Makefile
6
Makefile
|
@ -13,6 +13,12 @@ cmake_clean:
|
||||||
clean_code:
|
clean_code:
|
||||||
@rm -rf !(Makefile)
|
@rm -rf !(Makefile)
|
||||||
|
|
||||||
|
install_cmake:
|
||||||
|
$(MAKE) -C tools/cmake all
|
||||||
|
|
||||||
|
compile_llvm:
|
||||||
|
$(MAKE) -C tools/clang-tidy all
|
||||||
|
|
||||||
all:cmake
|
all:cmake
|
||||||
$(MAKE) -C cmake-shell all
|
$(MAKE) -C cmake-shell all
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ set(CLANG_FORMAT_FILE "LLVM ${CMAKE_SOURCE_DIR_IPCSDK}/tools/clang-format/.clang
|
||||||
if(${LINUX_TEST} MATCHES "true")
|
if(${LINUX_TEST} MATCHES "true")
|
||||||
set(CLANG_TIDY_SUPPORT "true")
|
set(CLANG_TIDY_SUPPORT "true")
|
||||||
set(CLANG_FORMAT_SUPPORT "true")
|
set(CLANG_FORMAT_SUPPORT "true")
|
||||||
set(LLVM_PATH "/home/xiaojiazhu/project/tmp/llvm-project")
|
set(LLVM_PATH "${CMAKE_SOURCE_DIR_IPCSDK}/tools/clang-tidy/llvm-project")
|
||||||
endif()
|
endif()
|
||||||
# ------------ build clang-tools end ------------ #
|
# ------------ build clang-tools end ------------ #
|
||||||
|
|
||||||
|
|
19
external/CMakeLists.txt
vendored
19
external/CMakeLists.txt
vendored
|
@ -1,5 +1,22 @@
|
||||||
|
|
||||||
add_subdirectory(sqlite3/sqlite-3430000)
|
add_subdirectory(sqlite3/sqlite-3430000)
|
||||||
add_subdirectory(goahead-5.2.0)
|
add_subdirectory(goahead-5.2.0)
|
||||||
|
|
||||||
|
# ================= httpserver ================= #
|
||||||
|
find_program(M4 m4)
|
||||||
|
if(NOT M4)
|
||||||
|
message("m4 not found. Install before continuing.")
|
||||||
|
execute_process(COMMAND sudo apt-get install m4
|
||||||
|
WORKING_DIRECTORY ${EXTERNAL_SOURCE_PATH}/gtest/)
|
||||||
|
endif()
|
||||||
|
find_program(RAGEL ragel)
|
||||||
|
if(NOT RAGEL)
|
||||||
|
message(FATAL_ERROR "ragel not found. Install before continuing.")
|
||||||
|
execute_process(COMMAND sudo apt-get install ragel
|
||||||
|
WORKING_DIRECTORY ${EXTERNAL_SOURCE_PATH}/gtest/)
|
||||||
|
endif()
|
||||||
add_subdirectory(httpserver.h-master/src)
|
add_subdirectory(httpserver.h-master/src)
|
||||||
add_subdirectory(cJSON-1.7.17)
|
# ================= httpserver end ================= #
|
||||||
|
|
||||||
|
add_subdirectory(cJSON-1.7.17)
|
||||||
|
add_subdirectory(libhv/libhv-1.3.2)
|
1
external/libhv/README.md
vendored
Normal file
1
external/libhv/README.md
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#
|
95
external/libhv/libhv-1.3.2/.clang-format
vendored
Normal file
95
external/libhv/libhv-1.3.2/.clang-format
vendored
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
# BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlinesLeft: true
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
|
AllowShortFunctionsOnASingleLine: Inline
|
||||||
|
AllowShortIfStatementsOnASingleLine: true
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: false
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
BeforeCatch: true
|
||||||
|
BeforeElse: true
|
||||||
|
IndentBraces: false
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: true
|
||||||
|
ColumnLimit: 160
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DerivePointerAlignment: true
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 1
|
||||||
|
- Regex: '^".*/'
|
||||||
|
Priority: 2
|
||||||
|
- Regex: '^<)'
|
||||||
|
Priority: 3
|
||||||
|
IncludeIsMainRegex: '$'
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBlockIndentWidth: 4
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: false
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Cpp11
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
...
|
||||||
|
|
1
external/libhv/libhv-1.3.2/.gitattributes
vendored
Normal file
1
external/libhv/libhv-1.3.2/.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
cpputil/json.hpp linguist-vendored
|
72
external/libhv/libhv-1.3.2/.gitignore
vendored
Normal file
72
external/libhv/libhv-1.3.2/.gitignore
vendored
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
# Compiled Object files
|
||||||
|
*.o
|
||||||
|
*.lo
|
||||||
|
*.slo
|
||||||
|
*.obj
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.a
|
||||||
|
*.la
|
||||||
|
*.lai
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
|
||||||
|
# cache
|
||||||
|
*~
|
||||||
|
*.bk
|
||||||
|
*.bak
|
||||||
|
*.old
|
||||||
|
*.new
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vs
|
||||||
|
.vscode
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
tags
|
||||||
|
cscope*
|
||||||
|
.ycm*
|
||||||
|
|
||||||
|
# generated
|
||||||
|
examples/protorpc/generated
|
||||||
|
|
||||||
|
# output
|
||||||
|
*.pid
|
||||||
|
*.log
|
||||||
|
*.db
|
||||||
|
|
||||||
|
include
|
||||||
|
lib
|
||||||
|
bin
|
||||||
|
tmp
|
||||||
|
dist
|
||||||
|
test
|
||||||
|
*_test
|
||||||
|
build
|
||||||
|
config.mk
|
||||||
|
hconfig.h
|
||||||
|
html/uploads
|
||||||
|
|
||||||
|
# msvc
|
||||||
|
*.VC.*
|
||||||
|
*.vcxproj.*
|
||||||
|
Debug
|
||||||
|
Release
|
||||||
|
|
||||||
|
# cmake
|
||||||
|
CMakeFiles
|
||||||
|
CMakeCache.txt
|
||||||
|
cmake_install.cmake
|
39
external/libhv/libhv-1.3.2/.travis.yml
vendored
Normal file
39
external/libhv/libhv-1.3.2/.travis.yml
vendored
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
language: cpp
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
include:
|
||||||
|
- os: linux
|
||||||
|
dist: xenial
|
||||||
|
compiler: gcc
|
||||||
|
env: COVERALLS=no
|
||||||
|
script:
|
||||||
|
- ./configure
|
||||||
|
- make libhv examples unittest evpp
|
||||||
|
|
||||||
|
- os: osx
|
||||||
|
compiler: clang
|
||||||
|
env: COVERALLS=no
|
||||||
|
script:
|
||||||
|
- ./configure
|
||||||
|
- make libhv examples unittest evpp
|
||||||
|
|
||||||
|
- os: windows
|
||||||
|
compiler: msvc
|
||||||
|
env: COVERALLS=no
|
||||||
|
script:
|
||||||
|
- mkdir win64
|
||||||
|
- cd win64
|
||||||
|
- cmake .. -G "Visual Studio 15 2017 Win64"
|
||||||
|
- cmake --build .
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- if [ "$COVERALLS" = "yes" ]; then
|
||||||
|
pip install --user cpp-coveralls;
|
||||||
|
export CC="$CC --coverage" CXX="$CXX --coverage";
|
||||||
|
fi
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- if [ "$COVERALLS" = "yes" ]; then
|
||||||
|
scripts/test-coverage.sh;
|
||||||
|
coveralls --gcov-options '\-lp' --include base --include event --include http;
|
||||||
|
fi
|
156
external/libhv/libhv-1.3.2/BUILD.md
vendored
Normal file
156
external/libhv/libhv-1.3.2/BUILD.md
vendored
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
## Prequired
|
||||||
|
|
||||||
|
- c99
|
||||||
|
- c++11
|
||||||
|
|
||||||
|
gcc4.8+, msvc2015 or later
|
||||||
|
|
||||||
|
## Makefile
|
||||||
|
options see [config.ini](config.ini)
|
||||||
|
```
|
||||||
|
./configure --with-openssl
|
||||||
|
make
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
## cmake
|
||||||
|
options see [CMakeLists.txt](CMakeLists.txt)
|
||||||
|
```
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -DWITH_OPENSSL=ON
|
||||||
|
cmake --build .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Unix
|
||||||
|
use Makefile or cmake
|
||||||
|
|
||||||
|
## Windows
|
||||||
|
use cmake
|
||||||
|
```
|
||||||
|
mkdir win64
|
||||||
|
cd win64
|
||||||
|
cmake .. -G "Visual Studio 15 2017 Win64"
|
||||||
|
#cmake .. -G "Visual Studio 16 2019" -A x64
|
||||||
|
#cmake .. -G "Visual Studio 17 2022" -A x64
|
||||||
|
cmake --build .
|
||||||
|
```
|
||||||
|
|
||||||
|
## CROSS_COMPILE
|
||||||
|
use Makefile
|
||||||
|
```
|
||||||
|
sudo apt install gcc-arm-linux-gnueabi g++-arm-linux-gnueabi # ubuntu
|
||||||
|
export CROSS_COMPILE=arm-linux-gnueabi-
|
||||||
|
./configure
|
||||||
|
make clean
|
||||||
|
make libhv
|
||||||
|
```
|
||||||
|
or use cmake
|
||||||
|
```
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -DCMAKE_C_COMPILER=arm-linux-gnueabi-gcc -DCMAKE_CXX_COMPILER=arm-linux-gnueabi-g++
|
||||||
|
cmake --build . --target libhv libhv_static
|
||||||
|
```
|
||||||
|
|
||||||
|
### mingw
|
||||||
|
see CROSS_COMPILE
|
||||||
|
```
|
||||||
|
sudo apt install mingw-w64 # ubuntu
|
||||||
|
#export CROSS_COMPILE=i686-w64-mingw32-
|
||||||
|
export CROSS_COMPILE=x86_64-w64-mingw32-
|
||||||
|
./configure
|
||||||
|
make clean
|
||||||
|
make libhv
|
||||||
|
```
|
||||||
|
|
||||||
|
### Android
|
||||||
|
```
|
||||||
|
#https://developer.android.com/ndk/downloads
|
||||||
|
#export ANDROID_NDK_ROOT=~/Downloads/android-ndk-r21b
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake" -DANDROID_ABI="arm64-v8a" -DANDROID_PLATFORM=android-21
|
||||||
|
cmake --build . --target hv --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
### iOS
|
||||||
|
```
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -G Xcode -DCMAKE_TOOLCHAIN_FILE=../cmake/ios.toolchain.cmake -DPLATFORM=OS64 -DARCHS="arm64" -DDEPLOYMENT_TARGET=9.0
|
||||||
|
cmake --build . --target hv_static --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
## targets
|
||||||
|
|
||||||
|
### lib
|
||||||
|
- make libhv
|
||||||
|
|
||||||
|
### examples
|
||||||
|
- make examples
|
||||||
|
|
||||||
|
### unittest
|
||||||
|
- make unittest
|
||||||
|
|
||||||
|
## options
|
||||||
|
|
||||||
|
### compile without c++
|
||||||
|
```
|
||||||
|
./configure --without-evpp
|
||||||
|
make clean && make libhv
|
||||||
|
```
|
||||||
|
|
||||||
|
### compile WITH_OPENSSL
|
||||||
|
Enable SSL/TLS in libhv is so easy :)
|
||||||
|
```
|
||||||
|
// see ssl/hssl.h
|
||||||
|
hssl_ctx_t hssl_ctx_new(hssl_ctx_opt_t* opt);
|
||||||
|
|
||||||
|
// see event/hloop.h
|
||||||
|
int hio_new_ssl_ctx(hio_t* io, hssl_ctx_opt_t* opt);
|
||||||
|
```
|
||||||
|
|
||||||
|
https is the best example.
|
||||||
|
```
|
||||||
|
sudo apt install openssl libssl-dev # ubuntu
|
||||||
|
./configure --with-openssl
|
||||||
|
make clean && make
|
||||||
|
bin/httpd -s restart -d
|
||||||
|
bin/curl -v http://localhost:8080
|
||||||
|
bin/curl -v https://localhost:8443
|
||||||
|
```
|
||||||
|
|
||||||
|
### compile WITH_CURL
|
||||||
|
```
|
||||||
|
./configure --with-curl
|
||||||
|
make clean && make
|
||||||
|
bin/httpd -s restart -d
|
||||||
|
bin/curl -v http://localhost:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
### compile WITH_NGHTTP2
|
||||||
|
```
|
||||||
|
sudo apt install libnghttp2-dev # ubuntu
|
||||||
|
./configure --with-nghttp2
|
||||||
|
make clean && make
|
||||||
|
bin/httpd -s restart -d
|
||||||
|
bin/curl -v http://localhost:8080 --http2
|
||||||
|
```
|
||||||
|
|
||||||
|
### compile WITH_KCP
|
||||||
|
```
|
||||||
|
./configure --with-kcp
|
||||||
|
make clean && make
|
||||||
|
```
|
||||||
|
|
||||||
|
### compile WITH_MQTT
|
||||||
|
```
|
||||||
|
./configure --with-mqtt
|
||||||
|
make clean && make
|
||||||
|
```
|
||||||
|
|
||||||
|
### More
|
||||||
|
```
|
||||||
|
./configure --help
|
||||||
|
```
|
283
external/libhv/libhv-1.3.2/CMakeLists.txt
vendored
Normal file
283
external/libhv/libhv-1.3.2/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,283 @@
|
||||||
|
cmake_minimum_required(VERSION 3.6)
|
||||||
|
|
||||||
|
project(hv VERSION 1.3.2)
|
||||||
|
|
||||||
|
option(BUILD_SHARED "build shared library" ON)
|
||||||
|
option(BUILD_STATIC "build static library" ON)
|
||||||
|
|
||||||
|
option(BUILD_EXAMPLES "build examples" ON)
|
||||||
|
option(BUILD_UNITTEST "build unittest" OFF)
|
||||||
|
|
||||||
|
# see config.ini
|
||||||
|
option(WITH_PROTOCOL "compile protocol" OFF)
|
||||||
|
|
||||||
|
option(WITH_EVPP "compile evpp" ON)
|
||||||
|
option(WITH_HTTP "compile http" ON)
|
||||||
|
option(WITH_HTTP_SERVER "compile http/server" ON)
|
||||||
|
option(WITH_HTTP_CLIENT "compile http/client" ON)
|
||||||
|
option(WITH_MQTT "compile mqtt" OFF)
|
||||||
|
|
||||||
|
option(ENABLE_UDS "Unix Domain Socket" OFF)
|
||||||
|
option(USE_MULTIMAP "MultiMap" OFF)
|
||||||
|
|
||||||
|
option(WITH_CURL "with curl library (deprecated)" OFF)
|
||||||
|
option(WITH_NGHTTP2 "with nghttp2 library" OFF)
|
||||||
|
|
||||||
|
option(WITH_OPENSSL "with openssl library" OFF)
|
||||||
|
option(WITH_GNUTLS "with gnutls library" OFF)
|
||||||
|
option(WITH_MBEDTLS "with mbedtls library" OFF)
|
||||||
|
|
||||||
|
option(WITH_KCP "compile event/kcp" OFF)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
option(WITH_WEPOLL "compile event/wepoll -> use iocp" ON)
|
||||||
|
option(ENABLE_WINDUMP "Windows MiniDumpWriteDump" OFF)
|
||||||
|
option(BUILD_FOR_MT "build for /MT" OFF)
|
||||||
|
if(BUILD_FOR_MT)
|
||||||
|
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd")
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
|
||||||
|
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT")
|
||||||
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "CMAKE_SOURCE_DIR=${CMAKE_SOURCE_DIR}")
|
||||||
|
message(STATUS "CMAKE_CURRENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}")
|
||||||
|
set(BUILD_EXAMPLES OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(IOS)
|
||||||
|
set(BUILD_SHARED OFF)
|
||||||
|
set(BUILD_EXAMPLES OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}")
|
||||||
|
include(utils)
|
||||||
|
include(vars)
|
||||||
|
|
||||||
|
# see configure
|
||||||
|
# Checks for header files
|
||||||
|
check_header("stdbool.h")
|
||||||
|
check_header("stdint.h")
|
||||||
|
check_header("stdatomic.h")
|
||||||
|
check_header("sys/types.h")
|
||||||
|
check_header("sys/stat.h")
|
||||||
|
check_header("sys/time.h")
|
||||||
|
check_header("fcntl.h")
|
||||||
|
check_header("pthread.h")
|
||||||
|
check_header("endian.h")
|
||||||
|
check_header("sys/endian.h")
|
||||||
|
|
||||||
|
# Checks for functions
|
||||||
|
if(NOT MSVC)
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES "-pthread")
|
||||||
|
endif()
|
||||||
|
check_function("gettid" "unistd.h")
|
||||||
|
check_function("strlcpy" "string.h")
|
||||||
|
check_function("strlcat" "string.h")
|
||||||
|
check_function("clock_gettime" "time.h")
|
||||||
|
check_function("gettimeofday" "sys/time.h")
|
||||||
|
check_function("pthread_spin_lock" "pthread.h")
|
||||||
|
check_function("pthread_mutex_timedlock" "pthread.h")
|
||||||
|
check_function("sem_timedwait" "semaphore.h")
|
||||||
|
check_function("pipe" "unistd.h")
|
||||||
|
check_function("socketpair" "sys/socket.h")
|
||||||
|
check_function("eventfd" "sys/eventfd.h")
|
||||||
|
check_function("setproctitle" "unistd.h")
|
||||||
|
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/hconfig.h.in ${CMAKE_CURRENT_SOURCE_DIR}/hconfig.h)
|
||||||
|
|
||||||
|
# see Makefile.in
|
||||||
|
set(CMAKE_C_STANDARD 99)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED True)
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
|
|
||||||
|
set(INCDIR include)
|
||||||
|
set(SRCDIR src)
|
||||||
|
set(LIBDIR lib)
|
||||||
|
set(BINDIR bin)
|
||||||
|
# ================== added by xiao ================== #
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBS_OUTPUT_PATH}})
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBS_OUTPUT_PATH}})
|
||||||
|
# ================== added by xiao ================== #
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${BINDIR})
|
||||||
|
message(STATUS "CMAKE_LIBRARY_OUTPUT_DIRECTORY=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
|
||||||
|
|
||||||
|
set(INCDIRS . include 3rd/include)
|
||||||
|
set(LIBDIRS . lib 3rd/lib)
|
||||||
|
include_directories(${INCDIRS} ${SRCDIR})
|
||||||
|
link_directories(${LIBDIRS})
|
||||||
|
|
||||||
|
message(STATUS "CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
|
||||||
|
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||||
|
add_definitions(-DDEBUG)
|
||||||
|
else()
|
||||||
|
add_definitions(-DNDEBUG)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(ENABLE_UDS)
|
||||||
|
add_definitions(-DENABLE_UDS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(USE_MULTIMAP)
|
||||||
|
add_definitions(-DUSE_MULTIMAP)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_CURL)
|
||||||
|
add_definitions(-DWITH_CURL)
|
||||||
|
set(LIBS ${LIBS} curl)
|
||||||
|
if(WIN32)
|
||||||
|
set(LIBS ${LIBS} wldap32 advapi32 crypt32)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_NGHTTP2)
|
||||||
|
add_definitions(-DWITH_NGHTTP2)
|
||||||
|
set(LIBS ${LIBS} nghttp2)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_OPENSSL)
|
||||||
|
add_definitions(-DWITH_OPENSSL)
|
||||||
|
find_package(OpenSSL)
|
||||||
|
if(OpenSSL_FOUND)
|
||||||
|
set(LIBS ${LIBS} OpenSSL::SSL OpenSSL::Crypto)
|
||||||
|
else()
|
||||||
|
set(LIBS ${LIBS} ssl crypto)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_GNUTLS)
|
||||||
|
add_definitions(-DWITH_GNUTLS)
|
||||||
|
set(LIBS ${LIBS} gnutls)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_MBEDTLS)
|
||||||
|
add_definitions(-DWITH_MBEDTLS)
|
||||||
|
set(LIBS ${LIBS} mbedtls mbedx509 mbedcrypto)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
add_definitions(-DWIN32_LEAN_AND_MEAN -D_CRT_SECURE_NO_WARNINGS -D_WIN32_WINNT=0x0600)
|
||||||
|
set(LIBS ${LIBS} secur32 crypt32 winmm iphlpapi ws2_32)
|
||||||
|
if(ENABLE_WINDUMP)
|
||||||
|
add_definitions(-DENABLE_WINDUMP)
|
||||||
|
set(LIBS ${LIBS} dbghelp)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(ANDROID)
|
||||||
|
set(LIBS ${LIBS} log)
|
||||||
|
elseif(UNIX)
|
||||||
|
set(LIBS ${LIBS} pthread m dl)
|
||||||
|
if(CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
set(LIBS ${LIBS} rt)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
set(LIBS ${LIBS} "-framework CoreFoundation" "-framework Security")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# see Makefile
|
||||||
|
set(ALL_SRCDIRS . base ssl event event/kcp util cpputil evpp protocol http http/client http/server mqtt)
|
||||||
|
set(CORE_SRCDIRS . base ssl event)
|
||||||
|
if(WIN32)
|
||||||
|
if(WITH_WEPOLL)
|
||||||
|
set(CORE_SRCDIRS ${CORE_SRCDIRS} event/wepoll)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if(WITH_KCP)
|
||||||
|
set(CORE_SRCDIRS ${CORE_SRCDIRS} event/kcp)
|
||||||
|
endif()
|
||||||
|
set(LIBHV_SRCDIRS ${CORE_SRCDIRS} util)
|
||||||
|
set(LIBHV_HEADERS hv.h hconfig.h hexport.h)
|
||||||
|
set(LIBHV_HEADERS ${LIBHV_HEADERS} ${BASE_HEADERS} ${SSL_HEADERS} ${EVENT_HEADERS} ${UTIL_HEADERS})
|
||||||
|
|
||||||
|
if(WITH_PROTOCOL)
|
||||||
|
set(LIBHV_HEADERS ${LIBHV_HEADERS} ${PROTOCOL_HEADERS})
|
||||||
|
set(LIBHV_SRCDIRS ${LIBHV_SRCDIRS} protocol)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_EVPP)
|
||||||
|
set(LIBHV_HEADERS ${LIBHV_HEADERS} ${CPPUTIL_HEADERS} ${EVPP_HEADERS})
|
||||||
|
set(LIBHV_SRCDIRS ${LIBHV_SRCDIRS} cpputil evpp)
|
||||||
|
if(WITH_HTTP)
|
||||||
|
set(LIBHV_HEADERS ${LIBHV_HEADERS} ${HTTP_HEADERS})
|
||||||
|
set(LIBHV_SRCDIRS ${LIBHV_SRCDIRS} http)
|
||||||
|
if(WITH_NGHTTP2)
|
||||||
|
set(LIBHV_HEADERS ${LIBHV_HEADERS} ${HTTP2_HEADERS})
|
||||||
|
endif()
|
||||||
|
if(WITH_HTTP_SERVER)
|
||||||
|
set(LIBHV_HEADERS ${LIBHV_HEADERS} ${HTTP_SERVER_HEADERS})
|
||||||
|
set(LIBHV_SRCDIRS ${LIBHV_SRCDIRS} http/server)
|
||||||
|
endif()
|
||||||
|
if(WITH_HTTP_CLIENT)
|
||||||
|
set(LIBHV_HEADERS ${LIBHV_HEADERS} ${HTTP_CLIENT_HEADERS})
|
||||||
|
set(LIBHV_SRCDIRS ${LIBHV_SRCDIRS} http/client)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
set(LIBS ${LIBS} stdc++)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_MQTT)
|
||||||
|
set(LIBHV_HEADERS ${LIBHV_HEADERS} ${MQTT_HEADERS})
|
||||||
|
set(LIBHV_SRCDIRS ${LIBHV_SRCDIRS} mqtt)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list_source_directories(LIBHV_SRCS ${LIBHV_SRCDIRS})
|
||||||
|
|
||||||
|
file(INSTALL ${LIBHV_HEADERS} DESTINATION include/hv)
|
||||||
|
file(INSTALL ${LIBHV_HEADERS} DESTINATION ${PROJECT_SOURCE_DIR}/include/hv)
|
||||||
|
|
||||||
|
if(BUILD_SHARED)
|
||||||
|
add_library(hv SHARED ${LIBHV_SRCS})
|
||||||
|
target_compile_definitions(hv PRIVATE HV_DYNAMICLIB)
|
||||||
|
target_include_directories(hv PRIVATE ${LIBHV_SRCDIRS}
|
||||||
|
INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include>)
|
||||||
|
target_link_libraries(hv ${LIBS})
|
||||||
|
install(TARGETS hv
|
||||||
|
EXPORT libhvConfig
|
||||||
|
ARCHIVE DESTINATION lib
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
RUNTIME DESTINATION bin)
|
||||||
|
add_custom_target(libhv DEPENDS hv)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(BUILD_STATIC)
|
||||||
|
add_library(hv_static STATIC ${LIBHV_SRCS})
|
||||||
|
target_compile_definitions(hv_static PUBLIC HV_STATICLIB)
|
||||||
|
target_include_directories(hv_static PRIVATE ${LIBHV_SRCDIRS}
|
||||||
|
INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include>)
|
||||||
|
target_link_libraries(hv_static ${LIBS})
|
||||||
|
install(TARGETS hv_static
|
||||||
|
EXPORT libhvConfig
|
||||||
|
ARCHIVE DESTINATION lib)
|
||||||
|
add_custom_target(libhv_static DEPENDS hv_static)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install(FILES ${LIBHV_HEADERS} DESTINATION include/hv)
|
||||||
|
install(EXPORT libhvConfig DESTINATION lib/cmake/libhv)
|
||||||
|
|
||||||
|
if(BUILD_SHARED)
|
||||||
|
set(HV_LIBRARIES hv CACHE INTERNAL "link hv libraries")
|
||||||
|
else()
|
||||||
|
add_definitions(-DHV_STATICLIB)
|
||||||
|
set(HV_LIBRARIES hv_static ${LIBS} CACHE INTERNAL "link hv libraries")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(BUILD_EXAMPLES)
|
||||||
|
add_subdirectory(examples)
|
||||||
|
# for httpd -c etc/httpd.conf
|
||||||
|
file(INSTALL etc DESTINATION ${CMAKE_BINARY_DIR})
|
||||||
|
file(INSTALL etc DESTINATION ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
file(INSTALL etc DESTINATION ${CMAKE_BINARY_DIR}/examples)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(BUILD_UNITTEST)
|
||||||
|
add_subdirectory(unittest)
|
||||||
|
endif()
|
30
external/libhv/libhv-1.3.2/LICENSE
vendored
Normal file
30
external/libhv/libhv-1.3.2/LICENSE
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2020, ithewei
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
283
external/libhv/libhv-1.3.2/Makefile
vendored
Normal file
283
external/libhv/libhv-1.3.2/Makefile
vendored
Normal file
|
@ -0,0 +1,283 @@
|
||||||
|
include config.mk
|
||||||
|
include Makefile.vars
|
||||||
|
|
||||||
|
MAKEF=$(MAKE) -f Makefile.in
|
||||||
|
ALL_SRCDIRS=. base ssl event event/kcp util cpputil evpp protocol http http/client http/server mqtt
|
||||||
|
CORE_SRCDIRS=. base ssl event
|
||||||
|
ifeq ($(WITH_KCP), yes)
|
||||||
|
CORE_SRCDIRS += event/kcp
|
||||||
|
endif
|
||||||
|
|
||||||
|
LIBHV_SRCDIRS = $(CORE_SRCDIRS) util
|
||||||
|
LIBHV_HEADERS = hv.h hconfig.h hexport.h
|
||||||
|
LIBHV_HEADERS += $(BASE_HEADERS) $(SSL_HEADERS) $(EVENT_HEADERS) $(UTIL_HEADERS)
|
||||||
|
|
||||||
|
ifeq ($(WITH_PROTOCOL), yes)
|
||||||
|
LIBHV_HEADERS += $(PROTOCOL_HEADERS)
|
||||||
|
LIBHV_SRCDIRS += protocol
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(WITH_EVPP), yes)
|
||||||
|
LIBHV_HEADERS += $(CPPUTIL_HEADERS) $(EVPP_HEADERS)
|
||||||
|
LIBHV_SRCDIRS += cpputil evpp
|
||||||
|
|
||||||
|
ifeq ($(WITH_HTTP), yes)
|
||||||
|
LIBHV_HEADERS += $(HTTP_HEADERS)
|
||||||
|
LIBHV_SRCDIRS += http
|
||||||
|
|
||||||
|
ifeq ($(WITH_NGHTTP2), yes)
|
||||||
|
LIBHV_HEADERS += $(HTTP2_HEADERS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(WITH_HTTP_SERVER), yes)
|
||||||
|
LIBHV_HEADERS += $(HTTP_SERVER_HEADERS)
|
||||||
|
LIBHV_SRCDIRS += http/server
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(WITH_HTTP_CLIENT), yes)
|
||||||
|
LIBHV_HEADERS += $(HTTP_CLIENT_HEADERS)
|
||||||
|
LIBHV_SRCDIRS += http/client
|
||||||
|
endif
|
||||||
|
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(WITH_MQTT), yes)
|
||||||
|
LIBHV_HEADERS += $(MQTT_HEADERS)
|
||||||
|
LIBHV_SRCDIRS += mqtt
|
||||||
|
endif
|
||||||
|
|
||||||
|
default: all
|
||||||
|
|
||||||
|
all: libhv examples
|
||||||
|
@echo "make all done, please enjoy libhv."
|
||||||
|
|
||||||
|
examples: hmain_test htimer_test hloop_test \
|
||||||
|
nc nmap tinyhttpd tinyproxyd httpd curl wget wrk consul \
|
||||||
|
tcp_client_test \
|
||||||
|
tcp_echo_server \
|
||||||
|
tcp_chat_server \
|
||||||
|
tcp_proxy_server \
|
||||||
|
udp_echo_server \
|
||||||
|
udp_proxy_server \
|
||||||
|
socks5_proxy_server \
|
||||||
|
multi-acceptor-processes \
|
||||||
|
multi-acceptor-threads \
|
||||||
|
one-acceptor-multi-workers \
|
||||||
|
http_server_test http_client_test \
|
||||||
|
websocket_server_test \
|
||||||
|
websocket_client_test \
|
||||||
|
mqtt_sub \
|
||||||
|
mqtt_pub \
|
||||||
|
mqtt_client_test \
|
||||||
|
jsonrpc
|
||||||
|
@echo "make examples done."
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(MAKEF) clean SRCDIRS="$(ALL_SRCDIRS)"
|
||||||
|
$(RM) examples/*.o examples/*/*.o
|
||||||
|
$(RM) include/hv
|
||||||
|
@echo "make clean done."
|
||||||
|
|
||||||
|
prepare:
|
||||||
|
$(MKDIR) bin
|
||||||
|
|
||||||
|
libhv:
|
||||||
|
$(MKDIR) lib
|
||||||
|
$(MAKEF) TARGET=$@ TARGET_TYPE="SHARED|STATIC" SRCDIRS="$(LIBHV_SRCDIRS)"
|
||||||
|
$(MKDIR) include/hv
|
||||||
|
$(CP) $(LIBHV_HEADERS) include/hv
|
||||||
|
@echo "make libhv done."
|
||||||
|
|
||||||
|
install:
|
||||||
|
$(MKDIR) $(INSTALL_INCDIR)
|
||||||
|
$(MKDIR) $(INSTALL_LIBDIR)
|
||||||
|
$(CP) include/hv/* $(INSTALL_INCDIR)
|
||||||
|
$(CP) lib/libhv.* $(INSTALL_LIBDIR)
|
||||||
|
$(LDCONFIG)
|
||||||
|
@echo "make install done."
|
||||||
|
|
||||||
|
uninstall: clean
|
||||||
|
$(RM) $(PREFIX)/include/hv
|
||||||
|
$(RM) $(PREFIX)/lib/libhv.*
|
||||||
|
@echo "make uninstall done."
|
||||||
|
|
||||||
|
hmain_test: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS=". base cpputil" SRCS="examples/hmain_test.cpp"
|
||||||
|
|
||||||
|
htimer_test: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/htimer_test.c"
|
||||||
|
|
||||||
|
hloop_test: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/hloop_test.c"
|
||||||
|
|
||||||
|
tcp_client_test: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/tcp_client_test.c"
|
||||||
|
|
||||||
|
tcp_echo_server: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/tcp_echo_server.c"
|
||||||
|
|
||||||
|
tcp_chat_server: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/tcp_chat_server.c"
|
||||||
|
|
||||||
|
tcp_proxy_server: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/tcp_proxy_server.c"
|
||||||
|
|
||||||
|
udp_echo_server: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/udp_echo_server.c"
|
||||||
|
|
||||||
|
udp_proxy_server: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/udp_proxy_server.c"
|
||||||
|
|
||||||
|
socks5_proxy_server: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/socks5_proxy_server.c"
|
||||||
|
|
||||||
|
multi-acceptor-processes: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/multi-thread/multi-acceptor-processes.c"
|
||||||
|
|
||||||
|
multi-acceptor-threads: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/multi-thread/multi-acceptor-threads.c"
|
||||||
|
|
||||||
|
one-acceptor-multi-workers: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/multi-thread/one-acceptor-multi-workers.c"
|
||||||
|
|
||||||
|
nc: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/nc.c"
|
||||||
|
|
||||||
|
tinyhttpd: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/tinyhttpd.c"
|
||||||
|
|
||||||
|
tinyproxyd: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/tinyproxyd.c"
|
||||||
|
|
||||||
|
nmap: prepare libhv
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) cpputil examples/nmap" DEFINES="PRINT_DEBUG"
|
||||||
|
|
||||||
|
wrk: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http" SRCS="examples/wrk.cpp"
|
||||||
|
|
||||||
|
httpd: prepare
|
||||||
|
$(RM) examples/httpd/*.o
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http http/client http/server examples/httpd"
|
||||||
|
|
||||||
|
consul: prepare libhv
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http http/client examples/consul" DEFINES="PRINT_DEBUG"
|
||||||
|
|
||||||
|
curl: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http http/client" SRCS="examples/curl.cpp"
|
||||||
|
# $(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http http/client" SRCS="examples/curl.cpp" WITH_CURL=yes
|
||||||
|
|
||||||
|
wget: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http http/client" SRCS="examples/wget.cpp"
|
||||||
|
|
||||||
|
http_server_test: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http http/server" SRCS="examples/http_server_test.cpp"
|
||||||
|
|
||||||
|
http_client_test: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http http/client" SRCS="examples/http_client_test.cpp"
|
||||||
|
|
||||||
|
websocket_server_test: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http http/server" SRCS="examples/websocket_server_test.cpp"
|
||||||
|
|
||||||
|
websocket_client_test: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http http/client" SRCS="examples/websocket_client_test.cpp"
|
||||||
|
|
||||||
|
mqtt_sub: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) mqtt" SRCS="examples/mqtt/mqtt_sub.c"
|
||||||
|
|
||||||
|
mqtt_pub: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) mqtt" SRCS="examples/mqtt/mqtt_pub.c"
|
||||||
|
|
||||||
|
mqtt_client_test: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) mqtt" SRCS="examples/mqtt/mqtt_client_test.cpp"
|
||||||
|
|
||||||
|
jsonrpc: jsonrpc_client jsonrpc_server
|
||||||
|
|
||||||
|
jsonrpc_client: prepare
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/jsonrpc/jsonrpc_client.c examples/jsonrpc/cJSON.c"
|
||||||
|
|
||||||
|
jsonrpc_server: prepare
|
||||||
|
$(RM) examples/jsonrpc/*.o
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/jsonrpc/jsonrpc_server.c examples/jsonrpc/cJSON.c"
|
||||||
|
|
||||||
|
protorpc: protorpc_client protorpc_server
|
||||||
|
|
||||||
|
protorpc_protoc:
|
||||||
|
bash examples/protorpc/proto/protoc.sh
|
||||||
|
|
||||||
|
protorpc_client: prepare protorpc_protoc
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) cpputil evpp examples/protorpc/generated" \
|
||||||
|
SRCS="examples/protorpc/protorpc_client.cpp examples/protorpc/protorpc.c" \
|
||||||
|
LIBS="protobuf"
|
||||||
|
|
||||||
|
protorpc_server: prepare protorpc_protoc
|
||||||
|
$(RM) examples/protorpc/*.o
|
||||||
|
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) cpputil evpp examples/protorpc/generated" \
|
||||||
|
SRCS="examples/protorpc/protorpc_server.cpp examples/protorpc/protorpc.c" \
|
||||||
|
LIBS="protobuf"
|
||||||
|
|
||||||
|
unittest: prepare
|
||||||
|
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -o bin/rbtree_test unittest/rbtree_test.c base/rbtree.c
|
||||||
|
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -o bin/hbase_test unittest/hbase_test.c base/hbase.c
|
||||||
|
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -o bin/mkdir_p unittest/mkdir_test.c base/hbase.c
|
||||||
|
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -o bin/rmdir_p unittest/rmdir_test.c base/hbase.c
|
||||||
|
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -o bin/date unittest/date_test.c base/htime.c
|
||||||
|
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -o bin/hatomic_test unittest/hatomic_test.c -pthread
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -o bin/hatomic_cpp_test unittest/hatomic_test.cpp -pthread
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -o bin/hthread_test unittest/hthread_test.cpp -pthread
|
||||||
|
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -o bin/hmutex_test unittest/hmutex_test.c base/htime.c -pthread
|
||||||
|
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -o bin/connect_test unittest/connect_test.c base/hsocket.c base/htime.c
|
||||||
|
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -o bin/socketpair_test unittest/socketpair_test.c base/hsocket.c
|
||||||
|
$(CC) -g -Wall -O0 -std=c99 -I. -Iutil -o bin/base64 unittest/base64_test.c util/base64.c
|
||||||
|
$(CC) -g -Wall -O0 -std=c99 -I. -Iutil -o bin/md5 unittest/md5_test.c util/md5.c
|
||||||
|
$(CC) -g -Wall -O0 -std=c99 -I. -Iutil -o bin/sha1 unittest/sha1_test.c util/sha1.c
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Icpputil -o bin/hstring_test unittest/hstring_test.cpp cpputil/hstring.cpp
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Icpputil -o bin/hpath_test unittest/hpath_test.cpp cpputil/hpath.cpp
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Icpputil -o bin/hurl_test unittest/hurl_test.cpp cpputil/hurl.cpp base/hbase.c
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Icpputil -o bin/ls unittest/listdir_test.cpp cpputil/hdir.cpp
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Icpputil -o bin/ifconfig unittest/ifconfig_test.cpp cpputil/ifconfig.cpp
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Icpputil -o bin/defer_test unittest/defer_test.cpp
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Icpputil -o bin/synchronized_test unittest/synchronized_test.cpp -pthread
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Icpputil -o bin/threadpool_test unittest/threadpool_test.cpp -pthread
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Icpputil -o bin/objectpool_test unittest/objectpool_test.cpp -pthread
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Ievpp -Icpputil -Ihttp -Ihttp/client -Ihttp/server -o bin/sizeof_test unittest/sizeof_test.cpp
|
||||||
|
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -Iprotocol -o bin/nslookup unittest/nslookup_test.c protocol/dns.c base/hsocket.c
|
||||||
|
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -Iprotocol -o bin/ping unittest/ping_test.c protocol/icmp.c base/hsocket.c base/htime.c -DPRINT_DEBUG
|
||||||
|
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -Iprotocol -o bin/ftp unittest/ftp_test.c protocol/ftp.c base/hsocket.c
|
||||||
|
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -Iprotocol -Iutil -o bin/sendmail unittest/sendmail_test.c protocol/smtp.c base/hsocket.c util/base64.c
|
||||||
|
|
||||||
|
run-unittest: unittest
|
||||||
|
bash scripts/unittest.sh
|
||||||
|
|
||||||
|
check: examples
|
||||||
|
bash scripts/check.sh
|
||||||
|
|
||||||
|
evpp: prepare libhv
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -o bin/EventLoop_test evpp/EventLoop_test.cpp -Llib -lhv -pthread
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -o bin/EventLoopThread_test evpp/EventLoopThread_test.cpp -Llib -lhv -pthread
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -o bin/EventLoopThreadPool_test evpp/EventLoopThreadPool_test.cpp -Llib -lhv -pthread
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -o bin/TimerThread_test evpp/TimerThread_test.cpp -Llib -lhv -pthread
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -o bin/TcpServer_test evpp/TcpServer_test.cpp -Llib -lhv -pthread
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -o bin/TcpClient_test evpp/TcpClient_test.cpp -Llib -lhv -pthread
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -o bin/TcpClientEventLoop_test evpp/TcpClientEventLoop_test.cpp -Llib -lhv -pthread
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -o bin/UdpServer_test evpp/UdpServer_test.cpp -Llib -lhv -pthread
|
||||||
|
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -o bin/UdpClient_test evpp/UdpClient_test.cpp -Llib -lhv -pthread
|
||||||
|
|
||||||
|
# UNIX only
|
||||||
|
webbench: prepare
|
||||||
|
$(CC) -o bin/webbench unittest/webbench.c
|
||||||
|
|
||||||
|
echo-servers:
|
||||||
|
$(CXX) -g -Wall -std=c++11 -O3 -o bin/pingpong_client echo-servers/pingpong_client.cpp -lhv -pthread
|
||||||
|
$(CC) -g -Wall -std=c99 -O3 -o bin/libevent_echo echo-servers/libevent_echo.c -levent
|
||||||
|
$(CC) -g -Wall -std=c99 -O3 -o bin/libev_echo echo-servers/libev_echo.c -lev
|
||||||
|
$(CC) -g -Wall -std=c99 -O3 -o bin/libuv_echo echo-servers/libuv_echo.c -luv
|
||||||
|
$(CC) -g -Wall -std=c99 -O3 -o bin/libhv_echo echo-servers/libhv_echo.c -lhv
|
||||||
|
$(CXX) -g -Wall -std=c++11 -O3 -o bin/asio_echo echo-servers/asio_echo.cpp -lboost_system -pthread
|
||||||
|
$(CXX) -g -Wall -std=c++11 -O3 -o bin/poco_echo echo-servers/poco_echo.cpp -lPocoNet -lPocoUtil -lPocoFoundation
|
||||||
|
# $(CXX) -g -Wall -std=c++11 -O3 -o bin/muduo_echo echo-servers/muduo_echo.cpp -lmuduo_net -lmuduo_base -pthread
|
||||||
|
|
||||||
|
echo-benchmark: echo-servers
|
||||||
|
bash echo-servers/benchmark.sh
|
||||||
|
|
||||||
|
.PHONY: clean prepare install uninstall libhv examples unittest evpp echo-servers
|
306
external/libhv/libhv-1.3.2/Makefile.in
vendored
Normal file
306
external/libhv/libhv-1.3.2/Makefile.in
vendored
Normal file
|
@ -0,0 +1,306 @@
|
||||||
|
#+++++++++++++++++++++++++++++++++configure++++++++++++++++++++++++++++++++++++++++
|
||||||
|
# OS=Windows,Linux,Android
|
||||||
|
# ARCH=x86,x86_64,arm,aarch64
|
||||||
|
# CC = $(CROSS_COMPILE)gcc
|
||||||
|
# CXX = $(CROSS_COMPILE)g++
|
||||||
|
# CPPFLAGS += $(addprefix -D, $(DEFINES))
|
||||||
|
# CPPFLAGS += $(addprefix -I, $(SRCDIRS))
|
||||||
|
# CPPFLAGS += $(addprefix -I, $(INCDIRS))
|
||||||
|
# LDFLAGS += $(addprefix -L, $(LIBDIRS))
|
||||||
|
# LDFLAGS += $(addprefix -l, $(LIBS))
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# make all \
|
||||||
|
# TARGET=libxx \
|
||||||
|
# TARGET_TYPE=SHARED \
|
||||||
|
# BUILD_TYPE=DEBUG \
|
||||||
|
# CROSS_COMPILE=arm-linux-androideabi- \
|
||||||
|
# SRCDIRS="src/base src/event" \
|
||||||
|
# INCDIRS="src/util" \
|
||||||
|
# SRCS="src/util/hmain.cpp src/util/iniparser.cpp" \
|
||||||
|
# DEFINES=USE_OPENCV \
|
||||||
|
# LIBS="opencv_core opencv_highgui"
|
||||||
|
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
-include config.mk
|
||||||
|
|
||||||
|
# VARIABLES
|
||||||
|
TARGET ?= test
|
||||||
|
# BUILD_TYPE=DEBUG,RELEASE
|
||||||
|
BUILD_TYPE ?= RELEASE
|
||||||
|
# TARGET_TYPE=EXECUTABLE,SHARED,STATIC,SHARED|STATIC
|
||||||
|
TARGET_TYPE ?= EXECUTABLE
|
||||||
|
|
||||||
|
# COMMANDS
|
||||||
|
ifdef CROSS_COMPILE
|
||||||
|
CC = $(CROSS_COMPILE)gcc
|
||||||
|
CXX = $(CROSS_COMPILE)g++
|
||||||
|
CPP = $(CC) -E
|
||||||
|
AS = $(CROSS_COMPILE)as
|
||||||
|
LD = $(CROSS_COMPILE)ld
|
||||||
|
AR = $(CROSS_COMPILE)ar
|
||||||
|
NM = $(CROSS_COMPILE)nm
|
||||||
|
STRIP = $(CROSS_COMPILE)strip
|
||||||
|
endif
|
||||||
|
|
||||||
|
MKDIR = -mkdir -p 2>/dev/null
|
||||||
|
CP = -cp -r 2>/dev/null
|
||||||
|
RM = -rm -r 2>/dev/null
|
||||||
|
|
||||||
|
# PLATFORM: OS, ARCH
|
||||||
|
CC_VERSION=$(shell $(CC) --version 2>&1 | head -n 1)
|
||||||
|
TARGET_PLATFORM=$(shell $(CC) -v 2>&1 | grep Target | sed 's/Target: //')
|
||||||
|
ifneq ($(findstring mingw, $(TARGET_PLATFORM)), )
|
||||||
|
OS=Windows
|
||||||
|
endif
|
||||||
|
ifneq ($(findstring android, $(TARGET_PLATFORM)), )
|
||||||
|
OS=Android
|
||||||
|
endif
|
||||||
|
ifneq ($(findstring darwin, $(TARGET_PLATFORM)), )
|
||||||
|
OS=Darwin
|
||||||
|
endif
|
||||||
|
ifndef OS
|
||||||
|
OS=Linux
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef ARCH
|
||||||
|
ARCH=$(shell echo $(TARGET_PLATFORM) | awk -F'-' '{print $$1}')
|
||||||
|
endif
|
||||||
|
|
||||||
|
# CFLAGS, CXXFLAGS, ARFLAGS
|
||||||
|
ifeq ($(BUILD_TYPE), DEBUG)
|
||||||
|
DEFAULT_CFLAGS = -g -Wall -O0
|
||||||
|
else
|
||||||
|
DEFAULT_CFLAGS += -O2
|
||||||
|
endif
|
||||||
|
|
||||||
|
CFLAGS ?= $(DEFAULT_CFLAGS)
|
||||||
|
CXXFLAGS ?= $(DEFAULT_CFLAGS)
|
||||||
|
|
||||||
|
ifneq ($(OS), Windows)
|
||||||
|
ifeq ($(findstring -fPIC, $(CFLAGS)), )
|
||||||
|
override CFLAGS += -fPIC
|
||||||
|
endif
|
||||||
|
ifeq ($(findstring -fPIC, $(CXXFLAGS)), )
|
||||||
|
override CXXFLAGS += -fPIC
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(findstring -std, $(CFLAGS)), )
|
||||||
|
override CFLAGS += -std=c99
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(findstring -std, $(CXXFLAGS)), )
|
||||||
|
override CXXFLAGS += -std=c++11
|
||||||
|
endif
|
||||||
|
|
||||||
|
ARFLAGS ?= cr
|
||||||
|
|
||||||
|
# DIRS
|
||||||
|
ifeq ($(OS), Linux)
|
||||||
|
PREFIX ?= /usr/local
|
||||||
|
else
|
||||||
|
PREFIX ?= install
|
||||||
|
endif
|
||||||
|
|
||||||
|
INCDIR = include
|
||||||
|
LIBDIR = lib
|
||||||
|
SRCDIR = src
|
||||||
|
BINDIR = bin
|
||||||
|
DEPDIR = 3rd
|
||||||
|
CONFDIR = etc
|
||||||
|
DISTDIR = dist
|
||||||
|
DOCDIR = docs
|
||||||
|
|
||||||
|
SRCDIRS += $(shell find $(SRCDIR) -type d)
|
||||||
|
override INCDIRS += $(INCDIR) $(DEPDIR) $(DEPDIR)/include
|
||||||
|
override LIBDIRS += $(LIBDIR) $(DEPDIR)/lib $(DEPDIR)/lib/$(TARGET_PLATFORM)
|
||||||
|
|
||||||
|
ALL_SRCS += $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c $(dir)/*.cc $(dir)/*.cpp))
|
||||||
|
ifeq ($(ALL_SRCS), )
|
||||||
|
ALL_SRCS = $(wildcard *.c *.cc *.cpp)
|
||||||
|
endif
|
||||||
|
override SRCS += $(filter-out %_test.c %_test.cc %_test.cpp, $(ALL_SRCS))
|
||||||
|
# OBJS += $(patsubst %.c, %.o, $(SRCS))
|
||||||
|
# OBJS += $(patsubst %.cc, %.o, $(SRCS))
|
||||||
|
# OBJS += $(patsubst %.cpp, %.o, $(SRCS))
|
||||||
|
OBJS := $(addsuffix .o, $(basename $(SRCS)))
|
||||||
|
|
||||||
|
INSTALLED_INCS=$(addprefix $(PREFIX)/$(INCDIR)/, $(shell ls $(INCDIR)))
|
||||||
|
INSTALLED_LIBS=$(addprefix $(PREFIX)/$(LIBDIR)/, $(shell ls $(LIBDIR)))
|
||||||
|
INSTALLED_BINS=$(addprefix $(PREFIX)/$(BINDIR)/, $(shell ls $(BINDIR)))
|
||||||
|
|
||||||
|
# CPPFLAGS
|
||||||
|
ifeq ($(OS), Windows)
|
||||||
|
CPPFLAGS += -D_WIN32_WINNT=0x600
|
||||||
|
ifeq ($(TARGET_TYPE), SHARED)
|
||||||
|
CPPFLAGS += -DDLL_EXPORTS
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(BUILD_TYPE), DEBUG)
|
||||||
|
CPPFLAGS += -DDEBUG
|
||||||
|
else
|
||||||
|
CPPFLAGS += -DNDEBUG
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ENABLE_UDS), yes)
|
||||||
|
CPPFLAGS += -DENABLE_UDS
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(USE_MULTIMAP), yes)
|
||||||
|
CPPFLAGS += -DUSE_MULTIMAP
|
||||||
|
endif
|
||||||
|
|
||||||
|
CPPFLAGS += $(addprefix -D, $(DEFINES))
|
||||||
|
CPPFLAGS += $(addprefix -I, $(INCDIRS))
|
||||||
|
CPPFLAGS += $(addprefix -I, $(SRCDIRS))
|
||||||
|
|
||||||
|
# LDFLAGS
|
||||||
|
ifeq ($(OS), Windows)
|
||||||
|
LDFLAGS += -static-libgcc -static-libstdc++
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(WITH_CURL), yes)
|
||||||
|
CPPFLAGS += -DWITH_CURL
|
||||||
|
LDFLAGS += -lcurl
|
||||||
|
ifeq ($(OS), Windows)
|
||||||
|
LDFLAGS += -lwldap32 -ladvapi32 -lcrypt32
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(WITH_NGHTTP2), yes)
|
||||||
|
CPPFLAGS += -DWITH_NGHTTP2
|
||||||
|
LDFLAGS += -lnghttp2
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(WITH_OPENSSL), yes)
|
||||||
|
CPPFLAGS += -DWITH_OPENSSL
|
||||||
|
LDFLAGS += -lssl -lcrypto
|
||||||
|
else
|
||||||
|
ifeq ($(WITH_GNUTLS), yes)
|
||||||
|
CPPFLAGS += -DWITH_GNUTLS
|
||||||
|
LDFLAGS += -lgnutls
|
||||||
|
else
|
||||||
|
ifeq ($(WITH_MBEDTLS), yes)
|
||||||
|
CPPFLAGS += -DWITH_MBEDTLS
|
||||||
|
LDFLAGS += -lmbedtls -lmbedx509 -lmbedcrypto
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
LDFLAGS += $(addprefix -L, $(LIBDIRS))
|
||||||
|
LDFLAGS += $(addprefix -l, $(LIBS))
|
||||||
|
|
||||||
|
ifeq ($(OS), Windows)
|
||||||
|
LDFLAGS += -lsecur32 -lcrypt32 -lwinmm -liphlpapi -lws2_32
|
||||||
|
ifeq ($(ENABLE_WINDUMP), yes)
|
||||||
|
CPPFLAGS += -DENABLE_WINDUMP
|
||||||
|
LDFLAGS += -ldbghelp
|
||||||
|
endif
|
||||||
|
LDFLAGS += -Wl,-Bstatic -lstdc++ -lpthread -lm
|
||||||
|
else
|
||||||
|
ifeq ($(filter %.cc %.cpp, $(SRCS)), )
|
||||||
|
LINK = $(CC)
|
||||||
|
else
|
||||||
|
LINK = $(CXX)
|
||||||
|
LDFLAGS += -lstdc++
|
||||||
|
endif
|
||||||
|
ifeq ($(OS), Android)
|
||||||
|
LDFLAGS += -lm -llog -ldl
|
||||||
|
else
|
||||||
|
LDFLAGS += -lpthread -lm -ldl
|
||||||
|
LINK_RT=$(shell echo "int main(){return 0;}" | $(CC) -x c - -lrt 2>&1)
|
||||||
|
ifeq ($(LINK_RT), )
|
||||||
|
LDFLAGS += -lrt
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(OS), Darwin)
|
||||||
|
LDFLAGS += -framework CoreFoundation -framework Security
|
||||||
|
endif
|
||||||
|
|
||||||
|
LINK ?= $(CC)
|
||||||
|
|
||||||
|
# info
|
||||||
|
$(info $(CC_VERSION))
|
||||||
|
|
||||||
|
$(info OS = $(OS))
|
||||||
|
$(info ARCH = $(ARCH))
|
||||||
|
$(info MAKE = $(MAKE))
|
||||||
|
$(info CC = $(CC))
|
||||||
|
$(info CXX = $(CXX))
|
||||||
|
|
||||||
|
$(info CFLAGS = $(CFLAGS))
|
||||||
|
$(info CXXFLAGS = $(CXXFLAGS))
|
||||||
|
$(info CPPFLAGS = $(CPPFLAGS))
|
||||||
|
$(info LDFLAGS = $(LDFLAGS))
|
||||||
|
|
||||||
|
$(info TARGET = $(TARGET))
|
||||||
|
$(info TARGET_TYPE = $(TARGET_TYPE))
|
||||||
|
$(info TARGET_PLATFORM = $(TARGET_PLATFORM))
|
||||||
|
$(info BUILD_TYPE = $(BUILD_TYPE))
|
||||||
|
|
||||||
|
$(info SRCS=$(SRCS))
|
||||||
|
$(info OBJS=$(OBJS))
|
||||||
|
|
||||||
|
# $(info INSTALLED_INCS=$(INSTALLED_INCS))
|
||||||
|
# $(info INSTALLED_LIBS=$(INSTALLED_LIBS))
|
||||||
|
# $(info INSTALLED_BINS=$(INSTALLED_BINS))
|
||||||
|
|
||||||
|
default: all
|
||||||
|
|
||||||
|
all: prepare $(TARGET)
|
||||||
|
|
||||||
|
prepare:
|
||||||
|
$(MKDIR) $(BINDIR) $(LIBDIR)
|
||||||
|
|
||||||
|
$(TARGET): $(OBJS)
|
||||||
|
ifneq ($(findstring SHARED, $(TARGET_TYPE)), )
|
||||||
|
ifeq ($(OS), Windows)
|
||||||
|
$(LINK) -shared $^ -o $(LIBDIR)/$@.dll $(LDFLAGS) -Wl,--output-def,$(LIBDIR)/$(@).def
|
||||||
|
else
|
||||||
|
ifeq ($(OS), Darwin)
|
||||||
|
$(LINK) -dynamiclib -install_name @rpath/$@.dylib $^ -o $(LIBDIR)/$@.dylib $(LDFLAGS)
|
||||||
|
else
|
||||||
|
$(LINK) -shared $^ -o $(LIBDIR)/$@.so $(LDFLAGS)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(findstring STATIC, $(TARGET_TYPE)), )
|
||||||
|
$(AR) $(ARFLAGS) $(LIBDIR)/$@.a $^
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(findstring EXECUTABLE, $(TARGET_TYPE)), )
|
||||||
|
ifeq ($(OS), Windows)
|
||||||
|
$(LINK) $^ -o $(BINDIR)/$@.exe $(LDFLAGS)
|
||||||
|
else
|
||||||
|
$(LINK) $^ -o $(BINDIR)/$@ $(LDFLAGS)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(OBJS)
|
||||||
|
#$(RM) $(LIBDIR)
|
||||||
|
#$(RM) $(BINDIR)
|
||||||
|
|
||||||
|
install:
|
||||||
|
$(CP) $(INCDIR)/* $(PREFIX)/$(INCDIR)/
|
||||||
|
$(CP) $(LIBDIR)/* $(PREFIX)/$(LIBDIR)/
|
||||||
|
$(CP) $(BINDIR)/* $(PREFIX)/$(BINDIR)/
|
||||||
|
$(LDCONFIG)
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
$(RM) $(INSTALLED_INCS)
|
||||||
|
$(RM) $(INSTALLED_LIBS)
|
||||||
|
$(RM) $(INSTALLED_BINS)
|
||||||
|
|
||||||
|
dist:
|
||||||
|
$(MKDIR) $(DISTDIR)
|
||||||
|
$(CP) $(INCDIR) $(LIBDIR) $(BINDIR) $(CONFDIR) $(DOCDIR) $(DISTDIR)
|
||||||
|
|
||||||
|
undist:
|
||||||
|
$(RM) $(DISTDIR)
|
||||||
|
|
||||||
|
.PHONY: default all prepare clean install uninstall dist undist
|
95
external/libhv/libhv-1.3.2/Makefile.vars
vendored
Normal file
95
external/libhv/libhv-1.3.2/Makefile.vars
vendored
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
MKDIR = -mkdir -p 2>/dev/null
|
||||||
|
CP = -cp -r 2>/dev/null
|
||||||
|
RM = -rm -r 2>/dev/null
|
||||||
|
LDCONFIG = -ldconfig 2>/dev/null
|
||||||
|
|
||||||
|
PREFIX ?= /usr/local
|
||||||
|
INSTALL_INCDIR ?= $(PREFIX)/include/hv
|
||||||
|
INSTALL_LIBDIR ?= $(PREFIX)/lib
|
||||||
|
|
||||||
|
BASE_HEADERS = base/hplatform.h\
|
||||||
|
\
|
||||||
|
base/hdef.h\
|
||||||
|
base/hatomic.h\
|
||||||
|
base/herr.h\
|
||||||
|
base/htime.h\
|
||||||
|
base/hmath.h\
|
||||||
|
base/hbase.h\
|
||||||
|
base/hversion.h\
|
||||||
|
base/hsysinfo.h\
|
||||||
|
base/hproc.h\
|
||||||
|
base/hthread.h\
|
||||||
|
base/hmutex.h\
|
||||||
|
base/hsocket.h\
|
||||||
|
base/hlog.h\
|
||||||
|
base/hbuf.h\
|
||||||
|
base/hmain.h\
|
||||||
|
base/hendian.h\
|
||||||
|
|
||||||
|
SSL_HEADERS = ssl/hssl.h
|
||||||
|
|
||||||
|
EVENT_HEADERS = event/hloop.h\
|
||||||
|
event/nlog.h\
|
||||||
|
|
||||||
|
UTIL_HEADERS = util/base64.h\
|
||||||
|
util/md5.h\
|
||||||
|
util/sha1.h\
|
||||||
|
|
||||||
|
CPPUTIL_HEADERS = cpputil/hmap.h\
|
||||||
|
cpputil/hstring.h\
|
||||||
|
cpputil/hfile.h\
|
||||||
|
cpputil/hpath.h\
|
||||||
|
cpputil/hdir.h\
|
||||||
|
cpputil/hurl.h\
|
||||||
|
cpputil/hscope.h\
|
||||||
|
cpputil/hthreadpool.h\
|
||||||
|
cpputil/hasync.h\
|
||||||
|
cpputil/hobjectpool.h\
|
||||||
|
cpputil/ifconfig.h\
|
||||||
|
cpputil/iniparser.h\
|
||||||
|
cpputil/json.hpp\
|
||||||
|
cpputil/singleton.h\
|
||||||
|
cpputil/ThreadLocalStorage.h\
|
||||||
|
|
||||||
|
EVPP_HEADERS = evpp/Buffer.h\
|
||||||
|
evpp/Channel.h\
|
||||||
|
evpp/Event.h\
|
||||||
|
evpp/EventLoop.h\
|
||||||
|
evpp/EventLoopThread.h\
|
||||||
|
evpp/EventLoopThreadPool.h\
|
||||||
|
evpp/Status.h\
|
||||||
|
evpp/TcpClient.h\
|
||||||
|
evpp/TcpServer.h\
|
||||||
|
evpp/UdpClient.h\
|
||||||
|
evpp/UdpServer.h\
|
||||||
|
|
||||||
|
PROTOCOL_HEADERS = protocol/icmp.h\
|
||||||
|
protocol/dns.h\
|
||||||
|
protocol/ftp.h\
|
||||||
|
protocol/smtp.h
|
||||||
|
|
||||||
|
HTTP_HEADERS = http/httpdef.h\
|
||||||
|
http/wsdef.h\
|
||||||
|
http/http_content.h\
|
||||||
|
http/HttpMessage.h\
|
||||||
|
http/HttpParser.h\
|
||||||
|
http/WebSocketParser.h\
|
||||||
|
http/WebSocketChannel.h\
|
||||||
|
|
||||||
|
HTTP2_HEADERS = http/http2def.h\
|
||||||
|
http/grpcdef.h\
|
||||||
|
|
||||||
|
HTTP_CLIENT_HEADERS = http/client/HttpClient.h\
|
||||||
|
http/client/requests.h\
|
||||||
|
http/client/axios.h\
|
||||||
|
http/client/AsyncHttpClient.h\
|
||||||
|
http/client/WebSocketClient.h\
|
||||||
|
|
||||||
|
HTTP_SERVER_HEADERS = http/server/HttpServer.h\
|
||||||
|
http/server/HttpService.h\
|
||||||
|
http/server/HttpContext.h\
|
||||||
|
http/server/HttpResponseWriter.h\
|
||||||
|
http/server/WebSocketServer.h\
|
||||||
|
|
||||||
|
MQTT_HEADERS = mqtt/mqtt_protocol.h\
|
||||||
|
mqtt/mqtt_client.h\
|
537
external/libhv/libhv-1.3.2/README-CN.md
vendored
Normal file
537
external/libhv/libhv-1.3.2/README-CN.md
vendored
Normal file
|
@ -0,0 +1,537 @@
|
||||||
|
[English](README.md) | 中文
|
||||||
|
|
||||||
|
# libhv
|
||||||
|
|
||||||
|
[](https://github.com/ithewei/libhv/actions/workflows/CI.yml?query=branch%3Amaster)
|
||||||
|
[](https://github.com/ithewei/libhv/actions/workflows/CI.yml?query=branch%3Amaster)
|
||||||
|
[](https://github.com/ithewei/libhv/actions/workflows/CI.yml?query=branch%3Amaster)
|
||||||
|
[](https://github.com/ithewei/libhv/actions/workflows/CI.yml?query=branch%3Amaster)
|
||||||
|
[](https://github.com/ithewei/libhv/actions/workflows/CI.yml?query=branch%3Amaster)
|
||||||
|
[](https://github.com/ithewei/libhv/actions/workflows/benchmark.yml?query=branch%3Amaster)
|
||||||
|
<br>
|
||||||
|
[](https://github.com/ithewei/libhv/releases)
|
||||||
|
[](https://github.com/ithewei/libhv/stargazers)
|
||||||
|
[](https://github.com/ithewei/libhv/forks)
|
||||||
|
[](https://github.com/ithewei/libhv/issues)
|
||||||
|
[](https://github.com/ithewei/libhv/pulls)
|
||||||
|
[](https://github.com/ithewei/libhv/contributors)
|
||||||
|
[](LICENSE)
|
||||||
|
<br>
|
||||||
|
[](https://gitee.com/libhv/libhv)
|
||||||
|
[](https://github.com/oz123/awesome-c)
|
||||||
|
[](https://github.com/fffaraz/awesome-cpp)
|
||||||
|
|
||||||
|
`libhv`是一个类似于`libevent、libev、libuv`的跨平台网络库,提供了更易用的接口和更丰富的协议。
|
||||||
|
|
||||||
|
## 📚 中文资料
|
||||||
|
|
||||||
|
- **libhv QQ群**: `739352073`,欢迎加群交流
|
||||||
|
- **libhv 源码剖析**: <https://hewei.blog.csdn.net/article/details/123295998>
|
||||||
|
- **libhv 接口手册**: <https://hewei.blog.csdn.net/article/details/103976875>
|
||||||
|
- **libhv 教程目录**: <https://hewei.blog.csdn.net/article/details/113733758>
|
||||||
|
- [libhv教程01--介绍与体验](https://hewei.blog.csdn.net/article/details/113702536)
|
||||||
|
- [libhv教程02--编译与安装](https://hewei.blog.csdn.net/article/details/113704737)
|
||||||
|
- [libhv教程03--链库与使用](https://hewei.blog.csdn.net/article/details/113706378)
|
||||||
|
- [libhv教程04--编写一个完整的命令行程序](https://hewei.blog.csdn.net/article/details/113719503)
|
||||||
|
- [libhv教程05--事件循环以及定时器的简单使用](https://hewei.blog.csdn.net/article/details/113724474)
|
||||||
|
- [libhv教程06--创建一个简单的TCP服务端](https://hewei.blog.csdn.net/article/details/113737580)
|
||||||
|
- [libhv教程07--创建一个简单的TCP客户端](https://hewei.blog.csdn.net/article/details/113738900)
|
||||||
|
- [libhv教程08--创建一个简单的UDP服务端](https://hewei.blog.csdn.net/article/details/113871498)
|
||||||
|
- [libhv教程09--创建一个简单的UDP客户端](https://hewei.blog.csdn.net/article/details/113871724)
|
||||||
|
- [libhv教程10--创建一个简单的HTTP服务端](https://hewei.blog.csdn.net/article/details/113982999)
|
||||||
|
- [libhv教程11--创建一个简单的HTTP客户端](https://hewei.blog.csdn.net/article/details/113984302)
|
||||||
|
- [libhv教程12--创建一个简单的WebSocket服务端](https://hewei.blog.csdn.net/article/details/113985321)
|
||||||
|
- [libhv教程13--创建一个简单的WebSocket客户端](https://hewei.blog.csdn.net/article/details/113985895)
|
||||||
|
- [libhv教程14--200行实现一个纯C版jsonrpc框架](https://hewei.blog.csdn.net/article/details/119920540)
|
||||||
|
- [libhv教程15--200行实现一个C++版protorpc框架](https://hewei.blog.csdn.net/article/details/119966701)
|
||||||
|
- [libhv教程16--多线程/多进程服务端编程](https://hewei.blog.csdn.net/article/details/120366024)
|
||||||
|
- [libhv教程17--Qt中使用libhv](https://hewei.blog.csdn.net/article/details/120699890)
|
||||||
|
- [libhv教程18--动手写一个tinyhttpd](https://hewei.blog.csdn.net/article/details/121706604)
|
||||||
|
- [libhv教程19--MQTT的实现与使用](https://hewei.blog.csdn.net/article/details/122753665)
|
||||||
|
|
||||||
|
## ✨ 特性
|
||||||
|
|
||||||
|
- 跨平台(Linux, Windows, macOS, Android, iOS, BSD, Solaris)
|
||||||
|
- 高性能事件循环(网络IO事件、定时器事件、空闲事件、自定义事件)
|
||||||
|
- TCP/UDP服务端/客户端/代理
|
||||||
|
- TCP支持心跳、重连、转发、多线程安全write和close等特性
|
||||||
|
- 内置常见的拆包模式(固定包长、分界符、头部长度字段)
|
||||||
|
- 可靠UDP支持: WITH_KCP
|
||||||
|
- SSL/TLS加密通信(可选WITH_OPENSSL、WITH_GNUTLS、WITH_MBEDTLS)
|
||||||
|
- HTTP服务端/客户端(支持https http1/x http2 grpc)
|
||||||
|
- HTTP支持静态文件服务、目录服务、正向/反向代理服务、同步/异步API处理器
|
||||||
|
- HTTP支持RESTful风格、路由、中间件、keep-alive长连接、chunked分块、SSE等特性
|
||||||
|
- WebSocket服务端/客户端
|
||||||
|
- MQTT客户端
|
||||||
|
|
||||||
|
## ⌛️ 构建
|
||||||
|
|
||||||
|
见[BUILD.md](BUILD.md)
|
||||||
|
|
||||||
|
libhv提供了以下构建方式:
|
||||||
|
|
||||||
|
1、通过Makefile:
|
||||||
|
```shell
|
||||||
|
./configure
|
||||||
|
make
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
2、通过cmake:
|
||||||
|
```shell
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
cmake --build .
|
||||||
|
```
|
||||||
|
|
||||||
|
3、通过vcpkg:
|
||||||
|
```shell
|
||||||
|
vcpkg install libhv
|
||||||
|
```
|
||||||
|
|
||||||
|
4、通过xmake:
|
||||||
|
```shell
|
||||||
|
xrepo install libhv
|
||||||
|
```
|
||||||
|
|
||||||
|
## ⚡️ 快速入门
|
||||||
|
|
||||||
|
### 体验
|
||||||
|
运行脚本`./getting_started.sh`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# 下载编译
|
||||||
|
git clone https://github.com/ithewei/libhv.git
|
||||||
|
cd libhv
|
||||||
|
./configure
|
||||||
|
make
|
||||||
|
|
||||||
|
# 运行httpd服务
|
||||||
|
bin/httpd -h
|
||||||
|
bin/httpd -d
|
||||||
|
#bin/httpd -c etc/httpd.conf -s restart -d
|
||||||
|
ps aux | grep httpd
|
||||||
|
|
||||||
|
# 文件服务
|
||||||
|
bin/curl -v localhost:8080
|
||||||
|
|
||||||
|
# 目录服务
|
||||||
|
bin/curl -v localhost:8080/downloads/
|
||||||
|
|
||||||
|
# API服务
|
||||||
|
bin/curl -v localhost:8080/ping
|
||||||
|
bin/curl -v localhost:8080/echo -d "hello,world!"
|
||||||
|
bin/curl -v localhost:8080/query?page_no=1\&page_size=10
|
||||||
|
bin/curl -v localhost:8080/kv -H "Content-Type:application/x-www-form-urlencoded" -d 'user=admin&pswd=123456'
|
||||||
|
bin/curl -v localhost:8080/json -H "Content-Type:application/json" -d '{"user":"admin","pswd":"123456"}'
|
||||||
|
bin/curl -v localhost:8080/form -F 'user=admin' -F 'pswd=123456'
|
||||||
|
bin/curl -v localhost:8080/upload -d "@LICENSE"
|
||||||
|
bin/curl -v localhost:8080/upload -F "file=@LICENSE"
|
||||||
|
|
||||||
|
bin/curl -v localhost:8080/test -H "Content-Type:application/x-www-form-urlencoded" -d 'bool=1&int=123&float=3.14&string=hello'
|
||||||
|
bin/curl -v localhost:8080/test -H "Content-Type:application/json" -d '{"bool":true,"int":123,"float":3.14,"string":"hello"}'
|
||||||
|
bin/curl -v localhost:8080/test -F 'bool=1' -F 'int=123' -F 'float=3.14' -F 'string=hello'
|
||||||
|
# RESTful API: /group/:group_name/user/:user_id
|
||||||
|
bin/curl -v -X DELETE localhost:8080/group/test/user/123
|
||||||
|
|
||||||
|
# 压力测试
|
||||||
|
bin/wrk -c 1000 -d 10 -t 4 http://127.0.0.1:8080/
|
||||||
|
```
|
||||||
|
|
||||||
|
### TCP
|
||||||
|
#### TCP服务端
|
||||||
|
**c版本**: [examples/tcp_echo_server.c](examples/tcp_echo_server.c)
|
||||||
|
|
||||||
|
**c++版本**: [evpp/TcpServer_test.cpp](evpp/TcpServer_test.cpp)
|
||||||
|
```c++
|
||||||
|
#include "TcpServer.h"
|
||||||
|
using namespace hv;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int port = 1234;
|
||||||
|
TcpServer srv;
|
||||||
|
int listenfd = srv.createsocket(port);
|
||||||
|
if (listenfd < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("server listen on port %d, listenfd=%d ...\n", port, listenfd);
|
||||||
|
srv.onConnection = [](const SocketChannelPtr& channel) {
|
||||||
|
std::string peeraddr = channel->peeraddr();
|
||||||
|
if (channel->isConnected()) {
|
||||||
|
printf("%s connected! connfd=%d\n", peeraddr.c_str(), channel->fd());
|
||||||
|
} else {
|
||||||
|
printf("%s disconnected! connfd=%d\n", peeraddr.c_str(), channel->fd());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
srv.onMessage = [](const SocketChannelPtr& channel, Buffer* buf) {
|
||||||
|
// echo
|
||||||
|
channel->write(buf);
|
||||||
|
};
|
||||||
|
srv.setThreadNum(4);
|
||||||
|
srv.start();
|
||||||
|
|
||||||
|
// press Enter to stop
|
||||||
|
while (getchar() != '\n');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**注意**:
|
||||||
|
|
||||||
|
以上示例只是简单的`echo`服务,TCP是流式协议,实际应用中请务必添加边界进行拆包。<br>
|
||||||
|
文本协议建议加上`\0`或者`\r\n`分隔符,可参考 [examples/jsonrpc](examples/jsonrpc);<br>
|
||||||
|
二进制协议建议加上自定义协议头,通过头部长度字段表明负载长度,可参考 [examples/protorpc](examples/protorpc);<br>
|
||||||
|
通过`setUnpack`(c接口即`hio_set_unpack`)设置拆包规则,支持固定包长、分隔符、头部长度字段三种常见的拆包方式,<br>
|
||||||
|
内部根据拆包规则处理粘包与分包,保证`onMessage`回调上来的是完整的一包数据,大大节省了上层处理粘包与分包的成本。<br>
|
||||||
|
不想自定义协议和拆包组包的可直接使用现成的`HTTP/WebSocket`协议。<br>
|
||||||
|
<br>
|
||||||
|
`channel->write`(c接口即`hio_write`)是非阻塞的(事件循环异步编程里所有的一切都要求是非阻塞的),且多线程安全的。<br>
|
||||||
|
发送大数据时应该做流控,通过`onWriteComplete`监听写完成事件,在可写时再发送下一帧数据。<br>
|
||||||
|
具体示例代码可参考 [examples/tinyhttpd.c](examples/tinyhttpd.c) 中的 `http_serve_file`。<br>
|
||||||
|
<br>
|
||||||
|
`channel->close`(c接口即`hio_close`) 也是多线程安全的,这可以让网络IO事件循环线程里接收数据、拆包组包、反序列化后放入队列,<br>
|
||||||
|
消费者线程/线程池从队列里取出数据、处理后发送响应和关闭连接,变得更加简单。<br>
|
||||||
|
|
||||||
|
#### TCP客户端
|
||||||
|
**c版本**: [examples/tcp_client_test.c](examples/tcp_client_test.c)
|
||||||
|
|
||||||
|
**c++版本**: [evpp/TcpClient_test.cpp](evpp/TcpClient_test.cpp)
|
||||||
|
```c++
|
||||||
|
#include <iostream>
|
||||||
|
#include "TcpClient.h"
|
||||||
|
using namespace hv;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int port = 1234;
|
||||||
|
TcpClient cli;
|
||||||
|
int connfd = cli.createsocket(port);
|
||||||
|
if (connfd < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cli.onConnection = [](const SocketChannelPtr& channel) {
|
||||||
|
std::string peeraddr = channel->peeraddr();
|
||||||
|
if (channel->isConnected()) {
|
||||||
|
printf("connected to %s! connfd=%d\n", peeraddr.c_str(), channel->fd());
|
||||||
|
} else {
|
||||||
|
printf("disconnected to %s! connfd=%d\n", peeraddr.c_str(), channel->fd());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cli.onMessage = [](const SocketChannelPtr& channel, Buffer* buf) {
|
||||||
|
printf("< %.*s\n", (int)buf->size(), (char*)buf->data());
|
||||||
|
};
|
||||||
|
cli.start();
|
||||||
|
|
||||||
|
std::string str;
|
||||||
|
while (std::getline(std::cin, str)) {
|
||||||
|
if (str == "close") {
|
||||||
|
cli.closesocket();
|
||||||
|
} else if (str == "start") {
|
||||||
|
cli.start();
|
||||||
|
} else if (str == "stop") {
|
||||||
|
cli.stop();
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (!cli.isConnected()) break;
|
||||||
|
cli.send(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTTP
|
||||||
|
#### HTTP服务端
|
||||||
|
见[examples/http_server_test.cpp](examples/http_server_test.cpp)
|
||||||
|
|
||||||
|
**golang gin 风格**
|
||||||
|
```c++
|
||||||
|
#include "HttpServer.h"
|
||||||
|
using namespace hv;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
HttpService router;
|
||||||
|
router.GET("/ping", [](HttpRequest* req, HttpResponse* resp) {
|
||||||
|
return resp->String("pong");
|
||||||
|
});
|
||||||
|
|
||||||
|
router.GET("/data", [](HttpRequest* req, HttpResponse* resp) {
|
||||||
|
static char data[] = "0123456789";
|
||||||
|
return resp->Data(data, 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.GET("/paths", [&router](HttpRequest* req, HttpResponse* resp) {
|
||||||
|
return resp->Json(router.Paths());
|
||||||
|
});
|
||||||
|
|
||||||
|
router.GET("/get", [](HttpRequest* req, HttpResponse* resp) {
|
||||||
|
resp->json["origin"] = req->client_addr.ip;
|
||||||
|
resp->json["url"] = req->url;
|
||||||
|
resp->json["args"] = req->query_params;
|
||||||
|
resp->json["headers"] = req->headers;
|
||||||
|
return 200;
|
||||||
|
});
|
||||||
|
|
||||||
|
router.POST("/echo", [](const HttpContextPtr& ctx) {
|
||||||
|
return ctx->send(ctx->body(), ctx->type());
|
||||||
|
});
|
||||||
|
|
||||||
|
HttpServer server(&router);
|
||||||
|
server.setPort(8080);
|
||||||
|
server.setThreadNum(4);
|
||||||
|
server.run();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**注意**:
|
||||||
|
|
||||||
|
上面示例直接运行在`main`主线程,`server.run()`会阻塞当前线程运行,所以`router`和`server`对象不会被析构,<br>
|
||||||
|
如使用`server.start()`内部会另起线程运行,不会阻塞当前线程,但需要注意`router`和`server`的生命周期,<br>
|
||||||
|
不要定义为局部变量被析构了,可定义为类成员变量或者全局变量,下面的`WebSocket`服务同理。<br>
|
||||||
|
|
||||||
|
#### HTTP客户端
|
||||||
|
见[examples/http_client_test.cpp](examples/http_client_test.cpp)
|
||||||
|
|
||||||
|
**python requests 风格**
|
||||||
|
```c++
|
||||||
|
#include "requests.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto resp = requests::get("http://www.example.com");
|
||||||
|
if (resp == NULL) {
|
||||||
|
printf("request failed!\n");
|
||||||
|
} else {
|
||||||
|
printf("%s\n", resp->body.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = requests::post("127.0.0.1:8080/echo", "hello,world!");
|
||||||
|
if (resp == NULL) {
|
||||||
|
printf("request failed!\n");
|
||||||
|
} else {
|
||||||
|
printf("%s\n", resp->body.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
附HTTP相关接口文档:
|
||||||
|
|
||||||
|
- [class HttpMessage](docs/cn/HttpMessage.md)
|
||||||
|
- [class HttpClient](docs/cn/HttpClient.md)
|
||||||
|
- [class HttpServer](docs/cn/HttpServer.md)
|
||||||
|
- [class HttpContext](docs/cn/HttpContext.md)
|
||||||
|
|
||||||
|
### WebSocket
|
||||||
|
#### WebSocket服务端
|
||||||
|
见[examples/websocket_server_test.cpp](examples/websocket_server_test.cpp)
|
||||||
|
```c++
|
||||||
|
#include "WebSocketServer.h"
|
||||||
|
using namespace hv;
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
WebSocketService ws;
|
||||||
|
ws.onopen = [](const WebSocketChannelPtr& channel, const HttpRequestPtr& req) {
|
||||||
|
printf("onopen: GET %s\n", req->Path().c_str());
|
||||||
|
};
|
||||||
|
ws.onmessage = [](const WebSocketChannelPtr& channel, const std::string& msg) {
|
||||||
|
printf("onmessage: %.*s\n", (int)msg.size(), msg.data());
|
||||||
|
};
|
||||||
|
ws.onclose = [](const WebSocketChannelPtr& channel) {
|
||||||
|
printf("onclose\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
WebSocketServer server(&ws);
|
||||||
|
server.setPort(9999);
|
||||||
|
server.setThreadNum(4);
|
||||||
|
server.run();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### WebSocket客户端
|
||||||
|
见[examples/websocket_client_test.cpp](examples/websocket_client_test.cpp)
|
||||||
|
```c++
|
||||||
|
#include "WebSocketClient.h"
|
||||||
|
using namespace hv;
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
WebSocketClient ws;
|
||||||
|
ws.onopen = []() {
|
||||||
|
printf("onopen\n");
|
||||||
|
};
|
||||||
|
ws.onmessage = [](const std::string& msg) {
|
||||||
|
printf("onmessage: %.*s\n", (int)msg.size(), msg.data());
|
||||||
|
};
|
||||||
|
ws.onclose = []() {
|
||||||
|
printf("onclose\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
// reconnect: 1,2,4,8,10,10,10...
|
||||||
|
reconn_setting_t reconn;
|
||||||
|
reconn_setting_init(&reconn);
|
||||||
|
reconn.min_delay = 1000;
|
||||||
|
reconn.max_delay = 10000;
|
||||||
|
reconn.delay_policy = 2;
|
||||||
|
ws.setReconnect(&reconn);
|
||||||
|
|
||||||
|
ws.open("ws://127.0.0.1:9999/test");
|
||||||
|
|
||||||
|
std::string str;
|
||||||
|
while (std::getline(std::cin, str)) {
|
||||||
|
if (!ws.isConnected()) break;
|
||||||
|
if (str == "quit") {
|
||||||
|
ws.close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ws.send(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🍭 更多示例
|
||||||
|
|
||||||
|
### c版本
|
||||||
|
- 事件循环: [examples/hloop_test.c](examples/hloop_test.c)
|
||||||
|
- 定时器: [examples/htimer_test.c](examples/htimer_test.c)
|
||||||
|
- TCP回显服务: [examples/tcp_echo_server.c](examples/tcp_echo_server.c)
|
||||||
|
- TCP聊天服务: [examples/tcp_chat_server.c](examples/tcp_chat_server.c)
|
||||||
|
- TCP代理服务: [examples/tcp_proxy_server.c](examples/tcp_proxy_server.c)
|
||||||
|
- UDP回显服务: [examples/udp_echo_server.c](examples/udp_echo_server.c)
|
||||||
|
- UDP代理服务: [examples/udp_proxy_server.c](examples/udp_proxy_server.c)
|
||||||
|
- SOCKS5代理服务: [examples/socks5_proxy_server.c](examples/socks5_proxy_server.c)
|
||||||
|
- HTTP服务: [examples/tinyhttpd.c](examples/tinyhttpd.c)
|
||||||
|
- HTTP代理服务: [examples/tinyproxyd.c](examples/tinyproxyd.c)
|
||||||
|
- jsonRPC示例: [examples/jsonrpc](examples/jsonrpc)
|
||||||
|
- MQTT示例: [examples/mqtt](examples/mqtt)
|
||||||
|
- 多accept进程模式: [examples/multi-thread/multi-acceptor-processes.c](examples/multi-thread/multi-acceptor-processes.c)
|
||||||
|
- 多accept线程模式: [examples/multi-thread/multi-acceptor-threads.c](examples/multi-thread/multi-acceptor-threads.c)
|
||||||
|
- 一个accept线程+多worker线程: [examples/multi-thread/one-acceptor-multi-workers.c](examples/multi-thread/one-acceptor-multi-workers.c)
|
||||||
|
|
||||||
|
### c++版本
|
||||||
|
- 事件循环: [evpp/EventLoop_test.cpp](evpp/EventLoop_test.cpp)
|
||||||
|
- 事件循环线程: [evpp/EventLoopThread_test.cpp](evpp/EventLoopThread_test.cpp)
|
||||||
|
- 事件循环线程池: [evpp/EventLoopThreadPool_test.cpp](evpp/EventLoopThreadPool_test.cpp)
|
||||||
|
- 定时器: [evpp/TimerThread_test.cpp](evpp/TimerThread_test.cpp)
|
||||||
|
- TCP服务端: [evpp/TcpServer_test.cpp](evpp/TcpServer_test.cpp)
|
||||||
|
- TCP客户端: [evpp/TcpClient_test.cpp](evpp/TcpClient_test.cpp)
|
||||||
|
- UDP服务端: [evpp/UdpServer_test.cpp](evpp/UdpServer_test.cpp)
|
||||||
|
- UDP客户端: [evpp/UdpClient_test.cpp](evpp/UdpClient_test.cpp)
|
||||||
|
- HTTP服务端: [examples/http_server_test.cpp](examples/http_server_test.cpp)
|
||||||
|
- HTTP客户端: [examples/http_client_test.cpp](examples/http_client_test.cpp)
|
||||||
|
- WebSocket服务端: [examples/websocket_server_test.cpp](examples/websocket_server_test.cpp)
|
||||||
|
- WebSocket客户端: [examples/websocket_client_test.cpp](examples/websocket_client_test.cpp)
|
||||||
|
- protobufRPC示例: [examples/protorpc](examples/protorpc)
|
||||||
|
- Qt中使用libhv示例: [hv-projects/QtDemo](https://github.com/hv-projects/QtDemo)
|
||||||
|
|
||||||
|
### 模拟实现著名的命令行工具
|
||||||
|
- 网络连接工具: [examples/nc](examples/nc.c)
|
||||||
|
- 网络扫描工具: [examples/nmap](examples/nmap)
|
||||||
|
- HTTP服务程序: [examples/httpd](examples/httpd)
|
||||||
|
- HTTP压测工具: [examples/wrk](examples/wrk.cpp)
|
||||||
|
- URL请求工具: [examples/curl](examples/curl.cpp)
|
||||||
|
- 文件下载工具: [examples/wget](examples/wget.cpp)
|
||||||
|
- 服务注册与发现: [examples/consul](examples/consul)
|
||||||
|
|
||||||
|
## 🥇 性能测试
|
||||||
|
|
||||||
|
### TCP回显服务pingpong测试
|
||||||
|
```shell
|
||||||
|
cd echo-servers
|
||||||
|
./build.sh
|
||||||
|
./benchmark.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**吞吐量**:
|
||||||
|
```shell
|
||||||
|
libevent running on port 2001
|
||||||
|
libev running on port 2002
|
||||||
|
libuv running on port 2003
|
||||||
|
libhv running on port 2004
|
||||||
|
asio running on port 2005
|
||||||
|
poco running on port 2006
|
||||||
|
|
||||||
|
==============2001=====================================
|
||||||
|
[127.0.0.1:2001] 4 threads 1000 connections run 10s
|
||||||
|
total readcount=1616761 readbytes=1655563264
|
||||||
|
throughput = 157 MB/s
|
||||||
|
|
||||||
|
==============2002=====================================
|
||||||
|
[127.0.0.1:2002] 4 threads 1000 connections run 10s
|
||||||
|
total readcount=2153171 readbytes=2204847104
|
||||||
|
throughput = 210 MB/s
|
||||||
|
|
||||||
|
==============2003=====================================
|
||||||
|
[127.0.0.1:2003] 4 threads 1000 connections run 10s
|
||||||
|
total readcount=1599727 readbytes=1638120448
|
||||||
|
throughput = 156 MB/s
|
||||||
|
|
||||||
|
==============2004=====================================
|
||||||
|
[127.0.0.1:2004] 4 threads 1000 connections run 10s
|
||||||
|
total readcount=2202271 readbytes=2255125504
|
||||||
|
throughput = 215 MB/s
|
||||||
|
|
||||||
|
==============2005=====================================
|
||||||
|
[127.0.0.1:2005] 4 threads 1000 connections run 10s
|
||||||
|
total readcount=1354230 readbytes=1386731520
|
||||||
|
throughput = 132 MB/s
|
||||||
|
|
||||||
|
==============2006=====================================
|
||||||
|
[127.0.0.1:2006] 4 threads 1000 connections run 10s
|
||||||
|
total readcount=1699652 readbytes=1740443648
|
||||||
|
throughput = 165 MB/s
|
||||||
|
```
|
||||||
|
|
||||||
|
### TCP代理服务压测
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# sudo apt install iperf
|
||||||
|
iperf -s -p 5001 > /dev/null &
|
||||||
|
bin/tcp_proxy_server 1212 127.0.0.1:5001 &
|
||||||
|
iperf -c 127.0.0.1 -p 5001 -l 8K
|
||||||
|
iperf -c 127.0.0.1 -p 1212 -l 8K
|
||||||
|
```
|
||||||
|
|
||||||
|
**带宽**:
|
||||||
|
```shell
|
||||||
|
------------------------------------------------------------
|
||||||
|
[ 3] local 127.0.0.1 port 52560 connected with 127.0.0.1 port 5001
|
||||||
|
[ ID] Interval Transfer Bandwidth
|
||||||
|
[ 3] 0.0-10.0 sec 20.8 GBytes 17.9 Gbits/sec
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
[ 3] local 127.0.0.1 port 48142 connected with 127.0.0.1 port 1212
|
||||||
|
[ ID] Interval Transfer Bandwidth
|
||||||
|
[ 3] 0.0-10.0 sec 11.9 GBytes 10.2 Gbits/sec
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTTP压测
|
||||||
|
```shell
|
||||||
|
# sudo apt install wrk
|
||||||
|
wrk -c 100 -t 4 -d 10s http://127.0.0.1:8080/
|
||||||
|
|
||||||
|
# sudo apt install apache2-utils
|
||||||
|
ab -c 100 -n 100000 http://127.0.0.1:8080/
|
||||||
|
```
|
||||||
|
|
||||||
|
**libhv(port:8080) vs nginx(port:80)**
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
以上测试结果可以在 [Github Actions](https://github.com/ithewei/libhv/actions/workflows/benchmark.yml) 中查看。
|
||||||
|
|
||||||
|
## 💎 用户案例
|
||||||
|
|
||||||
|
如果您在使用`libhv`,欢迎通过PR将信息提交至此列表,让更多的用户了解`libhv`的实际使用场景,以建立更好的网络生态。
|
||||||
|
|
||||||
|
| 用户 (公司名/项目名/个人联系方式) | 案例 (项目简介/业务场景) |
|
||||||
|
| :--- | :--- |
|
||||||
|
| [阅面科技](https://www.readsense.cn) | [猎户AIoT平台](https://orionweb.readsense.cn)设备管理、人脸检测HTTP服务、人脸搜索HTTP服务 |
|
||||||
|
| [socks5-libhv](https://gitee.com/billykang/socks5-libhv) | socks5代理 |
|
||||||
|
| [hvloop](https://github.com/xiispace/hvloop) | 类似[uvloop](https://github.com/MagicStack/uvloop)的python异步IO事件循环 |
|
||||||
|
| [tsproxyd-android](https://github.com/Haiwen-GitHub/tsproxyd-android) | 一个基于libhv实现的android端web代理服务 |
|
||||||
|
| [玄舟智维](https://zjzwxw.com) | C100K设备连接网关服务 |
|
||||||
|
|
462
external/libhv/libhv-1.3.2/README.md
vendored
Normal file
462
external/libhv/libhv-1.3.2/README.md
vendored
Normal file
|
@ -0,0 +1,462 @@
|
||||||
|
English | [中文](README-CN.md)
|
||||||
|
|
||||||
|
# libhv
|
||||||
|
|
||||||
|
[](https://github.com/ithewei/libhv/actions/workflows/CI.yml?query=branch%3Amaster)
|
||||||
|
[](https://github.com/ithewei/libhv/actions/workflows/CI.yml?query=branch%3Amaster)
|
||||||
|
[](https://github.com/ithewei/libhv/actions/workflows/CI.yml?query=branch%3Amaster)
|
||||||
|
[](https://github.com/ithewei/libhv/actions/workflows/CI.yml?query=branch%3Amaster)
|
||||||
|
[](https://github.com/ithewei/libhv/actions/workflows/CI.yml?query=branch%3Amaster)
|
||||||
|
[](https://github.com/ithewei/libhv/actions/workflows/benchmark.yml?query=branch%3Amaster)
|
||||||
|
<br>
|
||||||
|
[](https://github.com/ithewei/libhv/releases)
|
||||||
|
[](https://github.com/ithewei/libhv/stargazers)
|
||||||
|
[](https://github.com/ithewei/libhv/forks)
|
||||||
|
[](https://github.com/ithewei/libhv/issues)
|
||||||
|
[](https://github.com/ithewei/libhv/pulls)
|
||||||
|
[](https://github.com/ithewei/libhv/contributors)
|
||||||
|
[](LICENSE)
|
||||||
|
<br>
|
||||||
|
[](https://gitee.com/libhv/libhv)
|
||||||
|
[](https://github.com/oz123/awesome-c)
|
||||||
|
[](https://github.com/fffaraz/awesome-cpp)
|
||||||
|
|
||||||
|
Like `libevent, libev, and libuv`,
|
||||||
|
`libhv` provides event-loop with non-blocking IO and timer,
|
||||||
|
but simpler api and richer protocols.
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
|
||||||
|
- Cross-platform (Linux, Windows, macOS, Android, iOS, BSD, Solaris)
|
||||||
|
- High-performance EventLoop (IO, timer, idle, custom)
|
||||||
|
- TCP/UDP client/server/proxy
|
||||||
|
- TCP supports heartbeat, reconnect, upstream, MultiThread-safe write and close, etc.
|
||||||
|
- Built-in common unpacking modes (FixedLength, Delimiter, LengthField)
|
||||||
|
- RUDP support: WITH_KCP
|
||||||
|
- SSL/TLS support: (via WITH_OPENSSL or WITH_GNUTLS or WITH_MBEDTLS)
|
||||||
|
- HTTP client/server (support https http1/x http2 grpc)
|
||||||
|
- HTTP supports static service, indexof service, forward/reverse proxy service, sync/async API handler
|
||||||
|
- HTTP supports RESTful, router, middleware, keep-alive, chunked, SSE, etc.
|
||||||
|
- WebSocket client/server
|
||||||
|
- MQTT client
|
||||||
|
|
||||||
|
## ⌛️ Build
|
||||||
|
|
||||||
|
see [BUILD.md](BUILD.md)
|
||||||
|
|
||||||
|
Makefile:
|
||||||
|
```shell
|
||||||
|
./configure
|
||||||
|
make
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
or cmake:
|
||||||
|
```shell
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
cmake --build .
|
||||||
|
```
|
||||||
|
|
||||||
|
or vcpkg:
|
||||||
|
```shell
|
||||||
|
vcpkg install libhv
|
||||||
|
```
|
||||||
|
|
||||||
|
or xmake:
|
||||||
|
```shell
|
||||||
|
xrepo install libhv
|
||||||
|
```
|
||||||
|
|
||||||
|
## ⚡️ Getting Started
|
||||||
|
|
||||||
|
run `./getting_started.sh`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git clone https://github.com/ithewei/libhv.git
|
||||||
|
cd libhv
|
||||||
|
./configure
|
||||||
|
make
|
||||||
|
|
||||||
|
bin/httpd -h
|
||||||
|
bin/httpd -d
|
||||||
|
#bin/httpd -c etc/httpd.conf -s restart -d
|
||||||
|
ps aux | grep httpd
|
||||||
|
|
||||||
|
# http file service
|
||||||
|
bin/curl -v localhost:8080
|
||||||
|
|
||||||
|
# http indexof service
|
||||||
|
bin/curl -v localhost:8080/downloads/
|
||||||
|
|
||||||
|
# http api service
|
||||||
|
bin/curl -v localhost:8080/ping
|
||||||
|
bin/curl -v localhost:8080/echo -d "hello,world!"
|
||||||
|
bin/curl -v localhost:8080/query?page_no=1\&page_size=10
|
||||||
|
bin/curl -v localhost:8080/kv -H "Content-Type:application/x-www-form-urlencoded" -d 'user=admin&pswd=123456'
|
||||||
|
bin/curl -v localhost:8080/json -H "Content-Type:application/json" -d '{"user":"admin","pswd":"123456"}'
|
||||||
|
bin/curl -v localhost:8080/form -F 'user=admin' -F 'pswd=123456'
|
||||||
|
bin/curl -v localhost:8080/upload -d "@LICENSE"
|
||||||
|
bin/curl -v localhost:8080/upload -F "file=@LICENSE"
|
||||||
|
|
||||||
|
bin/curl -v localhost:8080/test -H "Content-Type:application/x-www-form-urlencoded" -d 'bool=1&int=123&float=3.14&string=hello'
|
||||||
|
bin/curl -v localhost:8080/test -H "Content-Type:application/json" -d '{"bool":true,"int":123,"float":3.14,"string":"hello"}'
|
||||||
|
bin/curl -v localhost:8080/test -F 'bool=1' -F 'int=123' -F 'float=3.14' -F 'string=hello'
|
||||||
|
# RESTful API: /group/:group_name/user/:user_id
|
||||||
|
bin/curl -v -X DELETE localhost:8080/group/test/user/123
|
||||||
|
|
||||||
|
# benchmark
|
||||||
|
bin/wrk -c 1000 -d 10 -t 4 http://127.0.0.1:8080/
|
||||||
|
```
|
||||||
|
|
||||||
|
### TCP
|
||||||
|
#### tcp server
|
||||||
|
**c version**: [examples/tcp_echo_server.c](examples/tcp_echo_server.c)
|
||||||
|
|
||||||
|
**c++ version**: [evpp/TcpServer_test.cpp](evpp/TcpServer_test.cpp)
|
||||||
|
```c++
|
||||||
|
#include "TcpServer.h"
|
||||||
|
using namespace hv;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int port = 1234;
|
||||||
|
TcpServer srv;
|
||||||
|
int listenfd = srv.createsocket(port);
|
||||||
|
if (listenfd < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("server listen on port %d, listenfd=%d ...\n", port, listenfd);
|
||||||
|
srv.onConnection = [](const SocketChannelPtr& channel) {
|
||||||
|
std::string peeraddr = channel->peeraddr();
|
||||||
|
if (channel->isConnected()) {
|
||||||
|
printf("%s connected! connfd=%d\n", peeraddr.c_str(), channel->fd());
|
||||||
|
} else {
|
||||||
|
printf("%s disconnected! connfd=%d\n", peeraddr.c_str(), channel->fd());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
srv.onMessage = [](const SocketChannelPtr& channel, Buffer* buf) {
|
||||||
|
// echo
|
||||||
|
channel->write(buf);
|
||||||
|
};
|
||||||
|
srv.setThreadNum(4);
|
||||||
|
srv.start();
|
||||||
|
|
||||||
|
// press Enter to stop
|
||||||
|
while (getchar() != '\n');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### tcp client
|
||||||
|
**c version**: [examples/tcp_client_test.c](examples/tcp_client_test.c)
|
||||||
|
|
||||||
|
**c++ version**: [evpp/TcpClient_test.cpp](evpp/TcpClient_test.cpp)
|
||||||
|
```c++
|
||||||
|
#include <iostream>
|
||||||
|
#include "TcpClient.h"
|
||||||
|
using namespace hv;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int port = 1234;
|
||||||
|
TcpClient cli;
|
||||||
|
int connfd = cli.createsocket(port);
|
||||||
|
if (connfd < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cli.onConnection = [](const SocketChannelPtr& channel) {
|
||||||
|
std::string peeraddr = channel->peeraddr();
|
||||||
|
if (channel->isConnected()) {
|
||||||
|
printf("connected to %s! connfd=%d\n", peeraddr.c_str(), channel->fd());
|
||||||
|
} else {
|
||||||
|
printf("disconnected to %s! connfd=%d\n", peeraddr.c_str(), channel->fd());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cli.onMessage = [](const SocketChannelPtr& channel, Buffer* buf) {
|
||||||
|
printf("< %.*s\n", (int)buf->size(), (char*)buf->data());
|
||||||
|
};
|
||||||
|
cli.start();
|
||||||
|
|
||||||
|
std::string str;
|
||||||
|
while (std::getline(std::cin, str)) {
|
||||||
|
if (str == "close") {
|
||||||
|
cli.closesocket();
|
||||||
|
} else if (str == "start") {
|
||||||
|
cli.start();
|
||||||
|
} else if (str == "stop") {
|
||||||
|
cli.stop();
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (!cli.isConnected()) break;
|
||||||
|
cli.send(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTTP
|
||||||
|
#### http server
|
||||||
|
see [examples/http_server_test.cpp](examples/http_server_test.cpp)
|
||||||
|
|
||||||
|
**golang gin style**
|
||||||
|
```c++
|
||||||
|
#include "HttpServer.h"
|
||||||
|
using namespace hv;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
HttpService router;
|
||||||
|
router.GET("/ping", [](HttpRequest* req, HttpResponse* resp) {
|
||||||
|
return resp->String("pong");
|
||||||
|
});
|
||||||
|
|
||||||
|
router.GET("/data", [](HttpRequest* req, HttpResponse* resp) {
|
||||||
|
static char data[] = "0123456789";
|
||||||
|
return resp->Data(data, 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.GET("/paths", [&router](HttpRequest* req, HttpResponse* resp) {
|
||||||
|
return resp->Json(router.Paths());
|
||||||
|
});
|
||||||
|
|
||||||
|
router.GET("/get", [](HttpRequest* req, HttpResponse* resp) {
|
||||||
|
resp->json["origin"] = req->client_addr.ip;
|
||||||
|
resp->json["url"] = req->url;
|
||||||
|
resp->json["args"] = req->query_params;
|
||||||
|
resp->json["headers"] = req->headers;
|
||||||
|
return 200;
|
||||||
|
});
|
||||||
|
|
||||||
|
router.POST("/echo", [](const HttpContextPtr& ctx) {
|
||||||
|
return ctx->send(ctx->body(), ctx->type());
|
||||||
|
});
|
||||||
|
|
||||||
|
HttpServer server(&router);
|
||||||
|
server.setPort(8080);
|
||||||
|
server.setThreadNum(4);
|
||||||
|
server.run();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
#### http client
|
||||||
|
see [examples/http_client_test.cpp](examples/http_client_test.cpp)
|
||||||
|
|
||||||
|
**python requests style**
|
||||||
|
```c++
|
||||||
|
#include "requests.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto resp = requests::get("http://www.example.com");
|
||||||
|
if (resp == NULL) {
|
||||||
|
printf("request failed!\n");
|
||||||
|
} else {
|
||||||
|
printf("%s\n", resp->body.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = requests::post("127.0.0.1:8080/echo", "hello,world!");
|
||||||
|
if (resp == NULL) {
|
||||||
|
printf("request failed!\n");
|
||||||
|
} else {
|
||||||
|
printf("%s\n", resp->body.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### WebSocket
|
||||||
|
#### WebSocket server
|
||||||
|
see [examples/websocket_server_test.cpp](examples/websocket_server_test.cpp)
|
||||||
|
```c++
|
||||||
|
#include "WebSocketServer.h"
|
||||||
|
using namespace hv;
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
WebSocketService ws;
|
||||||
|
ws.onopen = [](const WebSocketChannelPtr& channel, const HttpRequestPtr& req) {
|
||||||
|
printf("onopen: GET %s\n", req->Path().c_str());
|
||||||
|
};
|
||||||
|
ws.onmessage = [](const WebSocketChannelPtr& channel, const std::string& msg) {
|
||||||
|
printf("onmessage: %.*s\n", (int)msg.size(), msg.data());
|
||||||
|
};
|
||||||
|
ws.onclose = [](const WebSocketChannelPtr& channel) {
|
||||||
|
printf("onclose\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
WebSocketServer server(&ws);
|
||||||
|
server.setPort(9999);
|
||||||
|
server.setThreadNum(4);
|
||||||
|
server.run();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### WebSocket client
|
||||||
|
see [examples/websocket_client_test.cpp](examples/websocket_client_test.cpp)
|
||||||
|
```c++
|
||||||
|
#include "WebSocketClient.h"
|
||||||
|
using namespace hv;
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
WebSocketClient ws;
|
||||||
|
ws.onopen = []() {
|
||||||
|
printf("onopen\n");
|
||||||
|
};
|
||||||
|
ws.onmessage = [](const std::string& msg) {
|
||||||
|
printf("onmessage: %.*s\n", (int)msg.size(), msg.data());
|
||||||
|
};
|
||||||
|
ws.onclose = []() {
|
||||||
|
printf("onclose\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
// reconnect: 1,2,4,8,10,10,10...
|
||||||
|
reconn_setting_t reconn;
|
||||||
|
reconn_setting_init(&reconn);
|
||||||
|
reconn.min_delay = 1000;
|
||||||
|
reconn.max_delay = 10000;
|
||||||
|
reconn.delay_policy = 2;
|
||||||
|
ws.setReconnect(&reconn);
|
||||||
|
|
||||||
|
ws.open("ws://127.0.0.1:9999/test");
|
||||||
|
|
||||||
|
std::string str;
|
||||||
|
while (std::getline(std::cin, str)) {
|
||||||
|
if (!ws.isConnected()) break;
|
||||||
|
if (str == "quit") {
|
||||||
|
ws.close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ws.send(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🍭 More examples
|
||||||
|
### c version
|
||||||
|
- [examples/hloop_test.c](examples/hloop_test.c)
|
||||||
|
- [examples/htimer_test.c](examples/htimer_test.c)
|
||||||
|
- [examples/tcp_echo_server.c](examples/tcp_echo_server.c)
|
||||||
|
- [examples/tcp_chat_server.c](examples/tcp_chat_server.c)
|
||||||
|
- [examples/tcp_proxy_server.c](examples/tcp_proxy_server.c)
|
||||||
|
- [examples/udp_echo_server.c](examples/udp_echo_server.c)
|
||||||
|
- [examples/udp_proxy_server.c](examples/udp_proxy_server.c)
|
||||||
|
- [examples/socks5_proxy_server.c](examples/socks5_proxy_server.c)
|
||||||
|
- [examples/tinyhttpd.c](examples/tinyhttpd.c)
|
||||||
|
- [examples/tinyproxyd.c](examples/tinyproxyd.c)
|
||||||
|
- [examples/jsonrpc](examples/jsonrpc)
|
||||||
|
- [examples/mqtt](examples/mqtt)
|
||||||
|
- [examples/multi-thread/multi-acceptor-processes.c](examples/multi-thread/multi-acceptor-processes.c)
|
||||||
|
- [examples/multi-thread/multi-acceptor-threads.c](examples/multi-thread/multi-acceptor-threads.c)
|
||||||
|
- [examples/multi-thread/one-acceptor-multi-workers.c](examples/multi-thread/one-acceptor-multi-workers.c)
|
||||||
|
|
||||||
|
### c++ version
|
||||||
|
- [evpp/EventLoop_test.cpp](evpp/EventLoop_test.cpp)
|
||||||
|
- [evpp/EventLoopThread_test.cpp](evpp/EventLoopThread_test.cpp)
|
||||||
|
- [evpp/EventLoopThreadPool_test.cpp](evpp/EventLoopThreadPool_test.cpp)
|
||||||
|
- [evpp/TimerThread_test.cpp](evpp/TimerThread_test.cpp)
|
||||||
|
- [evpp/TcpServer_test.cpp](evpp/TcpServer_test.cpp)
|
||||||
|
- [evpp/TcpClient_test.cpp](evpp/TcpClient_test.cpp)
|
||||||
|
- [evpp/UdpServer_test.cpp](evpp/UdpServer_test.cpp)
|
||||||
|
- [evpp/UdpClient_test.cpp](evpp/UdpClient_test.cpp)
|
||||||
|
- [examples/http_server_test.cpp](examples/http_server_test.cpp)
|
||||||
|
- [examples/http_client_test.cpp](examples/http_client_test.cpp)
|
||||||
|
- [examples/websocket_server_test.cpp](examples/websocket_server_test.cpp)
|
||||||
|
- [examples/websocket_client_test.cpp](examples/websocket_client_test.cpp)
|
||||||
|
- [examples/protorpc](examples/protorpc)
|
||||||
|
- [hv-projects/QtDemo](https://github.com/hv-projects/QtDemo)
|
||||||
|
|
||||||
|
### simulate well-known command line tools
|
||||||
|
- [examples/nc](examples/nc.c)
|
||||||
|
- [examples/nmap](examples/nmap)
|
||||||
|
- [examples/httpd](examples/httpd)
|
||||||
|
- [examples/wrk](examples/wrk.cpp)
|
||||||
|
- [examples/curl](examples/curl.cpp)
|
||||||
|
- [examples/wget](examples/wget.cpp)
|
||||||
|
- [examples/consul](examples/consul)
|
||||||
|
|
||||||
|
## 🥇 Benchmark
|
||||||
|
### `pingpong echo-servers`
|
||||||
|
```shell
|
||||||
|
cd echo-servers
|
||||||
|
./build.sh
|
||||||
|
./benchmark.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**throughput**:
|
||||||
|
```shell
|
||||||
|
libevent running on port 2001
|
||||||
|
libev running on port 2002
|
||||||
|
libuv running on port 2003
|
||||||
|
libhv running on port 2004
|
||||||
|
asio running on port 2005
|
||||||
|
poco running on port 2006
|
||||||
|
|
||||||
|
==============2001=====================================
|
||||||
|
[127.0.0.1:2001] 4 threads 1000 connections run 10s
|
||||||
|
total readcount=1616761 readbytes=1655563264
|
||||||
|
throughput = 157 MB/s
|
||||||
|
|
||||||
|
==============2002=====================================
|
||||||
|
[127.0.0.1:2002] 4 threads 1000 connections run 10s
|
||||||
|
total readcount=2153171 readbytes=2204847104
|
||||||
|
throughput = 210 MB/s
|
||||||
|
|
||||||
|
==============2003=====================================
|
||||||
|
[127.0.0.1:2003] 4 threads 1000 connections run 10s
|
||||||
|
total readcount=1599727 readbytes=1638120448
|
||||||
|
throughput = 156 MB/s
|
||||||
|
|
||||||
|
==============2004=====================================
|
||||||
|
[127.0.0.1:2004] 4 threads 1000 connections run 10s
|
||||||
|
total readcount=2202271 readbytes=2255125504
|
||||||
|
throughput = 215 MB/s
|
||||||
|
|
||||||
|
==============2005=====================================
|
||||||
|
[127.0.0.1:2005] 4 threads 1000 connections run 10s
|
||||||
|
total readcount=1354230 readbytes=1386731520
|
||||||
|
throughput = 132 MB/s
|
||||||
|
|
||||||
|
==============2006=====================================
|
||||||
|
[127.0.0.1:2006] 4 threads 1000 connections run 10s
|
||||||
|
total readcount=1699652 readbytes=1740443648
|
||||||
|
throughput = 165 MB/s
|
||||||
|
```
|
||||||
|
|
||||||
|
### `iperf tcp_proxy_server`
|
||||||
|
```shell
|
||||||
|
# sudo apt install iperf
|
||||||
|
iperf -s -p 5001 > /dev/null &
|
||||||
|
bin/tcp_proxy_server 1212 127.0.0.1:5001 &
|
||||||
|
iperf -c 127.0.0.1 -p 5001 -l 8K
|
||||||
|
iperf -c 127.0.0.1 -p 1212 -l 8K
|
||||||
|
```
|
||||||
|
|
||||||
|
**Bandwidth**:
|
||||||
|
```shell
|
||||||
|
------------------------------------------------------------
|
||||||
|
[ 3] local 127.0.0.1 port 52560 connected with 127.0.0.1 port 5001
|
||||||
|
[ ID] Interval Transfer Bandwidth
|
||||||
|
[ 3] 0.0-10.0 sec 20.8 GBytes 17.9 Gbits/sec
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
[ 3] local 127.0.0.1 port 48142 connected with 127.0.0.1 port 1212
|
||||||
|
[ ID] Interval Transfer Bandwidth
|
||||||
|
[ 3] 0.0-10.0 sec 11.9 GBytes 10.2 Gbits/sec
|
||||||
|
```
|
||||||
|
|
||||||
|
### `webbench`
|
||||||
|
```shell
|
||||||
|
# sudo apt install wrk
|
||||||
|
wrk -c 100 -t 4 -d 10s http://127.0.0.1:8080/
|
||||||
|
|
||||||
|
# sudo apt install apache2-utils
|
||||||
|
ab -c 100 -n 100000 http://127.0.0.1:8080/
|
||||||
|
```
|
||||||
|
|
||||||
|
**libhv(port:8080) vs nginx(port:80)**
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Above test results can be found on [Github Actions](https://github.com/ithewei/libhv/actions/workflows/benchmark.yml).
|
36
external/libhv/libhv-1.3.2/TREE.md
vendored
Normal file
36
external/libhv/libhv-1.3.2/TREE.md
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── base libhv基础设施,如常用宏定义、数据结构、日期时间、线程、进程、日志、套接字
|
||||||
|
├── bin 可执行文件安装目录
|
||||||
|
├── build cmake默认构建目录
|
||||||
|
├── cert SSL证书存放目录
|
||||||
|
├── cmake cmake脚本存放目录
|
||||||
|
├── cpputil libhv工具类,如字符串、文件、路径、线程池、json解析、ini解析
|
||||||
|
├── docs 文档存放目录
|
||||||
|
├── echo-servers 包含libevent、libev、libuv、libhv、asio、poco、muduo等多个网络库的tcp echo server写法,并做压力测试
|
||||||
|
├── etc 应用程序配置目录
|
||||||
|
├── event libhv事件循环模块
|
||||||
|
├── evpp 事件循环c++封装类
|
||||||
|
├── examples 示例代码
|
||||||
|
│ └── httpd
|
||||||
|
├── html 网页document_root目录
|
||||||
|
│ ├── downloads 下载目录
|
||||||
|
│ └── uploads 上传目录
|
||||||
|
├── http libhv http模块
|
||||||
|
│ ├── client
|
||||||
|
│ └── server
|
||||||
|
├── include 头文件安装目录
|
||||||
|
│ └── hv
|
||||||
|
├── lib 库文件安装目录
|
||||||
|
├── logs 日志生成目录
|
||||||
|
├── misc 杂项
|
||||||
|
├── mqtt MQTT协议
|
||||||
|
├── protocol 包含icmp、dns、ftp、smtp等协议的实现
|
||||||
|
├── scripts shell脚本存放目录
|
||||||
|
├── ssl SSL/TLS加密通信
|
||||||
|
├── unittest 单元测试代码
|
||||||
|
└── util libhv工具函数,如base64、md5、sha1
|
||||||
|
|
||||||
|
```
|
28
external/libhv/libhv-1.3.2/base/README.md
vendored
Normal file
28
external/libhv/libhv-1.3.2/base/README.md
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── array.h 动态数组
|
||||||
|
├── hatomic.h 原子操作
|
||||||
|
├── hbase.h 基础函数
|
||||||
|
├── hbuf.h 缓存
|
||||||
|
├── hdef.h 常见宏定义
|
||||||
|
├── heap.h 堆
|
||||||
|
├── hendian.h 大小端
|
||||||
|
├── herr.h 错误码表
|
||||||
|
├── hlog.h 日志
|
||||||
|
├── hmain.h 命令行解析
|
||||||
|
├── hmath.h 数学函数
|
||||||
|
├── hmutex.h 线程同步锁
|
||||||
|
├── hplatform.h 平台相关宏
|
||||||
|
├── hproc.h 进程
|
||||||
|
├── hsocket.h 套接字
|
||||||
|
├── hsysinfo.h 系统信息
|
||||||
|
├── hthread.h 线程
|
||||||
|
├── htime.h 时间
|
||||||
|
├── hversion.h 版本
|
||||||
|
├── list.h 链表
|
||||||
|
├── queue.h 队列
|
||||||
|
└── rbtree.h 红黑树
|
||||||
|
|
||||||
|
```
|
152
external/libhv/libhv-1.3.2/base/array.h
vendored
Normal file
152
external/libhv/libhv-1.3.2/base/array.h
vendored
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
#ifndef HV_ARRAY_H_
|
||||||
|
#define HV_ARRAY_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* array
|
||||||
|
* at: random access by pos
|
||||||
|
* @effective
|
||||||
|
* push_back,pop_back,del_nomove,swap
|
||||||
|
* @ineffective
|
||||||
|
* add,del
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h> // for assert
|
||||||
|
#include <stddef.h> // for NULL
|
||||||
|
#include <stdlib.h> // for malloc,realloc,free
|
||||||
|
#include <string.h> // for memset,memmove
|
||||||
|
|
||||||
|
#include "hbase.h" // for HV_ALLOC, HV_FREE
|
||||||
|
|
||||||
|
#define ARRAY_INIT_SIZE 16
|
||||||
|
|
||||||
|
// #include <vector>
|
||||||
|
// typedef std::vector<type> atype;
|
||||||
|
#define ARRAY_DECL(type, atype) \
|
||||||
|
struct atype { \
|
||||||
|
type* ptr; \
|
||||||
|
size_t size; \
|
||||||
|
size_t maxsize;\
|
||||||
|
}; \
|
||||||
|
typedef struct atype atype;\
|
||||||
|
\
|
||||||
|
static inline type* atype##_data(atype* p) {\
|
||||||
|
return p->ptr;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline int atype##_size(atype* p) {\
|
||||||
|
return p->size;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline int atype##_maxsize(atype* p) {\
|
||||||
|
return p->maxsize;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline int atype##_empty(atype* p) {\
|
||||||
|
return p->size == 0;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline type* atype##_at(atype* p, int pos) {\
|
||||||
|
if (pos < 0) {\
|
||||||
|
pos += p->size;\
|
||||||
|
}\
|
||||||
|
assert(pos >= 0 && pos < p->size);\
|
||||||
|
return p->ptr + pos;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline type* atype##_front(atype* p) {\
|
||||||
|
return p->size == 0 ? NULL : p->ptr;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline type* atype##_back(atype* p) {\
|
||||||
|
return p->size == 0 ? NULL : p->ptr + p->size - 1;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void atype##_init(atype* p, int maxsize) {\
|
||||||
|
p->size = 0;\
|
||||||
|
p->maxsize = maxsize;\
|
||||||
|
HV_ALLOC(p->ptr, sizeof(type) * maxsize);\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void atype##_clear(atype* p) {\
|
||||||
|
p->size = 0;\
|
||||||
|
memset(p->ptr, 0, sizeof(type) * p->maxsize);\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void atype##_cleanup(atype* p) {\
|
||||||
|
HV_FREE(p->ptr);\
|
||||||
|
p->size = p->maxsize = 0;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void atype##_resize(atype* p, int maxsize) {\
|
||||||
|
if (maxsize == 0) maxsize = ARRAY_INIT_SIZE;\
|
||||||
|
p->ptr = (type*)hv_realloc(p->ptr, sizeof(type) * maxsize, sizeof(type) * p->maxsize);\
|
||||||
|
p->maxsize = maxsize;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void atype##_double_resize(atype* p) {\
|
||||||
|
atype##_resize(p, p->maxsize * 2);\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void atype##_push_back(atype* p, type* elem) {\
|
||||||
|
if (p->size == p->maxsize) {\
|
||||||
|
atype##_double_resize(p);\
|
||||||
|
}\
|
||||||
|
p->ptr[p->size] = *elem;\
|
||||||
|
p->size++;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void atype##_pop_back(atype* p) {\
|
||||||
|
assert(p->size > 0);\
|
||||||
|
p->size--;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void atype##_add(atype* p, type* elem, int pos) {\
|
||||||
|
if (pos < 0) {\
|
||||||
|
pos += p->size;\
|
||||||
|
}\
|
||||||
|
assert(pos >= 0 && pos <= p->size);\
|
||||||
|
if (p->size == p->maxsize) {\
|
||||||
|
atype##_double_resize(p);\
|
||||||
|
}\
|
||||||
|
if (pos < p->size) {\
|
||||||
|
memmove(p->ptr + pos+1, p->ptr + pos, sizeof(type) * (p->size - pos));\
|
||||||
|
}\
|
||||||
|
p->ptr[pos] = *elem;\
|
||||||
|
p->size++;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void atype##_del(atype* p, int pos) {\
|
||||||
|
if (pos < 0) {\
|
||||||
|
pos += p->size;\
|
||||||
|
}\
|
||||||
|
assert(pos >= 0 && pos < p->size);\
|
||||||
|
p->size--;\
|
||||||
|
if (pos < p->size) {\
|
||||||
|
memmove(p->ptr + pos, p->ptr + pos+1, sizeof(type) * (p->size - pos));\
|
||||||
|
}\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void atype##_del_nomove(atype* p, int pos) {\
|
||||||
|
if (pos < 0) {\
|
||||||
|
pos += p->size;\
|
||||||
|
}\
|
||||||
|
assert(pos >= 0 && pos < p->size);\
|
||||||
|
p->size--;\
|
||||||
|
if (pos < p->size) {\
|
||||||
|
p->ptr[pos] = p->ptr[p->size];\
|
||||||
|
}\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void atype##_swap(atype* p, int pos1, int pos2) {\
|
||||||
|
if (pos1 < 0) {\
|
||||||
|
pos1 += p->size;\
|
||||||
|
}\
|
||||||
|
if (pos2 < 0) {\
|
||||||
|
pos2 += p->size;\
|
||||||
|
}\
|
||||||
|
type tmp = p->ptr[pos1];\
|
||||||
|
p->ptr[pos1] = p->ptr[pos2];\
|
||||||
|
p->ptr[pos2] = tmp;\
|
||||||
|
}\
|
||||||
|
|
||||||
|
#endif // HV_ARRAY_H_
|
130
external/libhv/libhv-1.3.2/base/hatomic.h
vendored
Normal file
130
external/libhv/libhv-1.3.2/base/hatomic.h
vendored
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
#ifndef HV_ATOMIC_H_
|
||||||
|
#define HV_ATOMIC_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
// c++11
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
using std::atomic_flag;
|
||||||
|
using std::atomic_long;
|
||||||
|
|
||||||
|
#define ATOMIC_FLAG_TEST_AND_SET(p) ((p)->test_and_set())
|
||||||
|
#define ATOMIC_FLAG_CLEAR(p) ((p)->clear())
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include "hplatform.h" // for HAVE_STDATOMIC_H
|
||||||
|
#if HAVE_STDATOMIC_H
|
||||||
|
|
||||||
|
// c11
|
||||||
|
#include <stdatomic.h>
|
||||||
|
|
||||||
|
#define ATOMIC_FLAG_TEST_AND_SET atomic_flag_test_and_set
|
||||||
|
#define ATOMIC_FLAG_CLEAR atomic_flag_clear
|
||||||
|
#define ATOMIC_ADD atomic_fetch_add
|
||||||
|
#define ATOMIC_SUB atomic_fetch_sub
|
||||||
|
#define ATOMIC_INC(p) ATOMIC_ADD(p, 1)
|
||||||
|
#define ATOMIC_DEC(p) ATOMIC_SUB(p, 1)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
typedef volatile bool atomic_bool;
|
||||||
|
typedef volatile char atomic_char;
|
||||||
|
typedef volatile unsigned char atomic_uchar;
|
||||||
|
typedef volatile short atomic_short;
|
||||||
|
typedef volatile unsigned short atomic_ushort;
|
||||||
|
typedef volatile int atomic_int;
|
||||||
|
typedef volatile unsigned int atomic_uint;
|
||||||
|
typedef volatile long atomic_long;
|
||||||
|
typedef volatile unsigned long atomic_ulong;
|
||||||
|
typedef volatile long long atomic_llong;
|
||||||
|
typedef volatile unsigned long long atomic_ullong;
|
||||||
|
typedef volatile size_t atomic_size_t;
|
||||||
|
|
||||||
|
typedef struct atomic_flag { atomic_bool _Value; } atomic_flag;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#define ATOMIC_FLAG_TEST_AND_SET atomic_flag_test_and_set
|
||||||
|
static inline bool atomic_flag_test_and_set(atomic_flag* p) {
|
||||||
|
// return InterlockedIncrement((LONG*)&p->_Value, 1);
|
||||||
|
return InterlockedCompareExchange((LONG*)&p->_Value, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ATOMIC_ADD InterlockedAdd
|
||||||
|
#define ATOMIC_SUB(p, n) InterlockedAdd(p, -n)
|
||||||
|
#define ATOMIC_INC InterlockedIncrement
|
||||||
|
#define ATOMIC_DEC InterlockedDecrement
|
||||||
|
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
|
||||||
|
#define ATOMIC_FLAG_TEST_AND_SET atomic_flag_test_and_set
|
||||||
|
static inline bool atomic_flag_test_and_set(atomic_flag* p) {
|
||||||
|
return !__sync_bool_compare_and_swap(&p->_Value, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ATOMIC_ADD __sync_fetch_and_add
|
||||||
|
#define ATOMIC_SUB __sync_fetch_and_sub
|
||||||
|
#define ATOMIC_INC(p) ATOMIC_ADD(p, 1)
|
||||||
|
#define ATOMIC_DEC(p) ATOMIC_SUB(p, 1)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // HAVE_STDATOMIC_H
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#ifndef ATOMIC_FLAG_INIT
|
||||||
|
#define ATOMIC_FLAG_INIT { 0 }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ATOMIC_VAR_INIT
|
||||||
|
#define ATOMIC_VAR_INIT(value) (value)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ATOMIC_FLAG_TEST_AND_SET
|
||||||
|
#define ATOMIC_FLAG_TEST_AND_SET atomic_flag_test_and_set
|
||||||
|
static inline bool atomic_flag_test_and_set(atomic_flag* p) {
|
||||||
|
bool ret = p->_Value;
|
||||||
|
p->_Value = 1;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ATOMIC_FLAG_CLEAR
|
||||||
|
#define ATOMIC_FLAG_CLEAR atomic_flag_clear
|
||||||
|
static inline void atomic_flag_clear(atomic_flag* p) {
|
||||||
|
p->_Value = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ATOMIC_ADD
|
||||||
|
#define ATOMIC_ADD(p, n) (*(p) += (n))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ATOMIC_SUB
|
||||||
|
#define ATOMIC_SUB(p, n) (*(p) -= (n))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ATOMIC_INC
|
||||||
|
#define ATOMIC_INC(p) ((*(p))++)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ATOMIC_DEC
|
||||||
|
#define ATOMIC_DEC(p) ((*(p))--)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef atomic_flag hatomic_flag_t;
|
||||||
|
#define HATOMIC_FLAG_INIT ATOMIC_FLAG_INIT
|
||||||
|
#define hatomic_flag_test_and_set ATOMIC_FLAG_TEST_AND_SET
|
||||||
|
#define hatomic_flag_clear ATOMIC_FLAG_CLEAR
|
||||||
|
|
||||||
|
typedef atomic_long hatomic_t;
|
||||||
|
#define HATOMIC_VAR_INIT ATOMIC_VAR_INIT
|
||||||
|
#define hatomic_add ATOMIC_ADD
|
||||||
|
#define hatomic_sub ATOMIC_SUB
|
||||||
|
#define hatomic_inc ATOMIC_INC
|
||||||
|
#define hatomic_dec ATOMIC_DEC
|
||||||
|
|
||||||
|
#endif // HV_ATOMIC_H_
|
519
external/libhv/libhv-1.3.2/base/hbase.c
vendored
Normal file
519
external/libhv/libhv-1.3.2/base/hbase.c
vendored
Normal file
|
@ -0,0 +1,519 @@
|
||||||
|
#include "hbase.h"
|
||||||
|
|
||||||
|
#ifdef OS_DARWIN
|
||||||
|
#include <mach-o/dyld.h> // for _NSGetExecutablePath
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "hatomic.h"
|
||||||
|
|
||||||
|
#ifndef RAND_MAX
|
||||||
|
#define RAND_MAX 2147483647
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static hatomic_t s_alloc_cnt = HATOMIC_VAR_INIT(0);
|
||||||
|
static hatomic_t s_free_cnt = HATOMIC_VAR_INIT(0);
|
||||||
|
|
||||||
|
long hv_alloc_cnt() {
|
||||||
|
return s_alloc_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
long hv_free_cnt() {
|
||||||
|
return s_free_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* hv_malloc(size_t size) {
|
||||||
|
hatomic_inc(&s_alloc_cnt);
|
||||||
|
void* ptr = malloc(size);
|
||||||
|
if (!ptr) {
|
||||||
|
fprintf(stderr, "malloc failed!\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* hv_realloc(void* oldptr, size_t newsize, size_t oldsize) {
|
||||||
|
hatomic_inc(&s_alloc_cnt);
|
||||||
|
if (oldptr) hatomic_inc(&s_free_cnt);
|
||||||
|
void* ptr = realloc(oldptr, newsize);
|
||||||
|
if (!ptr) {
|
||||||
|
fprintf(stderr, "realloc failed!\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
if (newsize > oldsize) {
|
||||||
|
memset((char*)ptr + oldsize, 0, newsize - oldsize);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* hv_calloc(size_t nmemb, size_t size) {
|
||||||
|
hatomic_inc(&s_alloc_cnt);
|
||||||
|
void* ptr = calloc(nmemb, size);
|
||||||
|
if (!ptr) {
|
||||||
|
fprintf(stderr, "calloc failed!\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* hv_zalloc(size_t size) {
|
||||||
|
hatomic_inc(&s_alloc_cnt);
|
||||||
|
void* ptr = malloc(size);
|
||||||
|
if (!ptr) {
|
||||||
|
fprintf(stderr, "malloc failed!\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
memset(ptr, 0, size);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hv_free(void* ptr) {
|
||||||
|
if (ptr) {
|
||||||
|
free(ptr);
|
||||||
|
ptr = NULL;
|
||||||
|
hatomic_inc(&s_free_cnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* hv_strupper(char* str) {
|
||||||
|
char* p = str;
|
||||||
|
while (*p != '\0') {
|
||||||
|
if (*p >= 'a' && *p <= 'z') {
|
||||||
|
*p &= ~0x20;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* hv_strlower(char* str) {
|
||||||
|
char* p = str;
|
||||||
|
while (*p != '\0') {
|
||||||
|
if (*p >= 'A' && *p <= 'Z') {
|
||||||
|
*p |= 0x20;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* hv_strreverse(char* str) {
|
||||||
|
if (str == NULL) return NULL;
|
||||||
|
char* b = str;
|
||||||
|
char* e = str;
|
||||||
|
while(*e) {++e;}
|
||||||
|
--e;
|
||||||
|
char tmp;
|
||||||
|
while (e > b) {
|
||||||
|
tmp = *e;
|
||||||
|
*e = *b;
|
||||||
|
*b = tmp;
|
||||||
|
--e;
|
||||||
|
++b;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// n = sizeof(dest_buf)
|
||||||
|
char* hv_strncpy(char* dest, const char* src, size_t n) {
|
||||||
|
assert(dest != NULL && src != NULL);
|
||||||
|
char* ret = dest;
|
||||||
|
while (*src != '\0' && --n > 0) {
|
||||||
|
*dest++ = *src++;
|
||||||
|
}
|
||||||
|
*dest = '\0';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// n = sizeof(dest_buf)
|
||||||
|
char* hv_strncat(char* dest, const char* src, size_t n) {
|
||||||
|
assert(dest != NULL && src != NULL);
|
||||||
|
char* ret = dest;
|
||||||
|
while (*dest) {++dest;--n;}
|
||||||
|
while (*src != '\0' && --n > 0) {
|
||||||
|
*dest++ = *src++;
|
||||||
|
}
|
||||||
|
*dest = '\0';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hv_strstartswith(const char* str, const char* start) {
|
||||||
|
assert(str != NULL && start != NULL);
|
||||||
|
while (*str && *start && *str == *start) {
|
||||||
|
++str;
|
||||||
|
++start;
|
||||||
|
}
|
||||||
|
return *start == '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hv_strendswith(const char* str, const char* end) {
|
||||||
|
assert(str != NULL && end != NULL);
|
||||||
|
int len1 = 0;
|
||||||
|
int len2 = 0;
|
||||||
|
while (*str) {++str; ++len1;}
|
||||||
|
while (*end) {++end; ++len2;}
|
||||||
|
if (len1 < len2) return false;
|
||||||
|
while (len2-- > 0) {
|
||||||
|
--str;
|
||||||
|
--end;
|
||||||
|
if (*str != *end) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hv_strcontains(const char* str, const char* sub) {
|
||||||
|
assert(str != NULL && sub != NULL);
|
||||||
|
return strstr(str, sub) != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hv_wildcard_match(const char* str, const char* pattern) {
|
||||||
|
assert(str != NULL && pattern != NULL);
|
||||||
|
bool match = false;
|
||||||
|
while (*str && *pattern) {
|
||||||
|
if (*pattern == '*') {
|
||||||
|
match = hv_strendswith(str, pattern + 1);
|
||||||
|
break;
|
||||||
|
} else if (*str != *pattern) {
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
++str;
|
||||||
|
++pattern;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match ? match : (*str == '\0' && *pattern == '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
char* hv_strnchr(const char* s, char c, size_t n) {
|
||||||
|
assert(s != NULL);
|
||||||
|
const char* p = s;
|
||||||
|
while (*p != '\0' && n-- > 0) {
|
||||||
|
if (*p == c) return (char*)p;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* hv_strrchr_dir(const char* filepath) {
|
||||||
|
char* p = (char*)filepath;
|
||||||
|
while (*p) ++p;
|
||||||
|
while (--p >= filepath) {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
if (*p == '/' || *p == '\\')
|
||||||
|
#else
|
||||||
|
if (*p == '/')
|
||||||
|
#endif
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* hv_basename(const char* filepath) {
|
||||||
|
const char* pos = hv_strrchr_dir(filepath);
|
||||||
|
return pos ? pos+1 : filepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* hv_suffixname(const char* filename) {
|
||||||
|
const char* pos = hv_strrchr_dot(filename);
|
||||||
|
return pos ? pos+1 : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
int hv_mkdir_p(const char* dir) {
|
||||||
|
if (access(dir, 0) == 0) {
|
||||||
|
return EEXIST;
|
||||||
|
}
|
||||||
|
char tmp[MAX_PATH] = {0};
|
||||||
|
hv_strncpy(tmp, dir, sizeof(tmp));
|
||||||
|
char* p = tmp;
|
||||||
|
char delim = '/';
|
||||||
|
while (*p) {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
if (*p == '/' || *p == '\\') {
|
||||||
|
delim = *p;
|
||||||
|
#else
|
||||||
|
if (*p == '/') {
|
||||||
|
#endif
|
||||||
|
*p = '\0';
|
||||||
|
hv_mkdir(tmp);
|
||||||
|
*p = delim;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
if (hv_mkdir(tmp) != 0) {
|
||||||
|
return EPERM;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hv_rmdir_p(const char* dir) {
|
||||||
|
if (access(dir, 0) != 0) {
|
||||||
|
return ENOENT;
|
||||||
|
}
|
||||||
|
if (rmdir(dir) != 0) {
|
||||||
|
return EPERM;
|
||||||
|
}
|
||||||
|
char tmp[MAX_PATH] = {0};
|
||||||
|
hv_strncpy(tmp, dir, sizeof(tmp));
|
||||||
|
char* p = tmp;
|
||||||
|
while (*p) ++p;
|
||||||
|
while (--p >= tmp) {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
if (*p == '/' || *p == '\\') {
|
||||||
|
#else
|
||||||
|
if (*p == '/') {
|
||||||
|
#endif
|
||||||
|
*p = '\0';
|
||||||
|
if (rmdir(tmp) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hv_exists(const char* path) {
|
||||||
|
return access(path, 0) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hv_isdir(const char* path) {
|
||||||
|
if (access(path, 0) != 0) return false;
|
||||||
|
struct stat st;
|
||||||
|
memset(&st, 0, sizeof(st));
|
||||||
|
stat(path, &st);
|
||||||
|
return S_ISDIR(st.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hv_isfile(const char* path) {
|
||||||
|
if (access(path, 0) != 0) return false;
|
||||||
|
struct stat st;
|
||||||
|
memset(&st, 0, sizeof(st));
|
||||||
|
stat(path, &st);
|
||||||
|
return S_ISREG(st.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hv_islink(const char* path) {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
return hv_isdir(path) && (GetFileAttributes(path) & FILE_ATTRIBUTE_REPARSE_POINT);
|
||||||
|
#else
|
||||||
|
if (access(path, 0) != 0) return false;
|
||||||
|
struct stat st;
|
||||||
|
memset(&st, 0, sizeof(st));
|
||||||
|
lstat(path, &st);
|
||||||
|
return S_ISLNK(st.st_mode);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hv_filesize(const char* filepath) {
|
||||||
|
struct stat st;
|
||||||
|
memset(&st, 0, sizeof(st));
|
||||||
|
stat(filepath, &st);
|
||||||
|
return st.st_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* get_executable_path(char* buf, int size) {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
GetModuleFileName(NULL, buf, size);
|
||||||
|
#elif defined(OS_LINUX)
|
||||||
|
if (readlink("/proc/self/exe", buf, size) == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#elif defined(OS_DARWIN)
|
||||||
|
_NSGetExecutablePath(buf, (uint32_t*)&size);
|
||||||
|
#endif
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* get_executable_dir(char* buf, int size) {
|
||||||
|
char filepath[MAX_PATH] = {0};
|
||||||
|
get_executable_path(filepath, sizeof(filepath));
|
||||||
|
char* pos = hv_strrchr_dir(filepath);
|
||||||
|
if (pos) {
|
||||||
|
*pos = '\0';
|
||||||
|
strncpy(buf, filepath, size);
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* get_executable_file(char* buf, int size) {
|
||||||
|
char filepath[MAX_PATH] = {0};
|
||||||
|
get_executable_path(filepath, sizeof(filepath));
|
||||||
|
char* pos = hv_strrchr_dir(filepath);
|
||||||
|
if (pos) {
|
||||||
|
strncpy(buf, pos+1, size);
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* get_run_dir(char* buf, int size) {
|
||||||
|
return getcwd(buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int hv_rand(int min, int max) {
|
||||||
|
static int s_seed = 0;
|
||||||
|
assert(max > min);
|
||||||
|
|
||||||
|
if (s_seed == 0) {
|
||||||
|
s_seed = time(NULL);
|
||||||
|
srand(s_seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _rand = rand();
|
||||||
|
_rand = min + (int) ((double) ((double) (max) - (min) + 1.0) * ((_rand) / ((RAND_MAX) + 1.0)));
|
||||||
|
return _rand;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* hv_random_string(char *buf, int len) {
|
||||||
|
static char s_characters[] = {
|
||||||
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
|
||||||
|
'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
|
||||||
|
'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||||
|
};
|
||||||
|
int i = 0;
|
||||||
|
for (; i < len; i++) {
|
||||||
|
buf[i] = s_characters[hv_rand(0, sizeof(s_characters) - 1)];
|
||||||
|
}
|
||||||
|
buf[i] = '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hv_getboolean(const char* str) {
|
||||||
|
if (str == NULL) return false;
|
||||||
|
int len = strlen(str);
|
||||||
|
if (len == 0) return false;
|
||||||
|
switch (len) {
|
||||||
|
case 1: return *str == '1' || *str == 'y' || *str == 'Y';
|
||||||
|
case 2: return stricmp(str, "on") == 0;
|
||||||
|
case 3: return stricmp(str, "yes") == 0;
|
||||||
|
case 4: return stricmp(str, "true") == 0;
|
||||||
|
case 6: return stricmp(str, "enable") == 0;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hv_parse_size(const char* str) {
|
||||||
|
size_t size = 0, n = 0;
|
||||||
|
const char* p = str;
|
||||||
|
char c;
|
||||||
|
while ((c = *p) != '\0') {
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
n = n * 10 + c - '0';
|
||||||
|
} else {
|
||||||
|
switch (c) {
|
||||||
|
case 'K': case 'k': n <<= 10; break;
|
||||||
|
case 'M': case 'm': n <<= 20; break;
|
||||||
|
case 'G': case 'g': n <<= 30; break;
|
||||||
|
case 'T': case 't': n <<= 40; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
size += n;
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
return size + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t hv_parse_time(const char* str) {
|
||||||
|
time_t time = 0, n = 0;
|
||||||
|
const char* p = str;
|
||||||
|
char c;
|
||||||
|
while ((c = *p) != '\0') {
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
n = n * 10 + c - '0';
|
||||||
|
} else {
|
||||||
|
switch (c) {
|
||||||
|
case 's': break;
|
||||||
|
case 'm': n *= 60; break;
|
||||||
|
case 'h': n *= 60 * 60; break;
|
||||||
|
case 'd': n *= 24 * 60 * 60; break;
|
||||||
|
case 'w': n *= 7 * 24 * 60 * 60; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
time += n;
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
return time + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hv_parse_url(hurl_t* stURL, const char* strURL) {
|
||||||
|
if (stURL == NULL || strURL == NULL) return -1;
|
||||||
|
memset(stURL, 0, sizeof(hurl_t));
|
||||||
|
const char* begin = strURL;
|
||||||
|
const char* end = strURL;
|
||||||
|
while (*end != '\0') ++end;
|
||||||
|
if (end - begin > 65535) return -2;
|
||||||
|
// scheme://
|
||||||
|
const char* sp = strURL;
|
||||||
|
const char* ep = strstr(sp, "://");
|
||||||
|
if (ep) {
|
||||||
|
// stURL->fields[HV_URL_SCHEME].off = sp - begin;
|
||||||
|
stURL->fields[HV_URL_SCHEME].len = ep - sp;
|
||||||
|
sp = ep + 3;
|
||||||
|
}
|
||||||
|
// user:pswd@host:port
|
||||||
|
ep = strchr(sp, '/');
|
||||||
|
if (ep == NULL) ep = end;
|
||||||
|
const char* user = sp;
|
||||||
|
const char* host = sp;
|
||||||
|
const char* pos = hv_strnchr(sp, '@', ep - sp);
|
||||||
|
if (pos) {
|
||||||
|
// user:pswd
|
||||||
|
const char* pswd = hv_strnchr(user, ':', pos - user);
|
||||||
|
if (pswd) {
|
||||||
|
stURL->fields[HV_URL_PASSWORD].off = pswd + 1 - begin;
|
||||||
|
stURL->fields[HV_URL_PASSWORD].len = pos - pswd - 1;
|
||||||
|
} else {
|
||||||
|
pswd = pos;
|
||||||
|
}
|
||||||
|
stURL->fields[HV_URL_USERNAME].off = user - begin;
|
||||||
|
stURL->fields[HV_URL_USERNAME].len = pswd - user;
|
||||||
|
// @
|
||||||
|
host = pos + 1;
|
||||||
|
}
|
||||||
|
// port
|
||||||
|
const char* port = hv_strnchr(host, ':', ep - host);
|
||||||
|
if (port) {
|
||||||
|
stURL->fields[HV_URL_PORT].off = port + 1 - begin;
|
||||||
|
stURL->fields[HV_URL_PORT].len = ep - port - 1;
|
||||||
|
// atoi
|
||||||
|
for (unsigned short i = 1; i <= stURL->fields[HV_URL_PORT].len; ++i) {
|
||||||
|
stURL->port = stURL->port * 10 + (port[i] - '0');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
port = ep;
|
||||||
|
// set default port
|
||||||
|
stURL->port = 80;
|
||||||
|
if (stURL->fields[HV_URL_SCHEME].len > 0) {
|
||||||
|
if (strncmp(strURL, "https://", 8) == 0) {
|
||||||
|
stURL->port = 443;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// host
|
||||||
|
stURL->fields[HV_URL_HOST].off = host - begin;
|
||||||
|
stURL->fields[HV_URL_HOST].len = port - host;
|
||||||
|
if (ep == end) return 0;
|
||||||
|
// /path
|
||||||
|
sp = ep;
|
||||||
|
ep = strchr(sp, '?');
|
||||||
|
if (ep == NULL) ep = end;
|
||||||
|
stURL->fields[HV_URL_PATH].off = sp - begin;
|
||||||
|
stURL->fields[HV_URL_PATH].len = ep - sp;
|
||||||
|
if (ep == end) return 0;
|
||||||
|
// ?query
|
||||||
|
sp = ep + 1;
|
||||||
|
ep = strchr(sp, '#');
|
||||||
|
if (ep == NULL) ep = end;
|
||||||
|
stURL->fields[HV_URL_QUERY].off = sp - begin;
|
||||||
|
stURL->fields[HV_URL_QUERY].len = ep - sp;
|
||||||
|
if (ep == end) return 0;
|
||||||
|
// #fragment
|
||||||
|
sp = ep + 1;
|
||||||
|
ep = end;
|
||||||
|
stURL->fields[HV_URL_FRAGMENT].off = sp - begin;
|
||||||
|
stURL->fields[HV_URL_FRAGMENT].len = ep - sp;
|
||||||
|
return 0;
|
||||||
|
}
|
144
external/libhv/libhv-1.3.2/base/hbase.h
vendored
Normal file
144
external/libhv/libhv-1.3.2/base/hbase.h
vendored
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
#ifndef HV_BASE_H_
|
||||||
|
#define HV_BASE_H_
|
||||||
|
|
||||||
|
#include "hexport.h"
|
||||||
|
#include "hplatform.h" // for bool
|
||||||
|
#include "hdef.h" // for printd
|
||||||
|
|
||||||
|
BEGIN_EXTERN_C
|
||||||
|
|
||||||
|
//--------------------alloc/free---------------------------
|
||||||
|
HV_EXPORT void* hv_malloc(size_t size);
|
||||||
|
HV_EXPORT void* hv_realloc(void* oldptr, size_t newsize, size_t oldsize);
|
||||||
|
HV_EXPORT void* hv_calloc(size_t nmemb, size_t size);
|
||||||
|
HV_EXPORT void* hv_zalloc(size_t size);
|
||||||
|
HV_EXPORT void hv_free(void* ptr);
|
||||||
|
|
||||||
|
#define HV_ALLOC(ptr, size)\
|
||||||
|
do {\
|
||||||
|
*(void**)&(ptr) = hv_zalloc(size);\
|
||||||
|
printd("alloc(%p, size=%llu)\tat [%s:%d:%s]\n", ptr, (unsigned long long)size, __FILE__, __LINE__, __FUNCTION__);\
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define HV_ALLOC_SIZEOF(ptr) HV_ALLOC(ptr, sizeof(*(ptr)))
|
||||||
|
|
||||||
|
#define HV_FREE(ptr)\
|
||||||
|
do {\
|
||||||
|
if (ptr) {\
|
||||||
|
hv_free(ptr);\
|
||||||
|
printd("free( %p )\tat [%s:%d:%s]\n", ptr, __FILE__, __LINE__, __FUNCTION__);\
|
||||||
|
ptr = NULL;\
|
||||||
|
}\
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define STACK_OR_HEAP_ALLOC(ptr, size, stack_size)\
|
||||||
|
unsigned char _stackbuf_[stack_size] = { 0 };\
|
||||||
|
if ((size) > (stack_size)) {\
|
||||||
|
HV_ALLOC(ptr, size);\
|
||||||
|
} else {\
|
||||||
|
*(unsigned char**)&(ptr) = _stackbuf_;\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define STACK_OR_HEAP_FREE(ptr)\
|
||||||
|
if ((unsigned char*)(ptr) != _stackbuf_) {\
|
||||||
|
HV_FREE(ptr);\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HV_DEFAULT_STACKBUF_SIZE 1024
|
||||||
|
#define HV_STACK_ALLOC(ptr, size) STACK_OR_HEAP_ALLOC(ptr, size, HV_DEFAULT_STACKBUF_SIZE)
|
||||||
|
#define HV_STACK_FREE(ptr) STACK_OR_HEAP_FREE(ptr)
|
||||||
|
|
||||||
|
HV_EXPORT long hv_alloc_cnt();
|
||||||
|
HV_EXPORT long hv_free_cnt();
|
||||||
|
HV_INLINE void hv_memcheck(void) {
|
||||||
|
printf("Memcheck => alloc:%ld free:%ld\n", hv_alloc_cnt(), hv_free_cnt());
|
||||||
|
}
|
||||||
|
#define HV_MEMCHECK atexit(hv_memcheck);
|
||||||
|
|
||||||
|
//--------------------string-------------------------------
|
||||||
|
HV_EXPORT char* hv_strupper(char* str);
|
||||||
|
HV_EXPORT char* hv_strlower(char* str);
|
||||||
|
HV_EXPORT char* hv_strreverse(char* str);
|
||||||
|
|
||||||
|
HV_EXPORT bool hv_strstartswith(const char* str, const char* start);
|
||||||
|
HV_EXPORT bool hv_strendswith(const char* str, const char* end);
|
||||||
|
HV_EXPORT bool hv_strcontains(const char* str, const char* sub);
|
||||||
|
HV_EXPORT bool hv_wildcard_match(const char* str, const char* pattern);
|
||||||
|
|
||||||
|
// strncpy n = sizeof(dest_buf)-1
|
||||||
|
// hv_strncpy n = sizeof(dest_buf)
|
||||||
|
HV_EXPORT char* hv_strncpy(char* dest, const char* src, size_t n);
|
||||||
|
|
||||||
|
// strncat n = sizeof(dest_buf)-1-strlen(dest)
|
||||||
|
// hv_strncpy n = sizeof(dest_buf)
|
||||||
|
HV_EXPORT char* hv_strncat(char* dest, const char* src, size_t n);
|
||||||
|
|
||||||
|
#if !HAVE_STRLCPY
|
||||||
|
#define strlcpy hv_strncpy
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !HAVE_STRLCAT
|
||||||
|
#define strlcat hv_strncat
|
||||||
|
#endif
|
||||||
|
|
||||||
|
HV_EXPORT char* hv_strnchr(const char* s, char c, size_t n);
|
||||||
|
|
||||||
|
#define hv_strrchr_dot(str) strrchr(str, '.')
|
||||||
|
HV_EXPORT char* hv_strrchr_dir(const char* filepath);
|
||||||
|
|
||||||
|
// basename
|
||||||
|
HV_EXPORT const char* hv_basename(const char* filepath);
|
||||||
|
HV_EXPORT const char* hv_suffixname(const char* filename);
|
||||||
|
// mkdir -p
|
||||||
|
HV_EXPORT int hv_mkdir_p(const char* dir);
|
||||||
|
// rmdir -p
|
||||||
|
HV_EXPORT int hv_rmdir_p(const char* dir);
|
||||||
|
// path
|
||||||
|
HV_EXPORT bool hv_exists(const char* path);
|
||||||
|
HV_EXPORT bool hv_isdir(const char* path);
|
||||||
|
HV_EXPORT bool hv_isfile(const char* path);
|
||||||
|
HV_EXPORT bool hv_islink(const char* path);
|
||||||
|
HV_EXPORT size_t hv_filesize(const char* filepath);
|
||||||
|
|
||||||
|
HV_EXPORT char* get_executable_path(char* buf, int size);
|
||||||
|
HV_EXPORT char* get_executable_dir(char* buf, int size);
|
||||||
|
HV_EXPORT char* get_executable_file(char* buf, int size);
|
||||||
|
HV_EXPORT char* get_run_dir(char* buf, int size);
|
||||||
|
|
||||||
|
// random
|
||||||
|
HV_EXPORT int hv_rand(int min, int max);
|
||||||
|
HV_EXPORT char* hv_random_string(char *buf, int len);
|
||||||
|
|
||||||
|
// 1 y on yes true enable => true
|
||||||
|
HV_EXPORT bool hv_getboolean(const char* str);
|
||||||
|
// 1T2G3M4K5B => ?B
|
||||||
|
HV_EXPORT size_t hv_parse_size(const char* str);
|
||||||
|
// 1w2d3h4m5s => ?s
|
||||||
|
HV_EXPORT time_t hv_parse_time(const char* str);
|
||||||
|
|
||||||
|
// scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]
|
||||||
|
typedef enum {
|
||||||
|
HV_URL_SCHEME,
|
||||||
|
HV_URL_USERNAME,
|
||||||
|
HV_URL_PASSWORD,
|
||||||
|
HV_URL_HOST,
|
||||||
|
HV_URL_PORT,
|
||||||
|
HV_URL_PATH,
|
||||||
|
HV_URL_QUERY,
|
||||||
|
HV_URL_FRAGMENT,
|
||||||
|
HV_URL_FIELD_NUM,
|
||||||
|
} hurl_field_e;
|
||||||
|
|
||||||
|
typedef struct hurl_s {
|
||||||
|
struct {
|
||||||
|
unsigned short off;
|
||||||
|
unsigned short len;
|
||||||
|
} fields[HV_URL_FIELD_NUM];
|
||||||
|
unsigned short port;
|
||||||
|
} hurl_t;
|
||||||
|
|
||||||
|
HV_EXPORT int hv_parse_url(hurl_t* stURL, const char* strURL);
|
||||||
|
|
||||||
|
END_EXTERN_C
|
||||||
|
|
||||||
|
#endif // HV_BASE_H_
|
257
external/libhv/libhv-1.3.2/base/hbuf.h
vendored
Normal file
257
external/libhv/libhv-1.3.2/base/hbuf.h
vendored
Normal file
|
@ -0,0 +1,257 @@
|
||||||
|
#ifndef HV_BUF_H_
|
||||||
|
#define HV_BUF_H_
|
||||||
|
|
||||||
|
#include "hdef.h" // for MAX
|
||||||
|
#include "hbase.h" // for HV_ALLOC, HV_FREE
|
||||||
|
|
||||||
|
typedef struct hbuf_s {
|
||||||
|
char* base;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
hbuf_s() {
|
||||||
|
base = NULL;
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hbuf_s(void* data, size_t len) {
|
||||||
|
this->base = (char*)data;
|
||||||
|
this->len = len;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} hbuf_t;
|
||||||
|
|
||||||
|
typedef struct offset_buf_s {
|
||||||
|
char* base;
|
||||||
|
size_t len;
|
||||||
|
size_t offset;
|
||||||
|
#ifdef __cplusplus
|
||||||
|
offset_buf_s() {
|
||||||
|
base = NULL;
|
||||||
|
len = 0;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset_buf_s(void* data, size_t len) {
|
||||||
|
this->base = (char*)data;
|
||||||
|
this->len = len;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} offset_buf_t;
|
||||||
|
|
||||||
|
typedef struct fifo_buf_s {
|
||||||
|
char* base;
|
||||||
|
size_t len;
|
||||||
|
size_t head;
|
||||||
|
size_t tail;
|
||||||
|
#ifdef __cplusplus
|
||||||
|
fifo_buf_s() {
|
||||||
|
base = NULL;
|
||||||
|
len = 0;
|
||||||
|
head = tail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fifo_buf_s(void* data, size_t len) {
|
||||||
|
this->base = (char*)data;
|
||||||
|
this->len = len;
|
||||||
|
head = tail = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} fifo_buf_t;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
class HBuf : public hbuf_t {
|
||||||
|
public:
|
||||||
|
HBuf() : hbuf_t() {
|
||||||
|
cleanup_ = false;
|
||||||
|
}
|
||||||
|
HBuf(void* data, size_t len) : hbuf_t(data, len) {
|
||||||
|
cleanup_ = false;
|
||||||
|
}
|
||||||
|
HBuf(size_t cap) { resize(cap); }
|
||||||
|
|
||||||
|
virtual ~HBuf() {
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* data() { return base; }
|
||||||
|
size_t size() { return len; }
|
||||||
|
|
||||||
|
bool isNull() { return base == NULL || len == 0; }
|
||||||
|
|
||||||
|
void cleanup() {
|
||||||
|
if (cleanup_) {
|
||||||
|
HV_FREE(base);
|
||||||
|
len = 0;
|
||||||
|
cleanup_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize(size_t cap) {
|
||||||
|
if (cap == len) return;
|
||||||
|
|
||||||
|
if (base == NULL) {
|
||||||
|
HV_ALLOC(base, cap);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
base = (char*)hv_realloc(base, cap, len);
|
||||||
|
}
|
||||||
|
len = cap;
|
||||||
|
cleanup_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void copy(void* data, size_t len) {
|
||||||
|
resize(len);
|
||||||
|
memcpy(base, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void copy(hbuf_t* buf) {
|
||||||
|
copy(buf->base, buf->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool cleanup_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// VL: Variable-Length
|
||||||
|
class HVLBuf : public HBuf {
|
||||||
|
public:
|
||||||
|
HVLBuf() : HBuf() {_offset = _size = 0;}
|
||||||
|
HVLBuf(void* data, size_t len) : HBuf(data, len) {_offset = 0; _size = len;}
|
||||||
|
HVLBuf(size_t cap) : HBuf(cap) {_offset = _size = 0;}
|
||||||
|
virtual ~HVLBuf() {}
|
||||||
|
|
||||||
|
char* data() { return base + _offset; }
|
||||||
|
size_t size() { return _size; }
|
||||||
|
|
||||||
|
void push_front(void* ptr, size_t len) {
|
||||||
|
if (len > this->len - _size) {
|
||||||
|
size_t newsize = MAX(this->len, len)*2;
|
||||||
|
resize(newsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_offset < len) {
|
||||||
|
// move => end
|
||||||
|
memmove(base+this->len-_size, data(), _size);
|
||||||
|
_offset = this->len-_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(data()-len, ptr, len);
|
||||||
|
_offset -= len;
|
||||||
|
_size += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_back(void* ptr, size_t len) {
|
||||||
|
if (len > this->len - _size) {
|
||||||
|
size_t newsize = MAX(this->len, len)*2;
|
||||||
|
resize(newsize);
|
||||||
|
}
|
||||||
|
else if (len > this->len - _offset - _size) {
|
||||||
|
// move => start
|
||||||
|
memmove(base, data(), _size);
|
||||||
|
_offset = 0;
|
||||||
|
}
|
||||||
|
memcpy(data()+_size, ptr, len);
|
||||||
|
_size += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_front(void* ptr, size_t len) {
|
||||||
|
if (len <= _size) {
|
||||||
|
if (ptr) {
|
||||||
|
memcpy(ptr, data(), len);
|
||||||
|
}
|
||||||
|
_offset += len;
|
||||||
|
if (_offset >= this->len) _offset = 0;
|
||||||
|
_size -= len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_back(void* ptr, size_t len) {
|
||||||
|
if (len <= _size) {
|
||||||
|
if (ptr) {
|
||||||
|
memcpy(ptr, data()+_size-len, len);
|
||||||
|
}
|
||||||
|
_size -= len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
_offset = _size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepend(void* ptr, size_t len) {
|
||||||
|
push_front(ptr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(void* ptr, size_t len) {
|
||||||
|
push_back(ptr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(void* ptr, size_t len) {
|
||||||
|
push_back(ptr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(size_t len) {
|
||||||
|
pop_front(NULL, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t _offset;
|
||||||
|
size_t _size;
|
||||||
|
};
|
||||||
|
|
||||||
|
class HRingBuf : public HBuf {
|
||||||
|
public:
|
||||||
|
HRingBuf() : HBuf() {_head = _tail = _size = 0;}
|
||||||
|
HRingBuf(size_t cap) : HBuf(cap) {_head = _tail = _size = 0;}
|
||||||
|
virtual ~HRingBuf() {}
|
||||||
|
|
||||||
|
char* alloc(size_t len) {
|
||||||
|
char* ret = NULL;
|
||||||
|
if (_head < _tail || _size == 0) {
|
||||||
|
// [_tail, this->len) && [0, _head)
|
||||||
|
if (this->len - _tail >= len) {
|
||||||
|
ret = base + _tail;
|
||||||
|
_tail += len;
|
||||||
|
if (_tail == this->len) _tail = 0;
|
||||||
|
}
|
||||||
|
else if (_head >= len) {
|
||||||
|
ret = base;
|
||||||
|
_tail = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// [_tail, _head)
|
||||||
|
if (_head - _tail >= len) {
|
||||||
|
ret = base + _tail;
|
||||||
|
_tail += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_size += ret ? len : 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(size_t len) {
|
||||||
|
_size -= len;
|
||||||
|
if (len <= this->len - _head) {
|
||||||
|
_head += len;
|
||||||
|
if (_head == this->len) _head = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_head = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {_head = _tail = _size = 0;}
|
||||||
|
|
||||||
|
size_t size() {return _size;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t _head;
|
||||||
|
size_t _tail;
|
||||||
|
size_t _size;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // HV_BUF_H_
|
271
external/libhv/libhv-1.3.2/base/hdef.h
vendored
Normal file
271
external/libhv/libhv-1.3.2/base/hdef.h
vendored
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
#ifndef HV_DEF_H_
|
||||||
|
#define HV_DEF_H_
|
||||||
|
|
||||||
|
#include "hplatform.h"
|
||||||
|
|
||||||
|
#ifndef ABS
|
||||||
|
#define ABS(n) ((n) > 0 ? (n) : -(n))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NABS
|
||||||
|
#define NABS(n) ((n) < 0 ? (n) : -(n))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ARRAY_SIZE
|
||||||
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BITSET
|
||||||
|
#define BITSET(p, n) (*(p) |= (1u << (n)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BITCLR
|
||||||
|
#define BITCLR(p, n) (*(p) &= ~(1u << (n)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BITGET
|
||||||
|
#define BITGET(i, n) ((i) & (1u << (n)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifndef CR
|
||||||
|
#define CR '\r'
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LF
|
||||||
|
#define LF '\n'
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CRLF
|
||||||
|
#define CRLF "\r\n"
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define FLOAT_PRECISION 1e-6
|
||||||
|
#define FLOAT_EQUAL_ZERO(f) (ABS(f) < FLOAT_PRECISION)
|
||||||
|
|
||||||
|
#ifndef INFINITE
|
||||||
|
#define INFINITE (uint32_t)-1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
ASCII:
|
||||||
|
[0, 0x20) control-charaters
|
||||||
|
[0x20, 0x7F) printable-charaters
|
||||||
|
|
||||||
|
0x0A => LF
|
||||||
|
0x0D => CR
|
||||||
|
0x20 => SPACE
|
||||||
|
0x7F => DEL
|
||||||
|
|
||||||
|
[0x09, 0x0D] => \t\n\v\f\r
|
||||||
|
[0x30, 0x39] => 0~9
|
||||||
|
[0x41, 0x5A] => A~Z
|
||||||
|
[0x61, 0x7A] => a~z
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IS_ALPHA
|
||||||
|
#define IS_ALPHA(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// NOTE: IS_NUM conflicts with mysql.h
|
||||||
|
#ifndef IS_DIGIT
|
||||||
|
#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef IS_ALPHANUM
|
||||||
|
#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_DIGIT(c))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef IS_CNTRL
|
||||||
|
#define IS_CNTRL(c) ((c) >= 0 && (c) < 0x20)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef IS_GRAPH
|
||||||
|
#define IS_GRAPH(c) ((c) >= 0x20 && (c) < 0x7F)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef IS_HEX
|
||||||
|
#define IS_HEX(c) (IS_DIGIT(c) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef IS_LOWER
|
||||||
|
#define IS_LOWER(c) (((c) >= 'a' && (c) <= 'z'))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef IS_UPPER
|
||||||
|
#define IS_UPPER(c) (((c) >= 'A' && (c) <= 'Z'))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LOWER
|
||||||
|
#define LOWER(c) ((c) | 0x20)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef UPPER
|
||||||
|
#define UPPER(c) ((c) & ~0x20)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// LD, LU, LLD, LLU for explicit conversion of integer
|
||||||
|
// #ifndef LD
|
||||||
|
// #define LD(v) ((long)(v))
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifndef LU
|
||||||
|
// #define LU(v) ((unsigned long)(v))
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
#ifndef LLD
|
||||||
|
#define LLD(v) ((long long)(v))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LLU
|
||||||
|
#define LLU(v) ((unsigned long long)(v))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
|
||||||
|
// MAKEWORD, HIBYTE, LOBYTE
|
||||||
|
#ifndef MAKEWORD
|
||||||
|
#define MAKEWORD(h, l) ( (((WORD)h) << 8) | (l & 0xff) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HIBYTE
|
||||||
|
#define HIBYTE(w) ( (BYTE)(((WORD)w) >> 8) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LOBYTE
|
||||||
|
#define LOBYTE(w) ( (BYTE)(w & 0xff) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// MAKELONG, HIWORD, LOWORD
|
||||||
|
#ifndef MAKELONG
|
||||||
|
#define MAKELONG(h, l) ( ((int32_t)h) << 16 | (l & 0xffff) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HIWORD
|
||||||
|
#define HIWORD(n) ( (WORD)(((int32_t)n) >> 16) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LOWORD
|
||||||
|
#define LOWORD(n) ( (WORD)(n & 0xffff) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
// MAKEINT64, HIINT, LOINT
|
||||||
|
#ifndef MAKEINT64
|
||||||
|
#define MAKEINT64(h, l) ( ((int64_t)h) << 32 | (l & 0xffffffff) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HIINT
|
||||||
|
#define HIINT(n) ( (int32_t)(((int64_t)n) >> 32) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LOINT
|
||||||
|
#define LOINT(n) ( (int32_t)(n & 0xffffffff) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAKE_FOURCC
|
||||||
|
#define MAKE_FOURCC(a, b, c, d) \
|
||||||
|
( ((uint32)d) | ( ((uint32)c) << 8 ) | ( ((uint32)b) << 16 ) | ( ((uint32)a) << 24 ) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LIMIT
|
||||||
|
#define LIMIT(lower, v, upper) ((v) < (lower) ? (lower) : (v) > (upper) ? (upper) : (v))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX_PATH
|
||||||
|
#define MAX_PATH 260
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NULL
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define NULL 0
|
||||||
|
#else
|
||||||
|
#define NULL ((void*)0)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TRUE
|
||||||
|
#define TRUE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FALSE
|
||||||
|
#define FALSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SAFE_ALLOC
|
||||||
|
#define SAFE_ALLOC(p, size)\
|
||||||
|
do {\
|
||||||
|
void* ptr = malloc(size);\
|
||||||
|
if (!ptr) {\
|
||||||
|
fprintf(stderr, "malloc failed!\n");\
|
||||||
|
exit(-1);\
|
||||||
|
}\
|
||||||
|
memset(ptr, 0, size);\
|
||||||
|
*(void**)&(p) = ptr;\
|
||||||
|
} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SAFE_FREE
|
||||||
|
#define SAFE_FREE(p) do {if (p) {free(p); (p) = NULL;}} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SAFE_DELETE
|
||||||
|
#define SAFE_DELETE(p) do {if (p) {delete (p); (p) = NULL;}} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SAFE_DELETE_ARRAY
|
||||||
|
#define SAFE_DELETE_ARRAY(p) do {if (p) {delete[] (p); (p) = NULL;}} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SAFE_RELEASE
|
||||||
|
#define SAFE_RELEASE(p) do {if (p) {(p)->release(); (p) = NULL;}} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SAFE_CLOSE
|
||||||
|
#define SAFE_CLOSE(fd) do {if ((fd) >= 0) {close(fd); (fd) = -1;}} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
||||||
|
#define STRINGIFY_HELPER(x) #x
|
||||||
|
|
||||||
|
#define STRINGCAT(x, y) STRINGCAT_HELPER(x, y)
|
||||||
|
#define STRINGCAT_HELPER(x, y) x##y
|
||||||
|
|
||||||
|
#ifndef offsetof
|
||||||
|
#define offsetof(type, member) \
|
||||||
|
((size_t)(&((type*)0)->member))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef offsetofend
|
||||||
|
#define offsetofend(type, member) \
|
||||||
|
(offsetof(type, member) + sizeof(((type*)0)->member))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef container_of
|
||||||
|
#define container_of(ptr, type, member) \
|
||||||
|
((type*)((char*)(ptr) - offsetof(type, member)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PRINT_DEBUG
|
||||||
|
#define printd(...) printf(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define printd(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PRINT_ERROR
|
||||||
|
#define printe(...) fprintf(stderr, __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define printe(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // HV_DEF_H_
|
172
external/libhv/libhv-1.3.2/base/heap.h
vendored
Normal file
172
external/libhv/libhv-1.3.2/base/heap.h
vendored
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
#ifndef HV_HEAP_H_
|
||||||
|
#define HV_HEAP_H_
|
||||||
|
|
||||||
|
#include <assert.h> // for assert
|
||||||
|
#include <stddef.h> // for NULL
|
||||||
|
|
||||||
|
struct heap_node {
|
||||||
|
struct heap_node* parent;
|
||||||
|
struct heap_node* left;
|
||||||
|
struct heap_node* right;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef int (*heap_compare_fn)(const struct heap_node* lhs, const struct heap_node* rhs);
|
||||||
|
struct heap {
|
||||||
|
struct heap_node* root;
|
||||||
|
int nelts;
|
||||||
|
// if compare is less_than, root is min of heap
|
||||||
|
// if compare is larger_than, root is max of heap
|
||||||
|
heap_compare_fn compare;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void heap_init(struct heap* heap, heap_compare_fn fn) {
|
||||||
|
heap->root = NULL;
|
||||||
|
heap->nelts = 0;
|
||||||
|
heap->compare = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace s with r
|
||||||
|
static inline void heap_replace(struct heap* heap, struct heap_node* s, struct heap_node* r) {
|
||||||
|
// s->parent->child, s->left->parent, s->right->parent
|
||||||
|
if (s->parent == NULL) heap->root = r;
|
||||||
|
else if (s->parent->left == s) s->parent->left = r;
|
||||||
|
else if (s->parent->right == s) s->parent->right = r;
|
||||||
|
|
||||||
|
if (s->left) s->left->parent = r;
|
||||||
|
if (s->right) s->right->parent = r;
|
||||||
|
if (r) {
|
||||||
|
//*r = *s;
|
||||||
|
r->parent = s->parent;
|
||||||
|
r->left = s->left;
|
||||||
|
r->right = s->right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void heap_swap(struct heap* heap, struct heap_node* parent, struct heap_node* child) {
|
||||||
|
assert(child->parent == parent && (parent->left == child || parent->right == child));
|
||||||
|
struct heap_node* pparent = parent->parent;
|
||||||
|
struct heap_node* lchild = child->left;
|
||||||
|
struct heap_node* rchild = child->right;
|
||||||
|
struct heap_node* sibling = NULL;
|
||||||
|
|
||||||
|
if (pparent == NULL) heap->root = child;
|
||||||
|
else if (pparent->left == parent) pparent->left = child;
|
||||||
|
else if (pparent->right == parent) pparent->right = child;
|
||||||
|
|
||||||
|
if (lchild) lchild->parent = parent;
|
||||||
|
if (rchild) rchild->parent = parent;
|
||||||
|
|
||||||
|
child->parent = pparent;
|
||||||
|
if (parent->left == child) {
|
||||||
|
sibling = parent->right;
|
||||||
|
child->left = parent;
|
||||||
|
child->right = sibling;
|
||||||
|
} else {
|
||||||
|
sibling = parent->left;
|
||||||
|
child->left = sibling;
|
||||||
|
child->right = parent;
|
||||||
|
}
|
||||||
|
if (sibling) sibling->parent = child;
|
||||||
|
|
||||||
|
parent->parent = child;
|
||||||
|
parent->left = lchild;
|
||||||
|
parent->right = rchild;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void heap_insert(struct heap* heap, struct heap_node* node) {
|
||||||
|
// get last => insert node => sift up
|
||||||
|
// 0: left, 1: right
|
||||||
|
int path = 0;
|
||||||
|
int n,d;
|
||||||
|
++heap->nelts;
|
||||||
|
// traverse from bottom to up, get path of last node
|
||||||
|
for (d = 0, n = heap->nelts; n >= 2; ++d, n>>=1) {
|
||||||
|
path = (path << 1) | (n & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get last->parent by path
|
||||||
|
struct heap_node* parent = heap->root;
|
||||||
|
while(d > 1) {
|
||||||
|
parent = (path & 1) ? parent->right : parent->left;
|
||||||
|
--d;
|
||||||
|
path >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert node
|
||||||
|
node->parent = parent;
|
||||||
|
if (parent == NULL) heap->root = node;
|
||||||
|
else if (path & 1) parent->right = node;
|
||||||
|
else parent->left = node;
|
||||||
|
|
||||||
|
// sift up
|
||||||
|
if (heap->compare) {
|
||||||
|
while (node->parent && heap->compare(node, node->parent)) {
|
||||||
|
heap_swap(heap, node->parent, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void heap_remove(struct heap* heap, struct heap_node* node) {
|
||||||
|
if (heap->nelts == 0) return;
|
||||||
|
// get last => replace node with last => sift down and sift up
|
||||||
|
// 0: left, 1: right
|
||||||
|
int path = 0;
|
||||||
|
int n,d;
|
||||||
|
// traverse from bottom to up, get path of last node
|
||||||
|
for (d = 0, n = heap->nelts; n >= 2; ++d, n>>=1) {
|
||||||
|
path = (path << 1) | (n & 1);
|
||||||
|
}
|
||||||
|
--heap->nelts;
|
||||||
|
|
||||||
|
// get last->parent by path
|
||||||
|
struct heap_node* parent = heap->root;
|
||||||
|
while(d > 1) {
|
||||||
|
parent = (path & 1) ? parent->right : parent->left;
|
||||||
|
--d;
|
||||||
|
path >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace node with last
|
||||||
|
struct heap_node* last = NULL;
|
||||||
|
if (parent == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (path & 1) {
|
||||||
|
last = parent->right;
|
||||||
|
parent->right = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
last = parent->left;
|
||||||
|
parent->left = NULL;
|
||||||
|
}
|
||||||
|
if (last == NULL) {
|
||||||
|
if (heap->root == node) {
|
||||||
|
heap->root = NULL;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
heap_replace(heap, node, last);
|
||||||
|
node->parent = node->left = node->right = NULL;
|
||||||
|
|
||||||
|
if (!heap->compare) return;
|
||||||
|
struct heap_node* v = last;
|
||||||
|
struct heap_node* est = NULL;
|
||||||
|
// sift down
|
||||||
|
while (1) {
|
||||||
|
est = v;
|
||||||
|
if (v->left) est = heap->compare(est, v->left) ? est : v->left;
|
||||||
|
if (v->right) est = heap->compare(est, v->right) ? est : v->right;
|
||||||
|
if (est == v) break;
|
||||||
|
heap_swap(heap, v, est);
|
||||||
|
}
|
||||||
|
// sift up
|
||||||
|
while (v->parent && heap->compare(v, v->parent)) {
|
||||||
|
heap_swap(heap, v->parent, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void heap_dequeue(struct heap* heap) {
|
||||||
|
heap_remove(heap, heap->root);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // HV_HEAP_H_
|
244
external/libhv/libhv-1.3.2/base/hendian.h
vendored
Normal file
244
external/libhv/libhv-1.3.2/base/hendian.h
vendored
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
#ifndef HV_ENDIAN_H_
|
||||||
|
#define HV_ENDIAN_H_
|
||||||
|
|
||||||
|
#include "hplatform.h"
|
||||||
|
#if defined(OS_MAC)
|
||||||
|
#include <libkern/OSByteOrder.h>
|
||||||
|
#define htobe16(v) OSSwapHostToBigInt16(v)
|
||||||
|
#define htobe32(v) OSSwapHostToBigInt32(v)
|
||||||
|
#define htobe64(v) OSSwapHostToBigInt64(v)
|
||||||
|
#define be16toh(v) OSSwapBigToHostInt16(v)
|
||||||
|
#define be32toh(v) OSSwapBigToHostInt32(v)
|
||||||
|
#define be64toh(v) OSSwapBigToHostInt64(v)
|
||||||
|
|
||||||
|
#define htole16(v) OSSwapHostToLittleInt16(v)
|
||||||
|
#define htole32(v) OSSwapHostToLittleInt32(v)
|
||||||
|
#define htole64(v) OSSwapHostToLittleInt64(v)
|
||||||
|
#define le16toh(v) OSSwapLittleToHostInt16(v)
|
||||||
|
#define le32toh(v) OSSwapLittleToHostInt32(v)
|
||||||
|
#define le64toh(v) OSSwapLittleToHostInt64(v)
|
||||||
|
#elif defined(OS_WIN)
|
||||||
|
|
||||||
|
#if _WIN32_WINNT < _WIN32_WINNT_WIN8
|
||||||
|
/*
|
||||||
|
* Byte order conversion functions for 64-bit integers and 32 + 64 bit
|
||||||
|
* floating-point numbers. IEEE big-endian format is used for the
|
||||||
|
* network floating point format.
|
||||||
|
*/
|
||||||
|
#define _WS2_32_WINSOCK_SWAP_LONG(l) \
|
||||||
|
( ( ((l) >> 24) & 0x000000FFL ) | \
|
||||||
|
( ((l) >> 8) & 0x0000FF00L ) | \
|
||||||
|
( ((l) << 8) & 0x00FF0000L ) | \
|
||||||
|
( ((l) << 24) & 0xFF000000L ) )
|
||||||
|
|
||||||
|
#define _WS2_32_WINSOCK_SWAP_LONGLONG(l) \
|
||||||
|
( ( ((l) >> 56) & 0x00000000000000FFLL ) | \
|
||||||
|
( ((l) >> 40) & 0x000000000000FF00LL ) | \
|
||||||
|
( ((l) >> 24) & 0x0000000000FF0000LL ) | \
|
||||||
|
( ((l) >> 8) & 0x00000000FF000000LL ) | \
|
||||||
|
( ((l) << 8) & 0x000000FF00000000LL ) | \
|
||||||
|
( ((l) << 24) & 0x0000FF0000000000LL ) | \
|
||||||
|
( ((l) << 40) & 0x00FF000000000000LL ) | \
|
||||||
|
( ((l) << 56) & 0xFF00000000000000LL ) )
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef htonll
|
||||||
|
__inline unsigned __int64 htonll ( unsigned __int64 Value )
|
||||||
|
{
|
||||||
|
const unsigned __int64 Retval = _WS2_32_WINSOCK_SWAP_LONGLONG (Value);
|
||||||
|
return Retval;
|
||||||
|
}
|
||||||
|
#endif /* htonll */
|
||||||
|
|
||||||
|
#ifndef ntohll
|
||||||
|
__inline unsigned __int64 ntohll ( unsigned __int64 Value )
|
||||||
|
{
|
||||||
|
const unsigned __int64 Retval = _WS2_32_WINSOCK_SWAP_LONGLONG (Value);
|
||||||
|
return Retval;
|
||||||
|
}
|
||||||
|
#endif /* ntohll */
|
||||||
|
|
||||||
|
#ifndef htonf
|
||||||
|
__inline unsigned __int32 htonf ( float Value )
|
||||||
|
{
|
||||||
|
unsigned __int32 Tempval;
|
||||||
|
unsigned __int32 Retval;
|
||||||
|
Tempval = *(unsigned __int32*)(&Value);
|
||||||
|
Retval = _WS2_32_WINSOCK_SWAP_LONG (Tempval);
|
||||||
|
return Retval;
|
||||||
|
}
|
||||||
|
#endif /* htonf */
|
||||||
|
|
||||||
|
#ifndef ntohf
|
||||||
|
__inline float ntohf ( unsigned __int32 Value )
|
||||||
|
{
|
||||||
|
const unsigned __int32 Tempval = _WS2_32_WINSOCK_SWAP_LONG (Value);
|
||||||
|
float Retval;
|
||||||
|
*((unsigned __int32*)&Retval) = Tempval;
|
||||||
|
return Retval;
|
||||||
|
}
|
||||||
|
#endif /* ntohf */
|
||||||
|
|
||||||
|
#ifndef htond
|
||||||
|
__inline unsigned __int64 htond ( double Value )
|
||||||
|
{
|
||||||
|
unsigned __int64 Tempval;
|
||||||
|
unsigned __int64 Retval;
|
||||||
|
Tempval = *(unsigned __int64*)(&Value);
|
||||||
|
Retval = _WS2_32_WINSOCK_SWAP_LONGLONG (Tempval);
|
||||||
|
return Retval;
|
||||||
|
}
|
||||||
|
#endif /* htond */
|
||||||
|
|
||||||
|
#ifndef ntohd
|
||||||
|
__inline double ntohd ( unsigned __int64 Value )
|
||||||
|
{
|
||||||
|
const unsigned __int64 Tempval = _WS2_32_WINSOCK_SWAP_LONGLONG (Value);
|
||||||
|
double Retval;
|
||||||
|
*((unsigned __int64*)&Retval) = Tempval;
|
||||||
|
return Retval;
|
||||||
|
}
|
||||||
|
#endif /* ntohd */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define htobe16(v) htons(v)
|
||||||
|
#define htobe32(v) htonl(v)
|
||||||
|
#define htobe64(v) htonll(v)
|
||||||
|
#define be16toh(v) ntohs(v)
|
||||||
|
#define be32toh(v) ntohl(v)
|
||||||
|
#define be64toh(v) ntohll(v)
|
||||||
|
|
||||||
|
#if (BYTE_ORDER == LITTLE_ENDIAN)
|
||||||
|
#define htole16(v) (v)
|
||||||
|
#define htole32(v) (v)
|
||||||
|
#define htole64(v) (v)
|
||||||
|
#define le16toh(v) (v)
|
||||||
|
#define le32toh(v) (v)
|
||||||
|
#define le64toh(v) (v)
|
||||||
|
#elif (BYTE_ORDER == BIG_ENDIAN)
|
||||||
|
#define htole16(v) __builtin_bswap16(v)
|
||||||
|
#define htole32(v) __builtin_bswap32(v)
|
||||||
|
#define htole64(v) __builtin_bswap64(v)
|
||||||
|
#define le16toh(v) __builtin_bswap16(v)
|
||||||
|
#define le32toh(v) __builtin_bswap32(v)
|
||||||
|
#define le64toh(v) __builtin_bswap64(v)
|
||||||
|
#endif
|
||||||
|
#elif HAVE_ENDIAN_H
|
||||||
|
#include <endian.h>
|
||||||
|
#elif HAVE_SYS_ENDIAN_H
|
||||||
|
#include <sys/endian.h>
|
||||||
|
#else
|
||||||
|
#warning "Not found endian.h!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PI8(p) *(int8_t*)(p)
|
||||||
|
#define PI16(p) *(int16_t*)(p)
|
||||||
|
#define PI32(p) *(int32_t*)(p)
|
||||||
|
#define PI64(p) *(int64_t*)(p)
|
||||||
|
|
||||||
|
#define PU8(p) *(uint8_t*)(p)
|
||||||
|
#define PU16(p) *(uint16_t*)(p)
|
||||||
|
#define PU32(p) *(uint32_t*)(p)
|
||||||
|
#define PU64(p) *(uint64_t*)(p)
|
||||||
|
|
||||||
|
#define PF32(p) *(float*)(p)
|
||||||
|
#define PF64(p) *(double*)(p)
|
||||||
|
|
||||||
|
#define GET_BE16(p) be16toh(PU16(p))
|
||||||
|
#define GET_BE32(p) be32toh(PU32(p))
|
||||||
|
#define GET_BE64(p) be64toh(PU64(p))
|
||||||
|
|
||||||
|
#define GET_LE16(p) le16toh(PU16(p))
|
||||||
|
#define GET_LE32(p) le32toh(PU32(p))
|
||||||
|
#define GET_LE64(p) le64toh(PU64(p))
|
||||||
|
|
||||||
|
#define PUT_BE16(p, v) PU16(p) = htobe16(v)
|
||||||
|
#define PUT_BE32(p, v) PU32(p) = htobe32(v)
|
||||||
|
#define PUT_BE64(p, v) PU64(p) = htobe64(v)
|
||||||
|
|
||||||
|
#define PUT_LE16(p, v) PU16(p) = htole16(v)
|
||||||
|
#define PUT_LE32(p, v) PU32(p) = htole32(v)
|
||||||
|
#define PUT_LE64(p, v) PU64(p) = htole64(v)
|
||||||
|
|
||||||
|
// NOTE: uint8_t* p = (uint8_t*)buf;
|
||||||
|
#define POP_BE8(p, v) v = *p; ++p
|
||||||
|
#define POP_BE16(p, v) v = be16toh(PU16(p)); p += 2
|
||||||
|
#define POP_BE32(p, v) v = be32toh(PU32(p)); p += 4
|
||||||
|
#define POP_BE64(p, v) v = be64toh(PU64(p)); p += 8
|
||||||
|
|
||||||
|
#define POP_LE8(p, v) v= *p; ++p
|
||||||
|
#define POP_LE16(p, v) v = le16toh(PU16(p)); p += 2
|
||||||
|
#define POP_LE32(p, v) v = le32toh(PU32(p)); p += 4
|
||||||
|
#define POP_LE64(p, v) v = le64toh(PU64(p)); p += 8
|
||||||
|
|
||||||
|
#define PUSH_BE8(p, v) *p = v; ++p
|
||||||
|
#define PUSH_BE16(p, v) PU16(p) = htobe16(v); p += 2
|
||||||
|
#define PUSH_BE32(p, v) PU32(p) = htobe32(v); p += 4
|
||||||
|
#define PUSH_BE64(p, v) PU64(p) = htobe64(v); p += 8
|
||||||
|
|
||||||
|
#define PUSH_LE8(p, v) *p = v; ++p
|
||||||
|
#define PUSH_LE16(p, v) PU16(p) = htole16(v); p += 2
|
||||||
|
#define PUSH_LE32(p, v) PU32(p) = htole32(v); p += 4
|
||||||
|
#define PUSH_LE64(p, v) PU64(p) = htole64(v); p += 8
|
||||||
|
|
||||||
|
// NOTE: NET_ENDIAN = BIG_ENDIAN
|
||||||
|
#define POP8(p, v) POP_BE8(p, v)
|
||||||
|
#define POP16(p, v) POP_BE16(p, v)
|
||||||
|
#define POP32(p, v) POP_BE32(p, v)
|
||||||
|
#define POP64(p, v) POP_BE64(p, v)
|
||||||
|
#define POP_N(p, v, n) memcpy(v, p, n); p += n
|
||||||
|
|
||||||
|
#define PUSH8(p, v) PUSH_BE8(p, v)
|
||||||
|
#define PUSH16(p, v) PUSH_BE16(p, v)
|
||||||
|
#define PUSH32(p, v) PUSH_BE32(p, v)
|
||||||
|
#define PUSH64(p, v) PUSH_BE64(p, v)
|
||||||
|
#define PUSH_N(p, v, n) memcpy(p, v, n); p += n
|
||||||
|
|
||||||
|
static inline int detect_endian() {
|
||||||
|
union {
|
||||||
|
char c;
|
||||||
|
short s;
|
||||||
|
} u;
|
||||||
|
u.s = 0x1122;
|
||||||
|
return u.c ==0x11 ? BIG_ENDIAN : LITTLE_ENDIAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
template <typename T>
|
||||||
|
uint8_t* serialize(uint8_t* buf, T value, int host_endian = LITTLE_ENDIAN, int buf_endian = BIG_ENDIAN) {
|
||||||
|
size_t size = sizeof(T);
|
||||||
|
uint8_t* pDst = buf;
|
||||||
|
uint8_t* pSrc = (uint8_t*)&value;
|
||||||
|
|
||||||
|
if (host_endian == buf_endian) {
|
||||||
|
memcpy(pDst, pSrc, size);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
pDst[i] = pSrc[size-i-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf+size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
uint8_t* deserialize(uint8_t* buf, T* value, int host_endian = LITTLE_ENDIAN, int buf_endian = BIG_ENDIAN) {
|
||||||
|
size_t size = sizeof(T);
|
||||||
|
uint8_t* pSrc = buf;
|
||||||
|
uint8_t* pDst = (uint8_t*)value;
|
||||||
|
|
||||||
|
if (host_endian == buf_endian) {
|
||||||
|
memcpy(pDst, pSrc, size);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
pDst[i] = pSrc[size-i-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf+size;
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // HV_ENDIAN_H_
|
19
external/libhv/libhv-1.3.2/base/herr.c
vendored
Normal file
19
external/libhv/libhv-1.3.2/base/herr.c
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#include "herr.h"
|
||||||
|
|
||||||
|
#include <string.h> // for strerror
|
||||||
|
|
||||||
|
// errcode => errmsg
|
||||||
|
const char* hv_strerror(int err) {
|
||||||
|
if (err > 0 && err <= SYS_NERR) {
|
||||||
|
return strerror(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (err) {
|
||||||
|
#define F(errcode, name, errmsg) \
|
||||||
|
case errcode: return errmsg;
|
||||||
|
FOREACH_ERR(F)
|
||||||
|
#undef F
|
||||||
|
default:
|
||||||
|
return "Undefined error";
|
||||||
|
}
|
||||||
|
}
|
122
external/libhv/libhv-1.3.2/base/herr.h
vendored
Normal file
122
external/libhv/libhv-1.3.2/base/herr.h
vendored
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
#ifndef HV_ERR_H_
|
||||||
|
#define HV_ERR_H_
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "hexport.h"
|
||||||
|
|
||||||
|
#ifndef SYS_NERR
|
||||||
|
#define SYS_NERR 133
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// F(errcode, name, errmsg)
|
||||||
|
// [1, 133]
|
||||||
|
#define FOREACH_ERR_SYS(F)
|
||||||
|
|
||||||
|
// [1xx~5xx]
|
||||||
|
#define FOREACH_ERR_STATUS(F)
|
||||||
|
|
||||||
|
// [1xxx]
|
||||||
|
#define FOREACH_ERR_COMMON(F) \
|
||||||
|
F(0, OK, "OK") \
|
||||||
|
F(1000, UNKNOWN, "Unknown error") \
|
||||||
|
\
|
||||||
|
F(1001, NULL_PARAM, "Null parameter") \
|
||||||
|
F(1002, NULL_POINTER, "Null pointer") \
|
||||||
|
F(1003, NULL_DATA, "Null data") \
|
||||||
|
F(1004, NULL_HANDLE, "Null handle") \
|
||||||
|
\
|
||||||
|
F(1011, INVALID_PARAM, "Invalid parameter")\
|
||||||
|
F(1012, INVALID_POINTER, "Invalid pointer") \
|
||||||
|
F(1013, INVALID_DATA, "Invalid data") \
|
||||||
|
F(1014, INVALID_HANDLE, "Invalid handle") \
|
||||||
|
F(1015, INVALID_JSON, "Invalid json") \
|
||||||
|
F(1016, INVALID_XML, "Invalid xml") \
|
||||||
|
F(1017, INVALID_FMT, "Invalid format") \
|
||||||
|
F(1018, INVALID_PROTOCOL, "Invalid protocol") \
|
||||||
|
F(1019, INVALID_PACKAGE, "Invalid package") \
|
||||||
|
\
|
||||||
|
F(1021, OUT_OF_RANGE, "Out of range") \
|
||||||
|
F(1022, OVER_LIMIT, "Over the limit") \
|
||||||
|
F(1023, MISMATCH, "Mismatch") \
|
||||||
|
F(1024, PARSE, "Parse failed") \
|
||||||
|
\
|
||||||
|
F(1030, OPEN_FILE, "Open file failed") \
|
||||||
|
F(1031, SAVE_FILE, "Save file failed") \
|
||||||
|
F(1032, READ_FILE, "Read file failed") \
|
||||||
|
F(1033, WRITE_FILE, "Write file failed")\
|
||||||
|
\
|
||||||
|
F(1040, SSL, "SSL/TLS error") \
|
||||||
|
F(1041, NEW_SSL_CTX, "New SSL_CTX failed") \
|
||||||
|
F(1042, NEW_SSL, "New SSL failed") \
|
||||||
|
F(1043, SSL_HANDSHAKE, "SSL handshake failed") \
|
||||||
|
\
|
||||||
|
F(1100, TASK_TIMEOUT, "Task timeout") \
|
||||||
|
F(1101, TASK_QUEUE_FULL, "Task queue full") \
|
||||||
|
F(1102, TASK_QUEUE_EMPTY, "Task queue empty") \
|
||||||
|
\
|
||||||
|
F(1400, REQUEST, "Bad request") \
|
||||||
|
F(1401, RESPONSE, "Bad response") \
|
||||||
|
|
||||||
|
// [-1xxx]
|
||||||
|
#define FOREACH_ERR_FUNC(F) \
|
||||||
|
F(-1001, MALLOC, "malloc() error") \
|
||||||
|
F(-1002, REALLOC, "realloc() error") \
|
||||||
|
F(-1003, CALLOC, "calloc() error") \
|
||||||
|
F(-1004, FREE, "free() error") \
|
||||||
|
\
|
||||||
|
F(-1011, SOCKET, "socket() error") \
|
||||||
|
F(-1012, BIND, "bind() error") \
|
||||||
|
F(-1013, LISTEN, "listen() error") \
|
||||||
|
F(-1014, ACCEPT, "accept() error") \
|
||||||
|
F(-1015, CONNECT, "connect() error") \
|
||||||
|
F(-1016, RECV, "recv() error") \
|
||||||
|
F(-1017, SEND, "send() error") \
|
||||||
|
F(-1018, RECVFROM, "recvfrom() error") \
|
||||||
|
F(-1019, SENDTO, "sendto() error") \
|
||||||
|
F(-1020, SETSOCKOPT, "setsockopt() error") \
|
||||||
|
F(-1021, GETSOCKOPT, "getsockopt() error") \
|
||||||
|
|
||||||
|
// grpc [4xxx]
|
||||||
|
#define FOREACH_ERR_GRPC(F) \
|
||||||
|
F(4000, GRPC_FIRST, "grpc no error") \
|
||||||
|
F(4001, GRPC_STATUS_CANCELLED, "grpc status: cancelled") \
|
||||||
|
F(4002, GRPC_STATUS_UNKNOWN, "grpc unknown error") \
|
||||||
|
F(4003, GRPC_STATUS_INVALID_ARGUMENT, "grpc status: invalid argument")\
|
||||||
|
F(4004, GRPC_STATUS_DEADLINE, "grpc status: deadline") \
|
||||||
|
F(4005, GRPC_STATUS_NOT_FOUND, "grpc status: not found") \
|
||||||
|
F(4006, GRPC_STATUS_ALREADY_EXISTS, "grpc status: already exists") \
|
||||||
|
F(4007, GRPC_STATUS_PERMISSION_DENIED, "grpc status: permission denied") \
|
||||||
|
F(4008, GRPC_STATUS_RESOURCE_EXHAUSTED, "grpc status: resource exhausted") \
|
||||||
|
F(4009, GRPC_STATUS_FAILED_PRECONDITION,"grpc status: failed precondition") \
|
||||||
|
F(4010, GRPC_STATUS_ABORTED, "grpc status: aborted") \
|
||||||
|
F(4011, GRPC_STATUS_OUT_OF_RANGE, "grpc status: out of range") \
|
||||||
|
F(4012, GRPC_STATUS_UNIMPLEMENTED, "grpc status: unimplemented") \
|
||||||
|
F(4013, GRPC_STATUS_INTERNAL, "grpc internal error") \
|
||||||
|
F(4014, GRPC_STATUS_UNAVAILABLE, "grpc service unavailable") \
|
||||||
|
F(4015, GRPC_STATUS_DATA_LOSS, "grpc status: data loss") \
|
||||||
|
|
||||||
|
#define FOREACH_ERR(F) \
|
||||||
|
FOREACH_ERR_COMMON(F) \
|
||||||
|
FOREACH_ERR_FUNC(F) \
|
||||||
|
FOREACH_ERR_GRPC(F) \
|
||||||
|
|
||||||
|
#undef ERR_OK // prevent conflict
|
||||||
|
enum {
|
||||||
|
#define F(errcode, name, errmsg) ERR_##name = errcode,
|
||||||
|
FOREACH_ERR(F)
|
||||||
|
#undef F
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// errcode => errmsg
|
||||||
|
HV_EXPORT const char* hv_strerror(int err);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // HV_ERR_H_
|
463
external/libhv/libhv-1.3.2/base/hlog.c
vendored
Normal file
463
external/libhv/libhv-1.3.2/base/hlog.c
vendored
Normal file
|
@ -0,0 +1,463 @@
|
||||||
|
#include "hlog.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
//#include "hmutex.h"
|
||||||
|
#ifdef _WIN32
|
||||||
|
#pragma warning (disable: 4244) // conversion loss of data
|
||||||
|
#include <windows.h>
|
||||||
|
#define hmutex_t CRITICAL_SECTION
|
||||||
|
#define hmutex_init InitializeCriticalSection
|
||||||
|
#define hmutex_destroy DeleteCriticalSection
|
||||||
|
#define hmutex_lock EnterCriticalSection
|
||||||
|
#define hmutex_unlock LeaveCriticalSection
|
||||||
|
#else
|
||||||
|
#include <sys/time.h> // for gettimeofday
|
||||||
|
#include <pthread.h>
|
||||||
|
#define hmutex_t pthread_mutex_t
|
||||||
|
#define hmutex_init(mutex) pthread_mutex_init(mutex, NULL)
|
||||||
|
#define hmutex_destroy pthread_mutex_destroy
|
||||||
|
#define hmutex_lock pthread_mutex_lock
|
||||||
|
#define hmutex_unlock pthread_mutex_unlock
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#include "htime.h"
|
||||||
|
#define SECONDS_PER_HOUR 3600
|
||||||
|
#define SECONDS_PER_DAY 86400 // 24*3600
|
||||||
|
#define SECONDS_PER_WEEK 604800 // 7*24*3600;
|
||||||
|
|
||||||
|
static int s_gmtoff = 28800; // 8*3600
|
||||||
|
|
||||||
|
struct logger_s {
|
||||||
|
logger_handler handler;
|
||||||
|
unsigned int bufsize;
|
||||||
|
char* buf;
|
||||||
|
|
||||||
|
int level;
|
||||||
|
int enable_color;
|
||||||
|
char format[64];
|
||||||
|
|
||||||
|
// for file logger
|
||||||
|
char filepath[256];
|
||||||
|
unsigned long long max_filesize;
|
||||||
|
int remain_days;
|
||||||
|
int enable_fsync;
|
||||||
|
FILE* fp_;
|
||||||
|
char cur_logfile[256];
|
||||||
|
time_t last_logfile_ts;
|
||||||
|
int can_write_cnt;
|
||||||
|
|
||||||
|
hmutex_t mutex_; // thread-safe
|
||||||
|
};
|
||||||
|
|
||||||
|
static void logger_init(logger_t* logger) {
|
||||||
|
logger->handler = NULL;
|
||||||
|
logger->bufsize = DEFAULT_LOG_MAX_BUFSIZE;
|
||||||
|
logger->buf = (char*)malloc(logger->bufsize);
|
||||||
|
|
||||||
|
logger->level = DEFAULT_LOG_LEVEL;
|
||||||
|
logger->enable_color = 0;
|
||||||
|
// NOTE: format is faster 6% than snprintf
|
||||||
|
// logger->format[0] = '\0';
|
||||||
|
strncpy(logger->format, DEFAULT_LOG_FORMAT, sizeof(logger->format) - 1);
|
||||||
|
|
||||||
|
logger->fp_ = NULL;
|
||||||
|
logger->max_filesize = DEFAULT_LOG_MAX_FILESIZE;
|
||||||
|
logger->remain_days = DEFAULT_LOG_REMAIN_DAYS;
|
||||||
|
logger->enable_fsync = 1;
|
||||||
|
logger_set_file(logger, DEFAULT_LOG_FILE);
|
||||||
|
logger->last_logfile_ts = 0;
|
||||||
|
logger->can_write_cnt = -1;
|
||||||
|
hmutex_init(&logger->mutex_);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger_t* logger_create() {
|
||||||
|
// init gmtoff here
|
||||||
|
time_t ts = time(NULL);
|
||||||
|
struct tm* local_tm = localtime(&ts);
|
||||||
|
int local_hour = local_tm->tm_hour;
|
||||||
|
struct tm* gmt_tm = gmtime(&ts);
|
||||||
|
int gmt_hour = gmt_tm->tm_hour;
|
||||||
|
s_gmtoff = (local_hour - gmt_hour) * SECONDS_PER_HOUR;
|
||||||
|
|
||||||
|
logger_t* logger = (logger_t*)malloc(sizeof(logger_t));
|
||||||
|
logger_init(logger);
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
void logger_destroy(logger_t* logger) {
|
||||||
|
if (logger) {
|
||||||
|
if (logger->buf) {
|
||||||
|
free(logger->buf);
|
||||||
|
logger->buf = NULL;
|
||||||
|
}
|
||||||
|
if (logger->fp_) {
|
||||||
|
fclose(logger->fp_);
|
||||||
|
logger->fp_ = NULL;
|
||||||
|
}
|
||||||
|
hmutex_destroy(&logger->mutex_);
|
||||||
|
free(logger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void logger_set_handler(logger_t* logger, logger_handler fn) {
|
||||||
|
logger->handler = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void logger_set_level(logger_t* logger, int level) {
|
||||||
|
logger->level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void logger_set_level_by_str(logger_t* logger, const char* szLoglevel) {
|
||||||
|
int loglevel = DEFAULT_LOG_LEVEL;
|
||||||
|
if (strcmp(szLoglevel, "VERBOSE") == 0) {
|
||||||
|
loglevel = LOG_LEVEL_VERBOSE;
|
||||||
|
} else if (strcmp(szLoglevel, "DEBUG") == 0) {
|
||||||
|
loglevel = LOG_LEVEL_DEBUG;
|
||||||
|
} else if (strcmp(szLoglevel, "INFO") == 0) {
|
||||||
|
loglevel = LOG_LEVEL_INFO;
|
||||||
|
} else if (strcmp(szLoglevel, "WARN") == 0) {
|
||||||
|
loglevel = LOG_LEVEL_WARN;
|
||||||
|
} else if (strcmp(szLoglevel, "ERROR") == 0) {
|
||||||
|
loglevel = LOG_LEVEL_ERROR;
|
||||||
|
} else if (strcmp(szLoglevel, "FATAL") == 0) {
|
||||||
|
loglevel = LOG_LEVEL_FATAL;
|
||||||
|
} else if (strcmp(szLoglevel, "SILENT") == 0) {
|
||||||
|
loglevel = LOG_LEVEL_SILENT;
|
||||||
|
} else {
|
||||||
|
loglevel = DEFAULT_LOG_LEVEL;
|
||||||
|
}
|
||||||
|
logger->level = loglevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void logger_set_format(logger_t* logger, const char* format) {
|
||||||
|
if (format) {
|
||||||
|
strncpy(logger->format, format, sizeof(logger->format) - 1);
|
||||||
|
} else {
|
||||||
|
logger->format[0] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void logger_set_remain_days(logger_t* logger, int days) {
|
||||||
|
logger->remain_days = days;
|
||||||
|
}
|
||||||
|
|
||||||
|
void logger_set_max_bufsize(logger_t* logger, unsigned int bufsize) {
|
||||||
|
logger->bufsize = bufsize;
|
||||||
|
logger->buf = (char*)realloc(logger->buf, bufsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void logger_enable_color(logger_t* logger, int on) {
|
||||||
|
logger->enable_color = on;
|
||||||
|
}
|
||||||
|
|
||||||
|
void logger_set_file(logger_t* logger, const char* filepath) {
|
||||||
|
strncpy(logger->filepath, filepath, sizeof(logger->filepath) - 1);
|
||||||
|
// remove suffix .log
|
||||||
|
char* suffix = strrchr(logger->filepath, '.');
|
||||||
|
if (suffix && strcmp(suffix, ".log") == 0) {
|
||||||
|
*suffix = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void logger_set_max_filesize(logger_t* logger, unsigned long long filesize) {
|
||||||
|
logger->max_filesize = filesize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void logger_set_max_filesize_by_str(logger_t* logger, const char* str) {
|
||||||
|
int num = atoi(str);
|
||||||
|
if (num <= 0) return;
|
||||||
|
// 16 16M 16MB
|
||||||
|
const char* e = str;
|
||||||
|
while (*e != '\0') ++e;
|
||||||
|
--e;
|
||||||
|
char unit;
|
||||||
|
if (*e >= '0' && *e <= '9') unit = 'M';
|
||||||
|
else if (*e == 'B') unit = *(e-1);
|
||||||
|
else unit = *e;
|
||||||
|
unsigned long long filesize = num;
|
||||||
|
switch (unit) {
|
||||||
|
case 'K': filesize <<= 10; break;
|
||||||
|
case 'M': filesize <<= 20; break;
|
||||||
|
case 'G': filesize <<= 30; break;
|
||||||
|
default: filesize <<= 20; break;
|
||||||
|
}
|
||||||
|
logger->max_filesize = filesize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void logger_enable_fsync(logger_t* logger, int on) {
|
||||||
|
logger->enable_fsync = on;
|
||||||
|
}
|
||||||
|
|
||||||
|
void logger_fsync(logger_t* logger) {
|
||||||
|
hmutex_lock(&logger->mutex_);
|
||||||
|
if (logger->fp_) {
|
||||||
|
fflush(logger->fp_);
|
||||||
|
}
|
||||||
|
hmutex_unlock(&logger->mutex_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* logger_get_cur_file(logger_t* logger) {
|
||||||
|
return logger->cur_logfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logfile_name(const char* filepath, time_t ts, char* buf, int len) {
|
||||||
|
struct tm* tm = localtime(&ts);
|
||||||
|
snprintf(buf, len, "%s.%04d%02d%02d.log",
|
||||||
|
filepath,
|
||||||
|
tm->tm_year+1900,
|
||||||
|
tm->tm_mon+1,
|
||||||
|
tm->tm_mday);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FILE* logfile_shift(logger_t* logger) {
|
||||||
|
time_t ts_now = time(NULL);
|
||||||
|
int interval_days = logger->last_logfile_ts == 0 ? 0 : (ts_now+s_gmtoff) / SECONDS_PER_DAY - (logger->last_logfile_ts+s_gmtoff) / SECONDS_PER_DAY;
|
||||||
|
if (logger->fp_ == NULL || interval_days > 0) {
|
||||||
|
// close old logfile
|
||||||
|
if (logger->fp_) {
|
||||||
|
fclose(logger->fp_);
|
||||||
|
logger->fp_ = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
interval_days = 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger->remain_days >= 0) {
|
||||||
|
char rm_logfile[256] = {0};
|
||||||
|
if (interval_days >= logger->remain_days) {
|
||||||
|
// remove [today-interval_days, today-remain_days] logfile
|
||||||
|
for (int i = interval_days; i >= logger->remain_days; --i) {
|
||||||
|
time_t ts_rm = ts_now - i * SECONDS_PER_DAY;
|
||||||
|
logfile_name(logger->filepath, ts_rm, rm_logfile, sizeof(rm_logfile));
|
||||||
|
remove(rm_logfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// remove today-remain_days logfile
|
||||||
|
time_t ts_rm = ts_now - logger->remain_days * SECONDS_PER_DAY;
|
||||||
|
logfile_name(logger->filepath, ts_rm, rm_logfile, sizeof(rm_logfile));
|
||||||
|
remove(rm_logfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// open today logfile
|
||||||
|
if (logger->fp_ == NULL) {
|
||||||
|
logfile_name(logger->filepath, ts_now, logger->cur_logfile, sizeof(logger->cur_logfile));
|
||||||
|
logger->fp_ = fopen(logger->cur_logfile, "a");
|
||||||
|
logger->last_logfile_ts = ts_now;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: estimate can_write_cnt to avoid frequent fseek/ftell
|
||||||
|
if (logger->fp_ && --logger->can_write_cnt < 0) {
|
||||||
|
fseek(logger->fp_, 0, SEEK_END);
|
||||||
|
long filesize = ftell(logger->fp_);
|
||||||
|
if (filesize > logger->max_filesize) {
|
||||||
|
fclose(logger->fp_);
|
||||||
|
logger->fp_ = NULL;
|
||||||
|
// ftruncate
|
||||||
|
logger->fp_ = fopen(logger->cur_logfile, "w");
|
||||||
|
// reopen with O_APPEND for multi-processes
|
||||||
|
if (logger->fp_) {
|
||||||
|
fclose(logger->fp_);
|
||||||
|
logger->fp_ = fopen(logger->cur_logfile, "a");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logger->can_write_cnt = (logger->max_filesize - filesize) / logger->bufsize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return logger->fp_;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logfile_write(logger_t* logger, const char* buf, int len) {
|
||||||
|
FILE* fp = logfile_shift(logger);
|
||||||
|
if (fp) {
|
||||||
|
fwrite(buf, 1, len, fp);
|
||||||
|
if (logger->enable_fsync) {
|
||||||
|
fflush(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int i2a(int i, char* buf, int len) {
|
||||||
|
for (int l = len - 1; l >= 0; --l) {
|
||||||
|
if (i == 0) {
|
||||||
|
buf[l] = '0';
|
||||||
|
} else {
|
||||||
|
buf[l] = i % 10 + '0';
|
||||||
|
i /= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int logger_print(logger_t* logger, int level, const char* fmt, ...) {
|
||||||
|
if (level < logger->level)
|
||||||
|
return -10;
|
||||||
|
|
||||||
|
int year,month,day,hour,min,sec,us;
|
||||||
|
#ifdef _WIN32
|
||||||
|
SYSTEMTIME tm;
|
||||||
|
GetLocalTime(&tm);
|
||||||
|
year = tm.wYear;
|
||||||
|
month = tm.wMonth;
|
||||||
|
day = tm.wDay;
|
||||||
|
hour = tm.wHour;
|
||||||
|
min = tm.wMinute;
|
||||||
|
sec = tm.wSecond;
|
||||||
|
us = tm.wMilliseconds * 1000;
|
||||||
|
#else
|
||||||
|
struct timeval tv;
|
||||||
|
struct tm* tm = NULL;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
time_t tt = tv.tv_sec;
|
||||||
|
tm = localtime(&tt);
|
||||||
|
year = tm->tm_year + 1900;
|
||||||
|
month = tm->tm_mon + 1;
|
||||||
|
day = tm->tm_mday;
|
||||||
|
hour = tm->tm_hour;
|
||||||
|
min = tm->tm_min;
|
||||||
|
sec = tm->tm_sec;
|
||||||
|
us = tv.tv_usec;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char* pcolor = "";
|
||||||
|
const char* plevel = "";
|
||||||
|
#define XXX(id, str, clr) \
|
||||||
|
case id: plevel = str; pcolor = clr; break;
|
||||||
|
|
||||||
|
switch (level) {
|
||||||
|
LOG_LEVEL_MAP(XXX)
|
||||||
|
}
|
||||||
|
#undef XXX
|
||||||
|
|
||||||
|
// lock logger->buf
|
||||||
|
hmutex_lock(&logger->mutex_);
|
||||||
|
|
||||||
|
char* buf = logger->buf;
|
||||||
|
int bufsize = logger->bufsize;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (logger->enable_color) {
|
||||||
|
len = snprintf(buf, bufsize, "%s", pcolor);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* p = logger->format;
|
||||||
|
if (*p) {
|
||||||
|
while (*p) {
|
||||||
|
if (*p == '%') {
|
||||||
|
switch(*++p) {
|
||||||
|
case 'y':
|
||||||
|
len += i2a(year, buf + len, 4);
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
len += i2a(month, buf + len, 2);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
len += i2a(day, buf + len, 2);
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
len += i2a(hour, buf + len, 2);
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
len += i2a(min, buf + len, 2);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
len += i2a(sec, buf + len, 2);
|
||||||
|
break;
|
||||||
|
case 'z':
|
||||||
|
len += i2a(us/1000, buf + len, 3);
|
||||||
|
break;
|
||||||
|
case 'Z':
|
||||||
|
len += i2a(us, buf + len, 6);
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
buf[len++] = *plevel;
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
for (int i = 0; i < 5; ++i) {
|
||||||
|
buf[len++] = plevel[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
len += vsnprintf(buf + len, bufsize - len, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '%':
|
||||||
|
buf[len++] = '%';
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buf[len++] = *p;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
len += snprintf(buf + len, bufsize - len, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s ",
|
||||||
|
year, month, day, hour, min, sec, us/1000,
|
||||||
|
plevel);
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
len += vsnprintf(buf + len, bufsize - len, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger->enable_color) {
|
||||||
|
len += snprintf(buf + len, bufsize - len, "%s", CLR_CLR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(len<bufsize) {
|
||||||
|
buf[len++] = '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger->handler) {
|
||||||
|
logger->handler(level, buf, len);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logfile_write(logger, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
hmutex_unlock(&logger->mutex_);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static logger_t* s_logger = NULL;
|
||||||
|
logger_t* hv_default_logger() {
|
||||||
|
if (s_logger == NULL) {
|
||||||
|
s_logger = logger_create();
|
||||||
|
atexit(hv_destroy_default_logger);
|
||||||
|
}
|
||||||
|
return s_logger;
|
||||||
|
}
|
||||||
|
void hv_destroy_default_logger(void) {
|
||||||
|
if (s_logger) {
|
||||||
|
logger_fsync(s_logger);
|
||||||
|
logger_destroy(s_logger);
|
||||||
|
s_logger = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stdout_logger(int loglevel, const char* buf, int len) {
|
||||||
|
fprintf(stdout, "%.*s", len, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stderr_logger(int loglevel, const char* buf, int len) {
|
||||||
|
fprintf(stderr, "%.*s", len, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_logger(int loglevel, const char* buf, int len) {
|
||||||
|
logfile_write(hv_default_logger(), buf, len);
|
||||||
|
}
|
176
external/libhv/libhv-1.3.2/base/hlog.h
vendored
Normal file
176
external/libhv/libhv-1.3.2/base/hlog.h
vendored
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
#ifndef HV_LOG_H_
|
||||||
|
#define HV_LOG_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hlog is thread-safe
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define DIR_SEPARATOR '\\'
|
||||||
|
#define DIR_SEPARATOR_STR "\\"
|
||||||
|
#else
|
||||||
|
#define DIR_SEPARATOR '/'
|
||||||
|
#define DIR_SEPARATOR_STR "/"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __FILENAME__
|
||||||
|
// #define __FILENAME__ (strrchr(__FILE__, DIR_SEPARATOR) ? strrchr(__FILE__, DIR_SEPARATOR) + 1 : __FILE__)
|
||||||
|
#define __FILENAME__ (strrchr(DIR_SEPARATOR_STR __FILE__, DIR_SEPARATOR) + 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "hexport.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CLR_CLR "\033[0m" /* 恢复颜色 */
|
||||||
|
#define CLR_BLACK "\033[30m" /* 黑色字 */
|
||||||
|
#define CLR_RED "\033[31m" /* 红色字 */
|
||||||
|
#define CLR_GREEN "\033[32m" /* 绿色字 */
|
||||||
|
#define CLR_YELLOW "\033[33m" /* 黄色字 */
|
||||||
|
#define CLR_BLUE "\033[34m" /* 蓝色字 */
|
||||||
|
#define CLR_PURPLE "\033[35m" /* 紫色字 */
|
||||||
|
#define CLR_SKYBLUE "\033[36m" /* 天蓝字 */
|
||||||
|
#define CLR_WHITE "\033[37m" /* 白色字 */
|
||||||
|
|
||||||
|
#define CLR_BLK_WHT "\033[40;37m" /* 黑底白字 */
|
||||||
|
#define CLR_RED_WHT "\033[41;37m" /* 红底白字 */
|
||||||
|
#define CLR_GREEN_WHT "\033[42;37m" /* 绿底白字 */
|
||||||
|
#define CLR_YELLOW_WHT "\033[43;37m" /* 黄底白字 */
|
||||||
|
#define CLR_BLUE_WHT "\033[44;37m" /* 蓝底白字 */
|
||||||
|
#define CLR_PURPLE_WHT "\033[45;37m" /* 紫底白字 */
|
||||||
|
#define CLR_SKYBLUE_WHT "\033[46;37m" /* 天蓝底白字 */
|
||||||
|
#define CLR_WHT_BLK "\033[47;30m" /* 白底黑字 */
|
||||||
|
|
||||||
|
// XXX(id, str, clr)
|
||||||
|
#define LOG_LEVEL_MAP(XXX) \
|
||||||
|
XXX(LOG_LEVEL_DEBUG, "DEBUG", CLR_WHITE) \
|
||||||
|
XXX(LOG_LEVEL_INFO, "INFO ", CLR_GREEN) \
|
||||||
|
XXX(LOG_LEVEL_WARN, "WARN ", CLR_YELLOW) \
|
||||||
|
XXX(LOG_LEVEL_ERROR, "ERROR", CLR_RED) \
|
||||||
|
XXX(LOG_LEVEL_FATAL, "FATAL", CLR_RED_WHT)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LOG_LEVEL_VERBOSE = 0,
|
||||||
|
#define XXX(id, str, clr) id,
|
||||||
|
LOG_LEVEL_MAP(XXX)
|
||||||
|
#undef XXX
|
||||||
|
LOG_LEVEL_SILENT
|
||||||
|
} log_level_e;
|
||||||
|
|
||||||
|
#define DEFAULT_LOG_FILE "libhv"
|
||||||
|
#define DEFAULT_LOG_LEVEL LOG_LEVEL_INFO
|
||||||
|
#define DEFAULT_LOG_FORMAT "%y-%m-%d %H:%M:%S.%z %L %s"
|
||||||
|
#define DEFAULT_LOG_REMAIN_DAYS 1
|
||||||
|
#define DEFAULT_LOG_MAX_BUFSIZE (1<<14) // 16k
|
||||||
|
#define DEFAULT_LOG_MAX_FILESIZE (1<<24) // 16M
|
||||||
|
|
||||||
|
// logger: default file_logger
|
||||||
|
// network_logger() see event/nlog.h
|
||||||
|
typedef void (*logger_handler)(int loglevel, const char* buf, int len);
|
||||||
|
|
||||||
|
HV_EXPORT void stdout_logger(int loglevel, const char* buf, int len);
|
||||||
|
HV_EXPORT void stderr_logger(int loglevel, const char* buf, int len);
|
||||||
|
HV_EXPORT void file_logger(int loglevel, const char* buf, int len);
|
||||||
|
// network_logger implement see event/nlog.h
|
||||||
|
// HV_EXPORT void network_logger(int loglevel, const char* buf, int len);
|
||||||
|
|
||||||
|
typedef struct logger_s logger_t;
|
||||||
|
HV_EXPORT logger_t* logger_create();
|
||||||
|
HV_EXPORT void logger_destroy(logger_t* logger);
|
||||||
|
|
||||||
|
HV_EXPORT void logger_set_handler(logger_t* logger, logger_handler fn);
|
||||||
|
HV_EXPORT void logger_set_level(logger_t* logger, int level);
|
||||||
|
// level = [VERBOSE,DEBUG,INFO,WARN,ERROR,FATAL,SILENT]
|
||||||
|
HV_EXPORT void logger_set_level_by_str(logger_t* logger, const char* level);
|
||||||
|
/*
|
||||||
|
* format = "%y-%m-%d %H:%M:%S.%z %L %s"
|
||||||
|
* message = "2020-01-02 03:04:05.067 DEBUG message"
|
||||||
|
* %y year
|
||||||
|
* %m month
|
||||||
|
* %d day
|
||||||
|
* %H hour
|
||||||
|
* %M min
|
||||||
|
* %S sec
|
||||||
|
* %z ms
|
||||||
|
* %Z us
|
||||||
|
* %l First character of level
|
||||||
|
* %L All characters of level
|
||||||
|
* %s message
|
||||||
|
* %% %
|
||||||
|
*/
|
||||||
|
HV_EXPORT void logger_set_format(logger_t* logger, const char* format);
|
||||||
|
HV_EXPORT void logger_set_max_bufsize(logger_t* logger, unsigned int bufsize);
|
||||||
|
HV_EXPORT void logger_enable_color(logger_t* logger, int on);
|
||||||
|
HV_EXPORT int logger_print(logger_t* logger, int level, const char* fmt, ...);
|
||||||
|
|
||||||
|
// below for file logger
|
||||||
|
HV_EXPORT void logger_set_file(logger_t* logger, const char* filepath);
|
||||||
|
HV_EXPORT void logger_set_max_filesize(logger_t* logger, unsigned long long filesize);
|
||||||
|
// 16, 16M, 16MB
|
||||||
|
HV_EXPORT void logger_set_max_filesize_by_str(logger_t* logger, const char* filesize);
|
||||||
|
HV_EXPORT void logger_set_remain_days(logger_t* logger, int days);
|
||||||
|
HV_EXPORT void logger_enable_fsync(logger_t* logger, int on);
|
||||||
|
HV_EXPORT void logger_fsync(logger_t* logger);
|
||||||
|
HV_EXPORT const char* logger_get_cur_file(logger_t* logger);
|
||||||
|
|
||||||
|
// hlog: default logger instance
|
||||||
|
HV_EXPORT logger_t* hv_default_logger();
|
||||||
|
HV_EXPORT void hv_destroy_default_logger(void);
|
||||||
|
|
||||||
|
// macro hlog*
|
||||||
|
#define hlog hv_default_logger()
|
||||||
|
#define hlog_destory() hv_destroy_default_logger()
|
||||||
|
#define hlog_disable() logger_set_level(hlog, LOG_LEVEL_SILENT)
|
||||||
|
#define hlog_set_file(filepath) logger_set_file(hlog, filepath)
|
||||||
|
#define hlog_set_level(level) logger_set_level(hlog, level)
|
||||||
|
#define hlog_set_level_by_str(level) logger_set_level_by_str(hlog, level)
|
||||||
|
#define hlog_set_handler(fn) logger_set_handler(hlog, fn)
|
||||||
|
#define hlog_set_format(format) logger_set_format(hlog, format)
|
||||||
|
#define hlog_set_max_filesize(filesize) logger_set_max_filesize(hlog, filesize)
|
||||||
|
#define hlog_set_max_filesize_by_str(filesize) logger_set_max_filesize_by_str(hlog, filesize)
|
||||||
|
#define hlog_set_remain_days(days) logger_set_remain_days(hlog, days)
|
||||||
|
#define hlog_enable_fsync() logger_enable_fsync(hlog, 1)
|
||||||
|
#define hlog_disable_fsync() logger_enable_fsync(hlog, 0)
|
||||||
|
#define hlog_fsync() logger_fsync(hlog)
|
||||||
|
#define hlog_get_cur_file() logger_get_cur_file(hlog)
|
||||||
|
|
||||||
|
#define hlogd(fmt, ...) logger_print(hlog, LOG_LEVEL_DEBUG, fmt " [%s:%d:%s]", ## __VA_ARGS__, __FILENAME__, __LINE__, __FUNCTION__)
|
||||||
|
#define hlogi(fmt, ...) logger_print(hlog, LOG_LEVEL_INFO, fmt " [%s:%d:%s]", ## __VA_ARGS__, __FILENAME__, __LINE__, __FUNCTION__)
|
||||||
|
#define hlogw(fmt, ...) logger_print(hlog, LOG_LEVEL_WARN, fmt " [%s:%d:%s]", ## __VA_ARGS__, __FILENAME__, __LINE__, __FUNCTION__)
|
||||||
|
#define hloge(fmt, ...) logger_print(hlog, LOG_LEVEL_ERROR, fmt " [%s:%d:%s]", ## __VA_ARGS__, __FILENAME__, __LINE__, __FUNCTION__)
|
||||||
|
#define hlogf(fmt, ...) logger_print(hlog, LOG_LEVEL_FATAL, fmt " [%s:%d:%s]", ## __VA_ARGS__, __FILENAME__, __LINE__, __FUNCTION__)
|
||||||
|
|
||||||
|
// below for android
|
||||||
|
#if defined(ANDROID) || defined(__ANDROID__)
|
||||||
|
#include <android/log.h>
|
||||||
|
#define LOG_TAG "JNI"
|
||||||
|
#undef hlogd
|
||||||
|
#undef hlogi
|
||||||
|
#undef hlogw
|
||||||
|
#undef hloge
|
||||||
|
#undef hlogf
|
||||||
|
#define hlogd(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||||
|
#define hlogi(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||||
|
#define hlogw(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
|
||||||
|
#define hloge(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||||
|
#define hlogf(...) __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// macro alias
|
||||||
|
#if !defined(LOGD) && !defined(LOGI) && !defined(LOGW) && !defined(LOGE) && !defined(LOGF)
|
||||||
|
#define LOGD hlogd
|
||||||
|
#define LOGI hlogi
|
||||||
|
#define LOGW hlogw
|
||||||
|
#define LOGE hloge
|
||||||
|
#define LOGF hlogf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // HV_LOG_H_
|
674
external/libhv/libhv-1.3.2/base/hmain.c
vendored
Normal file
674
external/libhv/libhv-1.3.2/base/hmain.c
vendored
Normal file
|
@ -0,0 +1,674 @@
|
||||||
|
#include "hmain.h"
|
||||||
|
|
||||||
|
#include "hbase.h"
|
||||||
|
#include "hlog.h"
|
||||||
|
#include "herr.h"
|
||||||
|
#include "htime.h"
|
||||||
|
#include "hthread.h"
|
||||||
|
|
||||||
|
#ifdef OS_DARWIN
|
||||||
|
#include <crt_externs.h>
|
||||||
|
#define environ (*_NSGetEnviron())
|
||||||
|
#endif
|
||||||
|
|
||||||
|
main_ctx_t g_main_ctx;
|
||||||
|
|
||||||
|
static void init_arg_kv(int maxsize) {
|
||||||
|
g_main_ctx.arg_kv_size = 0;
|
||||||
|
SAFE_ALLOC(g_main_ctx.arg_kv, sizeof(char*) * maxsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save_arg_kv(const char* key, int key_len, const char* val, int val_len) {
|
||||||
|
if (key_len <= 0) key_len = strlen(key);
|
||||||
|
if (val_len <= 0) val_len = strlen(val);
|
||||||
|
char* arg = NULL;
|
||||||
|
SAFE_ALLOC(arg, key_len + val_len + 2);
|
||||||
|
memcpy(arg, key, key_len);
|
||||||
|
arg[key_len] = '=';
|
||||||
|
memcpy(arg + key_len + 1, val, val_len);
|
||||||
|
// printf("save_arg_kv: %s\n", arg);
|
||||||
|
g_main_ctx.arg_kv[g_main_ctx.arg_kv_size++] = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_arg_list(int maxsize) {
|
||||||
|
g_main_ctx.arg_list_size = 0;
|
||||||
|
SAFE_ALLOC(g_main_ctx.arg_list, sizeof(char*) * maxsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save_arg_list(const char* arg) {
|
||||||
|
// printf("save_arg_list: %s\n", arg);
|
||||||
|
g_main_ctx.arg_list[g_main_ctx.arg_list_size++] = strdup(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* get_val(char** kvs, const char* key) {
|
||||||
|
if (kvs == NULL) return NULL;
|
||||||
|
int key_len = strlen(key);
|
||||||
|
char* kv = NULL;
|
||||||
|
int kv_len = 0;
|
||||||
|
for (int i = 0; kvs[i]; ++i) {
|
||||||
|
kv = kvs[i];
|
||||||
|
kv_len = strlen(kv);
|
||||||
|
if (kv_len <= key_len) continue;
|
||||||
|
// key=val
|
||||||
|
if (memcmp(kv, key, key_len) == 0 && kv[key_len] == '=') {
|
||||||
|
return kv + key_len + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* get_arg(const char* key) {
|
||||||
|
return get_val(g_main_ctx.arg_kv, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* get_env(const char* key) {
|
||||||
|
return get_val(g_main_ctx.save_envp, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main_ctx_init(int argc, char** argv) {
|
||||||
|
if (argc == 0 || argv == NULL) {
|
||||||
|
argc = 1;
|
||||||
|
SAFE_ALLOC(argv, 2 * sizeof(char*));
|
||||||
|
SAFE_ALLOC(argv[0], MAX_PATH);
|
||||||
|
get_executable_path(argv[0], MAX_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
get_run_dir(g_main_ctx.run_dir, sizeof(g_main_ctx.run_dir));
|
||||||
|
//printf("run_dir=%s\n", g_main_ctx.run_dir);
|
||||||
|
strncpy(g_main_ctx.program_name, hv_basename(argv[0]), sizeof(g_main_ctx.program_name));
|
||||||
|
#ifdef OS_WIN
|
||||||
|
if (strcmp(g_main_ctx.program_name+strlen(g_main_ctx.program_name)-4, ".exe") == 0) {
|
||||||
|
*(g_main_ctx.program_name+strlen(g_main_ctx.program_name)-4) = '\0';
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
//printf("program_name=%s\n", g_main_ctx.program_name);
|
||||||
|
char logdir[MAX_PATH] = {0};
|
||||||
|
snprintf(logdir, sizeof(logdir), "%s/logs", g_main_ctx.run_dir);
|
||||||
|
hv_mkdir(logdir);
|
||||||
|
snprintf(g_main_ctx.confile, sizeof(g_main_ctx.confile), "%s/etc/%s.conf", g_main_ctx.run_dir, g_main_ctx.program_name);
|
||||||
|
snprintf(g_main_ctx.pidfile, sizeof(g_main_ctx.pidfile), "%s/logs/%s.pid", g_main_ctx.run_dir, g_main_ctx.program_name);
|
||||||
|
snprintf(g_main_ctx.logfile, sizeof(g_main_ctx.logfile), "%s/logs/%s.log", g_main_ctx.run_dir, g_main_ctx.program_name);
|
||||||
|
hlog_set_file(g_main_ctx.logfile);
|
||||||
|
|
||||||
|
g_main_ctx.pid = getpid();
|
||||||
|
g_main_ctx.oldpid = getpid_from_pidfile();
|
||||||
|
#ifdef OS_UNIX
|
||||||
|
if (kill(g_main_ctx.oldpid, 0) == -1 && errno == ESRCH) {
|
||||||
|
g_main_ctx.oldpid = -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
HANDLE hproc = OpenProcess(PROCESS_TERMINATE, FALSE, g_main_ctx.oldpid);
|
||||||
|
if (hproc == NULL) {
|
||||||
|
g_main_ctx.oldpid = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
CloseHandle(hproc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// save arg
|
||||||
|
int i = 0;
|
||||||
|
g_main_ctx.os_argv = argv;
|
||||||
|
g_main_ctx.argc = 0;
|
||||||
|
g_main_ctx.arg_len = 0;
|
||||||
|
for (i = 0; argv[i]; ++i) {
|
||||||
|
g_main_ctx.arg_len += strlen(argv[i]) + 1;
|
||||||
|
}
|
||||||
|
g_main_ctx.argc = i;
|
||||||
|
char* argp = NULL;
|
||||||
|
SAFE_ALLOC(argp, g_main_ctx.arg_len);
|
||||||
|
SAFE_ALLOC(g_main_ctx.save_argv, (g_main_ctx.argc + 1) * sizeof(char*));
|
||||||
|
char* cmdline = NULL;
|
||||||
|
SAFE_ALLOC(cmdline, g_main_ctx.arg_len);
|
||||||
|
g_main_ctx.cmdline = cmdline;
|
||||||
|
for (i = 0; argv[i]; ++i) {
|
||||||
|
strcpy(argp, argv[i]);
|
||||||
|
g_main_ctx.save_argv[i] = argp;
|
||||||
|
argp += strlen(argv[i]) + 1;
|
||||||
|
|
||||||
|
strcpy(cmdline, argv[i]);
|
||||||
|
cmdline += strlen(argv[i]);
|
||||||
|
*cmdline = ' ';
|
||||||
|
++cmdline;
|
||||||
|
}
|
||||||
|
g_main_ctx.save_argv[g_main_ctx.argc] = NULL;
|
||||||
|
g_main_ctx.cmdline[g_main_ctx.arg_len-1] = '\0';
|
||||||
|
|
||||||
|
#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_DARWIN)
|
||||||
|
// save env
|
||||||
|
g_main_ctx.os_envp = environ;
|
||||||
|
g_main_ctx.envc = 0;
|
||||||
|
g_main_ctx.env_len = 0;
|
||||||
|
for (i = 0; environ[i]; ++i) {
|
||||||
|
g_main_ctx.env_len += strlen(environ[i]) + 1;
|
||||||
|
}
|
||||||
|
g_main_ctx.envc = i;
|
||||||
|
char* envp = NULL;
|
||||||
|
SAFE_ALLOC(envp, g_main_ctx.env_len);
|
||||||
|
SAFE_ALLOC(g_main_ctx.save_envp, (g_main_ctx.envc + 1) * sizeof(char*));
|
||||||
|
for (i = 0; environ[i]; ++i) {
|
||||||
|
g_main_ctx.save_envp[i] = envp;
|
||||||
|
strcpy(g_main_ctx.save_envp[i], environ[i]);
|
||||||
|
envp += strlen(environ[i]) + 1;
|
||||||
|
}
|
||||||
|
g_main_ctx.save_envp[g_main_ctx.envc] = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// signals
|
||||||
|
g_main_ctx.reload_fn = NULL;
|
||||||
|
g_main_ctx.reload_userdata = NULL;
|
||||||
|
|
||||||
|
// master workers
|
||||||
|
g_main_ctx.worker_processes = 0;
|
||||||
|
g_main_ctx.worker_threads = 0;
|
||||||
|
g_main_ctx.worker_fn = 0;
|
||||||
|
g_main_ctx.worker_userdata = 0;
|
||||||
|
g_main_ctx.proc_ctxs = NULL;
|
||||||
|
|
||||||
|
atexit(main_ctx_free);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main_ctx_free(void) {
|
||||||
|
if (g_main_ctx.save_argv) {
|
||||||
|
SAFE_FREE(g_main_ctx.save_argv[0]);
|
||||||
|
SAFE_FREE(g_main_ctx.save_argv);
|
||||||
|
}
|
||||||
|
SAFE_FREE(g_main_ctx.cmdline);
|
||||||
|
if (g_main_ctx.save_envp) {
|
||||||
|
SAFE_FREE(g_main_ctx.save_envp[0]);
|
||||||
|
SAFE_FREE(g_main_ctx.save_envp);
|
||||||
|
}
|
||||||
|
if (g_main_ctx.arg_kv) {
|
||||||
|
for (int i = 0; i < g_main_ctx.arg_kv_size; ++i) {
|
||||||
|
SAFE_FREE(g_main_ctx.arg_kv[i]);
|
||||||
|
}
|
||||||
|
SAFE_FREE(g_main_ctx.arg_kv);
|
||||||
|
}
|
||||||
|
if (g_main_ctx.arg_list) {
|
||||||
|
for (int i = 0; i < g_main_ctx.arg_list_size; ++i) {
|
||||||
|
SAFE_FREE(g_main_ctx.arg_list[i]);
|
||||||
|
}
|
||||||
|
SAFE_FREE(g_main_ctx.arg_list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UNDEFINED_OPTION -1
|
||||||
|
static int get_arg_type(int short_opt, const char* options) {
|
||||||
|
if (options == NULL) return UNDEFINED_OPTION;
|
||||||
|
const char* p = options;
|
||||||
|
while (*p && *p != short_opt) ++p;
|
||||||
|
if (*p == '\0') return UNDEFINED_OPTION;
|
||||||
|
if (*(p+1) == ':') return REQUIRED_ARGUMENT;
|
||||||
|
return NO_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_opt(int argc, char** argv, const char* options) {
|
||||||
|
if (argc < 1) return 0;
|
||||||
|
init_arg_kv(strlen(options) + 1);
|
||||||
|
init_arg_list(argc);
|
||||||
|
|
||||||
|
for (int i = 1; argv[i]; ++i) {
|
||||||
|
char* p = argv[i];
|
||||||
|
if (*p != '-') {
|
||||||
|
save_arg_list(argv[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
while (*++p) {
|
||||||
|
int arg_type = get_arg_type(*p, options);
|
||||||
|
if (arg_type == UNDEFINED_OPTION) {
|
||||||
|
printf("Invalid option '%c'\n", *p);
|
||||||
|
return -20;
|
||||||
|
} else if (arg_type == NO_ARGUMENT) {
|
||||||
|
save_arg_kv(p, 1, OPTION_ENABLE, 0);
|
||||||
|
continue;
|
||||||
|
} else if (arg_type == REQUIRED_ARGUMENT) {
|
||||||
|
if (*(p+1) != '\0') {
|
||||||
|
save_arg_kv(p, 1, p+1, 0);
|
||||||
|
break;
|
||||||
|
} else if (argv[i+1] != NULL) {
|
||||||
|
save_arg_kv(p, 1, argv[++i], 0);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
printf("Option '%c' requires param\n", *p);
|
||||||
|
return -30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const option_t* get_option(const char* opt, const option_t* long_options, int size) {
|
||||||
|
if (opt == NULL || long_options == NULL) return NULL;
|
||||||
|
int len = strlen(opt);
|
||||||
|
if (len == 0) return NULL;
|
||||||
|
if (len == 1) {
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
if (long_options[i].short_opt == *opt) {
|
||||||
|
return &long_options[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
if (strcmp(long_options[i].long_opt, opt) == 0) {
|
||||||
|
return &long_options[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_OPTION 32
|
||||||
|
// opt type
|
||||||
|
#define NOPREFIX_OPTION 0
|
||||||
|
#define SHORT_OPTION -1
|
||||||
|
#define LONG_OPTION -2
|
||||||
|
int parse_opt_long(int argc, char** argv, const option_t* long_options, int size) {
|
||||||
|
if (argc < 1) return 0;
|
||||||
|
init_arg_kv(size + 1);
|
||||||
|
init_arg_list(argc);
|
||||||
|
|
||||||
|
char opt[MAX_OPTION+1] = {0};
|
||||||
|
for (int i = 1; argv[i]; ++i) {
|
||||||
|
char* arg = argv[i];
|
||||||
|
int opt_type = NOPREFIX_OPTION;
|
||||||
|
// prefix
|
||||||
|
if (*arg == OPTION_PREFIX) {
|
||||||
|
++arg;
|
||||||
|
opt_type = SHORT_OPTION;
|
||||||
|
if (*arg == OPTION_PREFIX) {
|
||||||
|
++arg;
|
||||||
|
opt_type = LONG_OPTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int arg_len = strlen(arg);
|
||||||
|
// delim
|
||||||
|
char* delim = strchr(arg, OPTION_DELIM);
|
||||||
|
if (delim) {
|
||||||
|
if (delim == arg || delim == arg+arg_len-1 || delim-arg > MAX_OPTION) {
|
||||||
|
printf("Invalid option '%s'\n", argv[i]);
|
||||||
|
return -10;
|
||||||
|
}
|
||||||
|
memcpy(opt, arg, delim-arg);
|
||||||
|
opt[delim-arg] = '\0';
|
||||||
|
} else {
|
||||||
|
if (opt_type == SHORT_OPTION) {
|
||||||
|
*opt = *arg;
|
||||||
|
opt[1] = '\0';
|
||||||
|
} else {
|
||||||
|
strncpy(opt, arg, MAX_OPTION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// get_option
|
||||||
|
const option_t* pOption = get_option(opt, long_options, size);
|
||||||
|
if (pOption == NULL) {
|
||||||
|
if (delim == NULL && opt_type == NOPREFIX_OPTION) {
|
||||||
|
save_arg_list(arg);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
printf("Invalid option: '%s'\n", argv[i]);
|
||||||
|
return -10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const char* value = NULL;
|
||||||
|
if (pOption->arg_type == NO_ARGUMENT) {
|
||||||
|
// -h
|
||||||
|
value = OPTION_ENABLE;
|
||||||
|
} else if (pOption->arg_type == REQUIRED_ARGUMENT) {
|
||||||
|
if (delim) {
|
||||||
|
// --port=80
|
||||||
|
value = delim+1;
|
||||||
|
} else {
|
||||||
|
if (opt_type == SHORT_OPTION && *(arg+1) != '\0') {
|
||||||
|
// p80
|
||||||
|
value = arg+1;
|
||||||
|
} else if (argv[i+1] != NULL) {
|
||||||
|
// --port 80
|
||||||
|
value = argv[++i];
|
||||||
|
} else {
|
||||||
|
printf("Option '%s' requires parament\n", opt);
|
||||||
|
return -20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// preferred to use short_opt as key
|
||||||
|
if (pOption->short_opt > 0) {
|
||||||
|
save_arg_kv(&pOption->short_opt, 1, value, 0);
|
||||||
|
} else if (pOption->long_opt) {
|
||||||
|
save_arg_kv(pOption->long_opt, 0, value, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(OS_UNIX) && !HAVE_SETPROCTITLE
|
||||||
|
/*
|
||||||
|
* memory layout
|
||||||
|
* argv[0]\0argv[1]\0argv[n]\0env[0]\0env[1]\0env[n]\0
|
||||||
|
*/
|
||||||
|
void setproctitle(const char* fmt, ...) {
|
||||||
|
char buf[256] = {0};
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
int len = g_main_ctx.arg_len + g_main_ctx.env_len;
|
||||||
|
if (g_main_ctx.os_argv && len) {
|
||||||
|
strncpy(g_main_ctx.os_argv[0], buf, len-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int create_pidfile() {
|
||||||
|
FILE* fp = fopen(g_main_ctx.pidfile, "w");
|
||||||
|
if (fp == NULL) {
|
||||||
|
hloge("fopen('%s') error: %d", g_main_ctx.pidfile, errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_main_ctx.pid = hv_getpid();
|
||||||
|
fprintf(fp, "%d\n", (int)g_main_ctx.pid);
|
||||||
|
fclose(fp);
|
||||||
|
hlogi("create_pidfile('%s') pid=%d", g_main_ctx.pidfile, g_main_ctx.pid);
|
||||||
|
atexit(delete_pidfile);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_pidfile(void) {
|
||||||
|
hlogi("delete_pidfile('%s') pid=%d", g_main_ctx.pidfile, g_main_ctx.pid);
|
||||||
|
remove(g_main_ctx.pidfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_t getpid_from_pidfile() {
|
||||||
|
FILE* fp = fopen(g_main_ctx.pidfile, "r");
|
||||||
|
if (fp == NULL) {
|
||||||
|
// hloge("fopen('%s') error: %d", g_main_ctx.pidfile, errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int pid = -1;
|
||||||
|
fscanf(fp, "%d", &pid);
|
||||||
|
fclose(fp);
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef OS_UNIX
|
||||||
|
// unix use signal
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
void signal_handler(int signo) {
|
||||||
|
hlogi("pid=%d recv signo=%d", getpid(), signo);
|
||||||
|
switch (signo) {
|
||||||
|
case SIGINT:
|
||||||
|
case SIGNAL_TERMINATE:
|
||||||
|
hlogi("killall processes");
|
||||||
|
signal(SIGCHLD, SIG_IGN);
|
||||||
|
// master send SIGKILL => workers
|
||||||
|
for (int i = 0; i < g_main_ctx.worker_processes; ++i) {
|
||||||
|
if (g_main_ctx.proc_ctxs[i].pid <= 0) break;
|
||||||
|
kill(g_main_ctx.proc_ctxs[i].pid, SIGKILL);
|
||||||
|
g_main_ctx.proc_ctxs[i].pid = -1;
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
case SIGCHLD:
|
||||||
|
{
|
||||||
|
pid_t pid = 0;
|
||||||
|
int status = 0;
|
||||||
|
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
|
||||||
|
hlogw("proc stop/waiting, pid=%d status=%d", pid, status);
|
||||||
|
for (int i = 0; i < g_main_ctx.worker_processes; ++i) {
|
||||||
|
proc_ctx_t* ctx = g_main_ctx.proc_ctxs + i;
|
||||||
|
if (ctx->pid == pid) {
|
||||||
|
ctx->pid = -1;
|
||||||
|
// NOTE: avoid frequent crash and restart
|
||||||
|
time_t run_time = time(NULL) - ctx->start_time;
|
||||||
|
if (ctx->spawn_cnt < 3 || run_time > 3600) {
|
||||||
|
hproc_spawn(ctx);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hloge("proc crash, pid=%d spawn_cnt=%d run_time=%us",
|
||||||
|
pid, ctx->spawn_cnt, (unsigned int)run_time);
|
||||||
|
|
||||||
|
bool have_worker = false;
|
||||||
|
for (int i = 0; i < g_main_ctx.worker_processes; ++i) {
|
||||||
|
if (g_main_ctx.proc_ctxs[i].pid > 0) {
|
||||||
|
have_worker = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!have_worker) {
|
||||||
|
hlogw("No alive worker process, exit master process!");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SIGNAL_RELOAD:
|
||||||
|
if (g_main_ctx.reload_fn) {
|
||||||
|
g_main_ctx.reload_fn(g_main_ctx.reload_userdata);
|
||||||
|
if (getpid_from_pidfile() == getpid()) {
|
||||||
|
// master send SIGNAL_RELOAD => workers
|
||||||
|
for (int i = 0; i < g_main_ctx.worker_processes; ++i) {
|
||||||
|
if (g_main_ctx.proc_ctxs[i].pid <= 0) break;
|
||||||
|
kill(g_main_ctx.proc_ctxs[i].pid, SIGNAL_RELOAD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int signal_init(procedure_t reload_fn, void* reload_userdata) {
|
||||||
|
g_main_ctx.reload_fn = reload_fn;
|
||||||
|
g_main_ctx.reload_userdata = reload_userdata;
|
||||||
|
|
||||||
|
signal(SIGINT, signal_handler);
|
||||||
|
signal(SIGCHLD, signal_handler);
|
||||||
|
signal(SIGNAL_TERMINATE, signal_handler);
|
||||||
|
signal(SIGNAL_RELOAD, signal_handler);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(OS_WIN)
|
||||||
|
#include <mmsystem.h> // for timeSetEvent
|
||||||
|
|
||||||
|
// win32 use Event
|
||||||
|
//static HANDLE s_hEventTerm = NULL;
|
||||||
|
static HANDLE s_hEventReload = NULL;
|
||||||
|
|
||||||
|
static void WINAPI on_timer(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) {
|
||||||
|
DWORD ret;
|
||||||
|
/*
|
||||||
|
ret = WaitForSingleObject(s_hEventTerm, 0);
|
||||||
|
if (ret == WAIT_OBJECT_0) {
|
||||||
|
hlogi("pid=%d recv event [TERM]", getpid());
|
||||||
|
if (getpid_from_pidfile() == getpid()) {
|
||||||
|
timeKillEvent(uTimerID);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
ret = WaitForSingleObject(s_hEventReload, 0);
|
||||||
|
if (ret == WAIT_OBJECT_0) {
|
||||||
|
hlogi("pid=%d recv event [RELOAD]", getpid());
|
||||||
|
if (g_main_ctx.reload_fn) {
|
||||||
|
g_main_ctx.reload_fn(g_main_ctx.reload_userdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void signal_cleanup(void) {
|
||||||
|
//CloseHandle(s_hEventTerm);
|
||||||
|
//s_hEventTerm = NULL;
|
||||||
|
CloseHandle(s_hEventReload);
|
||||||
|
s_hEventReload = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int signal_init(procedure_t reload_fn, void* reload_userdata) {
|
||||||
|
g_main_ctx.reload_fn = reload_fn;
|
||||||
|
g_main_ctx.reload_userdata = reload_userdata;
|
||||||
|
|
||||||
|
char eventname[MAX_PATH] = {0};
|
||||||
|
//snprintf(eventname, sizeof(eventname), "%s_term_event", g_main_ctx.program_name);
|
||||||
|
//s_hEventTerm = CreateEvent(NULL, FALSE, FALSE, eventname);
|
||||||
|
//s_hEventTerm = OpenEvent(EVENT_ALL_ACCESS, FALSE, eventname);
|
||||||
|
snprintf(eventname, sizeof(eventname), "%s_reload_event", g_main_ctx.program_name);
|
||||||
|
s_hEventReload = CreateEvent(NULL, FALSE, FALSE, eventname);
|
||||||
|
|
||||||
|
timeSetEvent(1000, 1000, on_timer, 0, TIME_PERIODIC);
|
||||||
|
|
||||||
|
atexit(signal_cleanup);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void kill_proc(int pid) {
|
||||||
|
#ifdef OS_UNIX
|
||||||
|
kill(pid, SIGNAL_TERMINATE);
|
||||||
|
#else
|
||||||
|
//SetEvent(s_hEventTerm);
|
||||||
|
//hv_sleep(1);
|
||||||
|
HANDLE hproc = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
|
||||||
|
if (hproc) {
|
||||||
|
TerminateProcess(hproc, 0);
|
||||||
|
CloseHandle(hproc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void signal_handle(const char* signal) {
|
||||||
|
if (strcmp(signal, "start") == 0) {
|
||||||
|
if (g_main_ctx.oldpid > 0) {
|
||||||
|
printf("%s is already running, pid=%d\n", g_main_ctx.program_name, g_main_ctx.oldpid);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
} else if (strcmp(signal, "stop") == 0) {
|
||||||
|
if (g_main_ctx.oldpid > 0) {
|
||||||
|
kill_proc(g_main_ctx.oldpid);
|
||||||
|
printf("%s stop/waiting\n", g_main_ctx.program_name);
|
||||||
|
} else {
|
||||||
|
printf("%s is already stopped\n", g_main_ctx.program_name);
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
} else if (strcmp(signal, "restart") == 0) {
|
||||||
|
if (g_main_ctx.oldpid > 0) {
|
||||||
|
kill_proc(g_main_ctx.oldpid);
|
||||||
|
printf("%s stop/waiting\n", g_main_ctx.program_name);
|
||||||
|
hv_sleep(1);
|
||||||
|
}
|
||||||
|
} else if (strcmp(signal, "status") == 0) {
|
||||||
|
if (g_main_ctx.oldpid > 0) {
|
||||||
|
printf("%s start/running, pid=%d\n", g_main_ctx.program_name, g_main_ctx.oldpid);
|
||||||
|
} else {
|
||||||
|
printf("%s stop/waiting\n", g_main_ctx.program_name);
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
} else if (strcmp(signal, "reload") == 0) {
|
||||||
|
if (g_main_ctx.oldpid > 0) {
|
||||||
|
printf("reload confile [%s]\n", g_main_ctx.confile);
|
||||||
|
#ifdef OS_UNIX
|
||||||
|
kill(g_main_ctx.oldpid, SIGNAL_RELOAD);
|
||||||
|
#else
|
||||||
|
SetEvent(s_hEventReload);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
hv_sleep(1);
|
||||||
|
exit(0);
|
||||||
|
} else {
|
||||||
|
printf("Invalid signal: '%s'\n", signal);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
printf("%s start/running\n", g_main_ctx.program_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// master-workers processes
|
||||||
|
static HTHREAD_ROUTINE(worker_thread) {
|
||||||
|
hlogi("worker_thread pid=%ld tid=%ld", hv_getpid(), hv_gettid());
|
||||||
|
if (g_main_ctx.worker_fn) {
|
||||||
|
g_main_ctx.worker_fn(g_main_ctx.worker_userdata);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void worker_init(void* userdata) {
|
||||||
|
#ifdef OS_UNIX
|
||||||
|
setproctitle("%s: worker process", g_main_ctx.program_name);
|
||||||
|
signal(SIGNAL_RELOAD, signal_handler);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void worker_proc(void* userdata) {
|
||||||
|
for (int i = 1; i < g_main_ctx.worker_threads; ++i) {
|
||||||
|
hthread_create(worker_thread, NULL);
|
||||||
|
}
|
||||||
|
worker_thread(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int master_workers_run(procedure_t worker_fn, void* worker_userdata,
|
||||||
|
int worker_processes, int worker_threads, bool wait) {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
// NOTE: Windows not provide MultiProcesses
|
||||||
|
if (worker_threads == 0) {
|
||||||
|
// MultiProcesses => MultiThreads
|
||||||
|
worker_threads = worker_processes;
|
||||||
|
}
|
||||||
|
worker_processes = 0;
|
||||||
|
#endif
|
||||||
|
if (worker_threads == 0) worker_threads = 1;
|
||||||
|
|
||||||
|
g_main_ctx.worker_threads = worker_threads;
|
||||||
|
g_main_ctx.worker_fn = worker_fn;
|
||||||
|
g_main_ctx.worker_userdata = worker_userdata;
|
||||||
|
|
||||||
|
if (worker_processes == 0) {
|
||||||
|
// single process
|
||||||
|
if (wait) {
|
||||||
|
for (int i = 1; i < worker_threads; ++i) {
|
||||||
|
hthread_create(worker_thread, NULL);
|
||||||
|
}
|
||||||
|
worker_thread(NULL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = 0; i < worker_threads; ++i) {
|
||||||
|
hthread_create(worker_thread, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (g_main_ctx.worker_processes != 0) {
|
||||||
|
return ERR_OVER_LIMIT;
|
||||||
|
}
|
||||||
|
// master-workers processes
|
||||||
|
#ifdef OS_UNIX
|
||||||
|
setproctitle("%s: master process", g_main_ctx.program_name);
|
||||||
|
signal(SIGNAL_RELOAD, signal_handler);
|
||||||
|
#endif
|
||||||
|
g_main_ctx.worker_processes = worker_processes;
|
||||||
|
int bytes = g_main_ctx.worker_processes * sizeof(proc_ctx_t);
|
||||||
|
SAFE_ALLOC(g_main_ctx.proc_ctxs, bytes);
|
||||||
|
proc_ctx_t* ctx = g_main_ctx.proc_ctxs;
|
||||||
|
for (int i = 0; i < g_main_ctx.worker_processes; ++i, ++ctx) {
|
||||||
|
ctx->init = worker_init;
|
||||||
|
ctx->proc = worker_proc;
|
||||||
|
hproc_spawn(ctx);
|
||||||
|
hlogi("workers[%d] start/running, pid=%d", i, ctx->pid);
|
||||||
|
}
|
||||||
|
g_main_ctx.pid = getpid();
|
||||||
|
hlogi("master start/running, pid=%d", g_main_ctx.pid);
|
||||||
|
if (wait) {
|
||||||
|
while (1) hv_sleep (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
117
external/libhv/libhv-1.3.2/base/hmain.h
vendored
Normal file
117
external/libhv/libhv-1.3.2/base/hmain.h
vendored
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
#ifndef HV_MAIN_H_
|
||||||
|
#define HV_MAIN_H_
|
||||||
|
|
||||||
|
#include "hexport.h"
|
||||||
|
#include "hplatform.h"
|
||||||
|
#include "hdef.h"
|
||||||
|
#include "hproc.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma comment(lib, "winmm.lib") // for timeSetEvent
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BEGIN_EXTERN_C
|
||||||
|
|
||||||
|
typedef struct main_ctx_s {
|
||||||
|
char run_dir[MAX_PATH];
|
||||||
|
char program_name[MAX_PATH];
|
||||||
|
|
||||||
|
char confile[MAX_PATH]; // default etc/${program}.conf
|
||||||
|
char pidfile[MAX_PATH]; // default logs/${program}.pid
|
||||||
|
char logfile[MAX_PATH]; // default logs/${program}.log
|
||||||
|
|
||||||
|
pid_t pid; // getpid
|
||||||
|
pid_t oldpid; // getpid_from_pidfile
|
||||||
|
|
||||||
|
// arg
|
||||||
|
int argc;
|
||||||
|
int arg_len;
|
||||||
|
char** os_argv;
|
||||||
|
char** save_argv;
|
||||||
|
char* cmdline;
|
||||||
|
// parsed arg
|
||||||
|
int arg_kv_size;
|
||||||
|
char** arg_kv;
|
||||||
|
int arg_list_size;
|
||||||
|
char** arg_list;
|
||||||
|
|
||||||
|
// env
|
||||||
|
int envc;
|
||||||
|
int env_len;
|
||||||
|
char** os_envp;
|
||||||
|
char** save_envp;
|
||||||
|
|
||||||
|
// signals
|
||||||
|
procedure_t reload_fn;
|
||||||
|
void* reload_userdata;
|
||||||
|
// master workers model
|
||||||
|
int worker_processes;
|
||||||
|
int worker_threads;
|
||||||
|
procedure_t worker_fn;
|
||||||
|
void* worker_userdata;
|
||||||
|
proc_ctx_t* proc_ctxs;
|
||||||
|
} main_ctx_t;
|
||||||
|
|
||||||
|
// arg_type
|
||||||
|
#define NO_ARGUMENT 0
|
||||||
|
#define REQUIRED_ARGUMENT 1
|
||||||
|
#define OPTIONAL_ARGUMENT 2
|
||||||
|
// option define
|
||||||
|
#define OPTION_PREFIX '-'
|
||||||
|
#define OPTION_DELIM '='
|
||||||
|
#define OPTION_ENABLE "1"
|
||||||
|
#define OPTION_DISABLE "0"
|
||||||
|
typedef struct option_s {
|
||||||
|
char short_opt;
|
||||||
|
const char* long_opt;
|
||||||
|
int arg_type;
|
||||||
|
} option_t;
|
||||||
|
|
||||||
|
HV_EXPORT int main_ctx_init(int argc, char** argv);
|
||||||
|
HV_EXPORT void main_ctx_free(void);
|
||||||
|
|
||||||
|
// ls -a -l
|
||||||
|
// ls -al
|
||||||
|
// watch -n 10 ls
|
||||||
|
// watch -n10 ls
|
||||||
|
HV_EXPORT int parse_opt(int argc, char** argv, const char* opt);
|
||||||
|
// gcc -g -Wall -O3 -std=cpp main.c
|
||||||
|
HV_EXPORT int parse_opt_long(int argc, char** argv, const option_t* long_options, int size);
|
||||||
|
HV_EXPORT const char* get_arg(const char* key);
|
||||||
|
HV_EXPORT const char* get_env(const char* key);
|
||||||
|
|
||||||
|
#if defined(OS_UNIX) && !HAVE_SETPROCTITLE
|
||||||
|
HV_EXPORT void setproctitle(const char* fmt, ...);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// pidfile
|
||||||
|
HV_EXPORT int create_pidfile();
|
||||||
|
HV_EXPORT void delete_pidfile(void);
|
||||||
|
HV_EXPORT pid_t getpid_from_pidfile();
|
||||||
|
|
||||||
|
// signal=[start,stop,restart,status,reload]
|
||||||
|
HV_EXPORT int signal_init(procedure_t reload_fn DEFAULT(NULL), void* reload_userdata DEFAULT(NULL));
|
||||||
|
HV_EXPORT void signal_handle(const char* signal);
|
||||||
|
#ifdef OS_UNIX
|
||||||
|
// we use SIGTERM to quit process, SIGUSR1 to reload confile
|
||||||
|
#define SIGNAL_TERMINATE SIGTERM
|
||||||
|
#define SIGNAL_RELOAD SIGUSR1
|
||||||
|
void signal_handler(int signo);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// global var
|
||||||
|
#define DEFAULT_WORKER_PROCESSES 4
|
||||||
|
#define MAXNUM_WORKER_PROCESSES 256
|
||||||
|
HV_EXPORT extern main_ctx_t g_main_ctx;
|
||||||
|
|
||||||
|
// master-workers processes
|
||||||
|
HV_EXPORT int master_workers_run(
|
||||||
|
procedure_t worker_fn,
|
||||||
|
void* worker_userdata DEFAULT(NULL),
|
||||||
|
int worker_processes DEFAULT(DEFAULT_WORKER_PROCESSES),
|
||||||
|
int worker_threads DEFAULT(0),
|
||||||
|
bool wait DEFAULT(true));
|
||||||
|
|
||||||
|
END_EXTERN_C
|
||||||
|
|
||||||
|
#endif // HV_MAIN_H_
|
68
external/libhv/libhv-1.3.2/base/hmath.h
vendored
Normal file
68
external/libhv/libhv-1.3.2/base/hmath.h
vendored
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#ifndef HV_MATH_H_
|
||||||
|
#define HV_MATH_H_
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
static inline unsigned long floor2e(unsigned long num) {
|
||||||
|
unsigned long n = num;
|
||||||
|
int e = 0;
|
||||||
|
while (n>>=1) ++e;
|
||||||
|
unsigned long ret = 1;
|
||||||
|
while (e--) ret<<=1;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned long ceil2e(unsigned long num) {
|
||||||
|
// 2**0 = 1
|
||||||
|
if (num == 0 || num == 1) return 1;
|
||||||
|
unsigned long n = num - 1;
|
||||||
|
int e = 1;
|
||||||
|
while (n>>=1) ++e;
|
||||||
|
unsigned long ret = 1;
|
||||||
|
while (e--) ret<<=1;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// varint little-endian
|
||||||
|
// MSB
|
||||||
|
static inline int varint_encode(long long value, unsigned char* buf) {
|
||||||
|
unsigned char ch;
|
||||||
|
unsigned char *p = buf;
|
||||||
|
int bytes = 0;
|
||||||
|
do {
|
||||||
|
ch = value & 0x7F;
|
||||||
|
value >>= 7;
|
||||||
|
*p++ = value == 0 ? ch : (ch | 0x80);
|
||||||
|
++bytes;
|
||||||
|
} while (value);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @param[IN|OUT] len: in=>buflen, out=>varint bytesize
|
||||||
|
static inline long long varint_decode(const unsigned char* buf, int* len) {
|
||||||
|
long long ret = 0;
|
||||||
|
int bytes = 0, bits = 0;
|
||||||
|
const unsigned char *p = buf;
|
||||||
|
do {
|
||||||
|
if (len && *len && bytes == *len) {
|
||||||
|
// Not enough length
|
||||||
|
*len = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ret |= ((long long)(*p & 0x7F)) << bits;
|
||||||
|
++bytes;
|
||||||
|
if ((*p & 0x80) == 0) {
|
||||||
|
// Found end
|
||||||
|
if (len) *len = bytes;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
bits += 7;
|
||||||
|
} while(bytes < 10);
|
||||||
|
|
||||||
|
// Not found end
|
||||||
|
if (len) *len = -1;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // HV_MATH_H_
|
268
external/libhv/libhv-1.3.2/base/hmutex.h
vendored
Normal file
268
external/libhv/libhv-1.3.2/base/hmutex.h
vendored
Normal file
|
@ -0,0 +1,268 @@
|
||||||
|
#ifndef HV_MUTEX_H_
|
||||||
|
#define HV_MUTEX_H_
|
||||||
|
|
||||||
|
#include "hexport.h"
|
||||||
|
#include "hplatform.h"
|
||||||
|
#include "htime.h"
|
||||||
|
|
||||||
|
BEGIN_EXTERN_C
|
||||||
|
|
||||||
|
#ifdef OS_WIN
|
||||||
|
#define hmutex_t CRITICAL_SECTION
|
||||||
|
#define hmutex_init InitializeCriticalSection
|
||||||
|
#define hmutex_destroy DeleteCriticalSection
|
||||||
|
#define hmutex_lock EnterCriticalSection
|
||||||
|
#define hmutex_unlock LeaveCriticalSection
|
||||||
|
|
||||||
|
#define hrecursive_mutex_t CRITICAL_SECTION
|
||||||
|
#define hrecursive_mutex_init InitializeCriticalSection
|
||||||
|
#define hrecursive_mutex_destroy DeleteCriticalSection
|
||||||
|
#define hrecursive_mutex_lock EnterCriticalSection
|
||||||
|
#define hrecursive_mutex_unlock LeaveCriticalSection
|
||||||
|
|
||||||
|
#define HSPINLOCK_COUNT -1
|
||||||
|
#define hspinlock_t CRITICAL_SECTION
|
||||||
|
#define hspinlock_init(pspin) InitializeCriticalSectionAndSpinCount(pspin, HSPINLOCK_COUNT)
|
||||||
|
#define hspinlock_destroy DeleteCriticalSection
|
||||||
|
#define hspinlock_lock EnterCriticalSection
|
||||||
|
#define hspinlock_unlock LeaveCriticalSection
|
||||||
|
|
||||||
|
#define hrwlock_t SRWLOCK
|
||||||
|
#define hrwlock_init InitializeSRWLock
|
||||||
|
#define hrwlock_destroy(plock)
|
||||||
|
#define hrwlock_rdlock AcquireSRWLockShared
|
||||||
|
#define hrwlock_rdunlock ReleaseSRWLockShared
|
||||||
|
#define hrwlock_wrlock AcquireSRWLockExclusive
|
||||||
|
#define hrwlock_wrunlock ReleaseSRWLockExclusive
|
||||||
|
|
||||||
|
#define htimed_mutex_t HANDLE
|
||||||
|
#define htimed_mutex_init(pmutex) *(pmutex) = CreateMutex(NULL, FALSE, NULL)
|
||||||
|
#define htimed_mutex_destroy(pmutex) CloseHandle(*(pmutex))
|
||||||
|
#define htimed_mutex_lock(pmutex) WaitForSingleObject(*(pmutex), INFINITE)
|
||||||
|
#define htimed_mutex_unlock(pmutex) ReleaseMutex(*(pmutex))
|
||||||
|
// true: WAIT_OBJECT_0
|
||||||
|
// false: WAIT_OBJECT_TIMEOUT
|
||||||
|
#define htimed_mutex_lock_for(pmutex, ms) ( WaitForSingleObject(*(pmutex), ms) == WAIT_OBJECT_0 )
|
||||||
|
|
||||||
|
#define hcondvar_t CONDITION_VARIABLE
|
||||||
|
#define hcondvar_init InitializeConditionVariable
|
||||||
|
#define hcondvar_destroy(pcond)
|
||||||
|
#define hcondvar_wait(pcond, pmutex) SleepConditionVariableCS(pcond, pmutex, INFINITE)
|
||||||
|
#define hcondvar_wait_for(pcond, pmutex, ms) SleepConditionVariableCS(pcond, pmutex, ms)
|
||||||
|
#define hcondvar_signal WakeConditionVariable
|
||||||
|
#define hcondvar_broadcast WakeAllConditionVariable
|
||||||
|
|
||||||
|
#define honce_t INIT_ONCE
|
||||||
|
#define HONCE_INIT INIT_ONCE_STATIC_INIT
|
||||||
|
typedef void (*honce_fn)();
|
||||||
|
static inline BOOL WINAPI s_once_func(INIT_ONCE* once, PVOID arg, PVOID* _) {
|
||||||
|
honce_fn fn = (honce_fn)arg;
|
||||||
|
fn();
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
static inline void honce(honce_t* once, honce_fn fn) {
|
||||||
|
PVOID dummy = NULL;
|
||||||
|
InitOnceExecuteOnce(once, s_once_func, (PVOID)fn, &dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define hsem_t HANDLE
|
||||||
|
#define hsem_init(psem, value) *(psem) = CreateSemaphore(NULL, value, value+100000, NULL)
|
||||||
|
#define hsem_destroy(psem) CloseHandle(*(psem))
|
||||||
|
#define hsem_wait(psem) WaitForSingleObject(*(psem), INFINITE)
|
||||||
|
#define hsem_post(psem) ReleaseSemaphore(*(psem), 1, NULL)
|
||||||
|
// true: WAIT_OBJECT_0
|
||||||
|
// false: WAIT_OBJECT_TIMEOUT
|
||||||
|
#define hsem_wait_for(psem, ms) ( WaitForSingleObject(*(psem), ms) == WAIT_OBJECT_0 )
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define hmutex_t pthread_mutex_t
|
||||||
|
#define hmutex_init(pmutex) pthread_mutex_init(pmutex, NULL)
|
||||||
|
#define hmutex_destroy pthread_mutex_destroy
|
||||||
|
#define hmutex_lock pthread_mutex_lock
|
||||||
|
#define hmutex_unlock pthread_mutex_unlock
|
||||||
|
|
||||||
|
#define hrecursive_mutex_t pthread_mutex_t
|
||||||
|
#define hrecursive_mutex_init(pmutex) \
|
||||||
|
do {\
|
||||||
|
pthread_mutexattr_t attr;\
|
||||||
|
pthread_mutexattr_init(&attr);\
|
||||||
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);\
|
||||||
|
pthread_mutex_init(pmutex, &attr);\
|
||||||
|
} while(0)
|
||||||
|
#define hrecursive_mutex_destroy pthread_mutex_destroy
|
||||||
|
#define hrecursive_mutex_lock pthread_mutex_lock
|
||||||
|
#define hrecursive_mutex_unlock pthread_mutex_unlock
|
||||||
|
|
||||||
|
#if HAVE_PTHREAD_SPIN_LOCK
|
||||||
|
#define hspinlock_t pthread_spinlock_t
|
||||||
|
#define hspinlock_init(pspin) pthread_spin_init(pspin, PTHREAD_PROCESS_PRIVATE)
|
||||||
|
#define hspinlock_destroy pthread_spin_destroy
|
||||||
|
#define hspinlock_lock pthread_spin_lock
|
||||||
|
#define hspinlock_unlock pthread_spin_unlock
|
||||||
|
#else
|
||||||
|
#define hspinlock_t pthread_mutex_t
|
||||||
|
#define hspinlock_init(pmutex) pthread_mutex_init(pmutex, NULL)
|
||||||
|
#define hspinlock_destroy pthread_mutex_destroy
|
||||||
|
#define hspinlock_lock pthread_mutex_lock
|
||||||
|
#define hspinlock_unlock pthread_mutex_unlock
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define hrwlock_t pthread_rwlock_t
|
||||||
|
#define hrwlock_init(prwlock) pthread_rwlock_init(prwlock, NULL)
|
||||||
|
#define hrwlock_destroy pthread_rwlock_destroy
|
||||||
|
#define hrwlock_rdlock pthread_rwlock_rdlock
|
||||||
|
#define hrwlock_rdunlock pthread_rwlock_unlock
|
||||||
|
#define hrwlock_wrlock pthread_rwlock_wrlock
|
||||||
|
#define hrwlock_wrunlock pthread_rwlock_unlock
|
||||||
|
|
||||||
|
#define htimed_mutex_t pthread_mutex_t
|
||||||
|
#define htimed_mutex_init(pmutex) pthread_mutex_init(pmutex, NULL)
|
||||||
|
#define htimed_mutex_destroy pthread_mutex_destroy
|
||||||
|
#define htimed_mutex_lock pthread_mutex_lock
|
||||||
|
#define htimed_mutex_unlock pthread_mutex_unlock
|
||||||
|
static inline void timespec_after(struct timespec* ts, unsigned int ms) {
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
ts->tv_sec = tv.tv_sec + ms / 1000;
|
||||||
|
ts->tv_nsec = tv.tv_usec * 1000 + ms % 1000 * 1000000;
|
||||||
|
if (ts->tv_nsec >= 1000000000) {
|
||||||
|
ts->tv_nsec -= 1000000000;
|
||||||
|
ts->tv_sec += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// true: OK
|
||||||
|
// false: ETIMEDOUT
|
||||||
|
static inline int htimed_mutex_lock_for(htimed_mutex_t* mutex, unsigned int ms) {
|
||||||
|
#if HAVE_PTHREAD_MUTEX_TIMEDLOCK
|
||||||
|
struct timespec ts;
|
||||||
|
timespec_after(&ts, ms);
|
||||||
|
return pthread_mutex_timedlock(mutex, &ts) != ETIMEDOUT;
|
||||||
|
#else
|
||||||
|
int ret = 0;
|
||||||
|
unsigned int end = gettick_ms() + ms;
|
||||||
|
while ((ret = pthread_mutex_trylock(mutex)) != 0) {
|
||||||
|
if (gettick_ms() >= end) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hv_msleep(1);
|
||||||
|
}
|
||||||
|
return ret == 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#define hcondvar_t pthread_cond_t
|
||||||
|
#define hcondvar_init(pcond) pthread_cond_init(pcond, NULL)
|
||||||
|
#define hcondvar_destroy pthread_cond_destroy
|
||||||
|
#define hcondvar_wait pthread_cond_wait
|
||||||
|
#define hcondvar_signal pthread_cond_signal
|
||||||
|
#define hcondvar_broadcast pthread_cond_broadcast
|
||||||
|
// true: OK
|
||||||
|
// false: ETIMEDOUT
|
||||||
|
static inline int hcondvar_wait_for(hcondvar_t* cond, hmutex_t* mutex, unsigned int ms) {
|
||||||
|
struct timespec ts;
|
||||||
|
timespec_after(&ts, ms);
|
||||||
|
return pthread_cond_timedwait(cond, mutex, &ts) != ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define honce_t pthread_once_t
|
||||||
|
#define HONCE_INIT PTHREAD_ONCE_INIT
|
||||||
|
#define honce pthread_once
|
||||||
|
|
||||||
|
#include <semaphore.h>
|
||||||
|
#define hsem_t sem_t
|
||||||
|
#define hsem_init(psem, value) sem_init(psem, 0, value)
|
||||||
|
#define hsem_destroy sem_destroy
|
||||||
|
#define hsem_wait sem_wait
|
||||||
|
#define hsem_post sem_post
|
||||||
|
// true: OK
|
||||||
|
// false: ETIMEDOUT
|
||||||
|
static inline int hsem_wait_for(hsem_t* sem, unsigned int ms) {
|
||||||
|
#if HAVE_SEM_TIMEDWAIT
|
||||||
|
struct timespec ts;
|
||||||
|
timespec_after(&ts, ms);
|
||||||
|
return sem_timedwait(sem, &ts) != ETIMEDOUT;
|
||||||
|
#else
|
||||||
|
int ret = 0;
|
||||||
|
unsigned int end = gettick_ms() + ms;
|
||||||
|
while ((ret = sem_trywait(sem)) != 0) {
|
||||||
|
if (gettick_ms() >= end) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hv_msleep(1);
|
||||||
|
}
|
||||||
|
return ret == 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
END_EXTERN_C
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
// using std::mutex;
|
||||||
|
// NOTE: test std::timed_mutex incorrect in some platforms, use htimed_mutex_t
|
||||||
|
// using std::timed_mutex;
|
||||||
|
using std::condition_variable;
|
||||||
|
using std::lock_guard;
|
||||||
|
using std::unique_lock;
|
||||||
|
|
||||||
|
BEGIN_NAMESPACE_HV
|
||||||
|
|
||||||
|
class MutexLock {
|
||||||
|
public:
|
||||||
|
MutexLock() { hmutex_init(&_mutex); }
|
||||||
|
~MutexLock() { hmutex_destroy(&_mutex); }
|
||||||
|
|
||||||
|
void lock() { hmutex_lock(&_mutex); }
|
||||||
|
void unlock() { hmutex_unlock(&_mutex); }
|
||||||
|
protected:
|
||||||
|
hmutex_t _mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SpinLock {
|
||||||
|
public:
|
||||||
|
SpinLock() { hspinlock_init(&_spin); }
|
||||||
|
~SpinLock() { hspinlock_destroy(&_spin); }
|
||||||
|
|
||||||
|
void lock() { hspinlock_lock(&_spin); }
|
||||||
|
void unlock() { hspinlock_unlock(&_spin); }
|
||||||
|
protected:
|
||||||
|
hspinlock_t _spin;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RWLock {
|
||||||
|
public:
|
||||||
|
RWLock() { hrwlock_init(&_rwlock); }
|
||||||
|
~RWLock() { hrwlock_destroy(&_rwlock); }
|
||||||
|
|
||||||
|
void rdlock() { hrwlock_rdlock(&_rwlock); }
|
||||||
|
void rdunlock() { hrwlock_rdunlock(&_rwlock); }
|
||||||
|
|
||||||
|
void wrlock() { hrwlock_wrlock(&_rwlock); }
|
||||||
|
void wrunlock() { hrwlock_wrunlock(&_rwlock); }
|
||||||
|
|
||||||
|
void lock() { rdlock(); }
|
||||||
|
void unlock() { rdunlock(); }
|
||||||
|
protected:
|
||||||
|
hrwlock_t _rwlock;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class LockGuard {
|
||||||
|
public:
|
||||||
|
LockGuard(T& t) : _lock(t) { _lock.lock(); }
|
||||||
|
~LockGuard() { _lock.unlock(); }
|
||||||
|
protected:
|
||||||
|
T& _lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
END_NAMESPACE_HV
|
||||||
|
|
||||||
|
// same as java synchronized(lock) { ... }
|
||||||
|
#define synchronized(lock) for (std::lock_guard<std::mutex> _lock_(lock), *p = &_lock_; p != NULL; p = NULL)
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // HV_MUTEX_H_
|
330
external/libhv/libhv-1.3.2/base/hplatform.h
vendored
Normal file
330
external/libhv/libhv-1.3.2/base/hplatform.h
vendored
Normal file
|
@ -0,0 +1,330 @@
|
||||||
|
#ifndef HV_PLATFORM_H_
|
||||||
|
#define HV_PLATFORM_H_
|
||||||
|
|
||||||
|
#include "hconfig.h"
|
||||||
|
|
||||||
|
// OS
|
||||||
|
#if defined(WIN64) || defined(_WIN64)
|
||||||
|
#define OS_WIN64
|
||||||
|
#define OS_WIN32
|
||||||
|
#elif defined(WIN32)|| defined(_WIN32)
|
||||||
|
#define OS_WIN32
|
||||||
|
#elif defined(ANDROID) || defined(__ANDROID__)
|
||||||
|
#define OS_ANDROID
|
||||||
|
#define OS_LINUX
|
||||||
|
#elif defined(linux) || defined(__linux) || defined(__linux__)
|
||||||
|
#define OS_LINUX
|
||||||
|
#elif defined(__APPLE__) && (defined(__GNUC__) || defined(__xlC__) || defined(__xlc__))
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
#if defined(TARGET_OS_MAC) && TARGET_OS_MAC
|
||||||
|
#define OS_MAC
|
||||||
|
#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
|
||||||
|
#define OS_IOS
|
||||||
|
#endif
|
||||||
|
#define OS_DARWIN
|
||||||
|
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||||
|
#define OS_FREEBSD
|
||||||
|
#define OS_BSD
|
||||||
|
#elif defined(__NetBSD__)
|
||||||
|
#define OS_NETBSD
|
||||||
|
#define OS_BSD
|
||||||
|
#elif defined(__OpenBSD__)
|
||||||
|
#define OS_OPENBSD
|
||||||
|
#define OS_BSD
|
||||||
|
#elif defined(sun) || defined(__sun) || defined(__sun__)
|
||||||
|
#define OS_SOLARIS
|
||||||
|
#else
|
||||||
|
#warning "Untested operating system platform!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OS_WIN32) || defined(OS_WIN64)
|
||||||
|
#undef OS_UNIX
|
||||||
|
#define OS_WIN
|
||||||
|
#else
|
||||||
|
#define OS_UNIX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ARCH
|
||||||
|
#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
|
||||||
|
#define ARCH_X64
|
||||||
|
#define ARCH_X86_64
|
||||||
|
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
|
||||||
|
#define ARCH_X86
|
||||||
|
#define ARCH_X86_32
|
||||||
|
#elif defined(__aarch64__) || defined(__ARM64__) || defined(_M_ARM64)
|
||||||
|
#define ARCH_ARM64
|
||||||
|
#elif defined(__arm__) || defined(_M_ARM)
|
||||||
|
#define ARCH_ARM
|
||||||
|
#elif defined(__mips64__)
|
||||||
|
#define ARCH_MIPS64
|
||||||
|
#elif defined(__mips__)
|
||||||
|
#define ARCH_MIPS
|
||||||
|
#else
|
||||||
|
#warning "Untested hardware architecture!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// COMPILER
|
||||||
|
#if defined (_MSC_VER)
|
||||||
|
#define COMPILER_MSVC
|
||||||
|
|
||||||
|
#if (_MSC_VER < 1200) // Visual C++ 6.0
|
||||||
|
#define MSVS_VERSION 1998
|
||||||
|
#define MSVC_VERSION 60
|
||||||
|
#elif (_MSC_VER >= 1200) && (_MSC_VER < 1300) // Visual Studio 2002, MSVC++ 7.0
|
||||||
|
#define MSVS_VERSION 2002
|
||||||
|
#define MSVC_VERSION 70
|
||||||
|
#elif (_MSC_VER >= 1300) && (_MSC_VER < 1400) // Visual Studio 2003, MSVC++ 7.1
|
||||||
|
#define MSVS_VERSION 2003
|
||||||
|
#define MSVC_VERSION 71
|
||||||
|
#elif (_MSC_VER >= 1400) && (_MSC_VER < 1500) // Visual Studio 2005, MSVC++ 8.0
|
||||||
|
#define MSVS_VERSION 2005
|
||||||
|
#define MSVC_VERSION 80
|
||||||
|
#elif (_MSC_VER >= 1500) && (_MSC_VER < 1600) // Visual Studio 2008, MSVC++ 9.0
|
||||||
|
#define MSVS_VERSION 2008
|
||||||
|
#define MSVC_VERSION 90
|
||||||
|
#elif (_MSC_VER >= 1600) && (_MSC_VER < 1700) // Visual Studio 2010, MSVC++ 10.0
|
||||||
|
#define MSVS_VERSION 2010
|
||||||
|
#define MSVC_VERSION 100
|
||||||
|
#elif (_MSC_VER >= 1700) && (_MSC_VER < 1800) // Visual Studio 2012, MSVC++ 11.0
|
||||||
|
#define MSVS_VERSION 2012
|
||||||
|
#define MSVC_VERSION 110
|
||||||
|
#elif (_MSC_VER >= 1800) && (_MSC_VER < 1900) // Visual Studio 2013, MSVC++ 12.0
|
||||||
|
#define MSVS_VERSION 2013
|
||||||
|
#define MSVC_VERSION 120
|
||||||
|
#elif (_MSC_VER >= 1900) && (_MSC_VER < 1910) // Visual Studio 2015, MSVC++ 14.0
|
||||||
|
#define MSVS_VERSION 2015
|
||||||
|
#define MSVC_VERSION 140
|
||||||
|
#elif (_MSC_VER >= 1910) && (_MSC_VER < 1920) // Visual Studio 2017, MSVC++ 15.0
|
||||||
|
#define MSVS_VERSION 2017
|
||||||
|
#define MSVC_VERSION 150
|
||||||
|
#elif (_MSC_VER >= 1920) && (_MSC_VER < 2000) // Visual Studio 2019, MSVC++ 16.0
|
||||||
|
#define MSVS_VERSION 2019
|
||||||
|
#define MSVC_VERSION 160
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef HAVE_STDATOMIC_H
|
||||||
|
#define HAVE_STDATOMIC_H 0
|
||||||
|
#undef HAVE_SYS_TIME_H
|
||||||
|
#define HAVE_SYS_TIME_H 0
|
||||||
|
#undef HAVE_PTHREAD_H
|
||||||
|
#define HAVE_PTHREAD_H 0
|
||||||
|
|
||||||
|
#pragma warning (disable: 4018) // signed/unsigned comparison
|
||||||
|
#pragma warning (disable: 4100) // unused param
|
||||||
|
#pragma warning (disable: 4102) // unreferenced label
|
||||||
|
#pragma warning (disable: 4244) // conversion loss of data
|
||||||
|
#pragma warning (disable: 4267) // size_t => int
|
||||||
|
#pragma warning (disable: 4819) // Unicode
|
||||||
|
#pragma warning (disable: 4996) // _CRT_SECURE_NO_WARNINGS
|
||||||
|
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define COMPILER_GCC
|
||||||
|
|
||||||
|
#ifndef _GNU_SOURCE
|
||||||
|
#define _GNU_SOURCE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(__clang__)
|
||||||
|
#define COMPILER_CLANG
|
||||||
|
|
||||||
|
#elif defined(__MINGW32__) || defined(__MINGW64__)
|
||||||
|
#define COMPILER_MINGW
|
||||||
|
|
||||||
|
#elif defined(__MSYS__)
|
||||||
|
#define COMPILER_MSYS
|
||||||
|
|
||||||
|
#elif defined(__CYGWIN__)
|
||||||
|
#define COMPILER_CYGWIN
|
||||||
|
|
||||||
|
#else
|
||||||
|
#warning "Untested compiler!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// headers
|
||||||
|
#ifdef OS_WIN
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#ifndef _CRT_NONSTDC_NO_DEPRECATE
|
||||||
|
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||||
|
#endif
|
||||||
|
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
|
||||||
|
#define _WINSOCK_DEPRECATED_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h> // for inet_pton,inet_ntop
|
||||||
|
#include <windows.h>
|
||||||
|
#include <process.h> // for getpid,exec
|
||||||
|
#include <direct.h> // for mkdir,rmdir,chdir,getcwd
|
||||||
|
#include <io.h> // for open,close,read,write,lseek,tell
|
||||||
|
|
||||||
|
#define hv_sleep(s) Sleep((s) * 1000)
|
||||||
|
#define hv_msleep(ms) Sleep(ms)
|
||||||
|
#define hv_usleep(us) Sleep((us) / 1000)
|
||||||
|
#define hv_delay(ms) hv_msleep(ms)
|
||||||
|
#define hv_mkdir(dir) mkdir(dir)
|
||||||
|
|
||||||
|
// access
|
||||||
|
#ifndef F_OK
|
||||||
|
#define F_OK 0 /* test for existence of file */
|
||||||
|
#endif
|
||||||
|
#ifndef X_OK
|
||||||
|
#define X_OK (1<<0) /* test for execute or search permission */
|
||||||
|
#endif
|
||||||
|
#ifndef W_OK
|
||||||
|
#define W_OK (1<<1) /* test for write permission */
|
||||||
|
#endif
|
||||||
|
#ifndef R_OK
|
||||||
|
#define R_OK (1<<2) /* test for read permission */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// stat
|
||||||
|
#ifndef S_ISREG
|
||||||
|
#define S_ISREG(st_mode) (((st_mode) & S_IFMT) == S_IFREG)
|
||||||
|
#endif
|
||||||
|
#ifndef S_ISDIR
|
||||||
|
#define S_ISDIR(st_mode) (((st_mode) & S_IFMT) == S_IFDIR)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dirent.h> // for mkdir,rmdir,chdir,getcwd
|
||||||
|
|
||||||
|
// socket
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <netinet/udp.h>
|
||||||
|
#include <netdb.h> // for gethostbyname
|
||||||
|
|
||||||
|
#define hv_sleep(s) sleep(s)
|
||||||
|
#define hv_msleep(ms) usleep((ms) * 1000)
|
||||||
|
#define hv_usleep(us) usleep(us)
|
||||||
|
#define hv_delay(ms) hv_msleep(ms)
|
||||||
|
#define hv_mkdir(dir) mkdir(dir, 0777)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
typedef int pid_t;
|
||||||
|
typedef int gid_t;
|
||||||
|
typedef int uid_t;
|
||||||
|
#define strcasecmp stricmp
|
||||||
|
#define strncasecmp strnicmp
|
||||||
|
#else
|
||||||
|
typedef int BOOL;
|
||||||
|
typedef unsigned char BYTE;
|
||||||
|
typedef unsigned short WORD;
|
||||||
|
typedef void* HANDLE;
|
||||||
|
#include <strings.h>
|
||||||
|
#define stricmp strcasecmp
|
||||||
|
#define strnicmp strncasecmp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ENDIAN
|
||||||
|
#ifndef BIG_ENDIAN
|
||||||
|
#define BIG_ENDIAN 4321
|
||||||
|
#endif
|
||||||
|
#ifndef LITTLE_ENDIAN
|
||||||
|
#define LITTLE_ENDIAN 1234
|
||||||
|
#endif
|
||||||
|
#ifndef NET_ENDIAN
|
||||||
|
#define NET_ENDIAN BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// BYTE_ORDER
|
||||||
|
#ifndef BYTE_ORDER
|
||||||
|
#if defined(__BYTE_ORDER)
|
||||||
|
#define BYTE_ORDER __BYTE_ORDER
|
||||||
|
#elif defined(__BYTE_ORDER__)
|
||||||
|
#define BYTE_ORDER __BYTE_ORDER__
|
||||||
|
#elif defined(ARCH_X86) || defined(ARCH_X86_64) || \
|
||||||
|
defined(__ARMEL__) || defined(__AARCH64EL__) || \
|
||||||
|
defined(__MIPSEL) || defined(__MIPS64EL)
|
||||||
|
#define BYTE_ORDER LITTLE_ENDIAN
|
||||||
|
#elif defined(__ARMEB__) || defined(__AARCH64EB__) || \
|
||||||
|
defined(__MIPSEB) || defined(__MIPS64EB)
|
||||||
|
#define BYTE_ORDER BIG_ENDIAN
|
||||||
|
#elif defined(OS_WIN)
|
||||||
|
#define BYTE_ORDER LITTLE_ENDIAN
|
||||||
|
#else
|
||||||
|
#warning "Unknown byte order!"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ANSI C
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
#if HAVE_STDBOOL_H
|
||||||
|
#include <stdbool.h>
|
||||||
|
#else
|
||||||
|
#ifndef bool
|
||||||
|
#define bool char
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef true
|
||||||
|
#define true 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef false
|
||||||
|
#define false 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_STDINT_H
|
||||||
|
#include <stdint.h>
|
||||||
|
#elif defined(_MSC_VER) && _MSC_VER < 1700
|
||||||
|
typedef __int8 int8_t;
|
||||||
|
typedef __int16 int16_t;
|
||||||
|
typedef __int32 int32_t;
|
||||||
|
typedef __int64 int64_t;
|
||||||
|
typedef unsigned __int8 uint8_t;
|
||||||
|
typedef unsigned __int16 uint16_t;
|
||||||
|
typedef unsigned __int32 uint32_t;
|
||||||
|
typedef unsigned __int64 uint64_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef float float32_t;
|
||||||
|
typedef double float64_t;
|
||||||
|
|
||||||
|
typedef int (*method_t)(void* userdata);
|
||||||
|
typedef void (*procedure_t)(void* userdata);
|
||||||
|
|
||||||
|
#if HAVE_SYS_TYPES_H
|
||||||
|
#include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_SYS_STAT_H
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_SYS_TIME_H
|
||||||
|
#include <sys/time.h> // for gettimeofday
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_FCNTL_H
|
||||||
|
#include <fcntl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_PTHREAD_H
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // HV_PLATFORM_H_
|
69
external/libhv/libhv-1.3.2/base/hproc.h
vendored
Normal file
69
external/libhv/libhv-1.3.2/base/hproc.h
vendored
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#ifndef HV_PROC_H_
|
||||||
|
#define HV_PROC_H_
|
||||||
|
|
||||||
|
#include "hplatform.h"
|
||||||
|
|
||||||
|
typedef struct proc_ctx_s {
|
||||||
|
pid_t pid; // tid in Windows
|
||||||
|
time_t start_time;
|
||||||
|
int spawn_cnt;
|
||||||
|
procedure_t init;
|
||||||
|
void* init_userdata;
|
||||||
|
procedure_t proc;
|
||||||
|
void* proc_userdata;
|
||||||
|
procedure_t exit;
|
||||||
|
void* exit_userdata;
|
||||||
|
} proc_ctx_t;
|
||||||
|
|
||||||
|
static inline void hproc_run(proc_ctx_t* ctx) {
|
||||||
|
if (ctx->init) {
|
||||||
|
ctx->init(ctx->init_userdata);
|
||||||
|
}
|
||||||
|
if (ctx->proc) {
|
||||||
|
ctx->proc(ctx->proc_userdata);
|
||||||
|
}
|
||||||
|
if (ctx->exit) {
|
||||||
|
ctx->exit(ctx->exit_userdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef OS_UNIX
|
||||||
|
// unix use multi-processes
|
||||||
|
static inline int hproc_spawn(proc_ctx_t* ctx) {
|
||||||
|
++ctx->spawn_cnt;
|
||||||
|
ctx->start_time = time(NULL);
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
perror("fork");
|
||||||
|
return -1;
|
||||||
|
} else if (pid == 0) {
|
||||||
|
// child process
|
||||||
|
ctx->pid = getpid();
|
||||||
|
hproc_run(ctx);
|
||||||
|
exit(0);
|
||||||
|
} else if (pid > 0) {
|
||||||
|
// parent process
|
||||||
|
ctx->pid = pid;
|
||||||
|
}
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
#elif defined(OS_WIN)
|
||||||
|
// win32 use multi-threads
|
||||||
|
static void win_thread(void* userdata) {
|
||||||
|
proc_ctx_t* ctx = (proc_ctx_t*)userdata;
|
||||||
|
ctx->pid = GetCurrentThreadId(); // tid in Windows
|
||||||
|
hproc_run(ctx);
|
||||||
|
}
|
||||||
|
static inline int hproc_spawn(proc_ctx_t* ctx) {
|
||||||
|
++ctx->spawn_cnt;
|
||||||
|
ctx->start_time = time(NULL);
|
||||||
|
HANDLE h = (HANDLE)_beginthread(win_thread, 0, ctx);
|
||||||
|
if (h == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ctx->pid = GetThreadId(h); // tid in Windows
|
||||||
|
return ctx->pid;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // HV_PROC_H_
|
408
external/libhv/libhv-1.3.2/base/hsocket.c
vendored
Normal file
408
external/libhv/libhv-1.3.2/base/hsocket.c
vendored
Normal file
|
@ -0,0 +1,408 @@
|
||||||
|
#include "hsocket.h"
|
||||||
|
|
||||||
|
#include "hdef.h"
|
||||||
|
|
||||||
|
#ifdef OS_WIN
|
||||||
|
#include "hatomic.h"
|
||||||
|
static hatomic_flag_t s_wsa_initialized = HATOMIC_FLAG_INIT;
|
||||||
|
void WSAInit() {
|
||||||
|
if (!hatomic_flag_test_and_set(&s_wsa_initialized)) {
|
||||||
|
WSADATA wsadata;
|
||||||
|
WSAStartup(MAKEWORD(2, 2), &wsadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WSADeinit() {
|
||||||
|
if (hatomic_flag_test_and_set(&s_wsa_initialized)) {
|
||||||
|
hatomic_flag_clear(&s_wsa_initialized);
|
||||||
|
WSACleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline int socket_errno_negative(int sockfd) {
|
||||||
|
int err = socket_errno();
|
||||||
|
if (sockfd >= 0) closesocket(sockfd);
|
||||||
|
return err > 0 ? -err : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* socket_strerror(int err) {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
static char buffer[128];
|
||||||
|
|
||||||
|
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
|
||||||
|
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||||||
|
FORMAT_MESSAGE_MAX_WIDTH_MASK,
|
||||||
|
0, ABS(err), 0, buffer, sizeof(buffer), NULL);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
#else
|
||||||
|
return strerror(ABS(err));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_ipv4(const char* host) {
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
return inet_pton(AF_INET, host, &sin) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_ipv6(const char* host) {
|
||||||
|
struct sockaddr_in6 sin6;
|
||||||
|
return inet_pton(AF_INET6, host, &sin6) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ResolveAddr(const char* host, sockaddr_u* addr) {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
WSAInit();
|
||||||
|
#endif
|
||||||
|
if (inet_pton(AF_INET, host, &addr->sin.sin_addr) == 1) {
|
||||||
|
addr->sa.sa_family = AF_INET; // host is ipv4, so easy ;)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inet_pton(AF_INET6, host, &addr->sin6.sin6_addr) == 1) {
|
||||||
|
addr->sa.sa_family = AF_INET6; // host is ipv6
|
||||||
|
}
|
||||||
|
|
||||||
|
struct addrinfo* ais = NULL;
|
||||||
|
int ret = getaddrinfo(host, NULL, NULL, &ais);
|
||||||
|
if (ret != 0 || ais == NULL || ais->ai_addr == NULL || ais->ai_addrlen == 0) {
|
||||||
|
printd("unknown host: %s err:%d:%s\n", host, ret, gai_strerror(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
struct addrinfo* pai = ais;
|
||||||
|
while (pai != NULL) {
|
||||||
|
if (pai->ai_family == AF_INET) break;
|
||||||
|
pai = pai->ai_next;
|
||||||
|
}
|
||||||
|
if (pai == NULL) pai = ais;
|
||||||
|
memcpy(addr, pai->ai_addr, pai->ai_addrlen);
|
||||||
|
freeaddrinfo(ais);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* sockaddr_ip(sockaddr_u* addr, char *ip, int len) {
|
||||||
|
if (addr->sa.sa_family == AF_INET) {
|
||||||
|
return inet_ntop(AF_INET, &addr->sin.sin_addr, ip, len);
|
||||||
|
}
|
||||||
|
else if (addr->sa.sa_family == AF_INET6) {
|
||||||
|
return inet_ntop(AF_INET6, &addr->sin6.sin6_addr, ip, len);
|
||||||
|
}
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t sockaddr_port(sockaddr_u* addr) {
|
||||||
|
uint16_t port = 0;
|
||||||
|
if (addr->sa.sa_family == AF_INET) {
|
||||||
|
port = ntohs(addr->sin.sin_port);
|
||||||
|
}
|
||||||
|
else if (addr->sa.sa_family == AF_INET6) {
|
||||||
|
port = ntohs(addr->sin6.sin6_port);
|
||||||
|
}
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sockaddr_set_ip(sockaddr_u* addr, const char* host) {
|
||||||
|
if (!host || *host == '\0') {
|
||||||
|
addr->sin.sin_family = AF_INET;
|
||||||
|
addr->sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ResolveAddr(host, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sockaddr_set_port(sockaddr_u* addr, int port) {
|
||||||
|
if (addr->sa.sa_family == AF_INET) {
|
||||||
|
addr->sin.sin_port = htons(port);
|
||||||
|
}
|
||||||
|
else if (addr->sa.sa_family == AF_INET6) {
|
||||||
|
addr->sin6.sin6_port = htons(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int sockaddr_set_ipport(sockaddr_u* addr, const char* host, int port) {
|
||||||
|
#ifdef ENABLE_UDS
|
||||||
|
if (port < 0) {
|
||||||
|
sockaddr_set_path(addr, host);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
int ret = sockaddr_set_ip(addr, host);
|
||||||
|
if (ret != 0) return ret;
|
||||||
|
sockaddr_set_port(addr, port);
|
||||||
|
// SOCKADDR_PRINT(addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
socklen_t sockaddr_len(sockaddr_u* addr) {
|
||||||
|
if (addr->sa.sa_family == AF_INET) {
|
||||||
|
return sizeof(struct sockaddr_in);
|
||||||
|
}
|
||||||
|
else if (addr->sa.sa_family == AF_INET6) {
|
||||||
|
return sizeof(struct sockaddr_in6);
|
||||||
|
}
|
||||||
|
#ifdef ENABLE_UDS
|
||||||
|
else if (addr->sa.sa_family == AF_UNIX) {
|
||||||
|
return sizeof(struct sockaddr_un);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return sizeof(sockaddr_u);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* sockaddr_str(sockaddr_u* addr, char* buf, int len) {
|
||||||
|
char ip[SOCKADDR_STRLEN] = {0};
|
||||||
|
uint16_t port = 0;
|
||||||
|
if (addr->sa.sa_family == AF_INET) {
|
||||||
|
inet_ntop(AF_INET, &addr->sin.sin_addr, ip, len);
|
||||||
|
port = ntohs(addr->sin.sin_port);
|
||||||
|
snprintf(buf, len, "%s:%d", ip, port);
|
||||||
|
}
|
||||||
|
else if (addr->sa.sa_family == AF_INET6) {
|
||||||
|
inet_ntop(AF_INET6, &addr->sin6.sin6_addr, ip, len);
|
||||||
|
port = ntohs(addr->sin6.sin6_port);
|
||||||
|
snprintf(buf, len, "[%s]:%d", ip, port);
|
||||||
|
}
|
||||||
|
#ifdef ENABLE_UDS
|
||||||
|
else if (addr->sa.sa_family == AF_UNIX) {
|
||||||
|
snprintf(buf, len, "%s", addr->sun.sun_path);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sockaddr_bind(sockaddr_u* localaddr, int type) {
|
||||||
|
// socket -> setsockopt -> bind
|
||||||
|
#ifdef SOCK_CLOEXEC
|
||||||
|
type |= SOCK_CLOEXEC;
|
||||||
|
#endif
|
||||||
|
int sockfd = socket(localaddr->sa.sa_family, type, 0);
|
||||||
|
if (sockfd < 0) {
|
||||||
|
perror("socket");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef OS_UNIX
|
||||||
|
so_reuseaddr(sockfd, 1);
|
||||||
|
// so_reuseport(sockfd, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (localaddr->sa.sa_family == AF_INET6) {
|
||||||
|
ip_v6only(sockfd, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind(sockfd, &localaddr->sa, sockaddr_len(localaddr)) < 0) {
|
||||||
|
perror("bind");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sockfd;
|
||||||
|
error:
|
||||||
|
return socket_errno_negative(sockfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sockaddr_connect(sockaddr_u* peeraddr, int nonblock) {
|
||||||
|
// socket -> nonblocking -> connect
|
||||||
|
int ret = 0;
|
||||||
|
int connfd = socket(peeraddr->sa.sa_family, SOCK_STREAM, 0);
|
||||||
|
if (connfd < 0) {
|
||||||
|
perror("socket");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nonblock) {
|
||||||
|
nonblocking(connfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = connect(connfd, &peeraddr->sa, sockaddr_len(peeraddr));
|
||||||
|
#ifdef OS_WIN
|
||||||
|
if (ret < 0 && socket_errno() != WSAEWOULDBLOCK) {
|
||||||
|
#else
|
||||||
|
if (ret < 0 && socket_errno() != EINPROGRESS) {
|
||||||
|
#endif
|
||||||
|
// perror("connect");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return connfd;
|
||||||
|
error:
|
||||||
|
return socket_errno_negative(connfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ListenFD(int sockfd) {
|
||||||
|
if (sockfd < 0) return sockfd;
|
||||||
|
if (listen(sockfd, SOMAXCONN) < 0) {
|
||||||
|
perror("listen");
|
||||||
|
return socket_errno_negative(sockfd);
|
||||||
|
}
|
||||||
|
return sockfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ConnectFDTimeout(int connfd, int ms) {
|
||||||
|
int err = 0;
|
||||||
|
socklen_t optlen = sizeof(err);
|
||||||
|
struct timeval tv = { ms / 1000, (ms % 1000) * 1000 };
|
||||||
|
fd_set writefds;
|
||||||
|
FD_ZERO(&writefds);
|
||||||
|
FD_SET(connfd, &writefds);
|
||||||
|
int ret = select(connfd+1, 0, &writefds, 0, &tv);
|
||||||
|
if (ret < 0) {
|
||||||
|
perror("select");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (ret == 0) {
|
||||||
|
errno = ETIMEDOUT;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (getsockopt(connfd, SOL_SOCKET, SO_ERROR, (char*)&err, &optlen) < 0 || err != 0) {
|
||||||
|
if (err != 0) errno = err;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
blocking(connfd);
|
||||||
|
return connfd;
|
||||||
|
error:
|
||||||
|
return socket_errno_negative(connfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Bind(int port, const char* host, int type) {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
WSAInit();
|
||||||
|
#endif
|
||||||
|
sockaddr_u localaddr;
|
||||||
|
memset(&localaddr, 0, sizeof(localaddr));
|
||||||
|
int ret = sockaddr_set_ipport(&localaddr, host, port);
|
||||||
|
if (ret != 0) {
|
||||||
|
return NABS(ret);
|
||||||
|
}
|
||||||
|
return sockaddr_bind(&localaddr, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Listen(int port, const char* host) {
|
||||||
|
int sockfd = Bind(port, host, SOCK_STREAM);
|
||||||
|
if (sockfd < 0) return sockfd;
|
||||||
|
return ListenFD(sockfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Connect(const char* host, int port, int nonblock) {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
WSAInit();
|
||||||
|
#endif
|
||||||
|
sockaddr_u peeraddr;
|
||||||
|
memset(&peeraddr, 0, sizeof(peeraddr));
|
||||||
|
int ret = sockaddr_set_ipport(&peeraddr, host, port);
|
||||||
|
if (ret != 0) {
|
||||||
|
return NABS(ret);
|
||||||
|
}
|
||||||
|
return sockaddr_connect(&peeraddr, nonblock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConnectNonblock(const char* host, int port) {
|
||||||
|
return Connect(host, port, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConnectTimeout(const char* host, int port, int ms) {
|
||||||
|
int connfd = Connect(host, port, 1);
|
||||||
|
if (connfd < 0) return connfd;
|
||||||
|
return ConnectFDTimeout(connfd, ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_UDS
|
||||||
|
int BindUnix(const char* path, int type) {
|
||||||
|
sockaddr_u localaddr;
|
||||||
|
memset(&localaddr, 0, sizeof(localaddr));
|
||||||
|
sockaddr_set_path(&localaddr, path);
|
||||||
|
return sockaddr_bind(&localaddr, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ListenUnix(const char* path) {
|
||||||
|
int sockfd = BindUnix(path, SOCK_STREAM);
|
||||||
|
if (sockfd < 0) return sockfd;
|
||||||
|
return ListenFD(sockfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConnectUnix(const char* path, int nonblock) {
|
||||||
|
sockaddr_u peeraddr;
|
||||||
|
memset(&peeraddr, 0, sizeof(peeraddr));
|
||||||
|
sockaddr_set_path(&peeraddr, path);
|
||||||
|
return sockaddr_connect(&peeraddr, nonblock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConnectUnixNonblock(const char* path) {
|
||||||
|
return ConnectUnix(path, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConnectUnixTimeout(const char* path, int ms) {
|
||||||
|
int connfd = ConnectUnix(path, 1);
|
||||||
|
if (connfd < 0) return connfd;
|
||||||
|
return ConnectFDTimeout(connfd, ms);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int Socketpair(int family, int type, int protocol, int sv[2]) {
|
||||||
|
#if defined(OS_UNIX) && HAVE_SOCKETPAIR
|
||||||
|
return socketpair(AF_LOCAL, type, protocol, sv);
|
||||||
|
#endif
|
||||||
|
if (family != AF_INET || type != SOCK_STREAM) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#ifdef OS_WIN
|
||||||
|
WSAInit();
|
||||||
|
#endif
|
||||||
|
int listenfd, connfd, acceptfd;
|
||||||
|
listenfd = connfd = acceptfd = INVALID_SOCKET;
|
||||||
|
struct sockaddr_in localaddr;
|
||||||
|
socklen_t addrlen = sizeof(localaddr);
|
||||||
|
memset(&localaddr, 0, addrlen);
|
||||||
|
localaddr.sin_family = AF_INET;
|
||||||
|
localaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
|
localaddr.sin_port = 0;
|
||||||
|
// listener
|
||||||
|
listenfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (listenfd < 0) {
|
||||||
|
perror("socket");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (bind(listenfd, (struct sockaddr*)&localaddr, addrlen) < 0) {
|
||||||
|
perror("bind");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (listen(listenfd, 1) < 0) {
|
||||||
|
perror("listen");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (getsockname(listenfd, (struct sockaddr*)&localaddr, &addrlen) < 0) {
|
||||||
|
perror("getsockname");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
// connector
|
||||||
|
connfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (connfd < 0) {
|
||||||
|
perror("socket");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (connect(connfd, (struct sockaddr*)&localaddr, addrlen) < 0) {
|
||||||
|
perror("connect");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
// acceptor
|
||||||
|
acceptfd = accept(listenfd, (struct sockaddr*)&localaddr, &addrlen);
|
||||||
|
if (acceptfd < 0) {
|
||||||
|
perror("accept");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
closesocket(listenfd);
|
||||||
|
sv[0] = connfd;
|
||||||
|
sv[1] = acceptfd;
|
||||||
|
return 0;
|
||||||
|
error:
|
||||||
|
if (listenfd != INVALID_SOCKET) {
|
||||||
|
closesocket(listenfd);
|
||||||
|
}
|
||||||
|
if (connfd != INVALID_SOCKET) {
|
||||||
|
closesocket(connfd);
|
||||||
|
}
|
||||||
|
if (acceptfd != INVALID_SOCKET) {
|
||||||
|
closesocket(acceptfd);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
272
external/libhv/libhv-1.3.2/base/hsocket.h
vendored
Normal file
272
external/libhv/libhv-1.3.2/base/hsocket.h
vendored
Normal file
|
@ -0,0 +1,272 @@
|
||||||
|
#ifndef HV_SOCKET_H_
|
||||||
|
#define HV_SOCKET_H_
|
||||||
|
|
||||||
|
#include "hexport.h"
|
||||||
|
#include "hplatform.h"
|
||||||
|
|
||||||
|
#ifdef ENABLE_UDS
|
||||||
|
#ifdef OS_WIN
|
||||||
|
#include <afunix.h> // import struct sockaddr_un
|
||||||
|
#else
|
||||||
|
#include <sys/un.h> // import struct sockaddr_un
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LOCALHOST "127.0.0.1"
|
||||||
|
#define ANYADDR "0.0.0.0"
|
||||||
|
|
||||||
|
BEGIN_EXTERN_C
|
||||||
|
|
||||||
|
HV_INLINE int socket_errno() {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
return WSAGetLastError();
|
||||||
|
#else
|
||||||
|
return errno;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
HV_EXPORT const char* socket_strerror(int err);
|
||||||
|
|
||||||
|
#ifdef OS_WIN
|
||||||
|
|
||||||
|
typedef int socklen_t;
|
||||||
|
|
||||||
|
void WSAInit();
|
||||||
|
void WSADeinit();
|
||||||
|
|
||||||
|
HV_INLINE int blocking(int sockfd) {
|
||||||
|
unsigned long nb = 0;
|
||||||
|
return ioctlsocket(sockfd, FIONBIO, &nb);
|
||||||
|
}
|
||||||
|
HV_INLINE int nonblocking(int sockfd) {
|
||||||
|
unsigned long nb = 1;
|
||||||
|
return ioctlsocket(sockfd, FIONBIO, &nb);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef EAGAIN
|
||||||
|
#define EAGAIN WSAEWOULDBLOCK
|
||||||
|
|
||||||
|
#undef EINPROGRESS
|
||||||
|
#define EINPROGRESS WSAEINPROGRESS
|
||||||
|
|
||||||
|
#undef EINTR
|
||||||
|
#define EINTR WSAEINTR
|
||||||
|
|
||||||
|
#undef ENOTSOCK
|
||||||
|
#define ENOTSOCK WSAENOTSOCK
|
||||||
|
|
||||||
|
#undef EMSGSIZE
|
||||||
|
#define EMSGSIZE WSAEMSGSIZE
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define blocking(s) fcntl(s, F_SETFL, fcntl(s, F_GETFL) & ~O_NONBLOCK)
|
||||||
|
#define nonblocking(s) fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK)
|
||||||
|
|
||||||
|
typedef int SOCKET;
|
||||||
|
#define INVALID_SOCKET -1
|
||||||
|
|
||||||
|
HV_INLINE int closesocket(int sockfd) {
|
||||||
|
return close(sockfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SAFE_CLOSESOCKET
|
||||||
|
#define SAFE_CLOSESOCKET(fd) do {if ((fd) >= 0) {closesocket(fd); (fd) = -1;}} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-----------------------------sockaddr_u----------------------------------------------
|
||||||
|
typedef union {
|
||||||
|
struct sockaddr sa;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
struct sockaddr_in6 sin6;
|
||||||
|
#ifdef ENABLE_UDS
|
||||||
|
struct sockaddr_un sun;
|
||||||
|
#endif
|
||||||
|
} sockaddr_u;
|
||||||
|
|
||||||
|
HV_EXPORT bool is_ipv4(const char* host);
|
||||||
|
HV_EXPORT bool is_ipv6(const char* host);
|
||||||
|
HV_INLINE bool is_ipaddr(const char* host) {
|
||||||
|
return is_ipv4(host) || is_ipv6(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @param host: domain or ip
|
||||||
|
// @retval 0:succeed
|
||||||
|
HV_EXPORT int ResolveAddr(const char* host, sockaddr_u* addr);
|
||||||
|
|
||||||
|
HV_EXPORT const char* sockaddr_ip(sockaddr_u* addr, char *ip, int len);
|
||||||
|
HV_EXPORT uint16_t sockaddr_port(sockaddr_u* addr);
|
||||||
|
HV_EXPORT int sockaddr_set_ip(sockaddr_u* addr, const char* host);
|
||||||
|
HV_EXPORT void sockaddr_set_port(sockaddr_u* addr, int port);
|
||||||
|
HV_EXPORT int sockaddr_set_ipport(sockaddr_u* addr, const char* host, int port);
|
||||||
|
HV_EXPORT socklen_t sockaddr_len(sockaddr_u* addr);
|
||||||
|
HV_EXPORT const char* sockaddr_str(sockaddr_u* addr, char* buf, int len);
|
||||||
|
|
||||||
|
//#define INET_ADDRSTRLEN 16
|
||||||
|
//#define INET6_ADDRSTRLEN 46
|
||||||
|
#ifdef ENABLE_UDS
|
||||||
|
#define SOCKADDR_STRLEN sizeof(((struct sockaddr_un*)(NULL))->sun_path)
|
||||||
|
HV_INLINE void sockaddr_set_path(sockaddr_u* addr, const char* path) {
|
||||||
|
addr->sa.sa_family = AF_UNIX;
|
||||||
|
strncpy(addr->sun.sun_path, path, sizeof(addr->sun.sun_path));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define SOCKADDR_STRLEN 64 // ipv4:port | [ipv6]:port
|
||||||
|
#endif
|
||||||
|
|
||||||
|
HV_INLINE void sockaddr_print(sockaddr_u* addr) {
|
||||||
|
char buf[SOCKADDR_STRLEN] = {0};
|
||||||
|
sockaddr_str(addr, buf, sizeof(buf));
|
||||||
|
puts(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SOCKADDR_LEN(addr) sockaddr_len((sockaddr_u*)addr)
|
||||||
|
#define SOCKADDR_STR(addr, buf) sockaddr_str((sockaddr_u*)addr, buf, sizeof(buf))
|
||||||
|
#define SOCKADDR_PRINT(addr) sockaddr_print((sockaddr_u*)addr)
|
||||||
|
//=====================================================================================
|
||||||
|
|
||||||
|
// socket -> setsockopt -> bind
|
||||||
|
// @param type: SOCK_STREAM(tcp) SOCK_DGRAM(udp)
|
||||||
|
// @return sockfd
|
||||||
|
HV_EXPORT int Bind(int port, const char* host DEFAULT(ANYADDR), int type DEFAULT(SOCK_STREAM));
|
||||||
|
|
||||||
|
// Bind -> listen
|
||||||
|
// @return listenfd
|
||||||
|
HV_EXPORT int Listen(int port, const char* host DEFAULT(ANYADDR));
|
||||||
|
|
||||||
|
// @return connfd
|
||||||
|
// ResolveAddr -> socket -> nonblocking -> connect
|
||||||
|
HV_EXPORT int Connect(const char* host, int port, int nonblock DEFAULT(0));
|
||||||
|
// Connect(host, port, 1)
|
||||||
|
HV_EXPORT int ConnectNonblock(const char* host, int port);
|
||||||
|
// Connect(host, port, 1) -> select -> blocking
|
||||||
|
#define DEFAULT_CONNECT_TIMEOUT 10000 // ms
|
||||||
|
HV_EXPORT int ConnectTimeout(const char* host, int port, int ms DEFAULT(DEFAULT_CONNECT_TIMEOUT));
|
||||||
|
|
||||||
|
#ifdef ENABLE_UDS
|
||||||
|
HV_EXPORT int BindUnix(const char* path, int type DEFAULT(SOCK_STREAM));
|
||||||
|
HV_EXPORT int ListenUnix(const char* path);
|
||||||
|
HV_EXPORT int ConnectUnix(const char* path, int nonblock DEFAULT(0));
|
||||||
|
HV_EXPORT int ConnectUnixNonblock(const char* path);
|
||||||
|
HV_EXPORT int ConnectUnixTimeout(const char* path, int ms DEFAULT(DEFAULT_CONNECT_TIMEOUT));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Just implement Socketpair(AF_INET, SOCK_STREAM, 0, sv);
|
||||||
|
HV_EXPORT int Socketpair(int family, int type, int protocol, int sv[2]);
|
||||||
|
|
||||||
|
HV_INLINE int tcp_nodelay(int sockfd, int on DEFAULT(1)) {
|
||||||
|
return setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
HV_INLINE int tcp_nopush(int sockfd, int on DEFAULT(1)) {
|
||||||
|
#ifdef TCP_NOPUSH
|
||||||
|
return setsockopt(sockfd, IPPROTO_TCP, TCP_NOPUSH, (const char*)&on, sizeof(int));
|
||||||
|
#elif defined(TCP_CORK)
|
||||||
|
return setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, (const char*)&on, sizeof(int));
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
HV_INLINE int tcp_keepalive(int sockfd, int on DEFAULT(1), int delay DEFAULT(60)) {
|
||||||
|
if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (const char*)&on, sizeof(int)) != 0) {
|
||||||
|
return socket_errno();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TCP_KEEPALIVE
|
||||||
|
return setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE, (const char*)&delay, sizeof(int));
|
||||||
|
#elif defined(TCP_KEEPIDLE)
|
||||||
|
// TCP_KEEPIDLE => tcp_keepalive_time
|
||||||
|
// TCP_KEEPCNT => tcp_keepalive_probes
|
||||||
|
// TCP_KEEPINTVL => tcp_keepalive_intvl
|
||||||
|
return setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (const char*)&delay, sizeof(int));
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
HV_INLINE int udp_broadcast(int sockfd, int on DEFAULT(1)) {
|
||||||
|
return setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (const char*)&on, sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
HV_INLINE int ip_v6only(int sockfd, int on DEFAULT(1)) {
|
||||||
|
#ifdef IPV6_V6ONLY
|
||||||
|
return setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(int));
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// send timeout
|
||||||
|
HV_INLINE int so_sndtimeo(int sockfd, int timeout) {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
return setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(int));
|
||||||
|
#else
|
||||||
|
struct timeval tv = {timeout/1000, (timeout%1000)*1000};
|
||||||
|
return setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// recv timeout
|
||||||
|
HV_INLINE int so_rcvtimeo(int sockfd, int timeout) {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
return setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(int));
|
||||||
|
#else
|
||||||
|
struct timeval tv = {timeout/1000, (timeout%1000)*1000};
|
||||||
|
return setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// send buffer size
|
||||||
|
HV_INLINE int so_sndbuf(int sockfd, int len) {
|
||||||
|
return setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char*)&len, sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
// recv buffer size
|
||||||
|
HV_INLINE int so_rcvbuf(int sockfd, int len) {
|
||||||
|
return setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (const char*)&len, sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
HV_INLINE int so_reuseaddr(int sockfd, int on DEFAULT(1)) {
|
||||||
|
#ifdef SO_REUSEADDR
|
||||||
|
// NOTE: SO_REUSEADDR allow to reuse sockaddr of TIME_WAIT status
|
||||||
|
return setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(int));
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
HV_INLINE int so_reuseport(int sockfd, int on DEFAULT(1)) {
|
||||||
|
#ifdef SO_REUSEPORT
|
||||||
|
// NOTE: SO_REUSEPORT allow multiple sockets to bind same port
|
||||||
|
return setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (const char*)&on, sizeof(int));
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
HV_INLINE int so_linger(int sockfd, int timeout DEFAULT(1)) {
|
||||||
|
#ifdef SO_LINGER
|
||||||
|
struct linger linger;
|
||||||
|
if (timeout >= 0) {
|
||||||
|
linger.l_onoff = 1;
|
||||||
|
linger.l_linger = timeout;
|
||||||
|
} else {
|
||||||
|
linger.l_onoff = 0;
|
||||||
|
linger.l_linger = 0;
|
||||||
|
}
|
||||||
|
// NOTE: SO_LINGER change the default behavior of close, send RST, avoid TIME_WAIT
|
||||||
|
return setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (const char*)&linger, sizeof(linger));
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
END_EXTERN_C
|
||||||
|
|
||||||
|
#endif // HV_SOCKET_H_
|
68
external/libhv/libhv-1.3.2/base/hsysinfo.h
vendored
Normal file
68
external/libhv/libhv-1.3.2/base/hsysinfo.h
vendored
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#ifndef HV_SYS_INFO_H_
|
||||||
|
#define HV_SYS_INFO_H_
|
||||||
|
|
||||||
|
#include "hplatform.h"
|
||||||
|
|
||||||
|
#ifdef OS_LINUX
|
||||||
|
#include <sys/sysinfo.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef OS_DARWIN
|
||||||
|
#include <mach/mach_host.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline int get_ncpu() {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
SYSTEM_INFO si;
|
||||||
|
GetSystemInfo(&si);
|
||||||
|
return si.dwNumberOfProcessors;
|
||||||
|
#else
|
||||||
|
//return get_nprocs();
|
||||||
|
//return get_nprocs_conf();
|
||||||
|
//return sysconf(_SC_NPROCESSORS_ONLN); // processors available
|
||||||
|
return sysconf(_SC_NPROCESSORS_CONF); // processors configured
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct meminfo_s {
|
||||||
|
unsigned long total; // KB
|
||||||
|
unsigned long free; // KB
|
||||||
|
} meminfo_t;
|
||||||
|
|
||||||
|
static inline int get_meminfo(meminfo_t* mem) {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
MEMORYSTATUSEX memstat;
|
||||||
|
memset(&memstat, 0, sizeof(memstat));
|
||||||
|
memstat.dwLength = sizeof(memstat);
|
||||||
|
GlobalMemoryStatusEx(&memstat);
|
||||||
|
mem->total = (unsigned long)(memstat.ullTotalPhys >> 10);
|
||||||
|
mem->free = (unsigned long)(memstat.ullAvailPhys >> 10);
|
||||||
|
return 0;
|
||||||
|
#elif defined(OS_LINUX)
|
||||||
|
struct sysinfo info;
|
||||||
|
if (sysinfo(&info) < 0) {
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
mem->total = info.totalram * info.mem_unit >> 10;
|
||||||
|
mem->free = info.freeram * info.mem_unit >> 10;
|
||||||
|
return 0;
|
||||||
|
#elif defined(OS_DARWIN)
|
||||||
|
uint64_t memsize = 0;
|
||||||
|
size_t size = sizeof(memsize);
|
||||||
|
int which[2] = {CTL_HW, HW_MEMSIZE};
|
||||||
|
sysctl(which, 2, &memsize, &size, NULL, 0);
|
||||||
|
mem->total = memsize >> 10;
|
||||||
|
|
||||||
|
vm_statistics_data_t info;
|
||||||
|
mach_msg_type_number_t count = sizeof(info) / sizeof(integer_t);
|
||||||
|
host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&info, &count);
|
||||||
|
mem->free = ((uint64_t)info.free_count * sysconf(_SC_PAGESIZE)) >> 10;
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
(void)(mem);
|
||||||
|
return -10;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // HV_SYS_INFO_H_
|
217
external/libhv/libhv-1.3.2/base/hthread.h
vendored
Normal file
217
external/libhv/libhv-1.3.2/base/hthread.h
vendored
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
#ifndef HV_THREAD_H_
|
||||||
|
#define HV_THREAD_H_
|
||||||
|
|
||||||
|
#include "hplatform.h"
|
||||||
|
|
||||||
|
#ifdef OS_WIN
|
||||||
|
#define hv_getpid (long)GetCurrentProcessId
|
||||||
|
#else
|
||||||
|
#define hv_getpid (long)getpid
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef OS_WIN
|
||||||
|
#define hv_gettid (long)GetCurrentThreadId
|
||||||
|
#elif HAVE_GETTID || defined(OS_ANDROID)
|
||||||
|
#define hv_gettid (long)gettid
|
||||||
|
#elif defined(OS_LINUX)
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#define hv_gettid() (long)syscall(SYS_gettid)
|
||||||
|
#elif defined(OS_DARWIN)
|
||||||
|
static inline long hv_gettid() {
|
||||||
|
uint64_t tid = 0;
|
||||||
|
pthread_threadid_np(NULL, &tid);
|
||||||
|
return tid;
|
||||||
|
}
|
||||||
|
#elif HAVE_PTHREAD_H
|
||||||
|
#define hv_gettid (long)pthread_self
|
||||||
|
#else
|
||||||
|
#define hv_gettid hv_getpid
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include "hthread.h"
|
||||||
|
|
||||||
|
HTHREAD_ROUTINE(thread_demo) {
|
||||||
|
printf("thread[%ld] start\n", hv_gettid());
|
||||||
|
hv_delay(3000);
|
||||||
|
printf("thread[%ld] end\n", hv_gettid());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
hthread_t th = hthread_create(thread_demo, NULL);
|
||||||
|
hthread_join(th);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef OS_WIN
|
||||||
|
typedef HANDLE hthread_t;
|
||||||
|
typedef DWORD (WINAPI *hthread_routine)(void*);
|
||||||
|
#define HTHREAD_RETTYPE DWORD
|
||||||
|
#define HTHREAD_ROUTINE(fname) DWORD WINAPI fname(void* userdata)
|
||||||
|
static inline hthread_t hthread_create(hthread_routine fn, void* userdata) {
|
||||||
|
return CreateThread(NULL, 0, fn, userdata, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int hthread_join(hthread_t th) {
|
||||||
|
WaitForSingleObject(th, INFINITE);
|
||||||
|
CloseHandle(th);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
typedef pthread_t hthread_t;
|
||||||
|
typedef void* (*hthread_routine)(void*);
|
||||||
|
#define HTHREAD_RETTYPE void*
|
||||||
|
#define HTHREAD_ROUTINE(fname) void* fname(void* userdata)
|
||||||
|
static inline hthread_t hthread_create(hthread_routine fn, void* userdata) {
|
||||||
|
pthread_t th;
|
||||||
|
pthread_create(&th, NULL, fn, userdata);
|
||||||
|
return th;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int hthread_join(hthread_t th) {
|
||||||
|
return pthread_join(th, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
/************************************************
|
||||||
|
* HThread
|
||||||
|
* Status: STOP,RUNNING,PAUSE
|
||||||
|
* Control: start,stop,pause,resume
|
||||||
|
* first-level virtual: doTask
|
||||||
|
* second-level virtual: run
|
||||||
|
************************************************/
|
||||||
|
#include <thread>
|
||||||
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
class HThread {
|
||||||
|
public:
|
||||||
|
enum Status {
|
||||||
|
STOP,
|
||||||
|
RUNNING,
|
||||||
|
PAUSE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SleepPolicy {
|
||||||
|
YIELD,
|
||||||
|
SLEEP_FOR,
|
||||||
|
SLEEP_UNTIL,
|
||||||
|
NO_SLEEP,
|
||||||
|
};
|
||||||
|
|
||||||
|
HThread() {
|
||||||
|
status = STOP;
|
||||||
|
status_changed = false;
|
||||||
|
dotask_cnt = 0;
|
||||||
|
sleep_policy = YIELD;
|
||||||
|
sleep_ms = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~HThread() {}
|
||||||
|
|
||||||
|
void setStatus(Status stat) {
|
||||||
|
status_changed = true;
|
||||||
|
status = stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSleepPolicy(SleepPolicy policy, uint32_t ms = 0) {
|
||||||
|
sleep_policy = policy;
|
||||||
|
sleep_ms = ms;
|
||||||
|
setStatus(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int start() {
|
||||||
|
if (status == STOP) {
|
||||||
|
thread = std::thread([this] {
|
||||||
|
if (!doPrepare()) return;
|
||||||
|
setStatus(RUNNING);
|
||||||
|
run();
|
||||||
|
setStatus(STOP);
|
||||||
|
if (!doFinish()) return;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int stop() {
|
||||||
|
if (status != STOP) {
|
||||||
|
setStatus(STOP);
|
||||||
|
}
|
||||||
|
if (thread.joinable()) {
|
||||||
|
thread.join(); // wait thread exit
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int pause() {
|
||||||
|
if (status == RUNNING) {
|
||||||
|
setStatus(PAUSE);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int resume() {
|
||||||
|
if (status == PAUSE) {
|
||||||
|
setStatus(RUNNING);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void run() {
|
||||||
|
while (status != STOP) {
|
||||||
|
while (status == PAUSE) {
|
||||||
|
std::this_thread::yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
doTask();
|
||||||
|
++dotask_cnt;
|
||||||
|
|
||||||
|
HThread::sleep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool doPrepare() {return true;}
|
||||||
|
virtual void doTask() {}
|
||||||
|
virtual bool doFinish() {return true;}
|
||||||
|
|
||||||
|
std::thread thread;
|
||||||
|
std::atomic<Status> status;
|
||||||
|
uint32_t dotask_cnt;
|
||||||
|
protected:
|
||||||
|
void sleep() {
|
||||||
|
switch (sleep_policy) {
|
||||||
|
case YIELD:
|
||||||
|
std::this_thread::yield();
|
||||||
|
break;
|
||||||
|
case SLEEP_FOR:
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms));
|
||||||
|
break;
|
||||||
|
case SLEEP_UNTIL: {
|
||||||
|
if (status_changed) {
|
||||||
|
status_changed = false;
|
||||||
|
base_tp = std::chrono::steady_clock::now();
|
||||||
|
}
|
||||||
|
base_tp += std::chrono::milliseconds(sleep_ms);
|
||||||
|
std::this_thread::sleep_until(base_tp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: // donothing, go all out.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SleepPolicy sleep_policy;
|
||||||
|
uint32_t sleep_ms;
|
||||||
|
// for SLEEP_UNTIL
|
||||||
|
std::atomic<bool> status_changed;
|
||||||
|
std::chrono::steady_clock::time_point base_tp;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // HV_THREAD_H_
|
290
external/libhv/libhv-1.3.2/base/htime.c
vendored
Normal file
290
external/libhv/libhv-1.3.2/base/htime.c
vendored
Normal file
|
@ -0,0 +1,290 @@
|
||||||
|
#include "htime.h"
|
||||||
|
|
||||||
|
static const char* s_weekdays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
|
||||||
|
|
||||||
|
static const char* s_months[] = {"January", "February", "March", "April", "May", "June",
|
||||||
|
"July", "August", "September", "October", "November", "December"};
|
||||||
|
|
||||||
|
static const uint8_t s_days[] = \
|
||||||
|
// 1 3 5 7 8 10 12
|
||||||
|
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||||
|
|
||||||
|
unsigned int gettick_ms() {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
return GetTickCount();
|
||||||
|
#elif HAVE_CLOCK_GETTIME
|
||||||
|
struct timespec ts;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||||
|
#else
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long gethrtime_us() {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
static LONGLONG s_freq = 0;
|
||||||
|
if (s_freq == 0) {
|
||||||
|
LARGE_INTEGER freq;
|
||||||
|
QueryPerformanceFrequency(&freq);
|
||||||
|
s_freq = freq.QuadPart;
|
||||||
|
}
|
||||||
|
if (s_freq != 0) {
|
||||||
|
LARGE_INTEGER count;
|
||||||
|
QueryPerformanceCounter(&count);
|
||||||
|
return (unsigned long long)(count.QuadPart / (double)s_freq * 1000000);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
#elif defined(OS_SOLARIS)
|
||||||
|
return gethrtime() / 1000;
|
||||||
|
#elif HAVE_CLOCK_GETTIME
|
||||||
|
struct timespec ts;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
return ts.tv_sec*(unsigned long long)1000000 + ts.tv_nsec / 1000;
|
||||||
|
#else
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
return tv.tv_sec*(unsigned long long)1000000 + tv.tv_usec;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
datetime_t datetime_now() {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
SYSTEMTIME tm;
|
||||||
|
GetLocalTime(&tm);
|
||||||
|
datetime_t dt;
|
||||||
|
dt.year = tm.wYear;
|
||||||
|
dt.month = tm.wMonth;
|
||||||
|
dt.day = tm.wDay;
|
||||||
|
dt.hour = tm.wHour;
|
||||||
|
dt.min = tm.wMinute;
|
||||||
|
dt.sec = tm.wSecond;
|
||||||
|
dt.ms = tm.wMilliseconds;
|
||||||
|
return dt;
|
||||||
|
#else
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
datetime_t dt = datetime_localtime(tv.tv_sec);
|
||||||
|
dt.ms = tv.tv_usec / 1000;
|
||||||
|
return dt;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
datetime_t datetime_localtime(time_t seconds) {
|
||||||
|
struct tm* tm = localtime(&seconds);
|
||||||
|
datetime_t dt;
|
||||||
|
dt.year = tm->tm_year + 1900;
|
||||||
|
dt.month = tm->tm_mon + 1;
|
||||||
|
dt.day = tm->tm_mday;
|
||||||
|
dt.hour = tm->tm_hour;
|
||||||
|
dt.min = tm->tm_min;
|
||||||
|
dt.sec = tm->tm_sec;
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t datetime_mktime(datetime_t* dt) {
|
||||||
|
struct tm tm;
|
||||||
|
time_t ts;
|
||||||
|
time(&ts);
|
||||||
|
struct tm* ptm = localtime(&ts);
|
||||||
|
memcpy(&tm, ptm, sizeof(struct tm));
|
||||||
|
tm.tm_year = dt->year - 1900;
|
||||||
|
tm.tm_mon = dt->month - 1;
|
||||||
|
tm.tm_mday = dt->day;
|
||||||
|
tm.tm_hour = dt->hour;
|
||||||
|
tm.tm_min = dt->min;
|
||||||
|
tm.tm_sec = dt->sec;
|
||||||
|
return mktime(&tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
int days_of_month(int month, int year) {
|
||||||
|
if (month < 1 || month > 12) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int days = s_days[month-1];
|
||||||
|
return (month == 2 && IS_LEAP_YEAR(year)) ? ++days : days;
|
||||||
|
}
|
||||||
|
|
||||||
|
datetime_t* datetime_past(datetime_t* dt, int days) {
|
||||||
|
assert(days >= 0);
|
||||||
|
int sub = days;
|
||||||
|
while (sub) {
|
||||||
|
if (dt->day > sub) {
|
||||||
|
dt->day -= sub;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sub -= dt->day;
|
||||||
|
if (--dt->month == 0) {
|
||||||
|
dt->month = 12;
|
||||||
|
--dt->year;
|
||||||
|
}
|
||||||
|
dt->day = days_of_month(dt->month, dt->year);
|
||||||
|
}
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
datetime_t* datetime_future(datetime_t* dt, int days) {
|
||||||
|
assert(days >= 0);
|
||||||
|
int sub = days;
|
||||||
|
int mdays;
|
||||||
|
while (sub) {
|
||||||
|
mdays = days_of_month(dt->month, dt->year);
|
||||||
|
if (dt->day + sub <= mdays) {
|
||||||
|
dt->day += sub;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sub -= (mdays - dt->day + 1);
|
||||||
|
if (++dt->month > 12) {
|
||||||
|
dt->month = 1;
|
||||||
|
++dt->year;
|
||||||
|
}
|
||||||
|
dt->day = 1;
|
||||||
|
}
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* duration_fmt(int sec, char* buf) {
|
||||||
|
int h, m, s;
|
||||||
|
m = sec / 60;
|
||||||
|
s = sec % 60;
|
||||||
|
h = m / 60;
|
||||||
|
m = m % 60;
|
||||||
|
sprintf(buf, TIME_FMT, h, m, s);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* datetime_fmt(datetime_t* dt, char* buf) {
|
||||||
|
sprintf(buf, DATETIME_FMT,
|
||||||
|
dt->year, dt->month, dt->day,
|
||||||
|
dt->hour, dt->min, dt->sec);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* datetime_fmt_iso(datetime_t* dt, char* buf) {
|
||||||
|
sprintf(buf, DATETIME_FMT_ISO,
|
||||||
|
dt->year, dt->month, dt->day,
|
||||||
|
dt->hour, dt->min, dt->sec,
|
||||||
|
dt->ms);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* gmtime_fmt(time_t time, char* buf) {
|
||||||
|
struct tm* tm = gmtime(&time);
|
||||||
|
//strftime(buf, GMTIME_FMT_BUFLEN, "%a, %d %b %Y %H:%M:%S GMT", tm);
|
||||||
|
sprintf(buf, GMTIME_FMT,
|
||||||
|
s_weekdays[tm->tm_wday],
|
||||||
|
tm->tm_mday, s_months[tm->tm_mon], tm->tm_year + 1900,
|
||||||
|
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int month_atoi(const char* month) {
|
||||||
|
for (size_t i = 0; i < 12; ++i) {
|
||||||
|
if (strnicmp(month, s_months[i], strlen(month)) == 0)
|
||||||
|
return i+1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* month_itoa(int month) {
|
||||||
|
assert(month >= 1 && month <= 12);
|
||||||
|
return s_months[month-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
int weekday_atoi(const char* weekday) {
|
||||||
|
for (size_t i = 0; i < 7; ++i) {
|
||||||
|
if (strnicmp(weekday, s_weekdays[i], strlen(weekday)) == 0)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* weekday_itoa(int weekday) {
|
||||||
|
assert(weekday >= 0 && weekday <= 7);
|
||||||
|
if (weekday == 7) weekday = 0;
|
||||||
|
return s_weekdays[weekday];
|
||||||
|
}
|
||||||
|
|
||||||
|
datetime_t hv_compile_datetime() {
|
||||||
|
datetime_t dt;
|
||||||
|
char month[32];
|
||||||
|
sscanf(__DATE__, "%s %d %d", month, &dt.day, &dt.year);
|
||||||
|
sscanf(__TIME__, "%d:%d:%d", &dt.hour, &dt.min, &dt.sec);
|
||||||
|
dt.month = month_atoi(month);
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t cron_next_timeout(int minute, int hour, int day, int week, int month) {
|
||||||
|
enum {
|
||||||
|
MINUTELY,
|
||||||
|
HOURLY,
|
||||||
|
DAILY,
|
||||||
|
WEEKLY,
|
||||||
|
MONTHLY,
|
||||||
|
YEARLY,
|
||||||
|
} period_type = MINUTELY;
|
||||||
|
struct tm tm;
|
||||||
|
time_t tt;
|
||||||
|
time(&tt);
|
||||||
|
tm = *localtime(&tt);
|
||||||
|
time_t tt_round = 0;
|
||||||
|
|
||||||
|
tm.tm_sec = 0;
|
||||||
|
if (minute >= 0) {
|
||||||
|
period_type = HOURLY;
|
||||||
|
tm.tm_min = minute;
|
||||||
|
}
|
||||||
|
if (hour >= 0) {
|
||||||
|
period_type = DAILY;
|
||||||
|
tm.tm_hour = hour;
|
||||||
|
}
|
||||||
|
if (week >= 0) {
|
||||||
|
period_type = WEEKLY;
|
||||||
|
}
|
||||||
|
else if (day > 0) {
|
||||||
|
period_type = MONTHLY;
|
||||||
|
tm.tm_mday = day;
|
||||||
|
if (month > 0) {
|
||||||
|
period_type = YEARLY;
|
||||||
|
tm.tm_mon = month - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tt_round = mktime(&tm);
|
||||||
|
if (week >= 0) {
|
||||||
|
tt_round += (week-tm.tm_wday)*SECONDS_PER_DAY;
|
||||||
|
}
|
||||||
|
if (tt_round > tt) {
|
||||||
|
return tt_round;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(period_type) {
|
||||||
|
case MINUTELY:
|
||||||
|
tt_round += SECONDS_PER_MINUTE;
|
||||||
|
return tt_round;
|
||||||
|
case HOURLY:
|
||||||
|
tt_round += SECONDS_PER_HOUR;
|
||||||
|
return tt_round;
|
||||||
|
case DAILY:
|
||||||
|
tt_round += SECONDS_PER_DAY;
|
||||||
|
return tt_round;
|
||||||
|
case WEEKLY:
|
||||||
|
tt_round += SECONDS_PER_WEEK;
|
||||||
|
return tt_round;
|
||||||
|
case MONTHLY:
|
||||||
|
if (++tm.tm_mon == 12) {
|
||||||
|
tm.tm_mon = 0;
|
||||||
|
++tm.tm_year;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case YEARLY:
|
||||||
|
++tm.tm_year;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mktime(&tm);
|
||||||
|
}
|
114
external/libhv/libhv-1.3.2/base/htime.h
vendored
Normal file
114
external/libhv/libhv-1.3.2/base/htime.h
vendored
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
#ifndef HV_TIME_H_
|
||||||
|
#define HV_TIME_H_
|
||||||
|
|
||||||
|
#include "hexport.h"
|
||||||
|
#include "hplatform.h"
|
||||||
|
|
||||||
|
BEGIN_EXTERN_C
|
||||||
|
|
||||||
|
#define SECONDS_PER_MINUTE 60
|
||||||
|
#define SECONDS_PER_HOUR 3600
|
||||||
|
#define SECONDS_PER_DAY 86400 // 24*3600
|
||||||
|
#define SECONDS_PER_WEEK 604800 // 7*24*3600
|
||||||
|
|
||||||
|
#define IS_LEAP_YEAR(year) (((year)%4 == 0 && (year)%100 != 0) || (year)%400 == 0)
|
||||||
|
|
||||||
|
typedef struct datetime_s {
|
||||||
|
int year;
|
||||||
|
int month;
|
||||||
|
int day;
|
||||||
|
int hour;
|
||||||
|
int min;
|
||||||
|
int sec;
|
||||||
|
int ms;
|
||||||
|
} datetime_t;
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
/* @see winsock2.h
|
||||||
|
// Structure used in select() call, taken from the BSD file sys/time.h
|
||||||
|
struct timeval {
|
||||||
|
long tv_sec;
|
||||||
|
long tv_usec;
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct timezone {
|
||||||
|
int tz_minuteswest; /* of Greenwich */
|
||||||
|
int tz_dsttime; /* type of dst correction to apply */
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <sys/timeb.h>
|
||||||
|
HV_INLINE int gettimeofday(struct timeval *tv, struct timezone *tz) {
|
||||||
|
struct _timeb tb;
|
||||||
|
_ftime(&tb);
|
||||||
|
if (tv) {
|
||||||
|
tv->tv_sec = (long)tb.time;
|
||||||
|
tv->tv_usec = tb.millitm * 1000;
|
||||||
|
}
|
||||||
|
if (tz) {
|
||||||
|
tz->tz_minuteswest = tb.timezone;
|
||||||
|
tz->tz_dsttime = tb.dstflag;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
HV_EXPORT unsigned int gettick_ms();
|
||||||
|
HV_INLINE unsigned long long gettimeofday_ms() {
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
return tv.tv_sec * (unsigned long long)1000 + tv.tv_usec/1000;
|
||||||
|
}
|
||||||
|
HV_INLINE unsigned long long gettimeofday_us() {
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
return tv.tv_sec * (unsigned long long)1000000 + tv.tv_usec;
|
||||||
|
}
|
||||||
|
HV_EXPORT unsigned long long gethrtime_us();
|
||||||
|
|
||||||
|
HV_EXPORT datetime_t datetime_now();
|
||||||
|
HV_EXPORT datetime_t datetime_localtime(time_t seconds);
|
||||||
|
HV_EXPORT time_t datetime_mktime(datetime_t* dt);
|
||||||
|
|
||||||
|
HV_EXPORT datetime_t* datetime_past(datetime_t* dt, int days DEFAULT(1));
|
||||||
|
HV_EXPORT datetime_t* datetime_future(datetime_t* dt, int days DEFAULT(1));
|
||||||
|
|
||||||
|
#define TIME_FMT "%02d:%02d:%02d"
|
||||||
|
#define TIME_FMT_BUFLEN 12
|
||||||
|
HV_EXPORT char* duration_fmt(int sec, char* buf);
|
||||||
|
|
||||||
|
#define DATETIME_FMT "%04d-%02d-%02d %02d:%02d:%02d"
|
||||||
|
#define DATETIME_FMT_ISO "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ"
|
||||||
|
#define DATETIME_FMT_BUFLEN 30
|
||||||
|
HV_EXPORT char* datetime_fmt(datetime_t* dt, char* buf);
|
||||||
|
HV_EXPORT char* datetime_fmt_iso(datetime_t* dt, char* buf);
|
||||||
|
|
||||||
|
#define GMTIME_FMT "%.3s, %02d %.3s %04d %02d:%02d:%02d GMT"
|
||||||
|
#define GMTIME_FMT_BUFLEN 30
|
||||||
|
HV_EXPORT char* gmtime_fmt(time_t time, char* buf);
|
||||||
|
|
||||||
|
HV_EXPORT int days_of_month(int month, int year);
|
||||||
|
|
||||||
|
HV_EXPORT int month_atoi(const char* month);
|
||||||
|
HV_EXPORT const char* month_itoa(int month);
|
||||||
|
|
||||||
|
HV_EXPORT int weekday_atoi(const char* weekday);
|
||||||
|
HV_EXPORT const char* weekday_itoa(int weekday);
|
||||||
|
|
||||||
|
HV_EXPORT datetime_t hv_compile_datetime();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* minute hour day week month action
|
||||||
|
* 0~59 0~23 1~31 0~6 1~12
|
||||||
|
* -1 -1 -1 -1 -1 cron.minutely
|
||||||
|
* 30 -1 -1 -1 -1 cron.hourly
|
||||||
|
* 30 1 -1 -1 -1 cron.daily
|
||||||
|
* 30 1 15 -1 -1 cron.monthly
|
||||||
|
* 30 1 -1 0 -1 cron.weekly
|
||||||
|
* 30 1 1 -1 10 cron.yearly
|
||||||
|
*/
|
||||||
|
HV_EXPORT time_t cron_next_timeout(int minute, int hour, int day, int week, int month);
|
||||||
|
|
||||||
|
END_EXTERN_C
|
||||||
|
|
||||||
|
#endif // HV_TIME_H_
|
48
external/libhv/libhv-1.3.2/base/hversion.c
vendored
Normal file
48
external/libhv/libhv-1.3.2/base/hversion.c
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#include "hversion.h"
|
||||||
|
|
||||||
|
#include "htime.h"
|
||||||
|
|
||||||
|
const char* hv_compile_version() {
|
||||||
|
static char s_version[16] = {0};
|
||||||
|
datetime_t dt = hv_compile_datetime();
|
||||||
|
snprintf(s_version, sizeof(s_version), "%d.%d.%d.%d",
|
||||||
|
HV_VERSION_MAJOR, dt.year%100, dt.month, dt.day);
|
||||||
|
return s_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
int version_atoi(const char* str) {
|
||||||
|
int hex = 0;
|
||||||
|
|
||||||
|
// trim v1.2.3.4
|
||||||
|
const char* pv = strchr(str, 'v');
|
||||||
|
const char* pdot = pv ? pv+1 : str;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
hex = (hex << 8) | atoi(pdot);
|
||||||
|
pdot = strchr(pdot, '.');
|
||||||
|
if (pdot == NULL) break;
|
||||||
|
++pdot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void version_itoa(int num, char* str) {
|
||||||
|
char* ch = (char*)#
|
||||||
|
sprintf(str, "%d.%d.%d.%d", ch[3], ch[2], ch[1], ch[0]);
|
||||||
|
|
||||||
|
// trim 0.1.2.3
|
||||||
|
const char* p = str;
|
||||||
|
while (1) {
|
||||||
|
if (p[0] == '0' && p[1] == '.') {
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p != str) {
|
||||||
|
strcpy(str, p);
|
||||||
|
}
|
||||||
|
}
|
34
external/libhv/libhv-1.3.2/base/hversion.h
vendored
Normal file
34
external/libhv/libhv-1.3.2/base/hversion.h
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef HV_VERSION_H_
|
||||||
|
#define HV_VERSION_H_
|
||||||
|
|
||||||
|
#include "hexport.h"
|
||||||
|
#include "hdef.h"
|
||||||
|
|
||||||
|
BEGIN_EXTERN_C
|
||||||
|
|
||||||
|
#define HV_VERSION_MAJOR 1
|
||||||
|
#define HV_VERSION_MINOR 3
|
||||||
|
#define HV_VERSION_PATCH 2
|
||||||
|
|
||||||
|
#define HV_VERSION_STRING STRINGIFY(HV_VERSION_MAJOR) "." \
|
||||||
|
STRINGIFY(HV_VERSION_MINOR) "." \
|
||||||
|
STRINGIFY(HV_VERSION_PATCH)
|
||||||
|
|
||||||
|
#define HV_VERSION_NUMBER ((HV_VERSION_MAJOR << 16) | (HV_VERSION_MINOR << 8) | HV_VERSION_PATCH)
|
||||||
|
|
||||||
|
|
||||||
|
HV_INLINE const char* hv_version() {
|
||||||
|
return HV_VERSION_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
HV_EXPORT const char* hv_compile_version();
|
||||||
|
|
||||||
|
// 1.2.3.4 => 0x01020304
|
||||||
|
HV_EXPORT int version_atoi(const char* str);
|
||||||
|
|
||||||
|
// 0x01020304 => 1.2.3.4
|
||||||
|
HV_EXPORT void version_itoa(int hex, char* str);
|
||||||
|
|
||||||
|
END_EXTERN_C
|
||||||
|
|
||||||
|
#endif // HV_VERSION_H_
|
733
external/libhv/libhv-1.3.2/base/list.h
vendored
Normal file
733
external/libhv/libhv-1.3.2/base/list.h
vendored
Normal file
|
@ -0,0 +1,733 @@
|
||||||
|
#ifndef _LINUX_LIST_H
|
||||||
|
#define _LINUX_LIST_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple doubly linked list implementation.
|
||||||
|
*
|
||||||
|
* Some of the internal functions ("__xxx") are useful when
|
||||||
|
* manipulating whole lists rather than single entries, as
|
||||||
|
* sometimes we already know the next/prev entries and we can
|
||||||
|
* generate better code by using them directly rather than
|
||||||
|
* using the generic single-entry routines.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifndef prefetch
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define prefetch(x) __builtin_prefetch(x)
|
||||||
|
#else
|
||||||
|
#define prefetch(x) (void)0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct list_head {
|
||||||
|
struct list_head *next, *prev;
|
||||||
|
};
|
||||||
|
#define list_node list_head
|
||||||
|
|
||||||
|
struct hlist_head {
|
||||||
|
struct hlist_node *first;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hlist_node {
|
||||||
|
struct hlist_node *next, **pprev;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||||
|
// TODO: <sys/queue.h> defined LIST_HEAD
|
||||||
|
#ifndef LIST_HEAD
|
||||||
|
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
|
||||||
|
#endif
|
||||||
|
#define INIT_LIST_HEAD list_init
|
||||||
|
static inline void list_init(struct list_head *list)
|
||||||
|
{
|
||||||
|
list->next = list;
|
||||||
|
list->prev = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert a new entry between two known consecutive entries.
|
||||||
|
*
|
||||||
|
* This is only for internal list manipulation where we know
|
||||||
|
* the prev/next entries already!
|
||||||
|
*/
|
||||||
|
static inline void __list_add(struct list_head *n,
|
||||||
|
struct list_head *prev,
|
||||||
|
struct list_head *next)
|
||||||
|
{
|
||||||
|
next->prev = n;
|
||||||
|
n->next = next;
|
||||||
|
n->prev = prev;
|
||||||
|
prev->next = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_add - add a new entry
|
||||||
|
* @new: new entry to be added
|
||||||
|
* @head: list head to add it after
|
||||||
|
*
|
||||||
|
* Insert a new entry after the specified head.
|
||||||
|
* This is good for implementing stacks.
|
||||||
|
*/
|
||||||
|
static inline void list_add(struct list_head *n, struct list_head *head)
|
||||||
|
{
|
||||||
|
__list_add(n, head, head->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_add_tail - add a new entry
|
||||||
|
* @new: new entry to be added
|
||||||
|
* @head: list head to add it before
|
||||||
|
*
|
||||||
|
* Insert a new entry before the specified head.
|
||||||
|
* This is useful for implementing queues.
|
||||||
|
*/
|
||||||
|
static inline void list_add_tail(struct list_head *n, struct list_head *head)
|
||||||
|
{
|
||||||
|
__list_add(n, head->prev, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete a list entry by making the prev/next entries
|
||||||
|
* point to each other.
|
||||||
|
*
|
||||||
|
* This is only for internal list manipulation where we know
|
||||||
|
* the prev/next entries already!
|
||||||
|
*/
|
||||||
|
static inline void __list_del(struct list_head * prev, struct list_head * next)
|
||||||
|
{
|
||||||
|
next->prev = prev;
|
||||||
|
prev->next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_del - deletes entry from list.
|
||||||
|
* @entry: the element to delete from the list.
|
||||||
|
* Note: list_empty() on entry does not return true after this, the entry is
|
||||||
|
* in an undefined state.
|
||||||
|
*/
|
||||||
|
static inline void __list_del_entry(struct list_head *entry)
|
||||||
|
{
|
||||||
|
__list_del(entry->prev, entry->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void list_del(struct list_head *entry)
|
||||||
|
{
|
||||||
|
__list_del(entry->prev, entry->next);
|
||||||
|
//entry->next = NULL;
|
||||||
|
//entry->prev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_replace - replace old entry by new one
|
||||||
|
* @old : the element to be replaced
|
||||||
|
* @new : the new element to insert
|
||||||
|
*
|
||||||
|
* If @old was empty, it will be overwritten.
|
||||||
|
*/
|
||||||
|
static inline void list_replace(struct list_head *old,
|
||||||
|
struct list_head *n)
|
||||||
|
{
|
||||||
|
n->next = old->next;
|
||||||
|
n->next->prev = n;
|
||||||
|
n->prev = old->prev;
|
||||||
|
n->prev->next = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void list_replace_init(struct list_head *old,
|
||||||
|
struct list_head *n)
|
||||||
|
{
|
||||||
|
list_replace(old, n);
|
||||||
|
INIT_LIST_HEAD(old);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_del_init - deletes entry from list and reinitialize it.
|
||||||
|
* @entry: the element to delete from the list.
|
||||||
|
*/
|
||||||
|
static inline void list_del_init(struct list_head *entry)
|
||||||
|
{
|
||||||
|
__list_del_entry(entry);
|
||||||
|
INIT_LIST_HEAD(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_move - delete from one list and add as another's head
|
||||||
|
* @list: the entry to move
|
||||||
|
* @head: the head that will precede our entry
|
||||||
|
*/
|
||||||
|
static inline void list_move(struct list_head *list, struct list_head *head)
|
||||||
|
{
|
||||||
|
__list_del_entry(list);
|
||||||
|
list_add(list, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_move_tail - delete from one list and add as another's tail
|
||||||
|
* @list: the entry to move
|
||||||
|
* @head: the head that will follow our entry
|
||||||
|
*/
|
||||||
|
static inline void list_move_tail(struct list_head *list,
|
||||||
|
struct list_head *head)
|
||||||
|
{
|
||||||
|
__list_del_entry(list);
|
||||||
|
list_add_tail(list, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_is_last - tests whether @list is the last entry in list @head
|
||||||
|
* @list: the entry to test
|
||||||
|
* @head: the head of the list
|
||||||
|
*/
|
||||||
|
static inline int list_is_last(const struct list_head *list,
|
||||||
|
const struct list_head *head)
|
||||||
|
{
|
||||||
|
return list->next == head;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_empty - tests whether a list is empty
|
||||||
|
* @head: the list to test.
|
||||||
|
*/
|
||||||
|
static inline int list_empty(const struct list_head *head)
|
||||||
|
{
|
||||||
|
return head->next == head;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_empty_careful - tests whether a list is empty and not being modified
|
||||||
|
* @head: the list to test
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* tests whether a list is empty _and_ checks that no other CPU might be
|
||||||
|
* in the process of modifying either member (next or prev)
|
||||||
|
*
|
||||||
|
* NOTE: using list_empty_careful() without synchronization
|
||||||
|
* can only be safe if the only activity that can happen
|
||||||
|
* to the list entry is list_del_init(). Eg. it cannot be used
|
||||||
|
* if another CPU could re-list_add() it.
|
||||||
|
*/
|
||||||
|
static inline int list_empty_careful(const struct list_head *head)
|
||||||
|
{
|
||||||
|
struct list_head *next = head->next;
|
||||||
|
return (next == head) && (next == head->prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_rotate_left - rotate the list to the left
|
||||||
|
* @head: the head of the list
|
||||||
|
*/
|
||||||
|
static inline void list_rotate_left(struct list_head *head)
|
||||||
|
{
|
||||||
|
struct list_head *first;
|
||||||
|
|
||||||
|
if (!list_empty(head)) {
|
||||||
|
first = head->next;
|
||||||
|
list_move_tail(first, head);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_is_singular - tests whether a list has just one entry.
|
||||||
|
* @head: the list to test.
|
||||||
|
*/
|
||||||
|
static inline int list_is_singular(const struct list_head *head)
|
||||||
|
{
|
||||||
|
return !list_empty(head) && (head->next == head->prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void __list_cut_position(struct list_head *list,
|
||||||
|
struct list_head *head, struct list_head *entry)
|
||||||
|
{
|
||||||
|
struct list_head *new_first = entry->next;
|
||||||
|
list->next = head->next;
|
||||||
|
list->next->prev = list;
|
||||||
|
list->prev = entry;
|
||||||
|
entry->next = list;
|
||||||
|
head->next = new_first;
|
||||||
|
new_first->prev = head;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_cut_position - cut a list into two
|
||||||
|
* @list: a new list to add all removed entries
|
||||||
|
* @head: a list with entries
|
||||||
|
* @entry: an entry within head, could be the head itself
|
||||||
|
* and if so we won't cut the list
|
||||||
|
*
|
||||||
|
* This helper moves the initial part of @head, up to and
|
||||||
|
* including @entry, from @head to @list. You should
|
||||||
|
* pass on @entry an element you know is on @head. @list
|
||||||
|
* should be an empty list or a list you do not care about
|
||||||
|
* losing its data.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static inline void list_cut_position(struct list_head *list,
|
||||||
|
struct list_head *head, struct list_head *entry)
|
||||||
|
{
|
||||||
|
if (list_empty(head))
|
||||||
|
return;
|
||||||
|
if (list_is_singular(head) &&
|
||||||
|
(head->next != entry && head != entry))
|
||||||
|
return;
|
||||||
|
if (entry == head)
|
||||||
|
INIT_LIST_HEAD(list);
|
||||||
|
else
|
||||||
|
__list_cut_position(list, head, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void __list_splice(const struct list_head *list,
|
||||||
|
struct list_head *prev,
|
||||||
|
struct list_head *next)
|
||||||
|
{
|
||||||
|
struct list_head *first = list->next;
|
||||||
|
struct list_head *last = list->prev;
|
||||||
|
|
||||||
|
first->prev = prev;
|
||||||
|
prev->next = first;
|
||||||
|
|
||||||
|
last->next = next;
|
||||||
|
next->prev = last;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_splice - join two lists, this is designed for stacks
|
||||||
|
* @list: the new list to add.
|
||||||
|
* @head: the place to add it in the first list.
|
||||||
|
*/
|
||||||
|
static inline void list_splice(const struct list_head *list,
|
||||||
|
struct list_head *head)
|
||||||
|
{
|
||||||
|
if (!list_empty(list))
|
||||||
|
__list_splice(list, head, head->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_splice_tail - join two lists, each list being a queue
|
||||||
|
* @list: the new list to add.
|
||||||
|
* @head: the place to add it in the first list.
|
||||||
|
*/
|
||||||
|
static inline void list_splice_tail(struct list_head *list,
|
||||||
|
struct list_head *head)
|
||||||
|
{
|
||||||
|
if (!list_empty(list))
|
||||||
|
__list_splice(list, head->prev, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_splice_init - join two lists and reinitialise the emptied list.
|
||||||
|
* @list: the new list to add.
|
||||||
|
* @head: the place to add it in the first list.
|
||||||
|
*
|
||||||
|
* The list at @list is reinitialised
|
||||||
|
*/
|
||||||
|
static inline void list_splice_init(struct list_head *list,
|
||||||
|
struct list_head *head)
|
||||||
|
{
|
||||||
|
if (!list_empty(list)) {
|
||||||
|
__list_splice(list, head, head->next);
|
||||||
|
INIT_LIST_HEAD(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_splice_tail_init - join two lists and reinitialise the emptied list
|
||||||
|
* @list: the new list to add.
|
||||||
|
* @head: the place to add it in the first list.
|
||||||
|
*
|
||||||
|
* Each of the lists is a queue.
|
||||||
|
* The list at @list is reinitialised
|
||||||
|
*/
|
||||||
|
static inline void list_splice_tail_init(struct list_head *list,
|
||||||
|
struct list_head *head)
|
||||||
|
{
|
||||||
|
if (!list_empty(list)) {
|
||||||
|
__list_splice(list, head->prev, head);
|
||||||
|
INIT_LIST_HEAD(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_entry - get the struct for this entry
|
||||||
|
* @ptr: the &struct list_head pointer.
|
||||||
|
* @type: the type of the struct this is embedded in.
|
||||||
|
* @member: the name of the list_struct within the struct.
|
||||||
|
*/
|
||||||
|
#define list_entry(ptr, type, member) \
|
||||||
|
container_of(ptr, type, member)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_first_entry - get the first element from a list
|
||||||
|
* @ptr: the list head to take the element from.
|
||||||
|
* @type: the type of the struct this is embedded in.
|
||||||
|
* @member: the name of the list_struct within the struct.
|
||||||
|
*
|
||||||
|
* Note, that list is expected to be not empty.
|
||||||
|
*/
|
||||||
|
#define list_first_entry(ptr, type, member) \
|
||||||
|
list_entry((ptr)->next, type, member)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each - iterate over a list
|
||||||
|
* @pos: the &struct list_head to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
*/
|
||||||
|
#define list_for_each(pos, head) \
|
||||||
|
for (pos = (head)->next; prefetch(pos->next), pos != (head); \
|
||||||
|
pos = pos->next)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __list_for_each - iterate over a list
|
||||||
|
* @pos: the &struct list_head to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
*
|
||||||
|
* This variant differs from list_for_each() in that it's the
|
||||||
|
* simplest possible list iteration code, no prefetching is done.
|
||||||
|
* Use this for code that knows the list to be very short (empty
|
||||||
|
* or 1 entry) most of the time.
|
||||||
|
*/
|
||||||
|
#define __list_for_each(pos, head) \
|
||||||
|
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_prev - iterate over a list backwards
|
||||||
|
* @pos: the &struct list_head to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
*/
|
||||||
|
#define list_for_each_prev(pos, head) \
|
||||||
|
for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
|
||||||
|
pos = pos->prev)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_safe - iterate over a list safe against removal of list entry
|
||||||
|
* @pos: the &struct list_head to use as a loop cursor.
|
||||||
|
* @n: another &struct list_head to use as temporary storage
|
||||||
|
* @head: the head for your list.
|
||||||
|
*/
|
||||||
|
#define list_for_each_safe(pos, n, head) \
|
||||||
|
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||||
|
pos = n, n = pos->next)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
|
||||||
|
* @pos: the &struct list_head to use as a loop cursor.
|
||||||
|
* @n: another &struct list_head to use as temporary storage
|
||||||
|
* @head: the head for your list.
|
||||||
|
*/
|
||||||
|
#define list_for_each_prev_safe(pos, n, head) \
|
||||||
|
for (pos = (head)->prev, n = pos->prev; \
|
||||||
|
prefetch(pos->prev), pos != (head); \
|
||||||
|
pos = n, n = pos->prev)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry - iterate over list of given type
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_struct within the struct.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry(pos, head, member) \
|
||||||
|
for (pos = list_entry((head)->next, typeof(*pos), member); \
|
||||||
|
prefetch(pos->member.next), &pos->member != (head); \
|
||||||
|
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry_reverse - iterate backwards over list of given type.
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_struct within the struct.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_reverse(pos, head, member) \
|
||||||
|
for (pos = list_entry((head)->prev, typeof(*pos), member); \
|
||||||
|
prefetch(pos->member.prev), &pos->member != (head); \
|
||||||
|
pos = list_entry(pos->member.prev, typeof(*pos), member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
|
||||||
|
* @pos: the type * to use as a start point
|
||||||
|
* @head: the head of the list
|
||||||
|
* @member: the name of the list_struct within the struct.
|
||||||
|
*
|
||||||
|
* Prepares a pos entry for use as a start point in list_for_each_entry_continue().
|
||||||
|
*/
|
||||||
|
#define list_prepare_entry(pos, head, member) \
|
||||||
|
((pos) ? : list_entry(head, typeof(*pos), member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry_continue - continue iteration over list of given type
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_struct within the struct.
|
||||||
|
*
|
||||||
|
* Continue to iterate over list of given type, continuing after
|
||||||
|
* the current position.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_continue(pos, head, member) \
|
||||||
|
for (pos = list_entry(pos->member.next, typeof(*pos), member); \
|
||||||
|
prefetch(pos->member.next), &pos->member != (head); \
|
||||||
|
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry_continue_reverse - iterate backwards from the given point
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_struct within the struct.
|
||||||
|
*
|
||||||
|
* Start to iterate over list of given type backwards, continuing after
|
||||||
|
* the current position.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_continue_reverse(pos, head, member) \
|
||||||
|
for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
|
||||||
|
prefetch(pos->member.prev), &pos->member != (head); \
|
||||||
|
pos = list_entry(pos->member.prev, typeof(*pos), member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry_from - iterate over list of given type from the current point
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_struct within the struct.
|
||||||
|
*
|
||||||
|
* Iterate over list of given type, continuing from current position.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_from(pos, head, member) \
|
||||||
|
for (; prefetch(pos->member.next), &pos->member != (head); \
|
||||||
|
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @n: another type * to use as temporary storage
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_struct within the struct.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_safe(pos, n, head, member) \
|
||||||
|
for (pos = list_entry((head)->next, typeof(*pos), member), \
|
||||||
|
n = list_entry(pos->member.next, typeof(*pos), member); \
|
||||||
|
&pos->member != (head); \
|
||||||
|
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry_safe_continue - continue list iteration safe against removal
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @n: another type * to use as temporary storage
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_struct within the struct.
|
||||||
|
*
|
||||||
|
* Iterate over list of given type, continuing after current point,
|
||||||
|
* safe against removal of list entry.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_safe_continue(pos, n, head, member) \
|
||||||
|
for (pos = list_entry(pos->member.next, typeof(*pos), member), \
|
||||||
|
n = list_entry(pos->member.next, typeof(*pos), member); \
|
||||||
|
&pos->member != (head); \
|
||||||
|
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry_safe_from - iterate over list from current point safe against removal
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @n: another type * to use as temporary storage
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_struct within the struct.
|
||||||
|
*
|
||||||
|
* Iterate over list of given type from current point, safe against
|
||||||
|
* removal of list entry.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_safe_from(pos, n, head, member) \
|
||||||
|
for (n = list_entry(pos->member.next, typeof(*pos), member); \
|
||||||
|
&pos->member != (head); \
|
||||||
|
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @n: another type * to use as temporary storage
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_struct within the struct.
|
||||||
|
*
|
||||||
|
* Iterate backwards over list of given type, safe against removal
|
||||||
|
* of list entry.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
|
||||||
|
for (pos = list_entry((head)->prev, typeof(*pos), member), \
|
||||||
|
n = list_entry(pos->member.prev, typeof(*pos), member); \
|
||||||
|
&pos->member != (head); \
|
||||||
|
pos = n, n = list_entry(n->member.prev, typeof(*n), member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_safe_reset_next - reset a stale list_for_each_entry_safe loop
|
||||||
|
* @pos: the loop cursor used in the list_for_each_entry_safe loop
|
||||||
|
* @n: temporary storage used in list_for_each_entry_safe
|
||||||
|
* @member: the name of the list_struct within the struct.
|
||||||
|
*
|
||||||
|
* list_safe_reset_next is not safe to use in general if the list may be
|
||||||
|
* modified concurrently (eg. the lock is dropped in the loop body). An
|
||||||
|
* exception to this is if the cursor element (pos) is pinned in the list,
|
||||||
|
* and list_safe_reset_next is called after re-taking the lock and before
|
||||||
|
* completing the current iteration of the loop body.
|
||||||
|
*/
|
||||||
|
#define list_safe_reset_next(pos, n, member) \
|
||||||
|
n = list_entry(pos->member.next, typeof(*pos), member)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Double linked lists with a single pointer list head.
|
||||||
|
* Mostly useful for hash tables where the two pointer list head is
|
||||||
|
* too wasteful.
|
||||||
|
* You lose the ability to access the tail in O(1).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define HLIST_HEAD_INIT { .first = NULL }
|
||||||
|
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
|
||||||
|
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
|
||||||
|
#define INIT_HLIST_NODE hlist_init
|
||||||
|
static inline void hlist_init(struct hlist_node *h)
|
||||||
|
{
|
||||||
|
h->next = NULL;
|
||||||
|
h->pprev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int hlist_unhashed(const struct hlist_node *h)
|
||||||
|
{
|
||||||
|
return !h->pprev;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int hlist_empty(const struct hlist_head *h)
|
||||||
|
{
|
||||||
|
return !h->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void __hlist_del(struct hlist_node *n)
|
||||||
|
{
|
||||||
|
struct hlist_node *next = n->next;
|
||||||
|
struct hlist_node **pprev = n->pprev;
|
||||||
|
*pprev = next;
|
||||||
|
if (next)
|
||||||
|
next->pprev = pprev;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void hlist_del(struct hlist_node *n)
|
||||||
|
{
|
||||||
|
__hlist_del(n);
|
||||||
|
//n->next = NULL;
|
||||||
|
//n->pprev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void hlist_del_init(struct hlist_node *n)
|
||||||
|
{
|
||||||
|
if (!hlist_unhashed(n)) {
|
||||||
|
__hlist_del(n);
|
||||||
|
INIT_HLIST_NODE(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
|
||||||
|
{
|
||||||
|
struct hlist_node *first = h->first;
|
||||||
|
n->next = first;
|
||||||
|
if (first)
|
||||||
|
first->pprev = &n->next;
|
||||||
|
h->first = n;
|
||||||
|
n->pprev = &h->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* next must be != NULL */
|
||||||
|
static inline void hlist_add_before(struct hlist_node *n,
|
||||||
|
struct hlist_node *next)
|
||||||
|
{
|
||||||
|
n->pprev = next->pprev;
|
||||||
|
n->next = next;
|
||||||
|
next->pprev = &n->next;
|
||||||
|
*(n->pprev) = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void hlist_add_after(struct hlist_node *n,
|
||||||
|
struct hlist_node *next)
|
||||||
|
{
|
||||||
|
next->next = n->next;
|
||||||
|
n->next = next;
|
||||||
|
next->pprev = &n->next;
|
||||||
|
|
||||||
|
if(next->next)
|
||||||
|
next->next->pprev = &next->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* after that we'll appear to be on some hlist and hlist_del will work */
|
||||||
|
static inline void hlist_add_fake(struct hlist_node *n)
|
||||||
|
{
|
||||||
|
n->pprev = &n->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Move a list from one list head to another. Fixup the pprev
|
||||||
|
* reference of the first entry if it exists.
|
||||||
|
*/
|
||||||
|
static inline void hlist_move_list(struct hlist_head *old,
|
||||||
|
struct hlist_head *n)
|
||||||
|
{
|
||||||
|
n->first = old->first;
|
||||||
|
if (n->first)
|
||||||
|
n->first->pprev = &n->first;
|
||||||
|
old->first = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
|
||||||
|
|
||||||
|
#define hlist_for_each(pos, head) \
|
||||||
|
for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
|
||||||
|
pos = pos->next)
|
||||||
|
|
||||||
|
#define hlist_for_each_safe(pos, n, head) \
|
||||||
|
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
|
||||||
|
pos = n)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hlist_for_each_entry - iterate over list of given type
|
||||||
|
* @tpos: the type * to use as a loop cursor.
|
||||||
|
* @pos: the &struct hlist_node to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the hlist_node within the struct.
|
||||||
|
*/
|
||||||
|
#define hlist_for_each_entry(tpos, pos, head, member) \
|
||||||
|
for (pos = (head)->first; \
|
||||||
|
pos && ({ prefetch(pos->next); 1;}) && \
|
||||||
|
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
||||||
|
pos = pos->next)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hlist_for_each_entry_continue - iterate over a hlist continuing after current point
|
||||||
|
* @tpos: the type * to use as a loop cursor.
|
||||||
|
* @pos: the &struct hlist_node to use as a loop cursor.
|
||||||
|
* @member: the name of the hlist_node within the struct.
|
||||||
|
*/
|
||||||
|
#define hlist_for_each_entry_continue(tpos, pos, member) \
|
||||||
|
for (pos = (pos)->next; \
|
||||||
|
pos && ({ prefetch(pos->next); 1;}) && \
|
||||||
|
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
||||||
|
pos = pos->next)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hlist_for_each_entry_from - iterate over a hlist continuing from current point
|
||||||
|
* @tpos: the type * to use as a loop cursor.
|
||||||
|
* @pos: the &struct hlist_node to use as a loop cursor.
|
||||||
|
* @member: the name of the hlist_node within the struct.
|
||||||
|
*/
|
||||||
|
#define hlist_for_each_entry_from(tpos, pos, member) \
|
||||||
|
for (; pos && ({ prefetch(pos->next); 1;}) && \
|
||||||
|
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
||||||
|
pos = pos->next)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||||
|
* @tpos: the type * to use as a loop cursor.
|
||||||
|
* @pos: the &struct hlist_node to use as a loop cursor.
|
||||||
|
* @n: another &struct hlist_node to use as temporary storage
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the hlist_node within the struct.
|
||||||
|
*/
|
||||||
|
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
|
||||||
|
for (pos = (head)->first; \
|
||||||
|
pos && ({ n = pos->next; 1; }) && \
|
||||||
|
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
||||||
|
pos = n)
|
||||||
|
|
||||||
|
#endif
|
194
external/libhv/libhv-1.3.2/base/netinet.h
vendored
Normal file
194
external/libhv/libhv-1.3.2/base/netinet.h
vendored
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
#ifndef HV_NETINET_H_
|
||||||
|
#define HV_NETINET_H_
|
||||||
|
|
||||||
|
#include "hplatform.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifdef OS_UNIX
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <netinet/udp.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <netinet/ip_icmp.h>
|
||||||
|
typedef struct iphdr iphdr_t;
|
||||||
|
typedef struct udphdr udphdr_t;
|
||||||
|
typedef struct tcphdr tcphdr_t;
|
||||||
|
|
||||||
|
typedef struct icmphdr icmphdr_t;
|
||||||
|
typedef struct icmp icmp_t;
|
||||||
|
#else
|
||||||
|
*/
|
||||||
|
// sizeof(iphdr_t) = 20
|
||||||
|
typedef struct iphdr_s {
|
||||||
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
|
uint8_t ihl:4; // ip header length
|
||||||
|
uint8_t version:4;
|
||||||
|
#elif BYTE_ORDER == BIG_ENDIAN
|
||||||
|
uint8_t version:4;
|
||||||
|
uint8_t ihl:4;
|
||||||
|
#else
|
||||||
|
#error "BYTE_ORDER undefined!"
|
||||||
|
#endif
|
||||||
|
uint8_t tos; // type of service
|
||||||
|
uint16_t tot_len; // total length
|
||||||
|
uint16_t id;
|
||||||
|
uint16_t frag_off; // fragment offset
|
||||||
|
uint8_t ttl; // Time To Live
|
||||||
|
uint8_t protocol;
|
||||||
|
uint16_t check; // checksum
|
||||||
|
uint32_t saddr; // srcaddr
|
||||||
|
uint32_t daddr; // dstaddr
|
||||||
|
/*The options start here.*/
|
||||||
|
} iphdr_t;
|
||||||
|
|
||||||
|
// sizeof(udphdr_t) = 8
|
||||||
|
typedef struct udphdr_s {
|
||||||
|
uint16_t source; // source port
|
||||||
|
uint16_t dest; // dest port
|
||||||
|
uint16_t len; // udp length
|
||||||
|
uint16_t check; // checksum
|
||||||
|
} udphdr_t;
|
||||||
|
|
||||||
|
// sizeof(tcphdr_t) = 20
|
||||||
|
typedef struct tcphdr_s {
|
||||||
|
uint16_t source; // source port
|
||||||
|
uint16_t dest; // dest port
|
||||||
|
uint32_t seq; // sequence
|
||||||
|
uint32_t ack_seq;
|
||||||
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
|
uint16_t res1:4;
|
||||||
|
uint16_t doff:4;
|
||||||
|
uint16_t fin:1;
|
||||||
|
uint16_t syn:1;
|
||||||
|
uint16_t rst:1;
|
||||||
|
uint16_t psh:1;
|
||||||
|
uint16_t ack:1;
|
||||||
|
uint16_t urg:1;
|
||||||
|
uint16_t res2:2;
|
||||||
|
#elif BYTE_ORDER == BIG_ENDIAN
|
||||||
|
uint16_t doff:4;
|
||||||
|
uint16_t res1:4;
|
||||||
|
uint16_t res2:2;
|
||||||
|
uint16_t urg:1;
|
||||||
|
uint16_t ack:1;
|
||||||
|
uint16_t psh:1;
|
||||||
|
uint16_t rst:1;
|
||||||
|
uint16_t syn:1;
|
||||||
|
uint16_t fin:1;
|
||||||
|
#else
|
||||||
|
#error "BYTE_ORDER undefined!"
|
||||||
|
#endif
|
||||||
|
uint16_t window;
|
||||||
|
uint16_t check; // checksum
|
||||||
|
uint16_t urg_ptr; // urgent pointer
|
||||||
|
} tcphdr_t;
|
||||||
|
|
||||||
|
//----------------------icmp----------------------------------
|
||||||
|
#define ICMP_ECHOREPLY 0 /* Echo Reply */
|
||||||
|
#define ICMP_DEST_UNREACH 3 /* Destination Unreachable */
|
||||||
|
#define ICMP_SOURCE_QUENCH 4 /* Source Quench */
|
||||||
|
#define ICMP_REDIRECT 5 /* Redirect (change route) */
|
||||||
|
#define ICMP_ECHO 8 /* Echo Request */
|
||||||
|
#define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */
|
||||||
|
#define ICMP_PARAMETERPROB 12 /* Parameter Problem */
|
||||||
|
#define ICMP_TIMESTAMP 13 /* Timestamp Request */
|
||||||
|
#define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */
|
||||||
|
#define ICMP_INFO_REQUEST 15 /* Information Request */
|
||||||
|
#define ICMP_INFO_REPLY 16 /* Information Reply */
|
||||||
|
#define ICMP_ADDRESS 17 /* Address Mask Request */
|
||||||
|
#define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */
|
||||||
|
|
||||||
|
// sizeof(icmphdr_t) = 8
|
||||||
|
typedef struct icmphdr_s {
|
||||||
|
uint8_t type; // message type
|
||||||
|
uint8_t code; // type sub-code
|
||||||
|
uint16_t checksum;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint16_t id;
|
||||||
|
uint16_t sequence;
|
||||||
|
} echo;
|
||||||
|
uint32_t gateway;
|
||||||
|
struct {
|
||||||
|
uint16_t reserved;
|
||||||
|
uint16_t mtu;
|
||||||
|
} frag;
|
||||||
|
} un;
|
||||||
|
} icmphdr_t;
|
||||||
|
|
||||||
|
typedef struct icmp_s {
|
||||||
|
uint8_t icmp_type;
|
||||||
|
uint8_t icmp_code;
|
||||||
|
uint16_t icmp_cksum;
|
||||||
|
union {
|
||||||
|
uint8_t ih_pptr;
|
||||||
|
struct in_addr ih_gwaddr;
|
||||||
|
struct ih_idseq {
|
||||||
|
uint16_t icd_id;
|
||||||
|
uint16_t icd_seq;
|
||||||
|
} ih_idseq;
|
||||||
|
uint32_t ih_void;
|
||||||
|
|
||||||
|
struct ih_pmtu {
|
||||||
|
uint16_t ipm_void;
|
||||||
|
uint16_t ipm_nextmtu;
|
||||||
|
} ih_pmtu;
|
||||||
|
|
||||||
|
struct ih_rtradv {
|
||||||
|
uint8_t irt_num_addrs;
|
||||||
|
uint8_t irt_wpa;
|
||||||
|
uint16_t irt_lifetime;
|
||||||
|
} ih_rtradv;
|
||||||
|
} icmp_hun;
|
||||||
|
#define icmp_pptr icmp_hun.ih_pptr
|
||||||
|
#define icmp_gwaddr icmp_hun.ih_gwaddr
|
||||||
|
#define icmp_id icmp_hun.ih_idseq.icd_id
|
||||||
|
#define icmp_seq icmp_hun.ih_idseq.icd_seq
|
||||||
|
#define icmp_void icmp_hun.ih_void
|
||||||
|
#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
|
||||||
|
#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
|
||||||
|
#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
|
||||||
|
#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
|
||||||
|
#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint32_t its_otime;
|
||||||
|
uint32_t its_rtime;
|
||||||
|
uint32_t its_ttime;
|
||||||
|
} id_ts;
|
||||||
|
/*
|
||||||
|
struct {
|
||||||
|
struct ip idi_ip;
|
||||||
|
} id_ip;
|
||||||
|
struct icmp_ra_addr id_radv;
|
||||||
|
*/
|
||||||
|
uint32_t id_mask;
|
||||||
|
uint8_t id_data[1];
|
||||||
|
} icmp_dun;
|
||||||
|
#define icmp_otime icmp_dun.id_ts.its_otime
|
||||||
|
#define icmp_rtime icmp_dun.id_ts.its_rtime
|
||||||
|
#define icmp_ttime icmp_dun.id_ts.its_ttime
|
||||||
|
#define icmp_ip icmp_dun.id_ip.idi_ip
|
||||||
|
#define icmp_radv icmp_dun.id_radv
|
||||||
|
#define icmp_mask icmp_dun.id_mask
|
||||||
|
#define icmp_data icmp_dun.id_data
|
||||||
|
} icmp_t;
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
static inline uint16_t checksum(uint8_t* buf, int len) {
|
||||||
|
unsigned int sum = 0;
|
||||||
|
uint16_t* ptr = (uint16_t*)buf;
|
||||||
|
while(len > 1) {
|
||||||
|
sum += *ptr++;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
if(len) {
|
||||||
|
sum += *(uint8_t*)ptr;
|
||||||
|
}
|
||||||
|
sum = (sum >> 16) + (sum & 0xffff);
|
||||||
|
sum += (sum >> 16);
|
||||||
|
return (uint16_t)(~sum);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HV_NETINET_H_
|
105
external/libhv/libhv-1.3.2/base/queue.h
vendored
Normal file
105
external/libhv/libhv-1.3.2/base/queue.h
vendored
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
#ifndef HV_QUEUE_H_
|
||||||
|
#define HV_QUEUE_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* queue
|
||||||
|
* FIFO: push_back,pop_front
|
||||||
|
* stack
|
||||||
|
* LIFO: push_back,pop_back
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h> // for assert
|
||||||
|
#include <stddef.h> // for NULL
|
||||||
|
#include <stdlib.h> // for malloc,realloc,free
|
||||||
|
#include <string.h> // for memset,memmove
|
||||||
|
|
||||||
|
#include "hbase.h" // for HV_ALLOC, HV_FREE
|
||||||
|
|
||||||
|
#define QUEUE_INIT_SIZE 16
|
||||||
|
|
||||||
|
// #include <deque>
|
||||||
|
// typedef std::deque<type> qtype;
|
||||||
|
#define QUEUE_DECL(type, qtype) \
|
||||||
|
struct qtype { \
|
||||||
|
type* ptr; \
|
||||||
|
size_t size; \
|
||||||
|
size_t maxsize;\
|
||||||
|
size_t _offset;\
|
||||||
|
}; \
|
||||||
|
typedef struct qtype qtype;\
|
||||||
|
\
|
||||||
|
static inline type* qtype##_data(qtype* p) {\
|
||||||
|
return p->ptr + p->_offset;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline int qtype##_size(qtype* p) {\
|
||||||
|
return p->size;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline int qtype##_maxsize(qtype* p) {\
|
||||||
|
return p->maxsize;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline int qtype##_empty(qtype* p) {\
|
||||||
|
return p->size == 0;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline type* qtype##_front(qtype* p) {\
|
||||||
|
return p->size == 0 ? NULL : p->ptr + p->_offset;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline type* qtype##_back(qtype* p) {\
|
||||||
|
return p->size == 0 ? NULL : p->ptr + p->_offset + p->size - 1;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void qtype##_init(qtype* p, int maxsize) {\
|
||||||
|
p->_offset = 0;\
|
||||||
|
p->size = 0;\
|
||||||
|
p->maxsize = maxsize;\
|
||||||
|
HV_ALLOC(p->ptr, sizeof(type) * maxsize);\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void qtype##_clear(qtype* p) {\
|
||||||
|
p->_offset = 0;\
|
||||||
|
p->size = 0;\
|
||||||
|
memset(p->ptr, 0, sizeof(type) * p->maxsize);\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void qtype##_cleanup(qtype* p) {\
|
||||||
|
HV_FREE(p->ptr);\
|
||||||
|
p->_offset = p->size = p->maxsize = 0;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void qtype##_resize(qtype* p, int maxsize) {\
|
||||||
|
if (maxsize == 0) maxsize = QUEUE_INIT_SIZE;\
|
||||||
|
p->ptr = (type*)hv_realloc(p->ptr, sizeof(type) * maxsize, sizeof(type) * p->maxsize);\
|
||||||
|
p->maxsize = maxsize;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void qtype##_double_resize(qtype* p) {\
|
||||||
|
qtype##_resize(p, p->maxsize * 2);\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void qtype##_push_back(qtype* p, type* elem) {\
|
||||||
|
if (p->size == p->maxsize) {\
|
||||||
|
qtype##_double_resize(p);\
|
||||||
|
}\
|
||||||
|
else if (p->_offset + p->size == p->maxsize) {\
|
||||||
|
memmove(p->ptr, p->ptr + p->_offset, sizeof(type) * p->size);\
|
||||||
|
p->_offset = 0;\
|
||||||
|
}\
|
||||||
|
p->ptr[p->_offset + p->size] = *elem;\
|
||||||
|
p->size++;\
|
||||||
|
}\
|
||||||
|
static inline void qtype##_pop_front(qtype* p) {\
|
||||||
|
assert(p->size > 0);\
|
||||||
|
p->size--;\
|
||||||
|
if (++p->_offset == p->maxsize) p->_offset = 0;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
static inline void qtype##_pop_back(qtype* p) {\
|
||||||
|
assert(p->size > 0);\
|
||||||
|
p->size--;\
|
||||||
|
}\
|
||||||
|
|
||||||
|
#endif // HV_QUEUE_H_
|
386
external/libhv/libhv-1.3.2/base/rbtree.c
vendored
Normal file
386
external/libhv/libhv-1.3.2/base/rbtree.c
vendored
Normal file
|
@ -0,0 +1,386 @@
|
||||||
|
/*
|
||||||
|
Red Black Trees
|
||||||
|
(C) 1999 Andrea Arcangeli <andrea@suse.de>
|
||||||
|
(C) 2002 David Woodhouse <dwmw2@infradead.org>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
linux/lib/rbtree.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rbtree.h"
|
||||||
|
|
||||||
|
static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
|
||||||
|
{
|
||||||
|
struct rb_node *right = node->rb_right;
|
||||||
|
|
||||||
|
if ((node->rb_right = right->rb_left))
|
||||||
|
right->rb_left->rb_parent = node;
|
||||||
|
right->rb_left = node;
|
||||||
|
|
||||||
|
if ((right->rb_parent = node->rb_parent))
|
||||||
|
{
|
||||||
|
if (node == node->rb_parent->rb_left)
|
||||||
|
node->rb_parent->rb_left = right;
|
||||||
|
else
|
||||||
|
node->rb_parent->rb_right = right;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
root->rb_node = right;
|
||||||
|
node->rb_parent = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
|
||||||
|
{
|
||||||
|
struct rb_node *left = node->rb_left;
|
||||||
|
|
||||||
|
if ((node->rb_left = left->rb_right))
|
||||||
|
left->rb_right->rb_parent = node;
|
||||||
|
left->rb_right = node;
|
||||||
|
|
||||||
|
if ((left->rb_parent = node->rb_parent))
|
||||||
|
{
|
||||||
|
if (node == node->rb_parent->rb_right)
|
||||||
|
node->rb_parent->rb_right = left;
|
||||||
|
else
|
||||||
|
node->rb_parent->rb_left = left;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
root->rb_node = left;
|
||||||
|
node->rb_parent = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rb_insert_color(struct rb_node *node, struct rb_root *root)
|
||||||
|
{
|
||||||
|
struct rb_node *parent, *gparent;
|
||||||
|
|
||||||
|
while ((parent = node->rb_parent) && parent->rb_color == RB_RED)
|
||||||
|
{
|
||||||
|
gparent = parent->rb_parent;
|
||||||
|
|
||||||
|
if (parent == gparent->rb_left)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
register struct rb_node *uncle = gparent->rb_right;
|
||||||
|
if (uncle && uncle->rb_color == RB_RED)
|
||||||
|
{
|
||||||
|
uncle->rb_color = RB_BLACK;
|
||||||
|
parent->rb_color = RB_BLACK;
|
||||||
|
gparent->rb_color = RB_RED;
|
||||||
|
node = gparent;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->rb_right == node)
|
||||||
|
{
|
||||||
|
register struct rb_node *tmp;
|
||||||
|
__rb_rotate_left(parent, root);
|
||||||
|
tmp = parent;
|
||||||
|
parent = node;
|
||||||
|
node = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent->rb_color = RB_BLACK;
|
||||||
|
gparent->rb_color = RB_RED;
|
||||||
|
__rb_rotate_right(gparent, root);
|
||||||
|
} else {
|
||||||
|
{
|
||||||
|
register struct rb_node *uncle = gparent->rb_left;
|
||||||
|
if (uncle && uncle->rb_color == RB_RED)
|
||||||
|
{
|
||||||
|
uncle->rb_color = RB_BLACK;
|
||||||
|
parent->rb_color = RB_BLACK;
|
||||||
|
gparent->rb_color = RB_RED;
|
||||||
|
node = gparent;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->rb_left == node)
|
||||||
|
{
|
||||||
|
register struct rb_node *tmp;
|
||||||
|
__rb_rotate_right(parent, root);
|
||||||
|
tmp = parent;
|
||||||
|
parent = node;
|
||||||
|
node = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent->rb_color = RB_BLACK;
|
||||||
|
gparent->rb_color = RB_RED;
|
||||||
|
__rb_rotate_left(gparent, root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root->rb_node->rb_color = RB_BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
|
||||||
|
struct rb_root *root)
|
||||||
|
{
|
||||||
|
struct rb_node *other;
|
||||||
|
|
||||||
|
while ((!node || node->rb_color == RB_BLACK) && node != root->rb_node)
|
||||||
|
{
|
||||||
|
if (parent->rb_left == node)
|
||||||
|
{
|
||||||
|
other = parent->rb_right;
|
||||||
|
if (other->rb_color == RB_RED)
|
||||||
|
{
|
||||||
|
other->rb_color = RB_BLACK;
|
||||||
|
parent->rb_color = RB_RED;
|
||||||
|
__rb_rotate_left(parent, root);
|
||||||
|
other = parent->rb_right;
|
||||||
|
}
|
||||||
|
if ((!other->rb_left ||
|
||||||
|
other->rb_left->rb_color == RB_BLACK)
|
||||||
|
&& (!other->rb_right ||
|
||||||
|
other->rb_right->rb_color == RB_BLACK))
|
||||||
|
{
|
||||||
|
other->rb_color = RB_RED;
|
||||||
|
node = parent;
|
||||||
|
parent = node->rb_parent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!other->rb_right ||
|
||||||
|
other->rb_right->rb_color == RB_BLACK)
|
||||||
|
{
|
||||||
|
register struct rb_node *o_left;
|
||||||
|
if ((o_left = other->rb_left))
|
||||||
|
o_left->rb_color = RB_BLACK;
|
||||||
|
other->rb_color = RB_RED;
|
||||||
|
__rb_rotate_right(other, root);
|
||||||
|
other = parent->rb_right;
|
||||||
|
}
|
||||||
|
other->rb_color = parent->rb_color;
|
||||||
|
parent->rb_color = RB_BLACK;
|
||||||
|
if (other->rb_right)
|
||||||
|
other->rb_right->rb_color = RB_BLACK;
|
||||||
|
__rb_rotate_left(parent, root);
|
||||||
|
node = root->rb_node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
other = parent->rb_left;
|
||||||
|
if (other->rb_color == RB_RED)
|
||||||
|
{
|
||||||
|
other->rb_color = RB_BLACK;
|
||||||
|
parent->rb_color = RB_RED;
|
||||||
|
__rb_rotate_right(parent, root);
|
||||||
|
other = parent->rb_left;
|
||||||
|
}
|
||||||
|
if ((!other->rb_left ||
|
||||||
|
other->rb_left->rb_color == RB_BLACK)
|
||||||
|
&& (!other->rb_right ||
|
||||||
|
other->rb_right->rb_color == RB_BLACK))
|
||||||
|
{
|
||||||
|
other->rb_color = RB_RED;
|
||||||
|
node = parent;
|
||||||
|
parent = node->rb_parent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!other->rb_left ||
|
||||||
|
other->rb_left->rb_color == RB_BLACK)
|
||||||
|
{
|
||||||
|
register struct rb_node *o_right;
|
||||||
|
if ((o_right = other->rb_right))
|
||||||
|
o_right->rb_color = RB_BLACK;
|
||||||
|
other->rb_color = RB_RED;
|
||||||
|
__rb_rotate_left(other, root);
|
||||||
|
other = parent->rb_left;
|
||||||
|
}
|
||||||
|
other->rb_color = parent->rb_color;
|
||||||
|
parent->rb_color = RB_BLACK;
|
||||||
|
if (other->rb_left)
|
||||||
|
other->rb_left->rb_color = RB_BLACK;
|
||||||
|
__rb_rotate_right(parent, root);
|
||||||
|
node = root->rb_node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (node)
|
||||||
|
node->rb_color = RB_BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rb_erase(struct rb_node *node, struct rb_root *root)
|
||||||
|
{
|
||||||
|
struct rb_node *child, *parent;
|
||||||
|
int color;
|
||||||
|
|
||||||
|
if (!node->rb_left)
|
||||||
|
child = node->rb_right;
|
||||||
|
else if (!node->rb_right)
|
||||||
|
child = node->rb_left;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct rb_node *old = node, *left;
|
||||||
|
|
||||||
|
node = node->rb_right;
|
||||||
|
while ((left = node->rb_left))
|
||||||
|
node = left;
|
||||||
|
child = node->rb_right;
|
||||||
|
parent = node->rb_parent;
|
||||||
|
color = node->rb_color;
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
child->rb_parent = parent;
|
||||||
|
if (parent)
|
||||||
|
{
|
||||||
|
if (parent->rb_left == node)
|
||||||
|
parent->rb_left = child;
|
||||||
|
else
|
||||||
|
parent->rb_right = child;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
root->rb_node = child;
|
||||||
|
|
||||||
|
if (node->rb_parent == old)
|
||||||
|
parent = node;
|
||||||
|
node->rb_parent = old->rb_parent;
|
||||||
|
node->rb_color = old->rb_color;
|
||||||
|
node->rb_right = old->rb_right;
|
||||||
|
node->rb_left = old->rb_left;
|
||||||
|
|
||||||
|
if (old->rb_parent)
|
||||||
|
{
|
||||||
|
if (old->rb_parent->rb_left == old)
|
||||||
|
old->rb_parent->rb_left = node;
|
||||||
|
else
|
||||||
|
old->rb_parent->rb_right = node;
|
||||||
|
} else
|
||||||
|
root->rb_node = node;
|
||||||
|
|
||||||
|
old->rb_left->rb_parent = node;
|
||||||
|
if (old->rb_right)
|
||||||
|
old->rb_right->rb_parent = node;
|
||||||
|
goto color;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = node->rb_parent;
|
||||||
|
color = node->rb_color;
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
child->rb_parent = parent;
|
||||||
|
if (parent)
|
||||||
|
{
|
||||||
|
if (parent->rb_left == node)
|
||||||
|
parent->rb_left = child;
|
||||||
|
else
|
||||||
|
parent->rb_right = child;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
root->rb_node = child;
|
||||||
|
|
||||||
|
color:
|
||||||
|
if (color == RB_BLACK)
|
||||||
|
__rb_erase_color(child, parent, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function returns the first node (in sort order) of the tree.
|
||||||
|
*/
|
||||||
|
struct rb_node *rb_first(struct rb_root *root)
|
||||||
|
{
|
||||||
|
struct rb_node *n;
|
||||||
|
|
||||||
|
n = root->rb_node;
|
||||||
|
if (!n)
|
||||||
|
return (struct rb_node *)0;
|
||||||
|
while (n->rb_left)
|
||||||
|
n = n->rb_left;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rb_node *rb_last(struct rb_root *root)
|
||||||
|
{
|
||||||
|
struct rb_node *n;
|
||||||
|
|
||||||
|
n = root->rb_node;
|
||||||
|
if (!n)
|
||||||
|
return (struct rb_node *)0;
|
||||||
|
while (n->rb_right)
|
||||||
|
n = n->rb_right;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rb_node *rb_next(struct rb_node *node)
|
||||||
|
{
|
||||||
|
/* If we have a right-hand child, go down and then left as far
|
||||||
|
as we can. */
|
||||||
|
if (node->rb_right) {
|
||||||
|
node = node->rb_right;
|
||||||
|
while (node->rb_left)
|
||||||
|
node = node->rb_left;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No right-hand children. Everything down and left is
|
||||||
|
smaller than us, so any 'next' node must be in the general
|
||||||
|
direction of our parent. Go up the tree; any time the
|
||||||
|
ancestor is a right-hand child of its parent, keep going
|
||||||
|
up. First time it's a left-hand child of its parent, said
|
||||||
|
parent is our 'next' node. */
|
||||||
|
while (node->rb_parent && node == node->rb_parent->rb_right)
|
||||||
|
node = node->rb_parent;
|
||||||
|
|
||||||
|
return node->rb_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rb_node *rb_prev(struct rb_node *node)
|
||||||
|
{
|
||||||
|
/* If we have a left-hand child, go down and then right as far
|
||||||
|
as we can. */
|
||||||
|
if (node->rb_left) {
|
||||||
|
node = node->rb_left;
|
||||||
|
while (node->rb_right)
|
||||||
|
node = node->rb_right;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No left-hand children. Go up till we find an ancestor which
|
||||||
|
is a right-hand child of its parent */
|
||||||
|
while (node->rb_parent && node == node->rb_parent->rb_left)
|
||||||
|
node = node->rb_parent;
|
||||||
|
|
||||||
|
return node->rb_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rb_replace_node(struct rb_node *victim, struct rb_node *newnode,
|
||||||
|
struct rb_root *root)
|
||||||
|
{
|
||||||
|
struct rb_node *parent = victim->rb_parent;
|
||||||
|
|
||||||
|
/* Set the surrounding nodes to point to the replacement */
|
||||||
|
if (parent) {
|
||||||
|
if (victim == parent->rb_left)
|
||||||
|
parent->rb_left = newnode;
|
||||||
|
else
|
||||||
|
parent->rb_right = newnode;
|
||||||
|
} else {
|
||||||
|
root->rb_node = newnode;
|
||||||
|
}
|
||||||
|
if (victim->rb_left)
|
||||||
|
victim->rb_left->rb_parent = newnode;
|
||||||
|
if (victim->rb_right)
|
||||||
|
victim->rb_right->rb_parent = newnode;
|
||||||
|
|
||||||
|
/* Copy the pointers/colour from the victim to the replacement */
|
||||||
|
*newnode = *victim;
|
||||||
|
}
|
147
external/libhv/libhv-1.3.2/base/rbtree.h
vendored
Normal file
147
external/libhv/libhv-1.3.2/base/rbtree.h
vendored
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
/*
|
||||||
|
Red Black Trees
|
||||||
|
(C) 1999 Andrea Arcangeli <andrea@suse.de>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
linux/include/linux/rbtree.h
|
||||||
|
|
||||||
|
To use rbtrees you'll have to implement your own insert and search cores.
|
||||||
|
This will avoid us to use callbacks and to drop drammatically performances.
|
||||||
|
I know it's not the cleaner way, but in C (not in C++) to get
|
||||||
|
performances and genericity...
|
||||||
|
|
||||||
|
Some example of insert and search follows here. The search is a plain
|
||||||
|
normal search over an ordered tree. The insert instead must be implemented
|
||||||
|
in two steps: First, the code must insert the element in order as a red leaf
|
||||||
|
in the tree, and then the support library function rb_insert_color() must
|
||||||
|
be called. Such function will do the not trivial work to rebalance the
|
||||||
|
rbtree, if necessary.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
static inline struct page * rb_search_page_cache(struct inode * inode,
|
||||||
|
unsigned long offset)
|
||||||
|
{
|
||||||
|
struct rb_node * n = inode->i_rb_page_cache.rb_node;
|
||||||
|
struct page * page;
|
||||||
|
|
||||||
|
while (n)
|
||||||
|
{
|
||||||
|
page = rb_entry(n, struct page, rb_page_cache);
|
||||||
|
|
||||||
|
if (offset < page->offset)
|
||||||
|
n = n->rb_left;
|
||||||
|
else if (offset > page->offset)
|
||||||
|
n = n->rb_right;
|
||||||
|
else
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct page * __rb_insert_page_cache(struct inode * inode,
|
||||||
|
unsigned long offset,
|
||||||
|
struct rb_node * node)
|
||||||
|
{
|
||||||
|
struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
|
||||||
|
struct rb_node * parent = NULL;
|
||||||
|
struct page * page;
|
||||||
|
|
||||||
|
while (*p)
|
||||||
|
{
|
||||||
|
parent = *p;
|
||||||
|
page = rb_entry(parent, struct page, rb_page_cache);
|
||||||
|
|
||||||
|
if (offset < page->offset)
|
||||||
|
p = &(*p)->rb_left;
|
||||||
|
else if (offset > page->offset)
|
||||||
|
p = &(*p)->rb_right;
|
||||||
|
else
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
rb_link_node(node, parent, p);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct page * rb_insert_page_cache(struct inode * inode,
|
||||||
|
unsigned long offset,
|
||||||
|
struct rb_node * node)
|
||||||
|
{
|
||||||
|
struct page * ret;
|
||||||
|
if ((ret = __rb_insert_page_cache(inode, offset, node)))
|
||||||
|
goto out;
|
||||||
|
rb_insert_color(node, &inode->i_rb_page_cache);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LINUX_RBTREE_H
|
||||||
|
#define _LINUX_RBTREE_H
|
||||||
|
|
||||||
|
struct rb_node
|
||||||
|
{
|
||||||
|
struct rb_node *rb_parent;
|
||||||
|
struct rb_node *rb_right;
|
||||||
|
struct rb_node *rb_left;
|
||||||
|
char rb_color;
|
||||||
|
#define RB_RED 0
|
||||||
|
#define RB_BLACK 1
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rb_root
|
||||||
|
{
|
||||||
|
struct rb_node *rb_node;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RB_ROOT (struct rb_root){ (struct rb_node *)0, }
|
||||||
|
#define rb_entry(ptr, type, member) \
|
||||||
|
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void rb_insert_color(struct rb_node *node, struct rb_root *root);
|
||||||
|
void rb_erase(struct rb_node *node, struct rb_root *root);
|
||||||
|
|
||||||
|
/* Find logical next and previous nodes in a tree */
|
||||||
|
struct rb_node *rb_next(struct rb_node *);
|
||||||
|
struct rb_node *rb_prev(struct rb_node *);
|
||||||
|
struct rb_node *rb_first(struct rb_root *);
|
||||||
|
struct rb_node *rb_last(struct rb_root *);
|
||||||
|
|
||||||
|
/* Fast replacement of a single node without remove/rebalance/add/rebalance */
|
||||||
|
void rb_replace_node(struct rb_node *victim, struct rb_node *newnode,
|
||||||
|
struct rb_root *root);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void rb_link_node(struct rb_node *node, struct rb_node *parent,
|
||||||
|
struct rb_node **link)
|
||||||
|
{
|
||||||
|
node->rb_parent = parent;
|
||||||
|
node->rb_color = RB_RED;
|
||||||
|
node->rb_left = node->rb_right = (struct rb_node *)0;
|
||||||
|
*link = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _LINUX_RBTREE_H */
|
3476
external/libhv/libhv-1.3.2/cert/cacert.pem
vendored
Normal file
3476
external/libhv/libhv-1.3.2/cert/cacert.pem
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
external/libhv/libhv-1.3.2/cert/gen.sh
vendored
Normal file
2
external/libhv/libhv-1.3.2/cert/gen.sh
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
openssl genrsa -out server.key 2048
|
||||||
|
openssl req -new -x509 -key server.key -out server.crt -days 3650
|
21
external/libhv/libhv-1.3.2/cert/server.crt
vendored
Normal file
21
external/libhv/libhv-1.3.2/cert/server.crt
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDgjCCAmqgAwIBAgIJAL/XKTs4cCwRMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
|
||||||
|
BAYTAkNOMREwDwYDVQQIDAhTaGFuZ2hhaTERMA8GA1UEBwwIU2hhbmdoYWkxITAf
|
||||||
|
BgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xOTA4MjkwNDA1NDda
|
||||||
|
Fw0yOTA4MjYwNDA1NDdaMFYxCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhTaGFuZ2hh
|
||||||
|
aTERMA8GA1UEBwwIU2hhbmdoYWkxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMg
|
||||||
|
UHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANJJ5DaZroEg
|
||||||
|
N34H6A3uq5qDRlJe/ELhWcmtkj57cYb5U/T39C7dEjqGfhURb/NEuYbYoEb+4/lD
|
||||||
|
xJOvn0qqXiJGPt0avecGhQUpggykEj4NZe6W1/WIX81Z1tF6QJZrpUDq4MD1S3KA
|
||||||
|
ETvnTDv0bc6lvT/YDDb8qYMKGNZUTIQKpucdrIet9kDVIrXON4icJL9PDi/zFu3S
|
||||||
|
e6feGsG7SAWv1ZInzF6wkEr8pCQc2Aab9R2BsbDsnVc8qZahfLniif7yDxiRbcEf
|
||||||
|
P4P4cJ7YCD6T1Vyv7bDCnxSEJ+b+j4Ih5XVwHUeK2wG9rrNQ6Z4sSMrv1oSoxVfG
|
||||||
|
mGdHHEhBN0ECAwEAAaNTMFEwHQYDVR0OBBYEFGPOMSeA6p3Vkf4uHdt5eRbrkoXU
|
||||||
|
MB8GA1UdIwQYMBaAFGPOMSeA6p3Vkf4uHdt5eRbrkoXUMA8GA1UdEwEB/wQFMAMB
|
||||||
|
Af8wDQYJKoZIhvcNAQELBQADggEBAEa3x7MzIBQvr43l6zuoK9SBoW6DET42yCRb
|
||||||
|
YA6as/8fFYc4A1GqJStjvOgS0nIhBeCdyLJCy40U5ERhhVKqjPLLHHB4i7sv98Ac
|
||||||
|
aXgVr91eUZcKeuiEkDHWRPCitkPj3p2v9J2VDAHpxfKvIB+r/q+7O4W6tjJT5fPq
|
||||||
|
iUgdpr/R6uBFndBtGc+k65byxSQgvAvdM4kpGA8nnypT9i8SGVp0gB7lMG8avUTU
|
||||||
|
zH16msecIEKLBHED40w9aiuOf3CnMDqGSTilP7p4gvMY4u+qm3zAXN29OHqoldbn
|
||||||
|
j/A8RE9Q1F1H3G+eSltBuug3DBGp0q0EskxiqtfJbzW9G5fwGxM=
|
||||||
|
-----END CERTIFICATE-----
|
27
external/libhv/libhv-1.3.2/cert/server.key
vendored
Normal file
27
external/libhv/libhv-1.3.2/cert/server.key
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpQIBAAKCAQEA0knkNpmugSA3fgfoDe6rmoNGUl78QuFZya2SPntxhvlT9Pf0
|
||||||
|
Lt0SOoZ+FRFv80S5htigRv7j+UPEk6+fSqpeIkY+3Rq95waFBSmCDKQSPg1l7pbX
|
||||||
|
9YhfzVnW0XpAlmulQOrgwPVLcoARO+dMO/RtzqW9P9gMNvypgwoY1lRMhAqm5x2s
|
||||||
|
h632QNUitc43iJwkv08OL/MW7dJ7p94awbtIBa/VkifMXrCQSvykJBzYBpv1HYGx
|
||||||
|
sOydVzyplqF8ueKJ/vIPGJFtwR8/g/hwntgIPpPVXK/tsMKfFIQn5v6PgiHldXAd
|
||||||
|
R4rbAb2us1DpnixIyu/WhKjFV8aYZ0ccSEE3QQIDAQABAoIBAG/JthbMdbbRAI7v
|
||||||
|
9w1I/lKCTKTHN8T59PhAXAj5KG2/J0GHenhbLzCLhIUAowmoVBP6HqH/KAO/YcW8
|
||||||
|
y6oujSIdQ5fYenFQxu/qk+bSZZw1FSXTbHRrDbqlcowjOCh+ivfKpLYO8A+rQv4c
|
||||||
|
RCtvEdyTwNoqqLumbxppCLEPWSmrZOuw/EegeDMRspMpPNsFsk7mcl2w3jJjiX9D
|
||||||
|
NB/yHZZzbZoTf/ayT/ca6FueKqPF52jIiuDzOncE1PqQ8hiPrXFIh4yZYCn1IpnK
|
||||||
|
48hotm3NSixpnag6UziwCRSoPsUCue8h2h3Tr690Lr/7LzILdtBJ+4Qxs3mU8Crz
|
||||||
|
+bM7Xo0CgYEA9K94Gp0gyIxEiIPQ/zcOLeY2y3gUpS5LNaM6lxm82u4nsrC4FQJZ
|
||||||
|
H72kV6YxvedmC1JZcYc6WiaAelkv9GqSekTMFv05rTsA4zQX59habsXPa5r3vzds
|
||||||
|
NzgdjhDfwvWZCp3QXDG1n0wEMKJleG9+CK7khQ4doHmjQtCt0w16AxMCgYEA3AM9
|
||||||
|
qxJSOADePq0G4fJ+4jAr4MgsMBsWaGEWU0Z7pBaTj+hm0ULiwShWy9/bbxw+zZgL
|
||||||
|
VqE0cCiqKsMZMFtZvwX89fIN71YLkyTbl5Y/Lb65HKfKI8a8LGSNNaAd6CG9vy2C
|
||||||
|
krqDKoHILCQdBpT7tSi2vF57+uDxJDH6+VyZ0tsCgYEAsVE7o2W87TihLaEA4wJ9
|
||||||
|
1wtfKCJUK8QZorwwaHGxZ6JwyFDChg8WkSb4IsCAiZNYYtoBkYEi61O9hWx+kQxu
|
||||||
|
LAcRM5O8qWn54azNqikil+Xnw54g7cR3OqkC2gImdf1PM99bsIQhj1giLTBygk2h
|
||||||
|
sx8y4a1yEOo1QuVBIpJAmlsCgYEAv3NehXAC9dLjkny0oYeIHEG43PizYwUfQaNC
|
||||||
|
byLFUquGqtKcLfrbISR+KxjYdV6J1BQ7wZ2z6Omp8l4lnCvR8+U9E7QXpi4lEl0f
|
||||||
|
bVCEF8WAhcwInYtBkgvJyWFUxPwfhq4OkqoUm7elvauLSn/4bNNJ+K7riguWK14G
|
||||||
|
vFl1TcMCgYEA9EDTbpBl1oXICe2xevuh1HJQ1eBXAXP0l3hy0h76czBoBlnoF13A
|
||||||
|
6TOy6iSE3tpEwGPZZ33goKZdKyBLXG3TmemthWMxjBHc31C55gpIIgYPlW4Blv35
|
||||||
|
djt8AlxF68VKIhY7CkaGhNmUpdSSfANHyirfw9rx70IRwRJfnZ5MN+M=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
1028
external/libhv/libhv-1.3.2/cmake/ios.toolchain.cmake
vendored
Normal file
1028
external/libhv/libhv-1.3.2/cmake/ios.toolchain.cmake
vendored
Normal file
File diff suppressed because it is too large
Load Diff
87
external/libhv/libhv-1.3.2/cmake/libhvConfig.cmake
vendored
Normal file
87
external/libhv/libhv-1.3.2/cmake/libhvConfig.cmake
vendored
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
|
||||||
|
include(SelectLibraryConfigurations)
|
||||||
|
|
||||||
|
find_path(libhv_INCLUDE_DIRS hv/hv.h)
|
||||||
|
message("libhv_INCLUDE_DIRS: " ${libhv_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
find_library(libhv_LIBRARY_RELEASE NAMES hv PATHS "${CMAKE_CURRENT_LIST_DIR}/../../lib" NO_DEFAULT_PATH)
|
||||||
|
|
||||||
|
find_library(libhv_LIBRARY_DEBUG NAMES hv PATHS "${CMAKE_CURRENT_LIST_DIR}/../../debug/lib" NO_DEFAULT_PATH)
|
||||||
|
select_library_configurations(libhv)
|
||||||
|
|
||||||
|
if(NOT libhv_LIBRARY)
|
||||||
|
set(libhv_FOUND FALSE)
|
||||||
|
set(LIBHV_FOUND FALSE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
find_file(libhv_LIBRARY_RELEASE_DLL NAMES hv.dll PATHS "${CMAKE_CURRENT_LIST_DIR}/../../bin" NO_DEFAULT_PATH)
|
||||||
|
find_file(libhv_LIBRARY_DEBUG_DLL NAMES hv.dll PATHS "${CMAKE_CURRENT_LIST_DIR}/../../debug/bin" NO_DEFAULT_PATH)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Manage Release Windows shared
|
||||||
|
if(EXISTS "${libhv_LIBRARY_RELEASE_DLL}")
|
||||||
|
add_library(libhv SHARED IMPORTED)
|
||||||
|
set_target_properties(libhv PROPERTIES
|
||||||
|
IMPORTED_CONFIGURATIONS Release
|
||||||
|
IMPORTED_LOCATION_RELEASE "${libhv_LIBRARY_RELEASE_DLL}"
|
||||||
|
IMPORTED_IMPLIB_RELEASE "${libhv_LIBRARY_RELEASE}"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${libhv_INCLUDE_DIRS}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Manage Debug Windows shared
|
||||||
|
if(EXISTS "${libhv_LIBRARY_DEBUG_DLL}")
|
||||||
|
if(EXISTS "${libhv_LIBRARY_RELEASE_DLL}")
|
||||||
|
#message("Debug mode")
|
||||||
|
set_target_properties(libhv PROPERTIES
|
||||||
|
IMPORTED_CONFIGURATIONS "Release;Debug"
|
||||||
|
IMPORTED_LOCATION_RELEASE "${libhv_LIBRARY_RELEASE_DLL}"
|
||||||
|
IMPORTED_IMPLIB_RELEASE "${libhv_LIBRARY_RELEASE}"
|
||||||
|
IMPORTED_LOCATION_DEBUG "${libhv_LIBRARY_DEBUG_DLL}"
|
||||||
|
IMPORTED_IMPLIB_DEBUG "${libhv_LIBRARY_DEBUG}"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${libhv_INCLUDE_DIRS}"
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
add_library(libhv SHARED IMPORTED)
|
||||||
|
set_target_properties(libhv PROPERTIES
|
||||||
|
IMPORTED_CONFIGURATIONS Debug
|
||||||
|
IMPORTED_LOCATION_DEBUG "${libhv_LIBRARY_DEBUG_DLL}"
|
||||||
|
IMPORTED_IMPLIB_DEBUG "${libhv_LIBRARY_DEBUG}"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${libhv_INCLUDE_DIRS}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Manage Release Windows static and Linux shared/static
|
||||||
|
if((NOT EXISTS "${libhv_LIBRARY_RELEASE_DLL}") AND (EXISTS "${libhv_LIBRARY_RELEASE}"))
|
||||||
|
add_library(libhv UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(libhv PROPERTIES
|
||||||
|
IMPORTED_CONFIGURATIONS Release
|
||||||
|
IMPORTED_LOCATION_RELEASE "${libhv_LIBRARY_RELEASE}"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${libhv_INCLUDE_DIRS}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Manage Debug Windows static and Linux shared/static
|
||||||
|
if((NOT EXISTS "${libhv_LIBRARY_DEBUG_DLL}") AND (EXISTS "${libhv_LIBRARY_DEBUG}"))
|
||||||
|
if(EXISTS "${libhv_LIBRARY_RELEASE}")
|
||||||
|
set_target_properties(libhv PROPERTIES
|
||||||
|
IMPORTED_CONFIGURATIONS "Release;Debug"
|
||||||
|
IMPORTED_LOCATION_RELEASE "${libhv_LIBRARY_RELEASE}"
|
||||||
|
IMPORTED_LOCATION_DEBUG "${libhv_LIBRARY_DEBUG}"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${libhv_INCLUDE_DIRS}"
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
add_library(libhv UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(libhv PROPERTIES
|
||||||
|
IMPORTED_CONFIGURATIONS Debug
|
||||||
|
IMPORTED_LOCATION_DEBUG "${libhv_LIBRARY_DEBUG}"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${libhv_INCLUDE_DIRS}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(libhv_FOUND TRUE)
|
||||||
|
set(LIBHV_FOUND TRUE)
|
42
external/libhv/libhv-1.3.2/cmake/utils.cmake
vendored
Normal file
42
external/libhv/libhv-1.3.2/cmake/utils.cmake
vendored
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
include(CheckIncludeFiles)
|
||||||
|
macro(check_header header)
|
||||||
|
string(TOUPPER ${header} str1)
|
||||||
|
string(REGEX REPLACE "[/.]" "_" str2 ${str1})
|
||||||
|
set(str3 HAVE_${str2})
|
||||||
|
check_include_files(${header} ${str3})
|
||||||
|
if (${str3})
|
||||||
|
set(${str3} 1)
|
||||||
|
else()
|
||||||
|
set(${str3} 0)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
include(CheckSymbolExists)
|
||||||
|
macro(check_function function header)
|
||||||
|
string(TOUPPER ${function} str1)
|
||||||
|
set(str2 HAVE_${str1})
|
||||||
|
check_symbol_exists(${function} ${header} ${str2})
|
||||||
|
if (${str2})
|
||||||
|
set(${str2} 1)
|
||||||
|
else()
|
||||||
|
set(${str2} 0)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(list_source_directories srcs)
|
||||||
|
unset(tmp)
|
||||||
|
foreach(dir ${ARGN})
|
||||||
|
aux_source_directory(${dir} tmp)
|
||||||
|
endforeach()
|
||||||
|
set(${srcs} ${tmp})
|
||||||
|
list(FILTER ${srcs} EXCLUDE REGEX ".*_test\\.c")
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(glob_headers_and_sources files)
|
||||||
|
unset(tmp)
|
||||||
|
foreach(dir ${ARGN})
|
||||||
|
file(GLOB tmp ${dir}/*.h ${dir}/*.c ${dir}/*.hpp ${dir}/*.cpp)
|
||||||
|
list(APPEND ${files} ${tmp})
|
||||||
|
endforeach()
|
||||||
|
list(FILTER ${files} EXCLUDE REGEX ".*_test\\.c")
|
||||||
|
endmacro()
|
110
external/libhv/libhv-1.3.2/cmake/vars.cmake
vendored
Normal file
110
external/libhv/libhv-1.3.2/cmake/vars.cmake
vendored
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
# see Makefile.vars
|
||||||
|
|
||||||
|
set(BASE_HEADERS
|
||||||
|
base/hplatform.h
|
||||||
|
base/hdef.h
|
||||||
|
base/hatomic.h
|
||||||
|
base/herr.h
|
||||||
|
base/htime.h
|
||||||
|
base/hmath.h
|
||||||
|
base/hbase.h
|
||||||
|
base/hversion.h
|
||||||
|
base/hsysinfo.h
|
||||||
|
base/hproc.h
|
||||||
|
base/hthread.h
|
||||||
|
base/hmutex.h
|
||||||
|
base/hsocket.h
|
||||||
|
base/hlog.h
|
||||||
|
base/hbuf.h
|
||||||
|
base/hmain.h
|
||||||
|
base/hendian.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SSL_HEADERS
|
||||||
|
ssl/hssl.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(EVENT_HEADERS
|
||||||
|
event/hloop.h
|
||||||
|
event/nlog.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(UTIL_HEADERS
|
||||||
|
util/base64.h
|
||||||
|
util/md5.h
|
||||||
|
util/sha1.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CPPUTIL_HEADERS
|
||||||
|
cpputil/hmap.h
|
||||||
|
cpputil/hstring.h
|
||||||
|
cpputil/hfile.h
|
||||||
|
cpputil/hpath.h
|
||||||
|
cpputil/hdir.h
|
||||||
|
cpputil/hurl.h
|
||||||
|
cpputil/hscope.h
|
||||||
|
cpputil/hthreadpool.h
|
||||||
|
cpputil/hasync.h
|
||||||
|
cpputil/hobjectpool.h
|
||||||
|
cpputil/ifconfig.h
|
||||||
|
cpputil/iniparser.h
|
||||||
|
cpputil/json.hpp
|
||||||
|
cpputil/singleton.h
|
||||||
|
cpputil/ThreadLocalStorage.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(EVPP_HEADERS
|
||||||
|
evpp/Buffer.h
|
||||||
|
evpp/Channel.h
|
||||||
|
evpp/Event.h
|
||||||
|
evpp/EventLoop.h
|
||||||
|
evpp/EventLoopThread.h
|
||||||
|
evpp/EventLoopThreadPool.h
|
||||||
|
evpp/Status.h
|
||||||
|
evpp/TcpClient.h
|
||||||
|
evpp/TcpServer.h
|
||||||
|
evpp/UdpClient.h
|
||||||
|
evpp/UdpServer.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(PROTOCOL_HEADERS
|
||||||
|
protocol/icmp.h
|
||||||
|
protocol/dns.h
|
||||||
|
protocol/ftp.h
|
||||||
|
protocol/smtp.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(HTTP_HEADERS
|
||||||
|
http/httpdef.h
|
||||||
|
http/wsdef.h
|
||||||
|
http/http_content.h
|
||||||
|
http/HttpMessage.h
|
||||||
|
http/HttpParser.h
|
||||||
|
http/WebSocketParser.h
|
||||||
|
http/WebSocketChannel.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(HTTP2_HEADERS
|
||||||
|
http/http2def.h
|
||||||
|
http/grpcdef.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(HTTP_CLIENT_HEADERS
|
||||||
|
http/client/HttpClient.h
|
||||||
|
http/client/requests.h
|
||||||
|
http/client/axios.h
|
||||||
|
http/client/AsyncHttpClient.h
|
||||||
|
http/client/WebSocketClient.h)
|
||||||
|
|
||||||
|
set(HTTP_SERVER_HEADERS
|
||||||
|
http/server/HttpServer.h
|
||||||
|
http/server/HttpService.h
|
||||||
|
http/server/HttpContext.h
|
||||||
|
http/server/HttpResponseWriter.h
|
||||||
|
http/server/WebSocketServer.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(MQTT_HEADERS
|
||||||
|
mqtt/mqtt_protocol.h
|
||||||
|
mqtt/mqtt_client.h
|
||||||
|
)
|
37
external/libhv/libhv-1.3.2/config.ini
vendored
Normal file
37
external/libhv/libhv-1.3.2/config.ini
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# Don't modify this file, you should modify config.mk or
|
||||||
|
# run ./configure --with-MODULE --enable-FEATURE
|
||||||
|
|
||||||
|
PREFIX=/usr/local
|
||||||
|
INSTALL_INCDIR=$(PREFIX)/include/hv
|
||||||
|
INSTALL_LIBDIR=$(PREFIX)/lib
|
||||||
|
|
||||||
|
# modules
|
||||||
|
# include icmp dns ftp smtp
|
||||||
|
WITH_PROTOCOL=no
|
||||||
|
|
||||||
|
WITH_EVPP=yes
|
||||||
|
WITH_HTTP=yes
|
||||||
|
WITH_HTTP_SERVER=yes
|
||||||
|
WITH_HTTP_CLIENT=yes
|
||||||
|
WITH_MQTT=no
|
||||||
|
|
||||||
|
# features
|
||||||
|
# base/hsocket.h: Unix Domain Socket
|
||||||
|
ENABLE_UDS=no
|
||||||
|
# base/RAII.cpp: Windows MiniDumpWriteDump
|
||||||
|
ENABLE_WINDUMP=no
|
||||||
|
# http/http_content.h: KeyValue,QueryParams,MultiPart
|
||||||
|
USE_MULTIMAP=no
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
# for http/client
|
||||||
|
WITH_CURL=no
|
||||||
|
# for http2
|
||||||
|
WITH_NGHTTP2=no
|
||||||
|
# for SSL/TLS
|
||||||
|
WITH_OPENSSL=no
|
||||||
|
WITH_GNUTLS=no
|
||||||
|
WITH_MBEDTLS=no
|
||||||
|
|
||||||
|
# rudp
|
||||||
|
WITH_KCP=no
|
288
external/libhv/libhv-1.3.2/configure
vendored
Executable file
288
external/libhv/libhv-1.3.2/configure
vendored
Executable file
|
@ -0,0 +1,288 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
. "$(dirname "$0")/scripts/shini.sh"
|
||||||
|
|
||||||
|
print_help() {
|
||||||
|
shini_parse "config.ini"
|
||||||
|
cat << END
|
||||||
|
Usage: ./configure [--option] ...
|
||||||
|
|
||||||
|
options:
|
||||||
|
--prefix=PREFIX (DEFAULT: $PREFIX)
|
||||||
|
--incdir=INSTALL_INCDIR (DEFAULT: $PREFIX/include/hv)
|
||||||
|
--libdir=INSTALL_LIBDIR (DEFAULT: $PREFIX/lib)
|
||||||
|
|
||||||
|
--with-MODULE
|
||||||
|
--without-MODULE
|
||||||
|
--enable-FEATURE
|
||||||
|
--disable-FEATURE
|
||||||
|
|
||||||
|
modules:
|
||||||
|
--with-protocol compile protocol module? (DEFAULT: $WITH_PROTOCOL)
|
||||||
|
--with-evpp compile evpp module? (DEFAULT: $WITH_EVPP)
|
||||||
|
--with-http compile http module? (DEFAULT: $WITH_HTTP)
|
||||||
|
--with-http-client compile http client module? (DEFAULT: $WITH_HTTP_CLIENT)
|
||||||
|
--with-http-server compile http server module? (DEFAULT: $WITH_HTTP_SERVER)
|
||||||
|
--with-mqtt compile mqtt module? (DEFAULT: $WITH_MQTT)
|
||||||
|
|
||||||
|
features:
|
||||||
|
--enable-uds enable Unix Domain Socket? (DEFAULT: $ENABLE_UDS)
|
||||||
|
--enable-windump enable Windows coredump? (DEFAULT: $ENABLE_WINDUMP)
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
--with-curl compile with curl? (DEFAULT: $WITH_CURL)
|
||||||
|
--with-nghttp2 compile with nghttp2? (DEFAULT: $WITH_NGHTTP2)
|
||||||
|
--with-openssl compile with openssl? (DEFAULT: $WITH_OPENSSL)
|
||||||
|
--with-gnutls compile with gnutls? (DEFAULT: $WITH_GNUTLS)
|
||||||
|
--with-mbedtls compile with mbedtls? (DEFAULT: $WITH_MBEDTLS)
|
||||||
|
|
||||||
|
rudp:
|
||||||
|
--with-kcp compile with kcp? (DEFAULT: $WITH_KCP)
|
||||||
|
|
||||||
|
END
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir tmp 2>/dev/null
|
||||||
|
while [ -n "$1" ]
|
||||||
|
do
|
||||||
|
opt="$1"
|
||||||
|
KEY=""
|
||||||
|
VAL=yes
|
||||||
|
case $opt in
|
||||||
|
--help)
|
||||||
|
print_help
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
--prefix=*)
|
||||||
|
KEY="PREFIX"
|
||||||
|
VAL=${opt:9}
|
||||||
|
;;
|
||||||
|
--incdir=*)
|
||||||
|
KEY="INSTALL_INCDIR"
|
||||||
|
VAL=${opt:9}
|
||||||
|
;;
|
||||||
|
--libdir=*)
|
||||||
|
KEY="INSTALL_LIBDIR"
|
||||||
|
VAL=${opt:9}
|
||||||
|
;;
|
||||||
|
--with-*)
|
||||||
|
KEY="WITH_${opt:7}"
|
||||||
|
;;
|
||||||
|
--without-*)
|
||||||
|
KEY="WITH_${opt:10}"
|
||||||
|
VAL=no
|
||||||
|
;;
|
||||||
|
--enable-*)
|
||||||
|
KEY="ENABLE_${opt:9}"
|
||||||
|
;;
|
||||||
|
--disable-*)
|
||||||
|
KEY="ENABLE_${opt:10}"
|
||||||
|
VAL=no
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
print_help
|
||||||
|
exit 255
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -n $KEY ]; then
|
||||||
|
FEATURE=$(echo "$KEY" | tr "a-z-" "A-Z_")
|
||||||
|
if [ ! -f tmp/config.mk ]; then
|
||||||
|
cp config.ini tmp/config.mk
|
||||||
|
fi
|
||||||
|
shini_write "tmp/config.mk" "" "$FEATURE" "$VAL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
shift 1
|
||||||
|
done
|
||||||
|
|
||||||
|
# config.mk
|
||||||
|
echo "[config.mk]"
|
||||||
|
if [ -f tmp/config.mk ]; then
|
||||||
|
mv tmp/config.mk config.mk
|
||||||
|
shini_write "config.mk" "" "CONFIG_DATE" "$(date +%Y%m%d)"
|
||||||
|
fi
|
||||||
|
cat config.mk
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Checks for compiler
|
||||||
|
echo -e "\nchecking for compiler..."
|
||||||
|
if [ $CROSS_COMPILE ]; then
|
||||||
|
CC=${CROSS_COMPILE}gcc
|
||||||
|
CXX=${CROSS_COMPILE}g++
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! $CC ]; then
|
||||||
|
CC=gcc
|
||||||
|
CXX=g++
|
||||||
|
fi
|
||||||
|
CC_VERSION=`$CC --version 2>&1 | head -n 1`
|
||||||
|
|
||||||
|
echo "CC = $CC"
|
||||||
|
echo "CXX = $CXX"
|
||||||
|
echo "$CC_VERSION"
|
||||||
|
|
||||||
|
# Checks for os
|
||||||
|
echo -e "\nchecking for os..."
|
||||||
|
HOST_OS=`uname -s`
|
||||||
|
HOST_ARCH=`uname -m`
|
||||||
|
TARGET_PLATFORM=`$CC -v 2>&1 | grep Target | sed 's/Target: //'`
|
||||||
|
TARGET_ARCH=`echo $TARGET_PLATFORM | awk -F'-' '{print $1}'`
|
||||||
|
|
||||||
|
case $TARGET_PLATFORM in
|
||||||
|
*mingw*) TARGET_OS=Windows ;;
|
||||||
|
*android*) TARGET_OS=Android ;;
|
||||||
|
*darwin*) TARGET_OS=Darwin ;;
|
||||||
|
*) TARGET_OS=Linux ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "HOST_OS = $HOST_OS"
|
||||||
|
echo "HOST_ARCH = $HOST_ARCH"
|
||||||
|
echo "TARGET_PLATFORM = $TARGET_PLATFORM"
|
||||||
|
echo "TARGET_OS = $TARGET_OS"
|
||||||
|
echo "TARGET_ARCH = $TARGET_ARCH"
|
||||||
|
|
||||||
|
# hconfig.h
|
||||||
|
echo -e "\n>> hconfig.h"
|
||||||
|
confile=hconfig.h
|
||||||
|
cat << END > $confile
|
||||||
|
#ifndef HV_CONFIG_H_
|
||||||
|
#define HV_CONFIG_H_
|
||||||
|
|
||||||
|
END
|
||||||
|
|
||||||
|
write_define() {
|
||||||
|
cat << END >> hconfig.h
|
||||||
|
#ifndef $macro
|
||||||
|
#define $macro $value
|
||||||
|
#endif
|
||||||
|
|
||||||
|
END
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckHeaderExists() {
|
||||||
|
rm tmp/check 2>/dev/null
|
||||||
|
cat << END > tmp/check.c
|
||||||
|
#include <$header>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
END
|
||||||
|
$CC -o tmp/check tmp/check.c 2>/dev/null
|
||||||
|
if [ -x tmp/check ]; then
|
||||||
|
value=1
|
||||||
|
else
|
||||||
|
value=0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckSymbolExists() {
|
||||||
|
CheckHeaderExists
|
||||||
|
if [ $value -eq 0 ]; then
|
||||||
|
return;
|
||||||
|
fi
|
||||||
|
rm tmp/check 2>/dev/null
|
||||||
|
cat << END > tmp/check.c
|
||||||
|
#include <$header>
|
||||||
|
|
||||||
|
int $function(void** pp) {return 0;}
|
||||||
|
int main() {
|
||||||
|
void* p;
|
||||||
|
return $function(&p);
|
||||||
|
}
|
||||||
|
|
||||||
|
END
|
||||||
|
$CC -o tmp/check tmp/check.c 2>/dev/null
|
||||||
|
if [ -x tmp/check ]; then
|
||||||
|
value=0
|
||||||
|
else
|
||||||
|
value=1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_header() {
|
||||||
|
echo -n "checking for $header... "
|
||||||
|
CheckHeaderExists
|
||||||
|
if [ $value -eq 0 ]; then
|
||||||
|
echo "no"
|
||||||
|
else
|
||||||
|
echo "yes"
|
||||||
|
fi
|
||||||
|
macro=HAVE_$(echo $header | tr a-z./ A-Z__)
|
||||||
|
write_define
|
||||||
|
}
|
||||||
|
|
||||||
|
check_function() {
|
||||||
|
echo -n "checking for $function... "
|
||||||
|
CheckSymbolExists
|
||||||
|
if [ $value -eq 0 ]; then
|
||||||
|
echo "no"
|
||||||
|
else
|
||||||
|
echo "yes"
|
||||||
|
fi
|
||||||
|
macro=HAVE_$(echo $function | tr a-z A-Z)
|
||||||
|
write_define
|
||||||
|
}
|
||||||
|
|
||||||
|
check_option() {
|
||||||
|
value=$(eval echo \$$option)
|
||||||
|
echo "checking for $option=$value"
|
||||||
|
if [ "$value" == "yes" ]; then
|
||||||
|
cat << END >> $confile
|
||||||
|
#define $option 1
|
||||||
|
END
|
||||||
|
else
|
||||||
|
cat << END >> $confile
|
||||||
|
/* #undef $option */
|
||||||
|
END
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Checks for programs
|
||||||
|
|
||||||
|
# Checks for libraries
|
||||||
|
|
||||||
|
# Checks for header files
|
||||||
|
header=stdbool.h && check_header
|
||||||
|
header=stdint.h && check_header
|
||||||
|
header=stdatomic.h && check_header
|
||||||
|
header=sys/types.h && check_header
|
||||||
|
header=sys/stat.h && check_header
|
||||||
|
header=sys/time.h && check_header
|
||||||
|
header=fcntl.h && check_header
|
||||||
|
header=pthread.h && check_header
|
||||||
|
header=endian.h && check_header
|
||||||
|
header=sys/endian.h && check_header
|
||||||
|
|
||||||
|
# Checks for functions
|
||||||
|
function=gettid && header=unistd.h && check_function
|
||||||
|
function=strlcpy && header=string.h && check_function
|
||||||
|
function=strlcat && header=string.h && check_function
|
||||||
|
function=clock_gettime && header=time.h && check_function
|
||||||
|
function=gettimeofday && header=sys/time.h && check_function
|
||||||
|
function=pthread_spin_lock && header=pthread.h && check_function
|
||||||
|
function=pthread_mutex_timedlock && header=pthread.h && check_function
|
||||||
|
function=sem_timedwait && header=semaphore.h && check_function
|
||||||
|
function=pipe && header=unistd.h && check_function
|
||||||
|
function=socketpair && header=sys/socket.h && check_function
|
||||||
|
function=eventfd && header=sys/eventfd.h && check_function
|
||||||
|
function=setproctitle && header=unistd.h && check_function
|
||||||
|
|
||||||
|
# Checks for options
|
||||||
|
source config.mk 2>/dev/null
|
||||||
|
option=WITH_OPENSSL && check_option
|
||||||
|
option=WITH_GNUTLS && check_option
|
||||||
|
option=WITH_MBEDTLS && check_option
|
||||||
|
option=ENABLE_UDS && check_option
|
||||||
|
option=USE_MULTIMAP && check_option
|
||||||
|
option=WITH_KCP && check_option
|
||||||
|
|
||||||
|
# end confile
|
||||||
|
cat << END >> $confile
|
||||||
|
|
||||||
|
#endif // HV_CONFIG_H_
|
||||||
|
END
|
||||||
|
|
||||||
|
echo "configure done."
|
66
external/libhv/libhv-1.3.2/cpputil/RAII.cpp
vendored
Normal file
66
external/libhv/libhv-1.3.2/cpputil/RAII.cpp
vendored
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#include "hplatform.h"
|
||||||
|
|
||||||
|
#ifdef OS_WIN
|
||||||
|
#ifdef ENABLE_WINDUMP
|
||||||
|
#include <dbghelp.h>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma comment(lib,"dbghelp.lib")
|
||||||
|
#endif
|
||||||
|
static LONG UnhandledException(EXCEPTION_POINTERS *pException) {
|
||||||
|
char modulefile[256];
|
||||||
|
GetModuleFileName(NULL, modulefile, sizeof(modulefile));
|
||||||
|
char* pos = strrchr(modulefile, '\\');
|
||||||
|
char* modulefilename = pos + 1;
|
||||||
|
SYSTEMTIME st;
|
||||||
|
GetLocalTime(&st);
|
||||||
|
char filename[256];
|
||||||
|
snprintf(filename, sizeof(filename), "core_%s_%04d%02d%02d_%02d%02d%02d_%03d.dump",
|
||||||
|
modulefilename,
|
||||||
|
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
|
||||||
|
HANDLE hDumpFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
|
||||||
|
dumpInfo.ExceptionPointers = pException;
|
||||||
|
dumpInfo.ThreadId = GetCurrentThreadId();
|
||||||
|
dumpInfo.ClientPointers = TRUE;
|
||||||
|
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);
|
||||||
|
CloseHandle(hDumpFile);
|
||||||
|
return EXCEPTION_EXECUTE_HANDLER;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "hsocket.h"
|
||||||
|
class WsaRAII {
|
||||||
|
public:
|
||||||
|
WsaRAII() {
|
||||||
|
WSAInit();
|
||||||
|
#ifdef ENABLE_WINDUMP
|
||||||
|
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)UnhandledException);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
~WsaRAII() {
|
||||||
|
WSADeinit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static WsaRAII s_wsa;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WITH_CURL
|
||||||
|
#include "curl/curl.h"
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
//#pragma comment(lib, "libcurl.a")
|
||||||
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
|
#pragma comment(lib, "wldap32.lib")
|
||||||
|
#pragma comment(lib, "advapi32.lib")
|
||||||
|
#pragma comment(lib, "crypt32.lib")
|
||||||
|
#endif
|
||||||
|
class CurlRAII {
|
||||||
|
public:
|
||||||
|
CurlRAII() {
|
||||||
|
curl_global_init(CURL_GLOBAL_ALL);
|
||||||
|
}
|
||||||
|
~CurlRAII() {
|
||||||
|
curl_global_cleanup();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static CurlRAII s_curl;
|
||||||
|
#endif
|
20
external/libhv/libhv-1.3.2/cpputil/README.md
vendored
Normal file
20
external/libhv/libhv-1.3.2/cpputil/README.md
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── hasync.h hv::async实现
|
||||||
|
├── hdir.h 目录(ls实现)
|
||||||
|
├── hfile.h 文件类
|
||||||
|
├── hobjectpool.h 对象池
|
||||||
|
├── hpath.h 路径操作
|
||||||
|
├── hscope.h 作用域模板类
|
||||||
|
├── hstring.h 字符串操作
|
||||||
|
├── hthreadpool.h 线程池
|
||||||
|
├── hurl.h URL操作
|
||||||
|
├── ifconfig.h 网络配置(ifconfig实现)
|
||||||
|
├── iniparser.h INI解析
|
||||||
|
├── json.hpp JSON解析
|
||||||
|
├── singleton.h 单例模式宏
|
||||||
|
└── ThreadLocalStorage.h 线程本地存储类
|
||||||
|
|
||||||
|
```
|
32
external/libhv/libhv-1.3.2/cpputil/ThreadLocalStorage.cpp
vendored
Normal file
32
external/libhv/libhv-1.3.2/cpputil/ThreadLocalStorage.cpp
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#include "ThreadLocalStorage.h"
|
||||||
|
|
||||||
|
#include "hthread.h"
|
||||||
|
|
||||||
|
namespace hv {
|
||||||
|
|
||||||
|
ThreadLocalStorage ThreadLocalStorage::tls[ThreadLocalStorage::MAX_NUM];
|
||||||
|
|
||||||
|
void ThreadLocalStorage::set(int idx, void* val) {
|
||||||
|
return tls[idx].set(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* ThreadLocalStorage::get(int idx) {
|
||||||
|
return tls[idx].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadLocalStorage::setThreadName(const char* name) {
|
||||||
|
set(THREAD_NAME, (void*)name);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ThreadLocalStorage::threadName() {
|
||||||
|
void* value = get(THREAD_NAME);
|
||||||
|
if (value) {
|
||||||
|
return (char*)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char unnamed[32] = {0};
|
||||||
|
snprintf(unnamed, sizeof(unnamed)-1, "thread-%ld", hv_gettid());
|
||||||
|
return unnamed;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
67
external/libhv/libhv-1.3.2/cpputil/ThreadLocalStorage.h
vendored
Normal file
67
external/libhv/libhv-1.3.2/cpputil/ThreadLocalStorage.h
vendored
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#ifndef HV_THREAD_LOCAL_STORAGE_H_
|
||||||
|
#define HV_THREAD_LOCAL_STORAGE_H_
|
||||||
|
|
||||||
|
#include "hexport.h"
|
||||||
|
#include "hplatform.h"
|
||||||
|
|
||||||
|
#ifdef OS_WIN
|
||||||
|
|
||||||
|
#define hthread_key_t DWORD
|
||||||
|
#define INVALID_HTHREAD_KEY 0xFFFFFFFF
|
||||||
|
#define hthread_key_create(pkey) *pkey = TlsAlloc()
|
||||||
|
#define hthread_key_delete TlsFree
|
||||||
|
#define hthread_get_value TlsGetValue
|
||||||
|
#define hthread_set_value TlsSetValue
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define hthread_key_t pthread_key_t
|
||||||
|
#define INVALID_HTHREAD_KEY 0xFFFFFFFF
|
||||||
|
#define hthread_key_create(pkey) pthread_key_create(pkey, NULL)
|
||||||
|
#define hthread_key_delete pthread_key_delete
|
||||||
|
#define hthread_get_value pthread_getspecific
|
||||||
|
#define hthread_set_value pthread_setspecific
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
namespace hv {
|
||||||
|
|
||||||
|
class HV_EXPORT ThreadLocalStorage {
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
THREAD_NAME = 0,
|
||||||
|
EVENT_LOOP = 1,
|
||||||
|
MAX_NUM = 16,
|
||||||
|
};
|
||||||
|
ThreadLocalStorage() {
|
||||||
|
hthread_key_create(&key);
|
||||||
|
}
|
||||||
|
|
||||||
|
~ThreadLocalStorage() {
|
||||||
|
hthread_key_delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(void* val) {
|
||||||
|
hthread_set_value(key, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* get() {
|
||||||
|
return hthread_get_value(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(int idx, void* val);
|
||||||
|
static void* get(int idx);
|
||||||
|
|
||||||
|
static void setThreadName(const char* name);
|
||||||
|
static const char* threadName();
|
||||||
|
|
||||||
|
private:
|
||||||
|
hthread_key_t key;
|
||||||
|
static ThreadLocalStorage tls[MAX_NUM];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // HV_THREAD_LOCAL_STORAGE_H_
|
7
external/libhv/libhv-1.3.2/cpputil/hasync.cpp
vendored
Normal file
7
external/libhv/libhv-1.3.2/cpputil/hasync.cpp
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#include "hasync.h"
|
||||||
|
|
||||||
|
namespace hv {
|
||||||
|
|
||||||
|
SINGLETON_IMPL(GlobalThreadPool)
|
||||||
|
|
||||||
|
}
|
49
external/libhv/libhv-1.3.2/cpputil/hasync.h
vendored
Normal file
49
external/libhv/libhv-1.3.2/cpputil/hasync.h
vendored
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#ifndef HV_ASYNC_H_
|
||||||
|
#define HV_ASYNC_H_
|
||||||
|
|
||||||
|
#include "hexport.h"
|
||||||
|
#include "hthreadpool.h"
|
||||||
|
#include "singleton.h"
|
||||||
|
|
||||||
|
namespace hv {
|
||||||
|
|
||||||
|
class HV_EXPORT GlobalThreadPool : public HThreadPool {
|
||||||
|
SINGLETON_DECL(GlobalThreadPool)
|
||||||
|
protected:
|
||||||
|
GlobalThreadPool() : HThreadPool() {}
|
||||||
|
~GlobalThreadPool() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return a future, calling future.get() will wait task done and return RetType.
|
||||||
|
* async(fn, args...)
|
||||||
|
* async(std::bind(&Class::mem_fn, &obj))
|
||||||
|
* async(std::mem_fn(&Class::mem_fn, &obj))
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
template<class Fn, class... Args>
|
||||||
|
auto async(Fn&& fn, Args&&... args) -> std::future<decltype(fn(args...))> {
|
||||||
|
return GlobalThreadPool::instance()->commit(std::forward<Fn>(fn), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
class async {
|
||||||
|
public:
|
||||||
|
static void startup(int min_threads = DEFAULT_THREAD_POOL_MIN_THREAD_NUM,
|
||||||
|
int max_threads = DEFAULT_THREAD_POOL_MAX_THREAD_NUM,
|
||||||
|
int max_idle_ms = DEFAULT_THREAD_POOL_MAX_IDLE_TIME) {
|
||||||
|
GlobalThreadPool* gtp = GlobalThreadPool::instance();
|
||||||
|
if (gtp->isStarted()) return;
|
||||||
|
gtp->setMinThreadNum(min_threads);
|
||||||
|
gtp->setMaxThreadNum(max_threads);
|
||||||
|
gtp->setMaxIdleTime(max_idle_ms);
|
||||||
|
gtp->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cleanup() {
|
||||||
|
GlobalThreadPool::exitInstance();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace hv
|
||||||
|
|
||||||
|
#endif // HV_ASYNC_H_
|
88
external/libhv/libhv-1.3.2/cpputil/hdir.cpp
vendored
Normal file
88
external/libhv/libhv-1.3.2/cpputil/hdir.cpp
vendored
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
#include "hdir.h"
|
||||||
|
|
||||||
|
#include "hplatform.h"
|
||||||
|
|
||||||
|
#ifdef OS_WIN
|
||||||
|
//FILETIME starts from 1601-01-01 UTC, epoch from 1970-01-01 UTC
|
||||||
|
//FILETIME unit (100ns)
|
||||||
|
#define FILETIME_EPOCH_DIFF 11644473600 // s
|
||||||
|
time_t FileTime2Epoch(FILETIME filetime) {
|
||||||
|
uint64_t ll = (((uint64_t)filetime.dwHighDateTime) << 32) | filetime.dwLowDateTime;
|
||||||
|
ll /= 1e7; // s
|
||||||
|
return ll - FILETIME_EPOCH_DIFF;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool less(const hdir_t& lhs, const hdir_t& rhs) {
|
||||||
|
return stricmp(lhs.name, rhs.name) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int listdir(const char* dir, std::list<hdir_t>& dirs) {
|
||||||
|
int dirlen = strlen(dir);
|
||||||
|
if (dirlen > 256) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
char path[512];
|
||||||
|
strcpy(path, dir);
|
||||||
|
if (dir[dirlen-1] != '/') {
|
||||||
|
strcat(path, "/");
|
||||||
|
++dirlen;
|
||||||
|
}
|
||||||
|
dirs.clear();
|
||||||
|
#ifdef OS_UNIX
|
||||||
|
// opendir -> readdir -> closedir
|
||||||
|
DIR* dp = opendir(dir);
|
||||||
|
if (dp == NULL) return -1;
|
||||||
|
struct dirent* result = NULL;
|
||||||
|
struct stat st;
|
||||||
|
hdir_t tmp;
|
||||||
|
while ((result = readdir(dp))) {
|
||||||
|
memset(&tmp, 0, sizeof(hdir_t));
|
||||||
|
strncpy(tmp.name, result->d_name, sizeof(tmp.name));
|
||||||
|
strncpy(path+dirlen, result->d_name, sizeof(path)-dirlen);
|
||||||
|
if (lstat(path, &st) == 0) {
|
||||||
|
if (S_ISREG(st.st_mode)) tmp.type = 'f';
|
||||||
|
else if (S_ISDIR(st.st_mode)) tmp.type = 'd';
|
||||||
|
else if (S_ISLNK(st.st_mode)) tmp.type = 'l';
|
||||||
|
else if (S_ISBLK(st.st_mode)) tmp.type = 'b';
|
||||||
|
else if (S_ISCHR(st.st_mode)) tmp.type = 'c';
|
||||||
|
else if (S_ISSOCK(st.st_mode)) tmp.type = 's';
|
||||||
|
else if (S_ISFIFO(st.st_mode)) tmp.type = 'p';
|
||||||
|
else tmp.type = '-';
|
||||||
|
tmp.mode = st.st_mode & 0777;
|
||||||
|
tmp.size = st.st_size;
|
||||||
|
tmp.atime = st.st_atime;
|
||||||
|
tmp.mtime = st.st_mtime;
|
||||||
|
tmp.ctime = st.st_ctime;
|
||||||
|
}
|
||||||
|
dirs.push_back(tmp);
|
||||||
|
}
|
||||||
|
closedir(dp);
|
||||||
|
#elif defined(OS_WIN)
|
||||||
|
// FindFirstFile -> FindNextFile -> FindClose
|
||||||
|
strcat(path, "*");
|
||||||
|
WIN32_FIND_DATAA data;
|
||||||
|
HANDLE h = FindFirstFileA(path, &data);
|
||||||
|
if (h == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
hdir_t tmp;
|
||||||
|
do {
|
||||||
|
memset(&tmp, 0, sizeof(hdir_t));
|
||||||
|
strncpy(tmp.name, data.cFileName, sizeof(tmp.name));
|
||||||
|
tmp.type = 'f';
|
||||||
|
if (data.dwFileAttributes & _A_SUBDIR) {
|
||||||
|
tmp.type = 'd';
|
||||||
|
}
|
||||||
|
tmp.mode = 0777;
|
||||||
|
tmp.size = (((uint64_t)data.nFileSizeHigh) << 32) | data.nFileSizeLow;
|
||||||
|
tmp.atime = FileTime2Epoch(data.ftLastAccessTime);
|
||||||
|
tmp.mtime = FileTime2Epoch(data.ftLastWriteTime);
|
||||||
|
tmp.ctime = FileTime2Epoch(data.ftCreationTime);
|
||||||
|
dirs.push_back(tmp);
|
||||||
|
} while (FindNextFileA(h, &data));
|
||||||
|
FindClose(h);
|
||||||
|
#endif
|
||||||
|
dirs.sort(less);
|
||||||
|
return dirs.size();
|
||||||
|
}
|
69
external/libhv/libhv-1.3.2/cpputil/hdir.h
vendored
Normal file
69
external/libhv/libhv-1.3.2/cpputil/hdir.h
vendored
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#ifndef HV_DIR_H_
|
||||||
|
#define HV_DIR_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
*@code
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
const char* dir = ".";
|
||||||
|
if (argc > 1) {
|
||||||
|
dir = argv[1];
|
||||||
|
}
|
||||||
|
std::list<hdir_t> dirs;
|
||||||
|
listdir(dir, dirs);
|
||||||
|
for (auto& item : dirs) {
|
||||||
|
printf("%c%c%c%c%c%c%c%c%c%c\t",
|
||||||
|
item.type,
|
||||||
|
item.mode & 0400 ? 'r' : '-',
|
||||||
|
item.mode & 0200 ? 'w' : '-',
|
||||||
|
item.mode & 0100 ? 'x' : '-',
|
||||||
|
item.mode & 0040 ? 'r' : '-',
|
||||||
|
item.mode & 0020 ? 'w' : '-',
|
||||||
|
item.mode & 0010 ? 'x' : '-',
|
||||||
|
item.mode & 0004 ? 'r' : '-',
|
||||||
|
item.mode & 0002 ? 'w' : '-',
|
||||||
|
item.mode & 0001 ? 'x' : '-');
|
||||||
|
float hsize;
|
||||||
|
if (item.size < 1024) {
|
||||||
|
printf("%lu\t", item.size);
|
||||||
|
}
|
||||||
|
else if ((hsize = item.size/1024.0f) < 1024.0f) {
|
||||||
|
printf("%.1fK\t", hsize);
|
||||||
|
}
|
||||||
|
else if ((hsize /= 1024.0f) < 1024.0f) {
|
||||||
|
printf("%.1fM\t", hsize);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hsize /= 1024.0f;
|
||||||
|
printf("%.1fG\t", hsize);
|
||||||
|
}
|
||||||
|
struct tm* tm = localtime(&item.mtime);
|
||||||
|
printf("%04d-%02d-%02d %02d:%02d:%02d\t",
|
||||||
|
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||||
|
printf("%s%s\n", item.name, item.type == 'd' ? "/" : "");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include "hexport.h"
|
||||||
|
|
||||||
|
typedef struct hdir_s {
|
||||||
|
char name[256];
|
||||||
|
char type; // f:file d:dir l:link b:block c:char s:socket p:pipe
|
||||||
|
char reserverd;
|
||||||
|
unsigned short mode;
|
||||||
|
size_t size;
|
||||||
|
time_t atime;
|
||||||
|
time_t mtime;
|
||||||
|
time_t ctime;
|
||||||
|
} hdir_t;
|
||||||
|
|
||||||
|
// listdir: same as ls on unix, dir on win
|
||||||
|
HV_EXPORT int listdir(const char* dir, std::list<hdir_t>& dirs);
|
||||||
|
|
||||||
|
#endif // HV_DIR_H_
|
134
external/libhv/libhv-1.3.2/cpputil/hfile.h
vendored
Normal file
134
external/libhv/libhv-1.3.2/cpputil/hfile.h
vendored
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
#ifndef HV_FILE_H_
|
||||||
|
#define HV_FILE_H_
|
||||||
|
|
||||||
|
#include <string> // for std::string
|
||||||
|
|
||||||
|
#include "hplatform.h" // for stat
|
||||||
|
#include "hbuf.h" // for HBuf
|
||||||
|
|
||||||
|
class HFile {
|
||||||
|
public:
|
||||||
|
HFile() {
|
||||||
|
filepath[0] = '\0';
|
||||||
|
fp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
~HFile() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
int open(const char* filepath, const char* mode) {
|
||||||
|
close();
|
||||||
|
strncpy(this->filepath, filepath, MAX_PATH - 1);
|
||||||
|
fp = fopen(filepath, mode);
|
||||||
|
return fp ? 0 : errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close() {
|
||||||
|
if (fp) {
|
||||||
|
fclose(fp);
|
||||||
|
fp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isopen() {
|
||||||
|
return fp != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int remove() {
|
||||||
|
close();
|
||||||
|
return ::remove(filepath);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rename(const char* newpath) {
|
||||||
|
close();
|
||||||
|
return ::rename(filepath, newpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t read(void* ptr, size_t len) {
|
||||||
|
return fread(ptr, 1, len, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t write(const void* ptr, size_t len) {
|
||||||
|
return fwrite(ptr, 1, len, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t write(const std::string& str) {
|
||||||
|
return write(str.c_str(), str.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
int seek(size_t offset, int whence = SEEK_SET) {
|
||||||
|
return fseek(fp, offset, whence);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tell() {
|
||||||
|
return ftell(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int flush() {
|
||||||
|
return fflush(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t size(const char* filepath) {
|
||||||
|
struct stat st;
|
||||||
|
memset(&st, 0, sizeof(st));
|
||||||
|
stat(filepath, &st);
|
||||||
|
return st.st_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() {
|
||||||
|
return HFile::size(filepath);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t readall(HBuf& buf) {
|
||||||
|
size_t filesize = size();
|
||||||
|
if (filesize == 0) return 0;
|
||||||
|
buf.resize(filesize);
|
||||||
|
return fread(buf.base, 1, filesize, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t readall(std::string& str) {
|
||||||
|
size_t filesize = size();
|
||||||
|
if (filesize == 0) return 0;
|
||||||
|
str.resize(filesize);
|
||||||
|
return fread((void*)str.data(), 1, filesize, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readline(std::string& str) {
|
||||||
|
str.clear();
|
||||||
|
char ch;
|
||||||
|
while (fread(&ch, 1, 1, fp)) {
|
||||||
|
if (ch == '\n') {
|
||||||
|
// unix: LF
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (ch == '\r') {
|
||||||
|
// dos: CRLF
|
||||||
|
// read LF
|
||||||
|
if (fread(&ch, 1, 1, fp) && ch != '\n') {
|
||||||
|
// mac: CR
|
||||||
|
fseek(fp, -1, SEEK_CUR);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
str += ch;
|
||||||
|
}
|
||||||
|
return str.length() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int readrange(std::string& str, size_t from = 0, size_t to = 0) {
|
||||||
|
size_t filesize = size();
|
||||||
|
if (filesize == 0) return 0;
|
||||||
|
if (to == 0 || to >= filesize) to = filesize - 1;
|
||||||
|
size_t readbytes = to - from + 1;
|
||||||
|
str.resize(readbytes);
|
||||||
|
fseek(fp, from, SEEK_SET);
|
||||||
|
return fread((void*)str.data(), 1, readbytes, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
char filepath[MAX_PATH];
|
||||||
|
FILE* fp;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HV_FILE_H_
|
55
external/libhv/libhv-1.3.2/cpputil/hmap.h
vendored
Normal file
55
external/libhv/libhv-1.3.2/cpputil/hmap.h
vendored
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#ifndef HV_MAP_H_
|
||||||
|
#define HV_MAP_H_
|
||||||
|
|
||||||
|
#include "hconfig.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// MultiMap
|
||||||
|
namespace std {
|
||||||
|
/*
|
||||||
|
int main() {
|
||||||
|
std::MultiMap<std::string, std::string> kvs;
|
||||||
|
kvs["name"] = "hw";
|
||||||
|
kvs["filename"] = "1.jpg";
|
||||||
|
kvs["filename"] = "2.jpg";
|
||||||
|
//kvs.insert(std::pair<std::string,std::string>("name", "hw"));
|
||||||
|
//kvs.insert(std::pair<std::string,std::string>("filename", "1.jpg"));
|
||||||
|
//kvs.insert(std::pair<std::string,std::string>("filename", "2.jpg"));
|
||||||
|
for (auto& pair : kvs) {
|
||||||
|
printf("%s:%s\n", pair.first.c_str(), pair.second.c_str());
|
||||||
|
}
|
||||||
|
auto iter = kvs.find("filename");
|
||||||
|
if (iter != kvs.end()) {
|
||||||
|
for (int i = 0; i < kvs.count("filename"); ++i, ++iter) {
|
||||||
|
printf("%s:%s\n", iter->first.c_str(), iter->second.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
template<typename Key,typename Value>
|
||||||
|
class MultiMap : public multimap<Key, Value> {
|
||||||
|
public:
|
||||||
|
Value& operator[](Key key) {
|
||||||
|
auto iter = this->insert(std::pair<Key,Value>(key,Value()));
|
||||||
|
return (*iter).second;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_MULTIMAP
|
||||||
|
#define HV_MAP std::MultiMap
|
||||||
|
#else
|
||||||
|
#define HV_MAP std::map
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// KeyValue
|
||||||
|
namespace hv {
|
||||||
|
typedef std::map<std::string, std::string> keyval_t;
|
||||||
|
typedef std::MultiMap<std::string, std::string> multi_keyval_t;
|
||||||
|
typedef HV_MAP<std::string, std::string> KeyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // HV_MAP_H_
|
183
external/libhv/libhv-1.3.2/cpputil/hobjectpool.h
vendored
Normal file
183
external/libhv/libhv-1.3.2/cpputil/hobjectpool.h
vendored
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
#ifndef HV_OBJECT_POOL_H_
|
||||||
|
#define HV_OBJECT_POOL_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @usage unittest/objectpool_test.cpp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
#define DEFAULT_OBJECT_POOL_INIT_NUM 0
|
||||||
|
#define DEFAULT_OBJECT_POOL_MAX_NUM 4
|
||||||
|
#define DEFAULT_OBJECT_POOL_TIMEOUT 3000 // ms
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class HObjectFactory {
|
||||||
|
public:
|
||||||
|
static T* create() {
|
||||||
|
return new T;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, class TFactory = HObjectFactory<T>>
|
||||||
|
class HObjectPool {
|
||||||
|
public:
|
||||||
|
HObjectPool(
|
||||||
|
int init_num = DEFAULT_OBJECT_POOL_INIT_NUM,
|
||||||
|
int max_num = DEFAULT_OBJECT_POOL_MAX_NUM,
|
||||||
|
int timeout = DEFAULT_OBJECT_POOL_TIMEOUT)
|
||||||
|
: _max_num(max_num)
|
||||||
|
, _timeout(timeout)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < init_num; ++i) {
|
||||||
|
T* p = TFactory::create();
|
||||||
|
if (p) {
|
||||||
|
objects_.push_back(std::shared_ptr<T>(p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_object_num = objects_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
~HObjectPool() {}
|
||||||
|
|
||||||
|
int ObjectNum() { return _object_num; }
|
||||||
|
int IdleNum() { return objects_.size(); }
|
||||||
|
int BorrowNum() { return ObjectNum() - IdleNum(); }
|
||||||
|
|
||||||
|
std::shared_ptr<T> TryBorrow() {
|
||||||
|
std::shared_ptr<T> pObj = NULL;
|
||||||
|
std::lock_guard<std::mutex> locker(mutex_);
|
||||||
|
if (!objects_.empty()) {
|
||||||
|
pObj = objects_.front();
|
||||||
|
objects_.pop_front();
|
||||||
|
}
|
||||||
|
return pObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<T> Borrow() {
|
||||||
|
std::shared_ptr<T> pObj = TryBorrow();
|
||||||
|
if (pObj) {
|
||||||
|
return pObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> locker(mutex_);
|
||||||
|
if (_object_num < _max_num) {
|
||||||
|
++_object_num;
|
||||||
|
// NOTE: unlock to avoid TFactory::create block
|
||||||
|
mutex_.unlock();
|
||||||
|
T* p = TFactory::create();
|
||||||
|
mutex_.lock();
|
||||||
|
if (!p) --_object_num;
|
||||||
|
return std::shared_ptr<T>(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_timeout > 0) {
|
||||||
|
std::cv_status status = cond_.wait_for(locker, std::chrono::milliseconds(_timeout));
|
||||||
|
if (status == std::cv_status::timeout) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!objects_.empty()) {
|
||||||
|
pObj = objects_.front();
|
||||||
|
objects_.pop_front();
|
||||||
|
return pObj;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// WARN: No idle object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Return(std::shared_ptr<T>& pObj) {
|
||||||
|
if (!pObj) return;
|
||||||
|
std::lock_guard<std::mutex> locker(mutex_);
|
||||||
|
objects_.push_back(pObj);
|
||||||
|
cond_.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Add(std::shared_ptr<T>& pObj) {
|
||||||
|
std::lock_guard<std::mutex> locker(mutex_);
|
||||||
|
if (_object_num >= _max_num) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
objects_.push_back(pObj);
|
||||||
|
++_object_num;
|
||||||
|
cond_.notify_one();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Remove(std::shared_ptr<T>& pObj) {
|
||||||
|
std::lock_guard<std::mutex> locker(mutex_);
|
||||||
|
auto iter = objects_.begin();
|
||||||
|
while (iter != objects_.end()) {
|
||||||
|
if (*iter == pObj) {
|
||||||
|
iter = objects_.erase(iter);
|
||||||
|
--_object_num;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear() {
|
||||||
|
std::lock_guard<std::mutex> locker(mutex_);
|
||||||
|
objects_.clear();
|
||||||
|
_object_num = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _object_num;
|
||||||
|
int _max_num;
|
||||||
|
int _timeout;
|
||||||
|
private:
|
||||||
|
std::list<std::shared_ptr<T>> objects_;
|
||||||
|
std::mutex mutex_;
|
||||||
|
std::condition_variable cond_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, class TFactory = HObjectFactory<T>>
|
||||||
|
class HPoolObject {
|
||||||
|
public:
|
||||||
|
typedef HObjectPool<T, TFactory> PoolType;
|
||||||
|
|
||||||
|
HPoolObject(PoolType& pool) : pool_(pool)
|
||||||
|
{
|
||||||
|
sptr_ = pool_.Borrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
~HPoolObject() {
|
||||||
|
if (sptr_) {
|
||||||
|
pool_.Return(sptr_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HPoolObject(const HPoolObject<T>&) = delete;
|
||||||
|
HPoolObject<T>& operator=(const HPoolObject<T>&) = delete;
|
||||||
|
|
||||||
|
T* get() {
|
||||||
|
return sptr_.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
operator bool() {
|
||||||
|
return sptr_.get() != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
T* operator->() {
|
||||||
|
return sptr_.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
T operator*() {
|
||||||
|
return *sptr_.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PoolType& pool_;
|
||||||
|
std::shared_ptr<T> sptr_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HV_OBJECT_POOL_H_
|
112
external/libhv/libhv-1.3.2/cpputil/hpath.cpp
vendored
Normal file
112
external/libhv/libhv-1.3.2/cpputil/hpath.cpp
vendored
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
#include "hpath.h"
|
||||||
|
|
||||||
|
#include "hplatform.h"
|
||||||
|
|
||||||
|
bool HPath::exists(const char* path) {
|
||||||
|
return access(path, 0) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HPath::isdir(const char* path) {
|
||||||
|
if (access(path, 0) != 0) return false;
|
||||||
|
struct stat st;
|
||||||
|
memset(&st, 0, sizeof(st));
|
||||||
|
stat(path, &st);
|
||||||
|
return S_ISDIR(st.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HPath::isfile(const char* path) {
|
||||||
|
if (access(path, 0) != 0) return false;
|
||||||
|
struct stat st;
|
||||||
|
memset(&st, 0, sizeof(st));
|
||||||
|
stat(path, &st);
|
||||||
|
return S_ISREG(st.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HPath::islink(const char* path) {
|
||||||
|
#ifdef OS_WIN
|
||||||
|
return HPath::isdir(path) && (GetFileAttributesA(path) & FILE_ATTRIBUTE_REPARSE_POINT);
|
||||||
|
#else
|
||||||
|
if (access(path, 0) != 0) return false;
|
||||||
|
struct stat st;
|
||||||
|
memset(&st, 0, sizeof(st));
|
||||||
|
lstat(path, &st);
|
||||||
|
return S_ISLNK(st.st_mode);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string HPath::basename(const std::string& filepath) {
|
||||||
|
std::string::size_type pos1 = filepath.find_last_not_of("/\\");
|
||||||
|
if (pos1 == std::string::npos) {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
std::string::size_type pos2 = filepath.find_last_of("/\\", pos1);
|
||||||
|
if (pos2 == std::string::npos) {
|
||||||
|
pos2 = 0;
|
||||||
|
} else {
|
||||||
|
pos2++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepath.substr(pos2, pos1-pos2+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string HPath::dirname(const std::string& filepath) {
|
||||||
|
std::string::size_type pos1 = filepath.find_last_not_of("/\\");
|
||||||
|
if (pos1 == std::string::npos) {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
std::string::size_type pos2 = filepath.find_last_of("/\\", pos1);
|
||||||
|
if (pos2 == std::string::npos) {
|
||||||
|
return ".";
|
||||||
|
} else if (pos2 == 0) {
|
||||||
|
pos2 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepath.substr(0, pos2);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string HPath::filename(const std::string& filepath) {
|
||||||
|
std::string::size_type pos1 = filepath.find_last_of("/\\");
|
||||||
|
if (pos1 == std::string::npos) {
|
||||||
|
pos1 = 0;
|
||||||
|
} else {
|
||||||
|
pos1++;
|
||||||
|
}
|
||||||
|
std::string file = filepath.substr(pos1, -1);
|
||||||
|
|
||||||
|
std::string::size_type pos2 = file.find_last_of(".");
|
||||||
|
if (pos2 == std::string::npos) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
return file.substr(0, pos2);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string HPath::suffixname(const std::string& filepath) {
|
||||||
|
std::string::size_type pos1 = filepath.find_last_of("/\\");
|
||||||
|
if (pos1 == std::string::npos) {
|
||||||
|
pos1 = 0;
|
||||||
|
} else {
|
||||||
|
pos1++;
|
||||||
|
}
|
||||||
|
std::string file = filepath.substr(pos1, -1);
|
||||||
|
|
||||||
|
std::string::size_type pos2 = file.find_last_of(".");
|
||||||
|
if (pos2 == std::string::npos) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return file.substr(pos2+1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string HPath::join(const std::string& dir, const std::string& filename) {
|
||||||
|
char separator = '/';
|
||||||
|
#ifdef OS_WIN
|
||||||
|
if (dir.find_first_of("\\") != std::string::npos) {
|
||||||
|
separator = '\\';
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
std::string filepath(dir);
|
||||||
|
if (dir[dir.length()-1] != separator) {
|
||||||
|
filepath += separator;
|
||||||
|
}
|
||||||
|
filepath += filename;
|
||||||
|
return filepath;
|
||||||
|
}
|
28
external/libhv/libhv-1.3.2/cpputil/hpath.h
vendored
Normal file
28
external/libhv/libhv-1.3.2/cpputil/hpath.h
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef HV_PATH_H_
|
||||||
|
#define HV_PATH_H_
|
||||||
|
|
||||||
|
#include <string> // for std::string
|
||||||
|
|
||||||
|
#include "hexport.h"
|
||||||
|
|
||||||
|
class HV_EXPORT HPath {
|
||||||
|
public:
|
||||||
|
static bool exists(const char* path);
|
||||||
|
static bool isdir(const char* path);
|
||||||
|
static bool isfile(const char* path);
|
||||||
|
static bool islink(const char* path);
|
||||||
|
|
||||||
|
// filepath = /mnt/share/image/test.jpg
|
||||||
|
// basename = test.jpg
|
||||||
|
// dirname = /mnt/share/image
|
||||||
|
// filename = test
|
||||||
|
// suffixname = jpg
|
||||||
|
static std::string basename(const std::string& filepath);
|
||||||
|
static std::string dirname(const std::string& filepath);
|
||||||
|
static std::string filename(const std::string& filepath);
|
||||||
|
static std::string suffixname(const std::string& filepath);
|
||||||
|
|
||||||
|
static std::string join(const std::string& dir, const std::string& filename);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HV_PATH_H_
|
79
external/libhv/libhv-1.3.2/cpputil/hscope.h
vendored
Normal file
79
external/libhv/libhv-1.3.2/cpputil/hscope.h
vendored
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
#ifndef HV_SCOPE_H_
|
||||||
|
#define HV_SCOPE_H_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
typedef std::function<void()> Function;
|
||||||
|
|
||||||
|
#include "hdef.h"
|
||||||
|
|
||||||
|
// same as golang defer
|
||||||
|
class Defer {
|
||||||
|
public:
|
||||||
|
Defer(Function&& fn) : _fn(std::move(fn)) {}
|
||||||
|
~Defer() { if(_fn) _fn();}
|
||||||
|
private:
|
||||||
|
Function _fn;
|
||||||
|
};
|
||||||
|
#define defer(code) Defer STRINGCAT(_defer_, __LINE__)([&](){code});
|
||||||
|
|
||||||
|
class ScopeCleanup {
|
||||||
|
public:
|
||||||
|
template<typename Fn, typename... Args>
|
||||||
|
ScopeCleanup(Fn&& fn, Args&&... args) {
|
||||||
|
_cleanup = std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
~ScopeCleanup() {
|
||||||
|
_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Function _cleanup;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class ScopeFree {
|
||||||
|
public:
|
||||||
|
ScopeFree(T* p) : _p(p) {}
|
||||||
|
~ScopeFree() {SAFE_FREE(_p);}
|
||||||
|
private:
|
||||||
|
T* _p;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class ScopeDelete {
|
||||||
|
public:
|
||||||
|
ScopeDelete(T* p) : _p(p) {}
|
||||||
|
~ScopeDelete() {SAFE_DELETE(_p);}
|
||||||
|
private:
|
||||||
|
T* _p;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class ScopeDeleteArray {
|
||||||
|
public:
|
||||||
|
ScopeDeleteArray(T* p) : _p(p) {}
|
||||||
|
~ScopeDeleteArray() {SAFE_DELETE_ARRAY(_p);}
|
||||||
|
private:
|
||||||
|
T* _p;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class ScopeRelease {
|
||||||
|
public:
|
||||||
|
ScopeRelease(T* p) : _p(p) {}
|
||||||
|
~ScopeRelease() {SAFE_RELEASE(_p);}
|
||||||
|
private:
|
||||||
|
T* _p;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class ScopeLock {
|
||||||
|
public:
|
||||||
|
ScopeLock(T& mutex) : _mutex(mutex) {_mutex.lock();}
|
||||||
|
~ScopeLock() {_mutex.unlock();}
|
||||||
|
private:
|
||||||
|
T& _mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HV_SCOPE_H_
|
205
external/libhv/libhv-1.3.2/cpputil/hstring.cpp
vendored
Normal file
205
external/libhv/libhv-1.3.2/cpputil/hstring.cpp
vendored
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
#include "hstring.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
namespace hv {
|
||||||
|
|
||||||
|
std::string empty_string;
|
||||||
|
std::map<std::string, std::string> empty_map;
|
||||||
|
|
||||||
|
std::string& toupper(std::string& str) {
|
||||||
|
// std::transform(str.begin(), str.end(), str.begin(), ::toupper);
|
||||||
|
char* p = (char*)str.c_str();
|
||||||
|
while (*p != '\0') {
|
||||||
|
if (*p >= 'a' && *p <= 'z') {
|
||||||
|
*p &= ~0x20;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& tolower(std::string& str) {
|
||||||
|
// std::transform(str.begin(), str.end(), str.begin(), ::tolower);
|
||||||
|
char* p = (char*)str.c_str();
|
||||||
|
while (*p != '\0') {
|
||||||
|
if (*p >= 'A' && *p <= 'Z') {
|
||||||
|
*p |= 0x20;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& reverse(std::string& str) {
|
||||||
|
// std::reverse(str.begin(), str.end());
|
||||||
|
char* b = (char*)str.c_str();
|
||||||
|
char* e = b + str.length() - 1;
|
||||||
|
char tmp;
|
||||||
|
while (e > b) {
|
||||||
|
tmp = *e;
|
||||||
|
*e = *b;
|
||||||
|
*b = tmp;
|
||||||
|
--e;
|
||||||
|
++b;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool startswith(const std::string& str, const std::string& start) {
|
||||||
|
if (str.length() < start.length()) return false;
|
||||||
|
return str.compare(0, start.length(), start) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool endswith(const std::string& str, const std::string& end) {
|
||||||
|
if (str.length() < end.length()) return false;
|
||||||
|
return str.compare(str.length() - end.length(), end.length(), end) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(const std::string& str, const std::string& sub) {
|
||||||
|
if (str.length() < sub.length()) return false;
|
||||||
|
return str.find(sub) != std::string::npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int vscprintf(const char* fmt, va_list ap) {
|
||||||
|
return vsnprintf(NULL, 0, fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string asprintf(const char* fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
int len = vscprintf(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
std::string str;
|
||||||
|
str.reserve(len+1);
|
||||||
|
// must resize to set str.size
|
||||||
|
str.resize(len);
|
||||||
|
// must recall va_start on unix
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vsnprintf((char*)str.data(), len+1, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringList split(const std::string& str, char delim) {
|
||||||
|
/*
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << str;
|
||||||
|
string item;
|
||||||
|
StringList res;
|
||||||
|
while (std::getline(ss, item, delim)) {
|
||||||
|
res.push_back(item);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
*/
|
||||||
|
const char* p = str.c_str();
|
||||||
|
const char* value = p;
|
||||||
|
StringList res;
|
||||||
|
while (*p != '\0') {
|
||||||
|
if (*p == delim) {
|
||||||
|
res.push_back(std::string(value, p-value));
|
||||||
|
value = p+1;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
res.push_back(value);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
hv::KeyValue splitKV(const std::string& str, char kv_kv, char k_v) {
|
||||||
|
enum {
|
||||||
|
s_key,
|
||||||
|
s_value,
|
||||||
|
} state = s_key;
|
||||||
|
const char* p = str.c_str();
|
||||||
|
const char* key = p;
|
||||||
|
const char* value = NULL;
|
||||||
|
int key_len = 0;
|
||||||
|
int value_len = 0;
|
||||||
|
hv::KeyValue kvs;
|
||||||
|
while (*p != '\0') {
|
||||||
|
if (*p == kv_kv) {
|
||||||
|
if (key_len && value_len) {
|
||||||
|
kvs[std::string(key, key_len)] = std::string(value, value_len);
|
||||||
|
key_len = value_len = 0;
|
||||||
|
}
|
||||||
|
state = s_key;
|
||||||
|
key = p+1;
|
||||||
|
}
|
||||||
|
else if (*p == k_v) {
|
||||||
|
state = s_value;
|
||||||
|
value = p+1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
state == s_key ? ++key_len : ++value_len;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
if (key_len && value_len) {
|
||||||
|
kvs[std::string(key, key_len)] = std::string(value, value_len);
|
||||||
|
}
|
||||||
|
return kvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string trim(const std::string& str, const char* chars) {
|
||||||
|
std::string::size_type pos1 = str.find_first_not_of(chars);
|
||||||
|
if (pos1 == std::string::npos) return "";
|
||||||
|
|
||||||
|
std::string::size_type pos2 = str.find_last_not_of(chars);
|
||||||
|
return str.substr(pos1, pos2-pos1+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ltrim(const std::string& str, const char* chars) {
|
||||||
|
std::string::size_type pos = str.find_first_not_of(chars);
|
||||||
|
if (pos == std::string::npos) return "";
|
||||||
|
return str.substr(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string rtrim(const std::string& str, const char* chars) {
|
||||||
|
std::string::size_type pos = str.find_last_not_of(chars);
|
||||||
|
return str.substr(0, pos+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string trim_pairs(const std::string& str, const char* pairs) {
|
||||||
|
const char* s = str.c_str();
|
||||||
|
const char* e = str.c_str() + str.size() - 1;
|
||||||
|
const char* p = pairs;
|
||||||
|
bool is_pair = false;
|
||||||
|
while (*p != '\0' && *(p+1) != '\0') {
|
||||||
|
if (*s == *p && *e == *(p+1)) {
|
||||||
|
is_pair = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
return is_pair ? str.substr(1, str.size()-2) : str;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string replace(const std::string& str, const std::string& find, const std::string& rep) {
|
||||||
|
std::string res(str);
|
||||||
|
std::string::size_type pos = res.find(find);
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
res.replace(pos, find.size(), rep);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string replaceAll(const std::string& str, const std::string& find, const std::string& rep) {
|
||||||
|
std::string::size_type pos = 0;
|
||||||
|
std::string::size_type a = find.size();
|
||||||
|
std::string::size_type b = rep.size();
|
||||||
|
|
||||||
|
std::string res(str);
|
||||||
|
while ((pos = res.find(find, pos)) != std::string::npos) {
|
||||||
|
res.replace(pos, a, rep);
|
||||||
|
pos += b;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end namespace hv
|
80
external/libhv/libhv-1.3.2/cpputil/hstring.h
vendored
Normal file
80
external/libhv/libhv-1.3.2/cpputil/hstring.h
vendored
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
#ifndef HV_STRING_H_
|
||||||
|
#define HV_STRING_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "hexport.h"
|
||||||
|
#include "hplatform.h"
|
||||||
|
#include "hmap.h"
|
||||||
|
|
||||||
|
#define SPACE_CHARS " \t\r\n"
|
||||||
|
#define PAIR_CHARS "{}[]()<>\"\"\'\'``"
|
||||||
|
|
||||||
|
namespace hv {
|
||||||
|
|
||||||
|
HV_EXPORT extern std::string empty_string;
|
||||||
|
HV_EXPORT extern std::map<std::string, std::string> empty_map;
|
||||||
|
|
||||||
|
typedef std::vector<std::string> StringList;
|
||||||
|
|
||||||
|
// std::map<std::string, std::string, StringCaseLess>
|
||||||
|
class StringCaseLess : public std::less<std::string> {
|
||||||
|
public:
|
||||||
|
bool operator()(const std::string& lhs, const std::string& rhs) const {
|
||||||
|
return strcasecmp(lhs.c_str(), rhs.c_str()) < 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOTE: low-version NDK not provide std::to_string
|
||||||
|
template<typename T>
|
||||||
|
HV_INLINE std::string to_string(const T& t) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << t;
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
HV_INLINE T from_string(const std::string& str) {
|
||||||
|
T t;
|
||||||
|
std::istringstream iss(str);
|
||||||
|
iss >> t;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
HV_INLINE void print(const T& t) {
|
||||||
|
std::cout << t;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
HV_INLINE void println(const T& t) {
|
||||||
|
std::cout << t << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
HV_EXPORT std::string& toupper(std::string& str);
|
||||||
|
HV_EXPORT std::string& tolower(std::string& str);
|
||||||
|
HV_EXPORT std::string& reverse(std::string& str);
|
||||||
|
|
||||||
|
HV_EXPORT bool startswith(const std::string& str, const std::string& start);
|
||||||
|
HV_EXPORT bool endswith(const std::string& str, const std::string& end);
|
||||||
|
HV_EXPORT bool contains(const std::string& str, const std::string& sub);
|
||||||
|
|
||||||
|
HV_EXPORT std::string asprintf(const char* fmt, ...);
|
||||||
|
// x,y,z
|
||||||
|
HV_EXPORT StringList split(const std::string& str, char delim = ',');
|
||||||
|
// k1=v1&k2=v2
|
||||||
|
HV_EXPORT hv::KeyValue splitKV(const std::string& str, char kv_kv = '&', char k_v = '=');
|
||||||
|
HV_EXPORT std::string trim(const std::string& str, const char* chars = SPACE_CHARS);
|
||||||
|
HV_EXPORT std::string ltrim(const std::string& str, const char* chars = SPACE_CHARS);
|
||||||
|
HV_EXPORT std::string rtrim(const std::string& str, const char* chars = SPACE_CHARS);
|
||||||
|
HV_EXPORT std::string trim_pairs(const std::string& str, const char* pairs = PAIR_CHARS);
|
||||||
|
HV_EXPORT std::string replace(const std::string& str, const std::string& find, const std::string& rep);
|
||||||
|
HV_EXPORT std::string replaceAll(const std::string& str, const std::string& find, const std::string& rep);
|
||||||
|
|
||||||
|
} // end namespace hv
|
||||||
|
|
||||||
|
#endif // HV_STRING_H_
|
249
external/libhv/libhv-1.3.2/cpputil/hthreadpool.h
vendored
Normal file
249
external/libhv/libhv-1.3.2/cpputil/hthreadpool.h
vendored
Normal file
|
@ -0,0 +1,249 @@
|
||||||
|
#ifndef HV_THREAD_POOL_H_
|
||||||
|
#define HV_THREAD_POOL_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @usage unittest/threadpool_test.cpp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <list>
|
||||||
|
#include <queue>
|
||||||
|
#include <functional>
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <future>
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#define DEFAULT_THREAD_POOL_MIN_THREAD_NUM 1
|
||||||
|
#define DEFAULT_THREAD_POOL_MAX_THREAD_NUM std::thread::hardware_concurrency()
|
||||||
|
#define DEFAULT_THREAD_POOL_MAX_IDLE_TIME 60000 // ms
|
||||||
|
|
||||||
|
class HThreadPool {
|
||||||
|
public:
|
||||||
|
using Task = std::function<void()>;
|
||||||
|
|
||||||
|
HThreadPool(int min_threads = DEFAULT_THREAD_POOL_MIN_THREAD_NUM,
|
||||||
|
int max_threads = DEFAULT_THREAD_POOL_MAX_THREAD_NUM,
|
||||||
|
int max_idle_ms = DEFAULT_THREAD_POOL_MAX_IDLE_TIME)
|
||||||
|
: min_thread_num(min_threads)
|
||||||
|
, max_thread_num(max_threads)
|
||||||
|
, max_idle_time(max_idle_ms)
|
||||||
|
, status(STOP)
|
||||||
|
, cur_thread_num(0)
|
||||||
|
, idle_thread_num(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual ~HThreadPool() {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMinThreadNum(int min_threads) {
|
||||||
|
min_thread_num = min_threads;
|
||||||
|
}
|
||||||
|
void setMaxThreadNum(int max_threads) {
|
||||||
|
max_thread_num = max_threads;
|
||||||
|
}
|
||||||
|
void setMaxIdleTime(int ms) {
|
||||||
|
max_idle_time = ms;
|
||||||
|
}
|
||||||
|
int currentThreadNum() {
|
||||||
|
return cur_thread_num;
|
||||||
|
}
|
||||||
|
int idleThreadNum() {
|
||||||
|
return idle_thread_num;
|
||||||
|
}
|
||||||
|
size_t taskNum() {
|
||||||
|
std::lock_guard<std::mutex> locker(task_mutex);
|
||||||
|
return tasks.size();
|
||||||
|
}
|
||||||
|
bool isStarted() {
|
||||||
|
return status != STOP;
|
||||||
|
}
|
||||||
|
bool isStopped() {
|
||||||
|
return status == STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
int start(int start_threads = 0) {
|
||||||
|
if (status != STOP) return -1;
|
||||||
|
status = RUNNING;
|
||||||
|
if (start_threads < min_thread_num) start_threads = min_thread_num;
|
||||||
|
if (start_threads > max_thread_num) start_threads = max_thread_num;
|
||||||
|
for (int i = 0; i < start_threads; ++i) {
|
||||||
|
createThread();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int stop() {
|
||||||
|
if (status == STOP) return -1;
|
||||||
|
status = STOP;
|
||||||
|
task_cond.notify_all();
|
||||||
|
for (auto& i : threads) {
|
||||||
|
if (i.thread->joinable()) {
|
||||||
|
i.thread->join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
threads.clear();
|
||||||
|
cur_thread_num = 0;
|
||||||
|
idle_thread_num = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pause() {
|
||||||
|
if (status == RUNNING) {
|
||||||
|
status = PAUSE;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int resume() {
|
||||||
|
if (status == PAUSE) {
|
||||||
|
status = RUNNING;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wait() {
|
||||||
|
while (status != STOP) {
|
||||||
|
if (tasks.empty() && idle_thread_num == cur_thread_num) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::this_thread::yield();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return a future, calling future.get() will wait task done and return RetType.
|
||||||
|
* commit(fn, args...)
|
||||||
|
* commit(std::bind(&Class::mem_fn, &obj))
|
||||||
|
* commit(std::mem_fn(&Class::mem_fn, &obj))
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
template<class Fn, class... Args>
|
||||||
|
auto commit(Fn&& fn, Args&&... args) -> std::future<decltype(fn(args...))> {
|
||||||
|
if (status == STOP) start();
|
||||||
|
if (idle_thread_num <= tasks.size() && cur_thread_num < max_thread_num) {
|
||||||
|
createThread();
|
||||||
|
}
|
||||||
|
using RetType = decltype(fn(args...));
|
||||||
|
auto task = std::make_shared<std::packaged_task<RetType()> >(
|
||||||
|
std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...));
|
||||||
|
std::future<RetType> future = task->get_future();
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> locker(task_mutex);
|
||||||
|
tasks.emplace([task]{
|
||||||
|
(*task)();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
task_cond.notify_one();
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool createThread() {
|
||||||
|
if (cur_thread_num >= max_thread_num) return false;
|
||||||
|
std::thread* thread = new std::thread([this] {
|
||||||
|
while (status != STOP) {
|
||||||
|
while (status == PAUSE) {
|
||||||
|
std::this_thread::yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
Task task;
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> locker(task_mutex);
|
||||||
|
task_cond.wait_for(locker, std::chrono::milliseconds(max_idle_time), [this]() {
|
||||||
|
return status == STOP || !tasks.empty();
|
||||||
|
});
|
||||||
|
if (status == STOP) return;
|
||||||
|
if (tasks.empty()) {
|
||||||
|
if (cur_thread_num > min_thread_num) {
|
||||||
|
delThread(std::this_thread::get_id());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
--idle_thread_num;
|
||||||
|
task = std::move(tasks.front());
|
||||||
|
tasks.pop();
|
||||||
|
}
|
||||||
|
if (task) {
|
||||||
|
task();
|
||||||
|
++idle_thread_num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
addThread(thread);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addThread(std::thread* thread) {
|
||||||
|
thread_mutex.lock();
|
||||||
|
++cur_thread_num;
|
||||||
|
++idle_thread_num;
|
||||||
|
ThreadData data;
|
||||||
|
data.thread = std::shared_ptr<std::thread>(thread);
|
||||||
|
data.id = thread->get_id();
|
||||||
|
data.status = RUNNING;
|
||||||
|
data.start_time = time(NULL);
|
||||||
|
data.stop_time = 0;
|
||||||
|
threads.emplace_back(data);
|
||||||
|
thread_mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void delThread(std::thread::id id) {
|
||||||
|
time_t now = time(NULL);
|
||||||
|
thread_mutex.lock();
|
||||||
|
--cur_thread_num;
|
||||||
|
--idle_thread_num;
|
||||||
|
auto iter = threads.begin();
|
||||||
|
while (iter != threads.end()) {
|
||||||
|
if (iter->status == STOP && now > iter->stop_time) {
|
||||||
|
if (iter->thread->joinable()) {
|
||||||
|
iter->thread->join();
|
||||||
|
iter = threads.erase(iter);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (iter->id == id) {
|
||||||
|
iter->status = STOP;
|
||||||
|
iter->stop_time = time(NULL);
|
||||||
|
}
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
thread_mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
int min_thread_num;
|
||||||
|
int max_thread_num;
|
||||||
|
int max_idle_time;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum Status {
|
||||||
|
STOP,
|
||||||
|
RUNNING,
|
||||||
|
PAUSE,
|
||||||
|
};
|
||||||
|
struct ThreadData {
|
||||||
|
std::shared_ptr<std::thread> thread;
|
||||||
|
std::thread::id id;
|
||||||
|
Status status;
|
||||||
|
time_t start_time;
|
||||||
|
time_t stop_time;
|
||||||
|
};
|
||||||
|
std::atomic<Status> status;
|
||||||
|
std::atomic<int> cur_thread_num;
|
||||||
|
std::atomic<int> idle_thread_num;
|
||||||
|
std::list<ThreadData> threads;
|
||||||
|
std::mutex thread_mutex;
|
||||||
|
std::queue<Task> tasks;
|
||||||
|
std::mutex task_mutex;
|
||||||
|
std::condition_variable task_cond;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HV_THREAD_POOL_H_
|
184
external/libhv/libhv-1.3.2/cpputil/hurl.cpp
vendored
Normal file
184
external/libhv/libhv-1.3.2/cpputil/hurl.cpp
vendored
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
#include "hurl.h"
|
||||||
|
|
||||||
|
#include "hdef.h"
|
||||||
|
#include "hbase.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
static bool Curl_isunreserved(unsigned char in)
|
||||||
|
{
|
||||||
|
switch(in) {
|
||||||
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
|
case 'a': case 'b': case 'c': case 'd': case 'e':
|
||||||
|
case 'f': case 'g': case 'h': case 'i': case 'j':
|
||||||
|
case 'k': case 'l': case 'm': case 'n': case 'o':
|
||||||
|
case 'p': case 'q': case 'r': case 's': case 't':
|
||||||
|
case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
|
||||||
|
case 'A': case 'B': case 'C': case 'D': case 'E':
|
||||||
|
case 'F': case 'G': case 'H': case 'I': case 'J':
|
||||||
|
case 'K': case 'L': case 'M': case 'N': case 'O':
|
||||||
|
case 'P': case 'Q': case 'R': case 'S': case 'T':
|
||||||
|
case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
|
||||||
|
case '-': case '.': case '_': case '~':
|
||||||
|
return TRUE;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return FLASE;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline bool is_unambiguous(char c) {
|
||||||
|
return IS_ALPHANUM(c) ||
|
||||||
|
c == '-' ||
|
||||||
|
c == '_' ||
|
||||||
|
c == '.' ||
|
||||||
|
c == '~';
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool char_in_str(char c, const char* str) {
|
||||||
|
const char* p = str;
|
||||||
|
while (*p && *p != c) ++p;
|
||||||
|
return *p != '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned char hex2i(char hex) {
|
||||||
|
return hex <= '9' ? hex - '0' :
|
||||||
|
hex <= 'F' ? hex - 'A' + 10 : hex - 'a' + 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string HUrl::escape(const std::string& str, const char* unescaped_chars) {
|
||||||
|
std::string ostr;
|
||||||
|
static char tab[] = "0123456789ABCDEF";
|
||||||
|
const unsigned char* p = reinterpret_cast<const unsigned char*>(str.c_str());
|
||||||
|
char szHex[4] = "%00";
|
||||||
|
while (*p != '\0') {
|
||||||
|
if (is_unambiguous(*p) || char_in_str(*p, unescaped_chars)) {
|
||||||
|
ostr += *p;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
szHex[1] = tab[*p >> 4];
|
||||||
|
szHex[2] = tab[*p & 0xF];
|
||||||
|
ostr += szHex;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
return ostr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string HUrl::unescape(const std::string& str) {
|
||||||
|
std::string ostr;
|
||||||
|
const char* p = str.c_str();
|
||||||
|
while (*p != '\0') {
|
||||||
|
if (*p == '%' &&
|
||||||
|
IS_HEX(p[1]) &&
|
||||||
|
IS_HEX(p[2])) {
|
||||||
|
ostr += ((hex2i(p[1]) << 4) | hex2i(p[2]));
|
||||||
|
p += 3;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (*p == '+') {
|
||||||
|
ostr += ' ';
|
||||||
|
} else {
|
||||||
|
ostr += *p;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ostr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HUrl::reset() {
|
||||||
|
url.clear();
|
||||||
|
scheme.clear();
|
||||||
|
username.clear();
|
||||||
|
password.clear();
|
||||||
|
host.clear();
|
||||||
|
port = 0;
|
||||||
|
path.clear();
|
||||||
|
query.clear();
|
||||||
|
fragment.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HUrl::parse(const std::string& url) {
|
||||||
|
reset();
|
||||||
|
this->url = url;
|
||||||
|
hurl_t stURL;
|
||||||
|
if (hv_parse_url(&stURL, url.c_str()) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int len = stURL.fields[HV_URL_SCHEME].len;
|
||||||
|
if (len > 0) {
|
||||||
|
scheme = url.substr(stURL.fields[HV_URL_SCHEME].off, len);
|
||||||
|
}
|
||||||
|
len = stURL.fields[HV_URL_USERNAME].len;
|
||||||
|
if (len > 0) {
|
||||||
|
username = url.substr(stURL.fields[HV_URL_USERNAME].off, len);
|
||||||
|
len = stURL.fields[HV_URL_PASSWORD].len;
|
||||||
|
if (len > 0) {
|
||||||
|
password = url.substr(stURL.fields[HV_URL_PASSWORD].off, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
len = stURL.fields[HV_URL_HOST].len;
|
||||||
|
if (len > 0) {
|
||||||
|
host = url.substr(stURL.fields[HV_URL_HOST].off, len);
|
||||||
|
}
|
||||||
|
port = stURL.port;
|
||||||
|
len = stURL.fields[HV_URL_PATH].len;
|
||||||
|
if (len > 0) {
|
||||||
|
path = url.substr(stURL.fields[HV_URL_PATH].off, len);
|
||||||
|
} else {
|
||||||
|
path = "/";
|
||||||
|
}
|
||||||
|
len = stURL.fields[HV_URL_QUERY].len;
|
||||||
|
if (len > 0) {
|
||||||
|
query = url.substr(stURL.fields[HV_URL_QUERY].off, len);
|
||||||
|
}
|
||||||
|
len = stURL.fields[HV_URL_FRAGMENT].len;
|
||||||
|
if (len > 0) {
|
||||||
|
fragment = url.substr(stURL.fields[HV_URL_FRAGMENT].off, len);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& HUrl::dump() {
|
||||||
|
url.clear();
|
||||||
|
// scheme://
|
||||||
|
if (!scheme.empty()) {
|
||||||
|
url += scheme;
|
||||||
|
url += "://";
|
||||||
|
}
|
||||||
|
// user:pswd@
|
||||||
|
if (!username.empty()) {
|
||||||
|
url += username;
|
||||||
|
if (!password.empty()) {
|
||||||
|
url += ":";
|
||||||
|
url += password;
|
||||||
|
}
|
||||||
|
url += "@";
|
||||||
|
}
|
||||||
|
// host:port
|
||||||
|
if (!host.empty()) {
|
||||||
|
url += host;
|
||||||
|
if (port != 80 && port != 443) {
|
||||||
|
char buf[16] = {0};
|
||||||
|
snprintf(buf, sizeof(buf), ":%d", port);
|
||||||
|
url += port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// /path
|
||||||
|
if (!path.empty()) {
|
||||||
|
url += path;
|
||||||
|
}
|
||||||
|
// ?query
|
||||||
|
if (!query.empty()) {
|
||||||
|
url += '?';
|
||||||
|
url += query;
|
||||||
|
}
|
||||||
|
// #fragment
|
||||||
|
if (!fragment.empty()) {
|
||||||
|
url += '#';
|
||||||
|
url += fragment;
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
34
external/libhv/libhv-1.3.2/cpputil/hurl.h
vendored
Normal file
34
external/libhv/libhv-1.3.2/cpputil/hurl.h
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef HV_URL_H_
|
||||||
|
#define HV_URL_H_
|
||||||
|
|
||||||
|
#include <string> // import std::string
|
||||||
|
|
||||||
|
#include "hexport.h"
|
||||||
|
|
||||||
|
class HV_EXPORT HUrl {
|
||||||
|
public:
|
||||||
|
static std::string escape(const std::string& str, const char* unescaped_chars = "");
|
||||||
|
static std::string unescape(const std::string& str);
|
||||||
|
static inline std::string escapeUrl(const std::string& url) {
|
||||||
|
return escape(url, ":/@?=&#+");
|
||||||
|
}
|
||||||
|
|
||||||
|
HUrl() : port(0) {}
|
||||||
|
~HUrl() {}
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
bool parse(const std::string& url);
|
||||||
|
const std::string& dump();
|
||||||
|
|
||||||
|
std::string url;
|
||||||
|
std::string scheme;
|
||||||
|
std::string username;
|
||||||
|
std::string password;
|
||||||
|
std::string host;
|
||||||
|
int port;
|
||||||
|
std::string path;
|
||||||
|
std::string query;
|
||||||
|
std::string fragment;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HV_URL_H_
|
223
external/libhv/libhv-1.3.2/cpputil/ifconfig.cpp
vendored
Normal file
223
external/libhv/libhv-1.3.2/cpputil/ifconfig.cpp
vendored
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
#include "ifconfig.h"
|
||||||
|
|
||||||
|
#include "hplatform.h"
|
||||||
|
|
||||||
|
#ifdef OS_LINUX
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <linux/if.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
int ifconfig(std::vector<ifconfig_t>& ifcs) {
|
||||||
|
int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (sock < 0) {
|
||||||
|
return -10;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ifconf ifc;
|
||||||
|
char buf[1024];
|
||||||
|
ifc.ifc_len = sizeof(buf);
|
||||||
|
ifc.ifc_buf = buf;
|
||||||
|
|
||||||
|
int iRet = ioctl(sock, SIOCGIFCONF, &ifc);
|
||||||
|
if (iRet != 0) {
|
||||||
|
close(sock);
|
||||||
|
return iRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cnt = ifc.ifc_len / sizeof(struct ifreq);
|
||||||
|
//printf("ifc.size=%d\n", cnt);
|
||||||
|
if (cnt == 0) {
|
||||||
|
close(sock);
|
||||||
|
return -20;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ifreq ifr;
|
||||||
|
ifcs.clear();
|
||||||
|
ifconfig_t tmp;
|
||||||
|
for (int i = 0; i < cnt; ++i) {
|
||||||
|
// name
|
||||||
|
strcpy(ifr.ifr_name, ifc.ifc_req[i].ifr_name);
|
||||||
|
//printf("name: %s\n", ifr.ifr_name);
|
||||||
|
strncpy(tmp.name, ifr.ifr_name, sizeof(tmp.name));
|
||||||
|
// flags
|
||||||
|
//iRet = ioctl(sock, SIOCGIFFLAGS, &ifr);
|
||||||
|
//short flags = ifr.ifr_flags;
|
||||||
|
// addr
|
||||||
|
iRet = ioctl(sock, SIOCGIFADDR, &ifr);
|
||||||
|
struct sockaddr_in* addr = (struct sockaddr_in*)&ifr.ifr_addr;
|
||||||
|
char* ip = inet_ntoa(addr->sin_addr);
|
||||||
|
//printf("ip: %s\n", ip);
|
||||||
|
strncpy(tmp.ip, ip, sizeof(tmp.ip));
|
||||||
|
// netmask
|
||||||
|
iRet = ioctl(sock, SIOCGIFNETMASK, &ifr);
|
||||||
|
addr = (struct sockaddr_in*)&ifr.ifr_netmask;
|
||||||
|
char* netmask = inet_ntoa(addr->sin_addr);
|
||||||
|
//printf("netmask: %s\n", netmask);
|
||||||
|
strncpy(tmp.mask, netmask, sizeof(tmp.mask));
|
||||||
|
// broadaddr
|
||||||
|
iRet = ioctl(sock, SIOCGIFBRDADDR, &ifr);
|
||||||
|
addr = (struct sockaddr_in*)&ifr.ifr_broadaddr;
|
||||||
|
char* broadaddr = inet_ntoa(addr->sin_addr);
|
||||||
|
//printf("broadaddr: %s\n", broadaddr);
|
||||||
|
strncpy(tmp.broadcast, broadaddr, sizeof(tmp.broadcast));
|
||||||
|
// hwaddr
|
||||||
|
iRet = ioctl(sock, SIOCGIFHWADDR, &ifr);
|
||||||
|
snprintf(tmp.mac, sizeof(tmp.mac), "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||||
|
(unsigned char)ifr.ifr_hwaddr.sa_data[0],
|
||||||
|
(unsigned char)ifr.ifr_hwaddr.sa_data[1],
|
||||||
|
(unsigned char)ifr.ifr_hwaddr.sa_data[2],
|
||||||
|
(unsigned char)ifr.ifr_hwaddr.sa_data[3],
|
||||||
|
(unsigned char)ifr.ifr_hwaddr.sa_data[4],
|
||||||
|
(unsigned char)ifr.ifr_hwaddr.sa_data[5]);
|
||||||
|
//printf("mac: %s\n", tmp.mac);
|
||||||
|
//printf("\n");
|
||||||
|
|
||||||
|
if (strcmp(tmp.ip, "0.0.0.0") == 0 ||
|
||||||
|
strcmp(tmp.ip, "127.0.0.1") == 0 ||
|
||||||
|
strcmp(tmp.mac, "00:00:00:00:00:00") == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ifcs.push_back(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(sock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#elif defined(OS_WIN)
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <ws2ipdef.h>
|
||||||
|
#include <iphlpapi.h>
|
||||||
|
int ifconfig(std::vector<ifconfig_t>& ifcs) {
|
||||||
|
PIP_ADAPTER_ADDRESSES pAddrs = NULL;
|
||||||
|
ULONG buflen = 0;
|
||||||
|
GetAdaptersAddresses(AF_INET, 0, NULL, pAddrs, &buflen);
|
||||||
|
pAddrs = (PIP_ADAPTER_ADDRESSES)malloc(buflen);
|
||||||
|
GetAdaptersAddresses(AF_INET, 0, NULL, pAddrs, &buflen);
|
||||||
|
|
||||||
|
PIP_ADAPTER_INFO pInfos = NULL;
|
||||||
|
buflen = 0;
|
||||||
|
GetAdaptersInfo(pInfos, &buflen);
|
||||||
|
pInfos = (PIP_ADAPTER_INFO)malloc(buflen);
|
||||||
|
GetAdaptersInfo(pInfos, &buflen);
|
||||||
|
|
||||||
|
ifconfig_t ifc;
|
||||||
|
std::vector<ifconfig_t> tmp_ifcs;
|
||||||
|
PIP_ADAPTER_ADDRESSES pAddr = pAddrs;
|
||||||
|
char mac[32] = {'\0'};
|
||||||
|
while (pAddr) {
|
||||||
|
snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||||
|
pAddr->PhysicalAddress[0],
|
||||||
|
pAddr->PhysicalAddress[1],
|
||||||
|
pAddr->PhysicalAddress[2],
|
||||||
|
pAddr->PhysicalAddress[3],
|
||||||
|
pAddr->PhysicalAddress[4],
|
||||||
|
pAddr->PhysicalAddress[5]);
|
||||||
|
|
||||||
|
memset(&ifc, 0, sizeof(ifc));
|
||||||
|
strncpy(ifc.name, pAddr->AdapterName, sizeof(ifc.name));
|
||||||
|
strncpy(ifc.ip, "0.0.0.0", sizeof(ifc.ip));
|
||||||
|
strncpy(ifc.mask, "255.255.255.255", sizeof(ifc.mask));
|
||||||
|
strncpy(ifc.mac, mac, sizeof(ifc.mac));
|
||||||
|
tmp_ifcs.push_back(ifc);
|
||||||
|
|
||||||
|
pAddr = pAddr->Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
PIP_ADAPTER_INFO pInfo = pInfos;
|
||||||
|
while (pInfo) {
|
||||||
|
for (auto& item : tmp_ifcs) {
|
||||||
|
if (strcmp(item.name, pInfo->AdapterName) == 0) {
|
||||||
|
// description more friendly
|
||||||
|
strncpy(item.name, pInfo->Description, sizeof(item.name));
|
||||||
|
strncpy(item.ip, pInfo->IpAddressList.IpAddress.String, sizeof(item.ip));
|
||||||
|
strncpy(item.mask, pInfo->IpAddressList.IpMask.String, sizeof(item.mask));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pInfo = pInfo->Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(pAddrs);
|
||||||
|
free(pInfos);
|
||||||
|
|
||||||
|
// filter
|
||||||
|
ifcs.clear();
|
||||||
|
for (auto& item : tmp_ifcs) {
|
||||||
|
if (strcmp(item.ip, "0.0.0.0") == 0 ||
|
||||||
|
strcmp(item.ip, "127.0.0.1") == 0 ||
|
||||||
|
strcmp(item.mac, "00:00:00:00:00:00") == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ifcs.push_back(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#elif defined(OS_MAC)
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
|
int ifconfig(std::vector<ifconfig_t>& ifcs) {
|
||||||
|
struct ifaddrs *ifas, *ifap;
|
||||||
|
int ret = getifaddrs(&ifas);
|
||||||
|
if (ret != 0) return ret;
|
||||||
|
ifconfig_s tmp;
|
||||||
|
for (ifap = ifas; ifap != NULL; ifap = ifap->ifa_next) {
|
||||||
|
if (ifap->ifa_addr->sa_family == AF_INET) {
|
||||||
|
// ipv4
|
||||||
|
struct sockaddr_in* addr = (struct sockaddr_in*)ifap->ifa_addr;
|
||||||
|
char* ip = inet_ntoa(addr->sin_addr);
|
||||||
|
// filter
|
||||||
|
if (strcmp(ip, "0.0.0.0") == 0 || strcmp(ip, "127.0.0.1") == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
memset(&tmp, 0, sizeof(tmp));
|
||||||
|
strncpy(tmp.name, ifap->ifa_name, sizeof(tmp.name));
|
||||||
|
strncpy(tmp.ip, ip, sizeof(tmp.ip));
|
||||||
|
// netmask
|
||||||
|
addr = (struct sockaddr_in*)ifap->ifa_netmask;
|
||||||
|
char* netmask = inet_ntoa(addr->sin_addr);
|
||||||
|
strncpy(tmp.mask, netmask, sizeof(tmp.mask));
|
||||||
|
// broadaddr
|
||||||
|
addr = (struct sockaddr_in*)ifap->ifa_broadaddr;
|
||||||
|
char* broadaddr = inet_ntoa(addr->sin_addr);
|
||||||
|
strncpy(tmp.broadcast, broadaddr, sizeof(tmp.broadcast));
|
||||||
|
// push_back
|
||||||
|
ifcs.push_back(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ifap = ifas; ifap != NULL; ifap = ifap->ifa_next) {
|
||||||
|
if (ifap->ifa_addr->sa_family == AF_LINK) {
|
||||||
|
// hwaddr
|
||||||
|
for (auto iter = ifcs.begin(); iter != ifcs.end(); ++iter) {
|
||||||
|
if (strcmp(iter->name, ifap->ifa_name) == 0) {
|
||||||
|
struct sockaddr_dl* addr = (struct sockaddr_dl*)ifap->ifa_addr;
|
||||||
|
unsigned char* pmac = (unsigned char*)LLADDR(addr);
|
||||||
|
snprintf(iter->mac, sizeof(iter->mac), "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||||
|
pmac[0], pmac[1], pmac[2], pmac[3], pmac[4], pmac[5]);
|
||||||
|
// filter
|
||||||
|
if (strcmp(iter->mac, "00:00:00:00:00:00") == 0) {
|
||||||
|
ifcs.erase(iter);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs(ifas);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
int ifconfig(std::vector<ifconfig_t>& ifcs) {
|
||||||
|
return -10; // unimplemented
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
36
external/libhv/libhv-1.3.2/cpputil/ifconfig.h
vendored
Normal file
36
external/libhv/libhv-1.3.2/cpputil/ifconfig.h
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#ifndef HV_IFCONFIG_H_
|
||||||
|
#define HV_IFCONFIG_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "hexport.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma comment(lib, "iphlpapi.lib")
|
||||||
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct ifconfig_s {
|
||||||
|
char name[128];
|
||||||
|
char ip[16];
|
||||||
|
char mask[16];
|
||||||
|
char broadcast[16];
|
||||||
|
char mac[20];
|
||||||
|
} ifconfig_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
std::vector<ifconfig_t> ifcs;
|
||||||
|
ifconfig(ifcs);
|
||||||
|
for (auto& item : ifcs) {
|
||||||
|
printf("%s\nip: %s\nmask: %s\nbroadcast: %s\nmac: %s\n\n",
|
||||||
|
item.name,
|
||||||
|
item.ip,
|
||||||
|
item.mask,
|
||||||
|
item.broadcast,
|
||||||
|
item.mac);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
HV_EXPORT int ifconfig(std::vector<ifconfig_t>& ifcs);
|
||||||
|
|
||||||
|
#endif // HV_IFCONFIG_H_
|
390
external/libhv/libhv-1.3.2/cpputil/iniparser.cpp
vendored
Normal file
390
external/libhv/libhv-1.3.2/cpputil/iniparser.cpp
vendored
Normal file
|
@ -0,0 +1,390 @@
|
||||||
|
#include "iniparser.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "hdef.h"
|
||||||
|
#include "herr.h"
|
||||||
|
#include "hstring.h"
|
||||||
|
#include "hfile.h"
|
||||||
|
#include "hbase.h"
|
||||||
|
|
||||||
|
using namespace hv;
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
# div
|
||||||
|
|
||||||
|
[section]
|
||||||
|
|
||||||
|
key = value # span
|
||||||
|
|
||||||
|
# div
|
||||||
|
***********************************/
|
||||||
|
|
||||||
|
class IniNode {
|
||||||
|
public:
|
||||||
|
enum Type {
|
||||||
|
INI_NODE_TYPE_UNKNOWN,
|
||||||
|
INI_NODE_TYPE_ROOT,
|
||||||
|
INI_NODE_TYPE_SECTION,
|
||||||
|
INI_NODE_TYPE_KEY_VALUE,
|
||||||
|
INI_NODE_TYPE_DIV,
|
||||||
|
INI_NODE_TYPE_SPAN,
|
||||||
|
} type;
|
||||||
|
std::string label; // section|key|comment
|
||||||
|
std::string value;
|
||||||
|
std::list<IniNode*> children;
|
||||||
|
|
||||||
|
virtual ~IniNode() {
|
||||||
|
for (auto pNode : children) {
|
||||||
|
if (pNode) {
|
||||||
|
delete pNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
children.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Add(IniNode* pNode) {
|
||||||
|
children.push_back(pNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Del(IniNode* pNode) {
|
||||||
|
for (auto iter = children.begin(); iter != children.end(); ++iter) {
|
||||||
|
if ((*iter) == pNode) {
|
||||||
|
delete (*iter);
|
||||||
|
children.erase(iter);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IniNode* Get(const std::string& label, Type type = INI_NODE_TYPE_KEY_VALUE) {
|
||||||
|
for (auto pNode : children) {
|
||||||
|
if (pNode->type == type && pNode->label == label) {
|
||||||
|
return pNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class IniSection : public IniNode {
|
||||||
|
public:
|
||||||
|
IniSection() : IniNode(), section(label) {
|
||||||
|
type = INI_NODE_TYPE_SECTION;
|
||||||
|
}
|
||||||
|
std::string §ion;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IniKeyValue : public IniNode {
|
||||||
|
public:
|
||||||
|
IniKeyValue() : IniNode(), key(label) {
|
||||||
|
type = INI_NODE_TYPE_KEY_VALUE;
|
||||||
|
}
|
||||||
|
std::string &key;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IniComment : public IniNode {
|
||||||
|
public:
|
||||||
|
IniComment() : IniNode(), comment(label) {
|
||||||
|
}
|
||||||
|
std::string &comment;
|
||||||
|
};
|
||||||
|
|
||||||
|
IniParser::IniParser() {
|
||||||
|
_comment = DEFAULT_INI_COMMENT;
|
||||||
|
_delim = DEFAULT_INI_DELIM;
|
||||||
|
root_ = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
IniParser::~IniParser() {
|
||||||
|
Unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
int IniParser::Unload() {
|
||||||
|
SAFE_DELETE(root_);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IniParser::Reload() {
|
||||||
|
return LoadFromFile(_filepath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
int IniParser::LoadFromFile(const char* filepath) {
|
||||||
|
_filepath = filepath;
|
||||||
|
|
||||||
|
HFile file;
|
||||||
|
if (file.open(filepath, "r") != 0) {
|
||||||
|
return ERR_OPEN_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string str;
|
||||||
|
file.readall(str);
|
||||||
|
const char* c_str = str.c_str();
|
||||||
|
unsigned char utf8_bom[3] = { 0xEF, 0xBB, 0xBF };
|
||||||
|
if (str.size() >= 3 && memcmp(c_str, utf8_bom, 3) == 0) {
|
||||||
|
c_str += 3;
|
||||||
|
}
|
||||||
|
return LoadFromMem(c_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IniParser::LoadFromMem(const char* data) {
|
||||||
|
Unload();
|
||||||
|
|
||||||
|
root_ = new IniNode;
|
||||||
|
root_->type = IniNode::INI_NODE_TYPE_ROOT;
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << data;
|
||||||
|
std::string strLine;
|
||||||
|
int line = 0;
|
||||||
|
std::string::size_type pos;
|
||||||
|
|
||||||
|
std::string content, comment, strDiv;
|
||||||
|
IniNode* pScopeNode = root_;
|
||||||
|
IniNode* pNewNode = NULL;
|
||||||
|
while (std::getline(ss, strLine)) {
|
||||||
|
++line;
|
||||||
|
|
||||||
|
content = ltrim(strLine);
|
||||||
|
if (content.length() == 0) {
|
||||||
|
// blank line
|
||||||
|
strDiv += '\n';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim_comment
|
||||||
|
comment = "";
|
||||||
|
pos = content.find_first_of(_comment);
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
comment = content.substr(pos);
|
||||||
|
content = content.substr(0, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
content = rtrim(content);
|
||||||
|
if (content.length() == 0) {
|
||||||
|
strDiv += strLine;
|
||||||
|
strDiv += '\n';
|
||||||
|
continue;
|
||||||
|
} else if (strDiv.length() != 0) {
|
||||||
|
IniNode* pNode = new IniNode;
|
||||||
|
pNode->type = IniNode::INI_NODE_TYPE_DIV;
|
||||||
|
pNode->label = strDiv;
|
||||||
|
pScopeNode->Add(pNode);
|
||||||
|
strDiv = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content[0] == '[') {
|
||||||
|
if (content[content.length()-1] == ']') {
|
||||||
|
// section
|
||||||
|
content = trim(content.substr(1, content.length()-2));
|
||||||
|
pNewNode = new IniNode;
|
||||||
|
pNewNode->type = IniNode::INI_NODE_TYPE_SECTION;
|
||||||
|
pNewNode->label = content;
|
||||||
|
root_->Add(pNewNode);
|
||||||
|
pScopeNode = pNewNode;
|
||||||
|
} else {
|
||||||
|
// hlogw("format error, line:%d", line);
|
||||||
|
continue; // ignore
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pos = content.find_first_of(_delim);
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
// key-value
|
||||||
|
pNewNode = new IniNode;
|
||||||
|
pNewNode->type = IniNode::INI_NODE_TYPE_KEY_VALUE;
|
||||||
|
pNewNode->label = trim(content.substr(0, pos));
|
||||||
|
pNewNode->value = trim(content.substr(pos+_delim.length()));
|
||||||
|
pScopeNode->Add(pNewNode);
|
||||||
|
} else {
|
||||||
|
// hlogw("format error, line:%d", line);
|
||||||
|
continue; // ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comment.length() != 0) {
|
||||||
|
// tail_comment
|
||||||
|
IniNode* pNode = new IniNode;
|
||||||
|
pNode->type = IniNode::INI_NODE_TYPE_SPAN;
|
||||||
|
pNode->label = comment;
|
||||||
|
pNewNode->Add(pNode);
|
||||||
|
comment = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// file end comment
|
||||||
|
if (strDiv.length() != 0) {
|
||||||
|
IniNode* pNode = new IniNode;
|
||||||
|
pNode->type = IniNode::INI_NODE_TYPE_DIV;
|
||||||
|
pNode->label = strDiv;
|
||||||
|
root_->Add(pNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IniParser::DumpString(IniNode* pNode, std::string& str) {
|
||||||
|
if (pNode == NULL) return;
|
||||||
|
|
||||||
|
if (pNode->type != IniNode::INI_NODE_TYPE_SPAN) {
|
||||||
|
if (str.length() > 0 && str[str.length()-1] != '\n') {
|
||||||
|
str += '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (pNode->type) {
|
||||||
|
case IniNode::INI_NODE_TYPE_SECTION: {
|
||||||
|
str += '[';
|
||||||
|
str += pNode->label;
|
||||||
|
str += ']';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IniNode::INI_NODE_TYPE_KEY_VALUE: {
|
||||||
|
str += asprintf("%s %s %s", pNode->label.c_str(), _delim.c_str(), pNode->value.c_str());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IniNode::INI_NODE_TYPE_DIV: {
|
||||||
|
str += pNode->label;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IniNode::INI_NODE_TYPE_SPAN: {
|
||||||
|
str += '\t';
|
||||||
|
str += pNode->label;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto p : pNode->children) {
|
||||||
|
DumpString(p, str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string IniParser::DumpString() {
|
||||||
|
std::string str;
|
||||||
|
DumpString(root_, str);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IniParser::Save() {
|
||||||
|
return SaveAs(_filepath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
int IniParser::SaveAs(const char* filepath) {
|
||||||
|
std::string str = DumpString();
|
||||||
|
if (str.length() == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HFile file;
|
||||||
|
if (file.open(filepath, "w") != 0) {
|
||||||
|
return ERR_SAVE_FILE;
|
||||||
|
}
|
||||||
|
file.write(str.c_str(), str.length());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<std::string> IniParser::GetSections() {
|
||||||
|
std::list<std::string> ret;
|
||||||
|
if (root_ == NULL) return std::move(ret);
|
||||||
|
|
||||||
|
for (auto pNode : root_->children) {
|
||||||
|
if (pNode->type == IniNode::INI_NODE_TYPE_SECTION) {
|
||||||
|
ret.push_back(pNode->label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::move(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<std::string> IniParser::GetKeys(const std::string& section) {
|
||||||
|
std::list<std::string> ret;
|
||||||
|
if (root_ == NULL) return std::move(ret);
|
||||||
|
|
||||||
|
IniNode* pSection = root_;
|
||||||
|
if (section.length() != 0) {
|
||||||
|
pSection = root_->Get(section, IniNode::INI_NODE_TYPE_SECTION);
|
||||||
|
if (pSection == NULL) return std::move(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto pNode : pSection->children) {
|
||||||
|
if (pNode->type == IniNode::INI_NODE_TYPE_KEY_VALUE) {
|
||||||
|
ret.push_back(pNode->label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::move(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string IniParser::GetValue(const std::string& key, const std::string& section) {
|
||||||
|
if (root_ == NULL) return "";
|
||||||
|
|
||||||
|
IniNode* pSection = root_;
|
||||||
|
if (section.length() != 0) {
|
||||||
|
pSection = root_->Get(section, IniNode::INI_NODE_TYPE_SECTION);
|
||||||
|
if (pSection == NULL) return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
IniNode* pKV = pSection->Get(key, IniNode::INI_NODE_TYPE_KEY_VALUE);
|
||||||
|
if (pKV == NULL) return "";
|
||||||
|
|
||||||
|
return pKV->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IniParser::SetValue(const std::string& key, const std::string& value, const std::string& section) {
|
||||||
|
if (root_ == NULL) {
|
||||||
|
root_ = new IniNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
IniNode* pSection = root_;
|
||||||
|
if (section.length() != 0) {
|
||||||
|
pSection = root_->Get(section, IniNode::INI_NODE_TYPE_SECTION);
|
||||||
|
if (pSection == NULL) {
|
||||||
|
pSection = new IniNode;
|
||||||
|
pSection->type = IniNode::INI_NODE_TYPE_SECTION;
|
||||||
|
pSection->label = section;
|
||||||
|
root_->Add(pSection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IniNode* pKV = pSection->Get(key, IniNode::INI_NODE_TYPE_KEY_VALUE);
|
||||||
|
if (pKV == NULL) {
|
||||||
|
pKV = new IniNode;
|
||||||
|
pKV->type = IniNode::INI_NODE_TYPE_KEY_VALUE;
|
||||||
|
pKV->label = key;
|
||||||
|
pSection->Add(pKV);
|
||||||
|
}
|
||||||
|
pKV->value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
HV_EXPORT bool IniParser::Get(const std::string& key, const std::string& section, bool defvalue) {
|
||||||
|
std::string str = GetValue(key, section);
|
||||||
|
return str.empty() ? defvalue : hv_getboolean(str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
HV_EXPORT int IniParser::Get(const std::string& key, const std::string& section, int defvalue) {
|
||||||
|
std::string str = GetValue(key, section);
|
||||||
|
return str.empty() ? defvalue : atoi(str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
HV_EXPORT float IniParser::Get(const std::string& key, const std::string& section, float defvalue) {
|
||||||
|
std::string str = GetValue(key, section);
|
||||||
|
return str.empty() ? defvalue : atof(str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
HV_EXPORT void IniParser::Set(const std::string& key, const bool& value, const std::string& section) {
|
||||||
|
SetValue(key, value ? "true" : "false", section);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
HV_EXPORT void IniParser::Set(const std::string& key, const int& value, const std::string& section) {
|
||||||
|
SetValue(key, asprintf("%d", value), section);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
HV_EXPORT void IniParser::Set(const std::string& key, const float& value, const std::string& section) {
|
||||||
|
SetValue(key, asprintf("%f", value), section);
|
||||||
|
}
|
53
external/libhv/libhv-1.3.2/cpputil/iniparser.h
vendored
Normal file
53
external/libhv/libhv-1.3.2/cpputil/iniparser.h
vendored
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#ifndef HV_INI_PARSER_H_
|
||||||
|
#define HV_INI_PARSER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include "hexport.h"
|
||||||
|
|
||||||
|
#define DEFAULT_INI_COMMENT "#"
|
||||||
|
#define DEFAULT_INI_DELIM "="
|
||||||
|
|
||||||
|
// fwd
|
||||||
|
class IniNode;
|
||||||
|
|
||||||
|
class HV_EXPORT IniParser {
|
||||||
|
public:
|
||||||
|
IniParser();
|
||||||
|
~IniParser();
|
||||||
|
|
||||||
|
int LoadFromFile(const char* filepath);
|
||||||
|
int LoadFromMem(const char* data);
|
||||||
|
int Unload();
|
||||||
|
int Reload();
|
||||||
|
|
||||||
|
std::string DumpString();
|
||||||
|
int Save();
|
||||||
|
int SaveAs(const char* filepath);
|
||||||
|
|
||||||
|
std::list<std::string> GetSections();
|
||||||
|
std::list<std::string> GetKeys(const std::string& section = "");
|
||||||
|
std::string GetValue(const std::string& key, const std::string& section = "");
|
||||||
|
void SetValue(const std::string& key, const std::string& value, const std::string& section = "");
|
||||||
|
|
||||||
|
// T = [bool, int, float]
|
||||||
|
template<typename T>
|
||||||
|
T Get(const std::string& key, const std::string& section = "", T defvalue = 0);
|
||||||
|
|
||||||
|
// T = [bool, int, float]
|
||||||
|
template<typename T>
|
||||||
|
void Set(const std::string& key, const T& value, const std::string& section = "");
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void DumpString(IniNode* pNode, std::string& str);
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string _comment;
|
||||||
|
std::string _delim;
|
||||||
|
std::string _filepath;
|
||||||
|
private:
|
||||||
|
IniNode* root_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HV_INI_PARSER_H_
|
25447
external/libhv/libhv-1.3.2/cpputil/json.hpp
vendored
Normal file
25447
external/libhv/libhv-1.3.2/cpputil/json.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
41
external/libhv/libhv-1.3.2/cpputil/singleton.h
vendored
Normal file
41
external/libhv/libhv-1.3.2/cpputil/singleton.h
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef HV_SINGLETON_H_
|
||||||
|
#define HV_SINGLETON_H_
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#define DISABLE_COPY(Class) \
|
||||||
|
Class(const Class&) = delete; \
|
||||||
|
Class& operator=(const Class&) = delete;
|
||||||
|
|
||||||
|
#define SINGLETON_DECL(Class) \
|
||||||
|
public: \
|
||||||
|
static Class* instance(); \
|
||||||
|
static void exitInstance(); \
|
||||||
|
private: \
|
||||||
|
DISABLE_COPY(Class) \
|
||||||
|
static Class* s_pInstance; \
|
||||||
|
static std::mutex s_mutex;
|
||||||
|
|
||||||
|
#define SINGLETON_IMPL(Class) \
|
||||||
|
Class* Class::s_pInstance = NULL; \
|
||||||
|
std::mutex Class::s_mutex; \
|
||||||
|
Class* Class::instance() { \
|
||||||
|
if (s_pInstance == NULL) { \
|
||||||
|
s_mutex.lock(); \
|
||||||
|
if (s_pInstance == NULL) { \
|
||||||
|
s_pInstance = new Class; \
|
||||||
|
} \
|
||||||
|
s_mutex.unlock(); \
|
||||||
|
} \
|
||||||
|
return s_pInstance; \
|
||||||
|
} \
|
||||||
|
void Class::exitInstance() { \
|
||||||
|
s_mutex.lock(); \
|
||||||
|
if (s_pInstance) { \
|
||||||
|
delete s_pInstance; \
|
||||||
|
s_pInstance = NULL; \
|
||||||
|
} \
|
||||||
|
s_mutex.unlock(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // HV_SINGLETON_H_
|
652
external/libhv/libhv-1.3.2/docs/API.md
vendored
Normal file
652
external/libhv/libhv-1.3.2/docs/API.md
vendored
Normal file
|
@ -0,0 +1,652 @@
|
||||||
|
# libhv API Manual
|
||||||
|
|
||||||
|
## base
|
||||||
|
|
||||||
|
### hplatform.h
|
||||||
|
- OS: OS_WIN, OS_UNIX (OS_LINUX, OS_ANDROID, OS_DARWIN ...)
|
||||||
|
- ARCH: ARCH_X86, ARCH_X64, ARCH_ARM, ARCH_ARM64
|
||||||
|
- COMPILER: COMPILER_MSVC, COMPILER_MINGW, COMPILER_GCC, COMPILER_CLANG
|
||||||
|
- BYTE_ORDER: BIG_ENDIAN, LITTLE_ENDIAN
|
||||||
|
- stdbool.h: bool, true, false
|
||||||
|
- stdint.h: int8_t, int16_t, int32_t, int64_t
|
||||||
|
- hv_sleep, hv_msleep, hv_usleep, hv_delay
|
||||||
|
- hv_mkdir
|
||||||
|
- stricmp, strcasecmp
|
||||||
|
|
||||||
|
### hexport.h
|
||||||
|
- HV_EXPORT, HV_INLINE
|
||||||
|
- HV_SOURCE, HV_STATICLIB, HV_DYNAMICLIB
|
||||||
|
- HV_DEPRECATED
|
||||||
|
- HV_UNUSED
|
||||||
|
- EXTERN_C, BEGIN_EXTERN_C, END_EXTERN_C
|
||||||
|
- BEGIN_NAMESPACE, END_NAMESPACE, USING_NAMESPACE
|
||||||
|
- DEFAULT
|
||||||
|
- ENUM, STRUCT
|
||||||
|
- IN, OUT, INOUT
|
||||||
|
- OPTIONAL, REQUIRED, REPEATED
|
||||||
|
|
||||||
|
### hdef.h
|
||||||
|
- ABS, NABS
|
||||||
|
- ARRAY_SIZE
|
||||||
|
- BITSET, BITCLR, BITGET
|
||||||
|
- CR, LF, CRLF
|
||||||
|
- FLOAT_EQUAL_ZERO
|
||||||
|
- INFINITE
|
||||||
|
- IS_ALPHA, IS_DIGIT, IS_ALPHANUM
|
||||||
|
- IS_CNTRL, IS_GRAPH
|
||||||
|
- IS_HEX
|
||||||
|
- IS_LOWER, IS_UPPER
|
||||||
|
- LOWER, UPPER
|
||||||
|
- MAKEWORD, LOBYTE, HIBYTE
|
||||||
|
- MAKELONG, LOWORD, HIWORD
|
||||||
|
- MAKEINT64, LOINT, HIINT
|
||||||
|
- MAKE_FOURCC
|
||||||
|
- MAX, MIN, LIMIT
|
||||||
|
- MAX_PATH
|
||||||
|
- NULL, TRUE, FALSE
|
||||||
|
- SAFE_FREE, SAFE_DELETE, SAFE_DELETE_ARRAY, SAFE_RELEASE
|
||||||
|
- STRINGCAT
|
||||||
|
- STRINGIFY
|
||||||
|
- offsetof, offsetofend
|
||||||
|
- container_of
|
||||||
|
- prefetch
|
||||||
|
- printd, printe
|
||||||
|
|
||||||
|
### hatomic.h
|
||||||
|
- hatomic_flag_t, hatomic_t
|
||||||
|
- hatomic_flag_test_and_set
|
||||||
|
- hatomic_flag_clear
|
||||||
|
- hatomic_add
|
||||||
|
- hatomic_sub
|
||||||
|
- hatomic_inc
|
||||||
|
- hatomic_dec
|
||||||
|
|
||||||
|
### herr.h
|
||||||
|
- hv_strerror
|
||||||
|
|
||||||
|
### htime.h
|
||||||
|
- IS_LEAP_YEAR
|
||||||
|
- datetime_t
|
||||||
|
- gettick_ms
|
||||||
|
- gettimeofday
|
||||||
|
- gettimeofday_ms
|
||||||
|
- gettimeofday_us
|
||||||
|
- gethrtime_us
|
||||||
|
- datetime_now
|
||||||
|
- datetime_localtime
|
||||||
|
- datetime_mktime
|
||||||
|
- datetime_past
|
||||||
|
- datetime_future
|
||||||
|
- duration_fmt
|
||||||
|
- datetime_fmt
|
||||||
|
- gmtime_fmt
|
||||||
|
- days_of_month
|
||||||
|
- month_atoi
|
||||||
|
- month_itoa
|
||||||
|
- weekday_atoi
|
||||||
|
- weekday_itoa
|
||||||
|
- hv_compile_datetime
|
||||||
|
- cron_next_timeout
|
||||||
|
|
||||||
|
### hmath.h
|
||||||
|
- floor2e
|
||||||
|
- ceil2e
|
||||||
|
- varint_encode
|
||||||
|
- varint_decode
|
||||||
|
|
||||||
|
### hbase.h
|
||||||
|
- hv_malloc
|
||||||
|
- hv_calloc
|
||||||
|
- hv_realloc
|
||||||
|
- hv_zalloc
|
||||||
|
- hv_strncpy
|
||||||
|
- hv_strncat
|
||||||
|
- hv_strlower
|
||||||
|
- hv_strupper
|
||||||
|
- hv_strreverse
|
||||||
|
- hv_strstartswith
|
||||||
|
- hv_strendswith
|
||||||
|
- hv_strcontains
|
||||||
|
- hv_wildcard_match
|
||||||
|
- hv_strnchr
|
||||||
|
- hv_strrchr_dot
|
||||||
|
- hv_strrchr_dir
|
||||||
|
- hv_basename
|
||||||
|
- hv_suffixname
|
||||||
|
- hv_mkdir_p
|
||||||
|
- hv_rmdir_p
|
||||||
|
- hv_exists
|
||||||
|
- hv_isdir
|
||||||
|
- hv_isfile
|
||||||
|
- hv_islink
|
||||||
|
- hv_filesize
|
||||||
|
- get_executable_path
|
||||||
|
- get_executable_dir
|
||||||
|
- get_executable_file
|
||||||
|
- get_run_dir
|
||||||
|
- hv_rand
|
||||||
|
- hv_random_string
|
||||||
|
- hv_getboolean
|
||||||
|
- hv_parse_size
|
||||||
|
- hv_parse_time
|
||||||
|
- hv_parse_url
|
||||||
|
|
||||||
|
### hversion.h
|
||||||
|
- hv_version
|
||||||
|
- hv_compile_version
|
||||||
|
- version_atoi
|
||||||
|
- version_itoa
|
||||||
|
|
||||||
|
### hsysinfo.h
|
||||||
|
- get_ncpu
|
||||||
|
- get_meminfo
|
||||||
|
|
||||||
|
### hproc.h
|
||||||
|
- hproc_spawn
|
||||||
|
|
||||||
|
### hthread.h
|
||||||
|
- hv_getpid
|
||||||
|
- hv_gettid
|
||||||
|
- HTHREAD_RETTYPE
|
||||||
|
- HTHREAD_ROUTINE
|
||||||
|
- hthread_create
|
||||||
|
- hthread_join
|
||||||
|
- class HThread
|
||||||
|
|
||||||
|
### hmutex.h
|
||||||
|
- hmutex_t
|
||||||
|
- hmutex_init
|
||||||
|
- hmutex_destroy
|
||||||
|
- hmutex_lock
|
||||||
|
- hmutex_unlock
|
||||||
|
- hspinlock_t
|
||||||
|
- hspinlock_init
|
||||||
|
- hspinlock_destroy
|
||||||
|
- hspinlock_lock
|
||||||
|
- hspinlock_unlock
|
||||||
|
- hrwlock_t
|
||||||
|
- hrwlock_init
|
||||||
|
- hrwlock_destroy
|
||||||
|
- hrwlock_rdlock
|
||||||
|
- hrwlock_rdunlock
|
||||||
|
- hrwlock_wrlock
|
||||||
|
- hrwlock_wrunlock
|
||||||
|
- htimed_mutex_t
|
||||||
|
- htimed_mutex_init
|
||||||
|
- htimed_mutex_destroy
|
||||||
|
- htimed_mutex_lock
|
||||||
|
- htimed_mutex_lock_for
|
||||||
|
- htimed_mutex_unlock
|
||||||
|
- hcondvar_t
|
||||||
|
- hcondvar_init
|
||||||
|
- hcondvar_destroy
|
||||||
|
- hcondvar_wait
|
||||||
|
- hcondvar_wait_for
|
||||||
|
- hcondvar_signal
|
||||||
|
- hcondvar_broadcast
|
||||||
|
- hsem_init
|
||||||
|
- hsem_destroy
|
||||||
|
- hsem_wait
|
||||||
|
- hsem_post
|
||||||
|
- hsem_timedwait
|
||||||
|
- honce_t
|
||||||
|
- HONCE_INIT
|
||||||
|
- honce
|
||||||
|
- class `hv::MutexLock`
|
||||||
|
- class `hv::SpinLock`
|
||||||
|
- class `hv::RWLock`
|
||||||
|
- class `hv::LockGuard`
|
||||||
|
- synchronized
|
||||||
|
|
||||||
|
### hsocket.h
|
||||||
|
- INVALID_SOCKET
|
||||||
|
- closesocket
|
||||||
|
- blocking
|
||||||
|
- nonblocking
|
||||||
|
- Bind
|
||||||
|
- Listen
|
||||||
|
- Connect
|
||||||
|
- ConnectNonblock
|
||||||
|
- ConnectTimeout
|
||||||
|
- ResolveAddr
|
||||||
|
- Socketpair
|
||||||
|
- socket_errno
|
||||||
|
- socket_strerror
|
||||||
|
- sockaddr_u
|
||||||
|
- sockaddr_ip
|
||||||
|
- sockaddr_port
|
||||||
|
- sockaddr_set_ip
|
||||||
|
- sockaddr_set_port
|
||||||
|
- sockaddr_set_ipport
|
||||||
|
- sockaddr_len
|
||||||
|
- sockaddr_str
|
||||||
|
- sockaddr_print
|
||||||
|
- SOCKADDR_LEN
|
||||||
|
- SOCKADDR_STR
|
||||||
|
- SOCKADDR_PRINT
|
||||||
|
- tcp_nodelay
|
||||||
|
- tcp_nopush
|
||||||
|
- tcp_keepalive
|
||||||
|
- udp_broadcast
|
||||||
|
- ip_v6only
|
||||||
|
- so_sndtimeo
|
||||||
|
- so_rcvtimeo
|
||||||
|
- so_sndbuf
|
||||||
|
- so_rcvbuf
|
||||||
|
- so_reuseaddr
|
||||||
|
- so_reuseport
|
||||||
|
- so_linger
|
||||||
|
|
||||||
|
### hlog.h
|
||||||
|
- default_logger
|
||||||
|
- file_logger
|
||||||
|
- stderr_logger
|
||||||
|
- stdout_logger
|
||||||
|
- logger_create
|
||||||
|
- logger_destroy
|
||||||
|
- logger_enable_color
|
||||||
|
- logger_enable_fsync
|
||||||
|
- logger_fsync
|
||||||
|
- logger_print
|
||||||
|
- logger_set_file
|
||||||
|
- logger_set_handler
|
||||||
|
- logger_set_level
|
||||||
|
- logger_set_max_bufsize
|
||||||
|
- logger_set_max_filesize
|
||||||
|
- logger_set_remain_days
|
||||||
|
- logger_get_cur_file
|
||||||
|
- hlogd, hlogi, hlogw, hloge, hlogf
|
||||||
|
- LOGD, LOGI, LOGW, LOGE, LOGF
|
||||||
|
|
||||||
|
### hbuf.h
|
||||||
|
- hbuf_t
|
||||||
|
- offset_buf_t
|
||||||
|
- class HBuf
|
||||||
|
- class HVLBuf
|
||||||
|
- class HRingBuf
|
||||||
|
|
||||||
|
### hmain.h
|
||||||
|
- main_ctx_init
|
||||||
|
- parse_opt
|
||||||
|
- parse_opt_long
|
||||||
|
- get_arg
|
||||||
|
- get_env
|
||||||
|
- setproctitle
|
||||||
|
- signal_init
|
||||||
|
- signal_handle
|
||||||
|
- create_pidfile
|
||||||
|
- delete_pidfile
|
||||||
|
- getpid_form_pidfile
|
||||||
|
- master_workers_run
|
||||||
|
|
||||||
|
### hstring.h
|
||||||
|
- to_string
|
||||||
|
- from_string
|
||||||
|
- toupper
|
||||||
|
- tolower
|
||||||
|
- reverse
|
||||||
|
- startswith
|
||||||
|
- endswith
|
||||||
|
- contains
|
||||||
|
- asprintf
|
||||||
|
- trim
|
||||||
|
- ltrim
|
||||||
|
- rtrim
|
||||||
|
- trim_pairs
|
||||||
|
- split
|
||||||
|
- splitKV
|
||||||
|
- replace
|
||||||
|
- replaceAll
|
||||||
|
|
||||||
|
### hfile.h
|
||||||
|
- class HFile
|
||||||
|
|
||||||
|
### hpath.h
|
||||||
|
- exists
|
||||||
|
- isdir
|
||||||
|
- isfile
|
||||||
|
- islink
|
||||||
|
- basename
|
||||||
|
- dirname
|
||||||
|
- filename
|
||||||
|
- suffixname
|
||||||
|
- join
|
||||||
|
|
||||||
|
### hdir.h
|
||||||
|
- listdir
|
||||||
|
|
||||||
|
### hurl.h
|
||||||
|
- HUrl::escape
|
||||||
|
- HUrl::unescape
|
||||||
|
- HUrl::parse
|
||||||
|
- HUrl::dump
|
||||||
|
|
||||||
|
### hscope.h
|
||||||
|
- defer
|
||||||
|
- template ScopeCleanup
|
||||||
|
- template ScopeFree
|
||||||
|
- template ScopeDelete
|
||||||
|
- template ScopeDeleteArray
|
||||||
|
- template ScopeRelease
|
||||||
|
- template ScopeLock
|
||||||
|
|
||||||
|
### ifconfig.h
|
||||||
|
- ifconfig
|
||||||
|
|
||||||
|
## utils
|
||||||
|
### md5.h
|
||||||
|
- HV_MD5Init
|
||||||
|
- HV_MD5Update
|
||||||
|
- HV_MD5Final
|
||||||
|
- hv_md5
|
||||||
|
- hv_md5_hex
|
||||||
|
|
||||||
|
### sha1.h
|
||||||
|
- HV_SHA1Init
|
||||||
|
- HV_SHA1Update
|
||||||
|
- HV_SHA1Final
|
||||||
|
- HV_SHA1
|
||||||
|
- hv_sha1
|
||||||
|
- hv_sha1_hex
|
||||||
|
|
||||||
|
### base64.h
|
||||||
|
- hv_base64_decode
|
||||||
|
- hv_base64_encode
|
||||||
|
|
||||||
|
### json.hpp
|
||||||
|
- json::parse
|
||||||
|
- json::dump
|
||||||
|
|
||||||
|
### singleton.h
|
||||||
|
- DISABLE_COPY
|
||||||
|
- SINGLETON_DECL
|
||||||
|
- SINGLETON_IMPL
|
||||||
|
|
||||||
|
## event
|
||||||
|
|
||||||
|
### hloop.h
|
||||||
|
- hloop_create_tcp_client
|
||||||
|
- hloop_create_tcp_server
|
||||||
|
- hloop_create_udp_client
|
||||||
|
- hloop_create_udp_server
|
||||||
|
- hloop_create_ssl_client
|
||||||
|
- hloop_create_ssl_server
|
||||||
|
- hloop_new
|
||||||
|
- hloop_free
|
||||||
|
- hloop_run
|
||||||
|
- hloop_stop
|
||||||
|
- hloop_pause
|
||||||
|
- hloop_resume
|
||||||
|
- hloop_status
|
||||||
|
- hloop_pid
|
||||||
|
- hloop_tid
|
||||||
|
- hloop_now
|
||||||
|
- hloop_now_ms
|
||||||
|
- hloop_now_us
|
||||||
|
- hloop_update_time
|
||||||
|
- hloop_set_userdata
|
||||||
|
- hloop_userdata
|
||||||
|
- hloop_wakeup
|
||||||
|
- hloop_post_event
|
||||||
|
- hevent_loop
|
||||||
|
- hevent_type
|
||||||
|
- hevent_id
|
||||||
|
- hevent_priority
|
||||||
|
- hevent_userdata
|
||||||
|
- hevent_set_priority
|
||||||
|
- hevent_ser_userdata
|
||||||
|
- haccept
|
||||||
|
- hconnect
|
||||||
|
- hread
|
||||||
|
- hwrite
|
||||||
|
- hrecv
|
||||||
|
- hsend
|
||||||
|
- hrecvfrom
|
||||||
|
- hsendto
|
||||||
|
- hio_add
|
||||||
|
- hio_del
|
||||||
|
- hio_get
|
||||||
|
- hio_detach
|
||||||
|
- hio_attach
|
||||||
|
- hio_read
|
||||||
|
- hio_read_start
|
||||||
|
- hio_read_stop
|
||||||
|
- hio_read_once
|
||||||
|
- hio_read_until
|
||||||
|
- hio_read_until_length
|
||||||
|
- hio_read_until_delim
|
||||||
|
- hio_read_readline
|
||||||
|
- hio_read_readstring
|
||||||
|
- hio_read_readbytes
|
||||||
|
- hio_write
|
||||||
|
- hio_close
|
||||||
|
- hio_accept
|
||||||
|
- hio_connect
|
||||||
|
- hio_fd
|
||||||
|
- hio_id
|
||||||
|
- hio_type
|
||||||
|
- hio_error
|
||||||
|
- hio_localaddr
|
||||||
|
- hio_peeraddr
|
||||||
|
- hio_events
|
||||||
|
- hio_revents
|
||||||
|
- hio_is_opened
|
||||||
|
- hio_is_closed
|
||||||
|
- hio_enable_ssl
|
||||||
|
- hio_is_ssl
|
||||||
|
- hio_get_ssl
|
||||||
|
- hio_set_ssl
|
||||||
|
- hio_get_ssl_ctx
|
||||||
|
- hio_set_ssl_ctx
|
||||||
|
- hio_new_ssl_ctx
|
||||||
|
- hio_setcb_accept
|
||||||
|
- hio_setcb_connect
|
||||||
|
- hio_setcb_read
|
||||||
|
- hio_setcb_write
|
||||||
|
- hio_setcb_close
|
||||||
|
- hio_getcb_accept
|
||||||
|
- hio_getcb_connect
|
||||||
|
- hio_getcb_read
|
||||||
|
- hio_getcb_write
|
||||||
|
- hio_getcb_close
|
||||||
|
- hio_set_type
|
||||||
|
- hio_set_localaddr
|
||||||
|
- hio_set_peeraddr
|
||||||
|
- hio_set_readbuf
|
||||||
|
- hio_set_connect_timeout
|
||||||
|
- hio_set_close_timeout
|
||||||
|
- hio_set_read_timeout
|
||||||
|
- hio_set_write_timeout
|
||||||
|
- hio_set_keepalive_timeout
|
||||||
|
- hio_set_heartbeat
|
||||||
|
- hio_set_unpack
|
||||||
|
- hio_unset_unpack
|
||||||
|
- hio_read_upstream
|
||||||
|
- hio_write_upstream
|
||||||
|
- hio_close_upstream
|
||||||
|
- hio_setup_upstream
|
||||||
|
- hio_get_upstream
|
||||||
|
- hio_setup_tcp_upstream
|
||||||
|
- hio_setup_ssl_upstream
|
||||||
|
- hio_setup_udp_upstream
|
||||||
|
- hio_create_socket
|
||||||
|
- hio_context
|
||||||
|
- hio_set_context
|
||||||
|
- htimer_add
|
||||||
|
- htimer_add_period
|
||||||
|
- htimer_del
|
||||||
|
- htimer_reset
|
||||||
|
- hidle_add
|
||||||
|
- hidle_del
|
||||||
|
|
||||||
|
### nlog.h
|
||||||
|
- network_logger
|
||||||
|
- nlog_listen
|
||||||
|
|
||||||
|
## evpp
|
||||||
|
- class Buffer
|
||||||
|
- class Channel
|
||||||
|
- class Event
|
||||||
|
- class EventLoop
|
||||||
|
- class EventLoopThread
|
||||||
|
- class EventLoopThreadPool
|
||||||
|
- class TcpClient
|
||||||
|
- class TcpServer
|
||||||
|
- class UdpClient
|
||||||
|
- class UdpServer
|
||||||
|
|
||||||
|
## ssl
|
||||||
|
- hssl_ctx_init
|
||||||
|
- hssl_ctx_cleanup
|
||||||
|
- hssl_ctx_instance
|
||||||
|
- hssl_ctx_new
|
||||||
|
- hssl_ctx_free
|
||||||
|
- hssl_new
|
||||||
|
- hssl_free
|
||||||
|
- hssl_accept
|
||||||
|
- hssl_connnect
|
||||||
|
- hssl_read
|
||||||
|
- hssl_write
|
||||||
|
- hssl_close
|
||||||
|
- hssl_set_sni_hostname
|
||||||
|
|
||||||
|
## protocol
|
||||||
|
|
||||||
|
### dns.h
|
||||||
|
- dns_name_decode
|
||||||
|
- dns_name_encode
|
||||||
|
- dns_pack
|
||||||
|
- dns_unpack
|
||||||
|
- dns_rr_pack
|
||||||
|
- dns_rr_unpack
|
||||||
|
- dns_query
|
||||||
|
- dns_free
|
||||||
|
- nslookup
|
||||||
|
|
||||||
|
### ftp.h
|
||||||
|
- ftp_command_str
|
||||||
|
- ftp_connect
|
||||||
|
- ftp_login
|
||||||
|
- ftp_exec
|
||||||
|
- ftp_upload
|
||||||
|
- ftp_download
|
||||||
|
- ftp_download_with_cb
|
||||||
|
- ftp_quit
|
||||||
|
- ftp_status_str
|
||||||
|
|
||||||
|
### smtp.h
|
||||||
|
- smtp_command_str
|
||||||
|
- smtp_status_str
|
||||||
|
- smtp_build_command
|
||||||
|
- sendmail
|
||||||
|
|
||||||
|
### icmp.h
|
||||||
|
- ping
|
||||||
|
|
||||||
|
## http
|
||||||
|
- class HttpMessage
|
||||||
|
- class HttpRequest
|
||||||
|
- class HttpResponse
|
||||||
|
- class HttpParser
|
||||||
|
|
||||||
|
### httpdef.h
|
||||||
|
- http_content_type_enum
|
||||||
|
- http_content_type_enum_by_suffix
|
||||||
|
- http_content_type_str
|
||||||
|
- http_content_type_str_by_suffix
|
||||||
|
- http_content_type_suffix
|
||||||
|
- http_errno_description
|
||||||
|
- http_errno_name
|
||||||
|
- http_method_enum
|
||||||
|
- http_method_str
|
||||||
|
- http_status_enum
|
||||||
|
- http_status_str
|
||||||
|
|
||||||
|
### http_content.h
|
||||||
|
- parse_query_params
|
||||||
|
- parse_json
|
||||||
|
- parse_multipart
|
||||||
|
- dump_query_params
|
||||||
|
- dump_json
|
||||||
|
- dump_multipart
|
||||||
|
|
||||||
|
### HttpClient.h
|
||||||
|
- http_client_new
|
||||||
|
- http_client_del
|
||||||
|
- http_client_send
|
||||||
|
- http_client_send_async
|
||||||
|
- http_client_strerror
|
||||||
|
- http_client_set_timeout
|
||||||
|
- http_client_set_header
|
||||||
|
- http_client_del_header
|
||||||
|
- http_client_get_header
|
||||||
|
- http_client_clear_headers
|
||||||
|
- http_client_set_http_proxy
|
||||||
|
- http_client_set_https_proxy
|
||||||
|
- http_client_add_no_proxy
|
||||||
|
- class HttpClient
|
||||||
|
|
||||||
|
### requests.h
|
||||||
|
- requests::request
|
||||||
|
- requests::get
|
||||||
|
- requests::post
|
||||||
|
- requests::put
|
||||||
|
- requests::patch
|
||||||
|
- requests::Delete
|
||||||
|
- requests::head
|
||||||
|
- requests::async
|
||||||
|
|
||||||
|
### axios.h
|
||||||
|
- axios::axios
|
||||||
|
- axios::get
|
||||||
|
- axios::post
|
||||||
|
- axios::put
|
||||||
|
- axios::patch
|
||||||
|
- axios::Delete
|
||||||
|
- axios::head
|
||||||
|
- axios::async
|
||||||
|
|
||||||
|
### HttpServer.h
|
||||||
|
- http_server_run
|
||||||
|
- http_server_stop
|
||||||
|
- class HttpService
|
||||||
|
- class HttpServer
|
||||||
|
|
||||||
|
### WebSocketClient.h
|
||||||
|
- class WebSocketClient
|
||||||
|
|
||||||
|
### WebSocketServer.h
|
||||||
|
- websocket_server_run
|
||||||
|
- websocket_server_stop
|
||||||
|
- class WebSocketService
|
||||||
|
- class WebSocketServer
|
||||||
|
|
||||||
|
## mqtt
|
||||||
|
- mqtt_client_new
|
||||||
|
- mqtt_client_free
|
||||||
|
- mqtt_client_run
|
||||||
|
- mqtt_client_stop
|
||||||
|
- mqtt_client_set_id
|
||||||
|
- mqtt_client_set_will
|
||||||
|
- mqtt_client_set_auth
|
||||||
|
- mqtt_client_set_callback
|
||||||
|
- mqtt_client_set_userdata
|
||||||
|
- mqtt_client_get_userdata
|
||||||
|
- mqtt_client_get_last_error
|
||||||
|
- mqtt_client_set_ssl_ctx
|
||||||
|
- mqtt_client_new_ssl_ctx
|
||||||
|
- mqtt_client_set_reconnect
|
||||||
|
- mqtt_client_reconnect
|
||||||
|
- mqtt_client_set_connect_timeout
|
||||||
|
- mqtt_client_connect
|
||||||
|
- mqtt_client_is_connected
|
||||||
|
- mqtt_client_disconnect
|
||||||
|
- mqtt_client_publish
|
||||||
|
- mqtt_client_subscribe
|
||||||
|
- mqtt_client_unsubscribe
|
||||||
|
- class MqttClient
|
||||||
|
|
||||||
|
## other
|
||||||
|
- class HThreadPool
|
||||||
|
- class HObjectPool
|
||||||
|
- class ThreadLocalStorage
|
31
external/libhv/libhv-1.3.2/docs/PLAN.md
vendored
Normal file
31
external/libhv/libhv-1.3.2/docs/PLAN.md
vendored
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
## Done
|
||||||
|
|
||||||
|
- base: cross platfrom infrastructure
|
||||||
|
- event: select/poll/epoll/wepoll/kqueue/port
|
||||||
|
- ssl: openssl/gnutls/mbedtls/wintls/appletls
|
||||||
|
- rudp: KCP
|
||||||
|
- evpp: c++ EventLoop interface similar to muduo and evpp
|
||||||
|
- http client/server: include https http1/x http2
|
||||||
|
- websocket client/server
|
||||||
|
- mqtt client
|
||||||
|
|
||||||
|
## Improving
|
||||||
|
|
||||||
|
- Path router: optimized matching via trie?
|
||||||
|
- FileCache use LRUCache
|
||||||
|
|
||||||
|
## Plan
|
||||||
|
|
||||||
|
- redis client
|
||||||
|
- async DNS
|
||||||
|
- lua binding
|
||||||
|
- js binding
|
||||||
|
- hrpc = libhv + protobuf
|
||||||
|
- rudp: FEC, ARQ, UDT, QUIC
|
||||||
|
- kcptun
|
||||||
|
- have a taste of io_uring
|
||||||
|
- coroutine
|
||||||
|
- cppsocket.io
|
||||||
|
- IM-libhv
|
||||||
|
- MediaServer-libhv
|
||||||
|
- GameServer-libhv
|
153
external/libhv/libhv-1.3.2/docs/cn/Channel.md
vendored
Normal file
153
external/libhv/libhv-1.3.2/docs/cn/Channel.md
vendored
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
通道类
|
||||||
|
|
||||||
|
```c++
|
||||||
|
|
||||||
|
class Channel {
|
||||||
|
|
||||||
|
// 返回底层的io结构体指针
|
||||||
|
hio_t* io() { return io_; }
|
||||||
|
|
||||||
|
// 返回socket文件描述符
|
||||||
|
int fd() { return fd_; }
|
||||||
|
|
||||||
|
// 返回一个唯一标示id
|
||||||
|
uint32_t id() { return id_; }
|
||||||
|
|
||||||
|
// 返回错误码
|
||||||
|
int error() { return hio_error(io_); }
|
||||||
|
|
||||||
|
// 获取/设置/新建/删除 上下文
|
||||||
|
void* context();
|
||||||
|
void setContext(void* ctx);
|
||||||
|
template<class T> T* newContext();
|
||||||
|
template<class T> T* getContext();
|
||||||
|
template<class T> void deleteContext();
|
||||||
|
|
||||||
|
// 获取/设置/新建/删除 上下文智能指针
|
||||||
|
std::shared_ptr<void> contextPtr();
|
||||||
|
void setContextPtr(const std::shared_ptr<void>& ctx);
|
||||||
|
void setContextPtr(std::shared_ptr<void>&& ctx);
|
||||||
|
template<class T> std::shared_ptr<T> newContextPtr();
|
||||||
|
template<class T> std::shared_ptr<T> getContextPtr();
|
||||||
|
void deleteContextPtr();
|
||||||
|
|
||||||
|
// 是否打开状态
|
||||||
|
bool isOpened();
|
||||||
|
|
||||||
|
// 是否关闭状态
|
||||||
|
bool isClosed();
|
||||||
|
|
||||||
|
// 开始读
|
||||||
|
int startRead();
|
||||||
|
|
||||||
|
// 停止读
|
||||||
|
int stopRead();
|
||||||
|
|
||||||
|
// 读一次
|
||||||
|
int readOnce();
|
||||||
|
// 读一个字符串
|
||||||
|
int readString();
|
||||||
|
// 读一行
|
||||||
|
int readLine();
|
||||||
|
// 读取N个字节
|
||||||
|
int readBytes(int len);
|
||||||
|
|
||||||
|
// 写
|
||||||
|
int write(const void* data, int size);
|
||||||
|
int write(Buffer* buf);
|
||||||
|
int write(const std::string& str);
|
||||||
|
|
||||||
|
// 设置最大读缓存
|
||||||
|
void setMaxReadBufsize(uint32_t size);
|
||||||
|
// 设置最大写缓存
|
||||||
|
void setMaxWriteBufsize(uint32_t size);
|
||||||
|
// 获取当前写缓存大小
|
||||||
|
size_t writeBufsize();
|
||||||
|
// 是否写完成
|
||||||
|
bool isWriteComplete();
|
||||||
|
|
||||||
|
// 关闭
|
||||||
|
int close(bool async = false);
|
||||||
|
|
||||||
|
// 读回调
|
||||||
|
std::function<void(Buffer*)> onread;
|
||||||
|
// 写回调
|
||||||
|
std::function<void(Buffer*)> onwrite;
|
||||||
|
// 关闭回调
|
||||||
|
std::function<void()> onclose;
|
||||||
|
};
|
||||||
|
|
||||||
|
// SocketChannel 继承自 Channel
|
||||||
|
class SocketChannel : public Channel {
|
||||||
|
// 连接状态回调
|
||||||
|
std::function<void()> onconnect;
|
||||||
|
// 心跳回调
|
||||||
|
std::function<void()> heartbeat;
|
||||||
|
|
||||||
|
// 启用SSL/TLS加密通信
|
||||||
|
int enableSSL();
|
||||||
|
// 是否是SSL/TLS加密通信
|
||||||
|
bool isSSL();
|
||||||
|
// 设置SSL
|
||||||
|
int setSSL(hssl_t ssl);
|
||||||
|
// 设置SSL_CTX
|
||||||
|
int setSslCtx(hssl_ctx_t ssl_ctx);
|
||||||
|
// 新建SSL_CTX
|
||||||
|
int newSslCtx(hssl_ctx_opt_t* opt);
|
||||||
|
// 设置主机名
|
||||||
|
int setHostname(const std::string& hostname);
|
||||||
|
|
||||||
|
// 设置连接超时
|
||||||
|
void setConnectTimeout(int timeout_ms);
|
||||||
|
|
||||||
|
// 设置关闭超时 (说明:非阻塞写队列非空时,需要等待写完成再关闭)
|
||||||
|
void setCloseTimeout(int timeout_ms);
|
||||||
|
|
||||||
|
// 设置读超时 (一段时间没有数据到来便自动关闭连接)
|
||||||
|
void setReadTimeout(int timeout_ms);
|
||||||
|
|
||||||
|
// 设置写超时 (一段时间没有数据发送便自动关闭连接)
|
||||||
|
void setWriteTimeout(int timeout_ms);
|
||||||
|
|
||||||
|
// 设置keepalive超时 (一段时间没有数据收发便自动关闭连接)
|
||||||
|
void setKeepaliveTimeout(int timeout_ms);
|
||||||
|
|
||||||
|
// 设置心跳 (定时发送心跳包)
|
||||||
|
void setHeartbeat(int interval_ms, std::function<void()> fn);
|
||||||
|
|
||||||
|
// 设置拆包规则
|
||||||
|
void setUnpack(unpack_setting_t* setting);
|
||||||
|
|
||||||
|
// 开始连接
|
||||||
|
int startConnect(int port, const char* host = "127.0.0.1");
|
||||||
|
int startConnect(struct sockaddr* peeraddr);
|
||||||
|
int startConnect();
|
||||||
|
|
||||||
|
// 是否已连接
|
||||||
|
bool isConnected();
|
||||||
|
|
||||||
|
// 返回本地地址
|
||||||
|
std::string localaddr();
|
||||||
|
|
||||||
|
// 返回对端地址
|
||||||
|
std::string peeraddr();
|
||||||
|
};
|
||||||
|
|
||||||
|
// WebSocketChannel 继承自 SocketChannel
|
||||||
|
class WebSocketChannel : public SocketChannel {
|
||||||
|
|
||||||
|
// 发送文本帧
|
||||||
|
int send(const std::string& msg, enum ws_opcode opcode = WS_OPCODE_TEXT, bool fin = true);
|
||||||
|
|
||||||
|
// 发送二进制帧
|
||||||
|
int send(const char* buf, int len, enum ws_opcode opcode = WS_OPCODE_BINARY, bool fin = true);
|
||||||
|
|
||||||
|
// 分片发送
|
||||||
|
int send(const char* buf, int len, int fragment, enum ws_opcode opcode = WS_OPCODE_BINARY);
|
||||||
|
|
||||||
|
// 关闭
|
||||||
|
int close();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
123
external/libhv/libhv-1.3.2/docs/cn/EventLoop.md
vendored
Normal file
123
external/libhv/libhv-1.3.2/docs/cn/EventLoop.md
vendored
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
事件循环类
|
||||||
|
|
||||||
|
```c++
|
||||||
|
|
||||||
|
class EventLoop {
|
||||||
|
|
||||||
|
// 返回底层的loop结构体指针
|
||||||
|
hloop_t* loop();
|
||||||
|
|
||||||
|
// 运行
|
||||||
|
void run();
|
||||||
|
// 停止
|
||||||
|
void stop();
|
||||||
|
// 暂停
|
||||||
|
void pause();
|
||||||
|
// 继续
|
||||||
|
void resume();
|
||||||
|
|
||||||
|
// 设置定时器
|
||||||
|
TimerID setTimer(int timeout_ms, TimerCallback cb, uint32_t repeat = INFINITE, TimerID timerID = INVALID_TIMER_ID);
|
||||||
|
|
||||||
|
// 设置一次性定时器
|
||||||
|
TimerID setTimeout(int timeout_ms, TimerCallback cb);
|
||||||
|
|
||||||
|
// 设置永久性定时器
|
||||||
|
TimerID setInterval(int interval_ms, TimerCallback cb);
|
||||||
|
|
||||||
|
// 杀掉定时器
|
||||||
|
void killTimer(TimerID timerID);
|
||||||
|
|
||||||
|
// 重置定时器
|
||||||
|
void resetTimer(TimerID timerID, int timeout_ms = 0);
|
||||||
|
|
||||||
|
// 返回事件循环所在的线程ID
|
||||||
|
long tid();
|
||||||
|
|
||||||
|
// 是否在事件循环所在线程
|
||||||
|
bool isInLoopThread();
|
||||||
|
|
||||||
|
// 断言在事件循环所在线程
|
||||||
|
void assertInLoopThread();
|
||||||
|
|
||||||
|
// 运行在事件循环里
|
||||||
|
void runInLoop(Functor fn);
|
||||||
|
|
||||||
|
// 队列在事件循环里
|
||||||
|
void queueInLoop(Functor fn);
|
||||||
|
|
||||||
|
// 投递一个事件到事件循环
|
||||||
|
void postEvent(EventCallback cb);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class EventLoopThread {
|
||||||
|
|
||||||
|
// 返回事件循环指针
|
||||||
|
const EventLoopPtr& loop();
|
||||||
|
|
||||||
|
// 返回底层的loop结构体指针
|
||||||
|
hloop_t* hloop();
|
||||||
|
|
||||||
|
// 是否运行中
|
||||||
|
bool isRunning();
|
||||||
|
|
||||||
|
/* 开始运行
|
||||||
|
* wait_thread_started: 是否阻塞等待线程开始
|
||||||
|
* pre: 线程开始后执行的函数
|
||||||
|
* post: 线程结束前执行的函数
|
||||||
|
*/
|
||||||
|
void start(bool wait_thread_started = true,
|
||||||
|
Functor pre = Functor(),
|
||||||
|
Functor post = Functor());
|
||||||
|
|
||||||
|
// 停止运行
|
||||||
|
void stop(bool wait_thread_stopped = false);
|
||||||
|
|
||||||
|
// 等待线程退出
|
||||||
|
void join();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class EventLoopThreadPool {
|
||||||
|
|
||||||
|
// 获取线程数量
|
||||||
|
int threadNum();
|
||||||
|
|
||||||
|
// 设置线程数量
|
||||||
|
void setThreadNum(int num);
|
||||||
|
|
||||||
|
// 返回下一个事件循环对象
|
||||||
|
// 支持轮询、随机、最少连接数等负载均衡策略
|
||||||
|
EventLoopPtr nextLoop(load_balance_e lb = LB_RoundRobin);
|
||||||
|
|
||||||
|
// 返回索引的事件循环对象
|
||||||
|
EventLoopPtr loop(int idx = -1);
|
||||||
|
|
||||||
|
// 返回索引的底层loop结构体指针
|
||||||
|
hloop_t* hloop(int idx = -1);
|
||||||
|
|
||||||
|
/* 开始运行
|
||||||
|
* wait_threads_started: 是否阻塞等待所有线程开始
|
||||||
|
* pre: 线程开始后执行的函数
|
||||||
|
* post: 线程结束前执行的函数
|
||||||
|
*/
|
||||||
|
void start(bool wait_threads_started = false,
|
||||||
|
std::function<void(const EventLoopPtr&)> pre = NULL,
|
||||||
|
std::function<void(const EventLoopPtr&)> post = NULL);
|
||||||
|
|
||||||
|
// 停止运行
|
||||||
|
void stop(bool wait_threads_stopped = false);
|
||||||
|
|
||||||
|
// 等待所有线程退出
|
||||||
|
void join();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
测试代码见:
|
||||||
|
|
||||||
|
- [evpp/EventLoop_test.cpp](../../evpp/EventLoop_test.cpp)
|
||||||
|
- [evpp/EventLoopThread_test.cpp](../../evpp/EventLoopThread_test.cpp)
|
||||||
|
- [evpp/EventLoopThreadPool_test.cpp](../../evpp/EventLoopThreadPool_test.cpp)
|
84
external/libhv/libhv-1.3.2/docs/cn/HttpClient.md
vendored
Normal file
84
external/libhv/libhv-1.3.2/docs/cn/HttpClient.md
vendored
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
HTTP 客户端类
|
||||||
|
|
||||||
|
```c++
|
||||||
|
|
||||||
|
class HttpClient {
|
||||||
|
|
||||||
|
// 设置超时
|
||||||
|
int setTimeout(int timeout);
|
||||||
|
|
||||||
|
// 设置SSL/TLS
|
||||||
|
int setSslCtx(hssl_ctx_t ssl_ctx);
|
||||||
|
// 新建SSL/TLS
|
||||||
|
int newSslCtx(hssl_ctx_opt_t* opt);
|
||||||
|
|
||||||
|
// 清除全部请求头部
|
||||||
|
int clearHeaders();
|
||||||
|
// 设置请求头部
|
||||||
|
int setHeader(const char* key, const char* value);
|
||||||
|
// 删除请求头部
|
||||||
|
int delHeader(const char* key);
|
||||||
|
// 获取请求头部
|
||||||
|
const char* getHeader(const char* key);
|
||||||
|
|
||||||
|
// 设置http代理
|
||||||
|
int setHttpProxy(const char* host, int port);
|
||||||
|
// 设置https代理
|
||||||
|
int setHttpsProxy(const char* host, int port);
|
||||||
|
// 添加不走代理
|
||||||
|
int addNoProxy(const char* host);
|
||||||
|
|
||||||
|
// 同步发送
|
||||||
|
int send(HttpRequest* req, HttpResponse* resp);
|
||||||
|
// 异步发送
|
||||||
|
int sendAsync(HttpRequestPtr req, HttpResponseCallback resp_cb = NULL);
|
||||||
|
|
||||||
|
// 关闭连接 (HttpClient对象析构时会自动调用)
|
||||||
|
int close();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace requests {
|
||||||
|
|
||||||
|
// 同步请求
|
||||||
|
Response request(Request req);
|
||||||
|
Response request(http_method method, const char* url, const http_body& body = NoBody, const http_headers& headers = DefaultHeaders);
|
||||||
|
|
||||||
|
// 上传文件
|
||||||
|
Response uploadFile(const char* url, const char* filepath, http_method method = HTTP_POST, const http_headers& headers = DefaultHeaders);
|
||||||
|
|
||||||
|
// 通过 `multipart/form-data` 格式上传文件
|
||||||
|
Response uploadFormFile(const char* url, const char* name, const char* filepath, std::map<std::string, std::string>& params = hv::empty_map, http_method method = HTTP_POST, const http_headers& headers = DefaultHeaders);
|
||||||
|
|
||||||
|
// 上传大文件(带上传进度回调)
|
||||||
|
Response uploadLargeFile(const char* url, const char* filepath, upload_progress_cb progress_cb = NULL, http_method method = HTTP_POST, const http_headers& headers = DefaultHeaders);
|
||||||
|
|
||||||
|
// 下载文件 (更详细的断点续传示例代码见`examples/wget.cpp`)
|
||||||
|
size_t downloadFile(const char* url, const char* filepath, download_progress_cb progress_cb = NULL);
|
||||||
|
|
||||||
|
// HEAD 请求
|
||||||
|
Response head(const char* url, const http_headers& headers = DefaultHeaders);
|
||||||
|
|
||||||
|
// GET 请求
|
||||||
|
Response get(const char* url, const http_headers& headers = DefaultHeaders);
|
||||||
|
|
||||||
|
// POST 请求
|
||||||
|
Response post(const char* url, const http_body& body = NoBody, const http_headers& headers = DefaultHeaders);
|
||||||
|
|
||||||
|
// PUT 请求
|
||||||
|
Response put(const char* url, const http_body& body = NoBody, const http_headers& headers = DefaultHeaders);
|
||||||
|
|
||||||
|
// PATCH 请求
|
||||||
|
Response patch(const char* url, const http_body& body = NoBody, const http_headers& headers = DefaultHeaders);
|
||||||
|
|
||||||
|
// DELETE 请求
|
||||||
|
Response Delete(const char* url, const http_headers& headers = DefaultHeaders);
|
||||||
|
|
||||||
|
// 异步请求
|
||||||
|
int async(Request req, ResponseCallback resp_cb);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
测试代码见 [examples/http_client_test.cpp](../../examples/http_client_test.cpp)
|
83
external/libhv/libhv-1.3.2/docs/cn/HttpContext.md
vendored
Normal file
83
external/libhv/libhv-1.3.2/docs/cn/HttpContext.md
vendored
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
```c++
|
||||||
|
|
||||||
|
class HttpContext {
|
||||||
|
|
||||||
|
/* 获取请求信息 */
|
||||||
|
// 获取客户端IP
|
||||||
|
std::string ip();
|
||||||
|
// 获取客户端端口
|
||||||
|
int port();
|
||||||
|
// 获取请求method
|
||||||
|
http_method method();
|
||||||
|
// 获取请求url
|
||||||
|
std::string url();
|
||||||
|
// 获取请求path
|
||||||
|
std::string path();
|
||||||
|
// 获取请求host
|
||||||
|
std::string host();
|
||||||
|
// 获取请求头部
|
||||||
|
const http_headers& headers();
|
||||||
|
std::string header(const char* key, const std::string& defvalue = hv::empty_string);
|
||||||
|
// 获取请求参数
|
||||||
|
const hv::QueryParams& params();
|
||||||
|
std::string param(const char* key, const std::string& defvalue = hv::empty_string);
|
||||||
|
// 获取请求cookie
|
||||||
|
const HttpCookie& cookie(const char* name);
|
||||||
|
// 获取请求 `Content-Length`
|
||||||
|
int length();
|
||||||
|
// 获取请求 `Content-Type`
|
||||||
|
http_content_type type();
|
||||||
|
// 判断请求 `Content-Type`
|
||||||
|
bool is(http_content_type content_type);
|
||||||
|
// 获取请求body
|
||||||
|
std::string& body();
|
||||||
|
// 获取 `application/json` 格式数据
|
||||||
|
const hv::Json& json();
|
||||||
|
// 获取 `multipart/form-data` 格式数据
|
||||||
|
const hv::MultiPart& form();
|
||||||
|
std::string form(const char* name, const std::string& defvalue = hv::empty_string);
|
||||||
|
// 获取 `application/x-www-urlencoded` 格式数据
|
||||||
|
const hv::KeyValue& urlencoded();
|
||||||
|
std::string urlencoded(const char* key, const std::string& defvalue = hv::empty_string);
|
||||||
|
// 根据 `Content-Type` 获取对应格式数据
|
||||||
|
template<typename T>
|
||||||
|
T get(const char* key, T defvalue = 0);
|
||||||
|
std::string get(const char* key, const std::string& defvalue = hv::empty_string);
|
||||||
|
|
||||||
|
/* 设置响应信息 */
|
||||||
|
// 设置响应状态码
|
||||||
|
void setStatus(http_status status);
|
||||||
|
// 设置响应 `Content-Type`
|
||||||
|
void setContentType(http_content_type type);
|
||||||
|
// 设置响应头部
|
||||||
|
void setHeader(const char* key, const std::string& value);
|
||||||
|
// 设置响应cookie
|
||||||
|
void setCookie(const HttpCookie& cookie);
|
||||||
|
// 设置响应body
|
||||||
|
void setBody(const std::string& body);
|
||||||
|
template<typename T>
|
||||||
|
// 根据 `Content-Type` 设置对应格式数据
|
||||||
|
void set(const char* key, const T& value);
|
||||||
|
|
||||||
|
// 发送
|
||||||
|
int send();
|
||||||
|
int send(const std::string& str, http_content_type type = APPLICATION_JSON);
|
||||||
|
// 发送文本数据
|
||||||
|
int sendString(const std::string& str);
|
||||||
|
// 发送二进制数据
|
||||||
|
int sendData(void* data, int len, bool nocopy = true);
|
||||||
|
// 发送文件
|
||||||
|
int sendFile(const char* filepath);
|
||||||
|
// 发送json数据
|
||||||
|
template<typename T>
|
||||||
|
int sendJson(const T& t);
|
||||||
|
|
||||||
|
// 重定向
|
||||||
|
int redirect(const std::string& location, http_status status = HTTP_STATUS_FOUND);
|
||||||
|
|
||||||
|
// 主动关闭连接
|
||||||
|
int close();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
110
external/libhv/libhv-1.3.2/docs/cn/HttpMessage.md
vendored
Normal file
110
external/libhv/libhv-1.3.2/docs/cn/HttpMessage.md
vendored
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
```c++
|
||||||
|
|
||||||
|
class HttpMessage {
|
||||||
|
// 设置/获取头部
|
||||||
|
void SetHeader(const char* key, const std::string& value);
|
||||||
|
std::string GetHeader(const char* key, const std::string& defvalue = hv::empty_string);
|
||||||
|
|
||||||
|
// 添加/获取cookie
|
||||||
|
void AddCookie(const HttpCookie& cookie);
|
||||||
|
const HttpCookie& GetCookie(const std::string& name);
|
||||||
|
|
||||||
|
// 设置/获取 `Content-Type`
|
||||||
|
void SetContentType(http_content_type type);
|
||||||
|
http_content_type ContentType();
|
||||||
|
|
||||||
|
// 获取 `Content-Length`
|
||||||
|
size_t ContentLength();
|
||||||
|
|
||||||
|
// 填充数据
|
||||||
|
void SetBody(const std::string& body);
|
||||||
|
// 获取数据
|
||||||
|
const std::string& Body();
|
||||||
|
// 解析数据
|
||||||
|
int ParseBody();
|
||||||
|
|
||||||
|
// 填充/获取 `application/json` 格式数据
|
||||||
|
template<typename T>
|
||||||
|
int Json(const T& t);
|
||||||
|
const hv::Json& GetJson();
|
||||||
|
|
||||||
|
// 填充/获取 `multipart/form-data` 格式数据
|
||||||
|
template<typename T>
|
||||||
|
void SetFormData(const char* name, const T& t);
|
||||||
|
void SetFormFile(const char* name, const char* filepath);
|
||||||
|
std::string GetFormData(const char* name, const std::string& defvalue = hv::empty_string);
|
||||||
|
int SaveFormFile(const char* name, const char* path);
|
||||||
|
|
||||||
|
// 填充/获取 `application/x-www-urlencoded` 格式数据
|
||||||
|
template<typename T>
|
||||||
|
void SetUrlEncoded(const char* key, const T& t);
|
||||||
|
std::string GetUrlEncoded(const char* key, const std::string& defvalue = hv::empty_string);
|
||||||
|
|
||||||
|
// 根据 `Content-Type` 填充对应格式数据
|
||||||
|
template<typename T>
|
||||||
|
void Set(const char* key, const T& value);
|
||||||
|
// 根据 `Content-Type` 获取对应格式数据
|
||||||
|
template<typename T>
|
||||||
|
T Get(const char* key, T defvalue = 0);
|
||||||
|
// 根据 `Content-Type` 获取对应格式数据并转换成字符串
|
||||||
|
std::string GetString(const char* key, const std::string& = "");
|
||||||
|
// 根据 `Content-Type` 获取对应格式数据并转换成Boolean类型
|
||||||
|
bool GetBool(const char* key, bool defvalue = 0);
|
||||||
|
// 根据 `Content-Type` 获取对应格式数据并转换成整型
|
||||||
|
int64_t GetInt(const char* key, int64_t defvalue = 0);
|
||||||
|
// 根据 `Content-Type` 获取对应格式数据并转换成浮点数
|
||||||
|
double GetFloat(const char* key, double defvalue = 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
// HttpRequest 继承自 HttpMessage
|
||||||
|
class HttpRequest : public HttpMessage {
|
||||||
|
// 设置/获取method
|
||||||
|
void SetMethod(const char* method);
|
||||||
|
const char* Method();
|
||||||
|
|
||||||
|
// 设置URL
|
||||||
|
void SetUrl(const char* url);
|
||||||
|
// 获取URL
|
||||||
|
const std::string& Url();
|
||||||
|
// 解析URL
|
||||||
|
void ParseUrl();
|
||||||
|
// 获取Host
|
||||||
|
std::string Host();
|
||||||
|
// 获取Path
|
||||||
|
std::string Path();
|
||||||
|
|
||||||
|
// 设置/获取参数
|
||||||
|
template<typename T>
|
||||||
|
void SetParam(const char* key, const T& t);
|
||||||
|
std::string GetParam(const char* key, const std::string& defvalue = hv::empty_string);
|
||||||
|
|
||||||
|
// 设置代理
|
||||||
|
void SetProxy(const char* host, int port);
|
||||||
|
|
||||||
|
// 设置认证
|
||||||
|
void SetAuth(const std::string& auth);
|
||||||
|
void SetBasicAuth(const std::string& username, const std::string& password);
|
||||||
|
void SetBearerTokenAuth(const std::string& token);
|
||||||
|
|
||||||
|
// 设置请求超时
|
||||||
|
void SetTimeout(int sec);
|
||||||
|
// 设置连接超时
|
||||||
|
void SetConnectTimeout(int sec);
|
||||||
|
// 允许重定向
|
||||||
|
void AllowRedirect(bool on = true);
|
||||||
|
// 设置重试
|
||||||
|
void SetRetry(int count = DEFAULT_HTTP_FAIL_RETRY_COUNT,
|
||||||
|
int delay = DEFAULT_HTTP_FAIL_RETRY_DELAY);
|
||||||
|
// 取消
|
||||||
|
void Cancel();
|
||||||
|
};
|
||||||
|
|
||||||
|
// HttpResponse 继承自 HttpMessage
|
||||||
|
class HttpResponse : public HttpMessage {
|
||||||
|
// 状态码
|
||||||
|
http_status status_code;
|
||||||
|
// 状态字符串
|
||||||
|
const char* status_message();
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
140
external/libhv/libhv-1.3.2/docs/cn/HttpServer.md
vendored
Normal file
140
external/libhv/libhv-1.3.2/docs/cn/HttpServer.md
vendored
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
HTTP 服务端类
|
||||||
|
|
||||||
|
```c++
|
||||||
|
|
||||||
|
// HTTP服务类
|
||||||
|
class HttpServer {
|
||||||
|
|
||||||
|
// 注册HTTP业务类
|
||||||
|
void registerHttpService(HttpService* service);
|
||||||
|
|
||||||
|
// 设置监听主机
|
||||||
|
void setHost(const char* host = "0.0.0.0");
|
||||||
|
// 设置监听端口
|
||||||
|
void setPort(int port = 0, int ssl_port = 0);
|
||||||
|
// 设置监听文件描述符
|
||||||
|
void setListenFD(int fd = -1, int ssl_fd = -1);
|
||||||
|
|
||||||
|
// 设置IO进程数 (仅`linux`下有效)
|
||||||
|
void setProcessNum(int num);
|
||||||
|
// 设置IO线程数
|
||||||
|
void setThreadNum(int num);
|
||||||
|
|
||||||
|
// 设置SSL/TLS
|
||||||
|
int setSslCtx(hssl_ctx_t ssl_ctx);
|
||||||
|
// 新建SSL/TLS
|
||||||
|
int newSslCtx(hssl_ctx_opt_t* opt);
|
||||||
|
|
||||||
|
// hooks
|
||||||
|
// 事件循环开始时执行的回调函数
|
||||||
|
std::function<void()> onWorkerStart;
|
||||||
|
// 事件循环结束时执行的回调函数
|
||||||
|
std::function<void()> onWorkerStop;
|
||||||
|
|
||||||
|
// 占用当前线程运行
|
||||||
|
int run(bool wait = true);
|
||||||
|
|
||||||
|
// 不占用当前线程运行
|
||||||
|
int start();
|
||||||
|
|
||||||
|
// 停止服务
|
||||||
|
int stop();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// HTTP业务类
|
||||||
|
class HttpService {
|
||||||
|
|
||||||
|
// 添加静态资源映射
|
||||||
|
void Static(const char* path, const char* dir);
|
||||||
|
|
||||||
|
// 允许跨域访问
|
||||||
|
void AllowCORS();
|
||||||
|
|
||||||
|
// 添加可信代理 (代理白名单)
|
||||||
|
void AddTrustProxy(const char* host);
|
||||||
|
|
||||||
|
// 添加不可信代理 (代理黑名单)
|
||||||
|
void AddNoProxy(const char* host);
|
||||||
|
|
||||||
|
// 开启正向转发代理
|
||||||
|
void EnableForwardProxy();
|
||||||
|
|
||||||
|
// 添加反向代理映射
|
||||||
|
void Proxy(const char* path, const char* url);
|
||||||
|
|
||||||
|
// 添加中间件
|
||||||
|
void Use(Handler handlerFunc);
|
||||||
|
|
||||||
|
// 添加路由处理器
|
||||||
|
void Handle(const char* httpMethod, const char* relativePath, Handler handlerFunc);
|
||||||
|
|
||||||
|
// 添加`HEAD`路由
|
||||||
|
void HEAD(const char* relativePath, Handler handlerFunc);
|
||||||
|
|
||||||
|
// 添加`GET`路由
|
||||||
|
void GET(const char* relativePath, Handler handlerFunc);
|
||||||
|
|
||||||
|
// 添加`POST`路由
|
||||||
|
void POST(const char* relativePath, Handler handlerFunc);
|
||||||
|
|
||||||
|
// 添加`PUT`路由
|
||||||
|
void PUT(const char* relativePath, Handler handlerFunc);
|
||||||
|
|
||||||
|
// 添加`DELETE`路由
|
||||||
|
void Delete(const char* relativePath, Handler handlerFunc);
|
||||||
|
|
||||||
|
// 添加`PATCH`路由
|
||||||
|
void PATCH(const char* relativePath, Handler handlerFunc);
|
||||||
|
|
||||||
|
// 添加任意`HTTP method`路由
|
||||||
|
void Any(const char* relativePath, Handler handlerFunc);
|
||||||
|
|
||||||
|
// 返回注册的路由路径列表
|
||||||
|
hv::StringList Paths();
|
||||||
|
|
||||||
|
// 处理流程:前处理器 -> 中间件 -> 处理器 -> 后处理器
|
||||||
|
// preprocessor -> middleware -> processor -> postprocessor
|
||||||
|
|
||||||
|
// 数据成员
|
||||||
|
http_handler preprocessor; // 前处理器
|
||||||
|
http_handlers middleware; // 中间件
|
||||||
|
http_handler processor; // 处理器
|
||||||
|
http_handler postprocessor; // 后处理器
|
||||||
|
std::string base_url; // 基本路径
|
||||||
|
std::string document_root; // 文档根目录
|
||||||
|
std::string home_page; // 主页
|
||||||
|
std::string error_page; // 默认错误页
|
||||||
|
std::string index_of; // 目录
|
||||||
|
http_handler errorHandler; // 错误处理器
|
||||||
|
|
||||||
|
int proxy_connect_timeout; // 代理连接超时
|
||||||
|
int proxy_read_timeout; // 代理读超时
|
||||||
|
int proxy_write_timeout; // 代理写超时
|
||||||
|
|
||||||
|
int keepalive_timeout; // 长连接保活超时
|
||||||
|
int max_file_cache_size; // 文件缓存最大尺寸
|
||||||
|
int file_cache_stat_interval; // 文件缓存stat间隔,查询文件是否修改
|
||||||
|
int file_cache_expired_time; // 文件缓存过期时间,过期自动释放
|
||||||
|
|
||||||
|
int limit_rate; // 下载速度限制
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 几种`handler`处理函数区别说明: */
|
||||||
|
|
||||||
|
// 同步`handler`运行在IO线程
|
||||||
|
typedef std::function<int(HttpRequest* req, HttpResponse* resp)> http_sync_handler;
|
||||||
|
|
||||||
|
// 异步`handler`运行在`hv::async`全局线程池,可通过`hv::async::startup`设置线程池属性
|
||||||
|
typedef std::function<void(const HttpRequestPtr& req, const HttpResponseWriterPtr& writer)> http_async_handler;
|
||||||
|
|
||||||
|
// 上下文`handler`运行在IO线程,你可以很方便的将`HttpContextPtr`智能指针抛到你的消费者线程/线程池去处理
|
||||||
|
typedef std::function<int(const HttpContextPtr& ctx)> http_ctx_handler;
|
||||||
|
|
||||||
|
// 中间状态`handler`运行在IO线程,用来实现大数据量的边接收边处理
|
||||||
|
typedef std::function<int(const HttpContextPtr& ctx, http_parser_state state, const char* data, size_t size)> http_state_handler;
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
测试代码见 [examples/http_server_test.cpp](../../examples/http_server_test.cpp)
|
18
external/libhv/libhv-1.3.2/docs/cn/README.md
vendored
Normal file
18
external/libhv/libhv-1.3.2/docs/cn/README.md
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
## c接口
|
||||||
|
|
||||||
|
- [hloop: 事件循环](hloop.md)
|
||||||
|
- [hbase: 基础函数](hbase.md)
|
||||||
|
- [hlog: 日志](hlog.md)
|
||||||
|
|
||||||
|
## c++接口
|
||||||
|
|
||||||
|
- [class EventLoop: 事件循环类](EventLoop.md)
|
||||||
|
- [class Channel: 通道类](Channel.md)
|
||||||
|
- [class TcpServer: TCP服务端类](TcpServer.md)
|
||||||
|
- [class TcpClient: TCP客户端类](TcpClient.md)
|
||||||
|
- [class UdpServer: UDP服务端类](UdpServer.md)
|
||||||
|
- [class UdpClient: UDP客户端类](UdpClient.md)
|
||||||
|
- [class HttpServer: HTTP服务端类](HttpServer.md)
|
||||||
|
- [class HttpClient: HTTP客户端类](HttpClient.md)
|
||||||
|
- [class WebSocketServer: WebSocket服务端类](WebSocketServer.md)
|
||||||
|
- [class WebSocketClient: WebSocket客户端类](WebSocketClient.md)
|
63
external/libhv/libhv-1.3.2/docs/cn/TcpClient.md
vendored
Normal file
63
external/libhv/libhv-1.3.2/docs/cn/TcpClient.md
vendored
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
TCP 客户端类
|
||||||
|
|
||||||
|
```c++
|
||||||
|
|
||||||
|
class TcpClient {
|
||||||
|
|
||||||
|
// 返回所在的事件循环
|
||||||
|
const EventLoopPtr& loop();
|
||||||
|
|
||||||
|
// 创建套接字
|
||||||
|
int createsocket(int remote_port, const char* remote_host = "127.0.0.1");
|
||||||
|
int createsocket(struct sockaddr* remote_addr);
|
||||||
|
|
||||||
|
// 绑定端口
|
||||||
|
int bind(int local_port, const char* local_host = "0.0.0.0");
|
||||||
|
int bind(struct sockaddr* local_addr);
|
||||||
|
|
||||||
|
// 关闭套接字
|
||||||
|
void closesocket();
|
||||||
|
|
||||||
|
// 开始运行
|
||||||
|
void start(bool wait_threads_started = true);
|
||||||
|
|
||||||
|
// 停止运行
|
||||||
|
void stop(bool wait_threads_stopped = true);
|
||||||
|
|
||||||
|
// 是否已连接
|
||||||
|
bool isConnected();
|
||||||
|
|
||||||
|
// 发送
|
||||||
|
int send(const void* data, int size);
|
||||||
|
int send(Buffer* buf);
|
||||||
|
int send(const std::string& str);
|
||||||
|
|
||||||
|
// 设置SSL/TLS加密通信
|
||||||
|
int withTLS(hssl_ctx_opt_t* opt = NULL);
|
||||||
|
|
||||||
|
// 设置连接超时
|
||||||
|
void setConnectTimeout(int ms);
|
||||||
|
|
||||||
|
// 设置重连
|
||||||
|
void setReconnect(reconn_setting_t* setting);
|
||||||
|
|
||||||
|
// 是否是重连
|
||||||
|
bool isReconnect();
|
||||||
|
|
||||||
|
// 设置拆包规则
|
||||||
|
void setUnpack(unpack_setting_t* setting);
|
||||||
|
|
||||||
|
// 连接状态回调
|
||||||
|
std::function<void(const TSocketChannelPtr&)> onConnection;
|
||||||
|
|
||||||
|
// 消息回调
|
||||||
|
std::function<void(const TSocketChannelPtr&, Buffer*)> onMessage;
|
||||||
|
|
||||||
|
// 写完成回调
|
||||||
|
std::function<void(const TSocketChannelPtr&, Buffer*)> onWriteComplete;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
测试代码见 [evpp/TcpClient_test.cpp](../../evpp/TcpClient_test.cpp)
|
60
external/libhv/libhv-1.3.2/docs/cn/TcpServer.md
vendored
Normal file
60
external/libhv/libhv-1.3.2/docs/cn/TcpServer.md
vendored
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
TCP 服务端类
|
||||||
|
|
||||||
|
```c++
|
||||||
|
|
||||||
|
class TcpServer {
|
||||||
|
|
||||||
|
// 返回索引的事件循环
|
||||||
|
EventLoopPtr loop(int idx = -1);
|
||||||
|
|
||||||
|
// 创建套接字
|
||||||
|
int createsocket(int port, const char* host = "0.0.0.0");
|
||||||
|
|
||||||
|
// 关闭套接字
|
||||||
|
void closesocket();
|
||||||
|
|
||||||
|
// 设置最大连接数
|
||||||
|
void setMaxConnectionNum(uint32_t num);
|
||||||
|
|
||||||
|
// 设置负载均衡策略
|
||||||
|
void setLoadBalance(load_balance_e lb);
|
||||||
|
|
||||||
|
// 设置线程数
|
||||||
|
void setThreadNum(int num);
|
||||||
|
|
||||||
|
// 开始运行
|
||||||
|
void start(bool wait_threads_started = true);
|
||||||
|
|
||||||
|
// 停止运行
|
||||||
|
void stop(bool wait_threads_stopped = true);
|
||||||
|
|
||||||
|
// 设置SSL/TLS加密通信
|
||||||
|
int withTLS(hssl_ctx_opt_t* opt = NULL);
|
||||||
|
|
||||||
|
// 设置拆包规则
|
||||||
|
void setUnpack(unpack_setting_t* setting);
|
||||||
|
|
||||||
|
// 返回当前连接数
|
||||||
|
size_t connectionNum();
|
||||||
|
|
||||||
|
// 遍历连接
|
||||||
|
int foreachChannel(std::function<void(const TSocketChannelPtr& channel)> fn);
|
||||||
|
|
||||||
|
// 广播消息
|
||||||
|
int broadcast(const void* data, int size);
|
||||||
|
int broadcast(const std::string& str);
|
||||||
|
|
||||||
|
// 连接到来/断开回调
|
||||||
|
std::function<void(const TSocketChannelPtr&)> onConnection;
|
||||||
|
|
||||||
|
// 消息回调
|
||||||
|
std::function<void(const TSocketChannelPtr&, Buffer*)> onMessage;
|
||||||
|
|
||||||
|
// 写完成回调
|
||||||
|
std::function<void(const TSocketChannelPtr&, Buffer*)> onWriteComplete;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
测试代码见 [evpp/TcpServer_test.cpp](../../evpp/TcpServer_test.cpp)
|
42
external/libhv/libhv-1.3.2/docs/cn/UdpClient.md
vendored
Normal file
42
external/libhv/libhv-1.3.2/docs/cn/UdpClient.md
vendored
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
UDP 客户端类
|
||||||
|
|
||||||
|
```c++
|
||||||
|
|
||||||
|
class UdpClient {
|
||||||
|
|
||||||
|
// 返回所在的事件循环
|
||||||
|
const EventLoopPtr& loop();
|
||||||
|
|
||||||
|
// 创建套接字
|
||||||
|
int createsocket(int remote_port, const char* remote_host = "127.0.0.1");
|
||||||
|
|
||||||
|
// 绑定端口
|
||||||
|
int bind(int local_port, const char* local_host = "0.0.0.0");
|
||||||
|
|
||||||
|
// 关闭套接字
|
||||||
|
void closesocket();
|
||||||
|
|
||||||
|
// 开始运行
|
||||||
|
void start(bool wait_threads_started = true);
|
||||||
|
|
||||||
|
// 停止运行
|
||||||
|
void stop(bool wait_threads_stopped = true);
|
||||||
|
|
||||||
|
// 发送
|
||||||
|
int sendto(const void* data, int size, struct sockaddr* peeraddr = NULL);
|
||||||
|
int sendto(Buffer* buf, struct sockaddr* peeraddr = NULL);
|
||||||
|
int sendto(const std::string& str, struct sockaddr* peeraddr = NULL);
|
||||||
|
|
||||||
|
// 设置KCP
|
||||||
|
void setKcp(kcp_setting_t* setting);
|
||||||
|
|
||||||
|
// 消息回调
|
||||||
|
std::function<void(const TSocketChannelPtr&, Buffer*)> onMessage;
|
||||||
|
|
||||||
|
// 写完成回调
|
||||||
|
std::function<void(const TSocketChannelPtr&, Buffer*)> onWriteComplete;
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
测试代码见 [evpp/UdpClient_test.cpp](../../evpp/UdpClient_test.cpp)
|
39
external/libhv/libhv-1.3.2/docs/cn/UdpServer.md
vendored
Normal file
39
external/libhv/libhv-1.3.2/docs/cn/UdpServer.md
vendored
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
UDP 服务端类
|
||||||
|
|
||||||
|
```c++
|
||||||
|
|
||||||
|
class UdpServer {
|
||||||
|
|
||||||
|
// 返回所在的事件循环
|
||||||
|
const EventLoopPtr& loop();
|
||||||
|
|
||||||
|
// 创建套接字
|
||||||
|
int createsocket(int port, const char* host = "0.0.0.0");
|
||||||
|
|
||||||
|
// 关闭套接字
|
||||||
|
void closesocket();
|
||||||
|
|
||||||
|
// 开始运行
|
||||||
|
void start(bool wait_threads_started = true);
|
||||||
|
|
||||||
|
// 停止运行
|
||||||
|
void stop(bool wait_threads_stopped = true);
|
||||||
|
|
||||||
|
// 发送
|
||||||
|
int sendto(const void* data, int size, struct sockaddr* peeraddr = NULL);
|
||||||
|
int sendto(Buffer* buf, struct sockaddr* peeraddr = NULL);
|
||||||
|
int sendto(const std::string& str, struct sockaddr* peeraddr = NULL);
|
||||||
|
|
||||||
|
// 设置KCP
|
||||||
|
void setKcp(kcp_setting_t* setting);
|
||||||
|
|
||||||
|
// 消息回调
|
||||||
|
std::function<void(const TSocketChannelPtr&, Buffer*)> onMessage;
|
||||||
|
|
||||||
|
// 写完成回调
|
||||||
|
std::function<void(const TSocketChannelPtr&, Buffer*)> onWriteComplete;
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
测试代码见 [evpp/UdpServer_test.cpp](../../evpp/UdpServer_test.cpp)
|
37
external/libhv/libhv-1.3.2/docs/cn/WebSocketClient.md
vendored
Normal file
37
external/libhv/libhv-1.3.2/docs/cn/WebSocketClient.md
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
WebSocket 客户端类
|
||||||
|
|
||||||
|
```c++
|
||||||
|
|
||||||
|
class WebSocketClient {
|
||||||
|
|
||||||
|
// 打开回调
|
||||||
|
std::function<void()> onopen;
|
||||||
|
// 关闭回调
|
||||||
|
std::function<void()> onclose;
|
||||||
|
// 消息回调
|
||||||
|
std::function<void(const std::string& msg)> onmessage;
|
||||||
|
|
||||||
|
// 打开
|
||||||
|
int open(const char* url, const http_headers& headers = DefaultHeaders);
|
||||||
|
|
||||||
|
// 关闭
|
||||||
|
int close();
|
||||||
|
|
||||||
|
// 发送
|
||||||
|
int send(const std::string& msg);
|
||||||
|
int send(const char* buf, int len, enum ws_opcode opcode = WS_OPCODE_BINARY);
|
||||||
|
|
||||||
|
// 设置心跳间隔
|
||||||
|
void setPingInterval(int ms);
|
||||||
|
|
||||||
|
// 设置WebSocket握手阶段的HTTP请求
|
||||||
|
void setHttpRequest(const HttpRequestPtr& req);
|
||||||
|
|
||||||
|
// 获取WebSocket握手阶段的HTTP响应
|
||||||
|
const HttpResponsePtr& getHttpResponse();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
测试代码见 [examples/websocket_client_test.cpp](../../examples/websocket_client_test.cpp)
|
30
external/libhv/libhv-1.3.2/docs/cn/WebSocketServer.md
vendored
Normal file
30
external/libhv/libhv-1.3.2/docs/cn/WebSocketServer.md
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
WebSocket 服务端类
|
||||||
|
|
||||||
|
```c++
|
||||||
|
|
||||||
|
// WebSocketServer 继承自 HttpServer
|
||||||
|
class WebSocketServer : public HttpServer {
|
||||||
|
|
||||||
|
// 注册WebSocket业务类
|
||||||
|
void registerWebSocketService(WebSocketService* service);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// WebSocket业务类
|
||||||
|
struct WebSocketService {
|
||||||
|
// 打开回调
|
||||||
|
std::function<void(const WebSocketChannelPtr&, const HttpRequestPtr&)> onopen;
|
||||||
|
|
||||||
|
// 消息回调
|
||||||
|
std::function<void(const WebSocketChannelPtr&, const std::string&)> onmessage;
|
||||||
|
|
||||||
|
// 关闭回调
|
||||||
|
std::function<void(const WebSocketChannelPtr&)> onclose;
|
||||||
|
|
||||||
|
// 心跳间隔
|
||||||
|
int ping_interval;
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
测试代码见 [examples/websocket_server_test.cpp](../../examples/websocket_server_test.cpp)
|
111
external/libhv/libhv-1.3.2/docs/cn/hbase.md
vendored
Normal file
111
external/libhv/libhv-1.3.2/docs/cn/hbase.md
vendored
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
一些基础函数
|
||||||
|
|
||||||
|
```c
|
||||||
|
|
||||||
|
/* hv内存分配/释放函数 */
|
||||||
|
void* hv_malloc(size_t size);
|
||||||
|
void* hv_realloc(void* oldptr, size_t newsize, size_t oldsize);
|
||||||
|
void* hv_calloc(size_t nmemb, size_t size);
|
||||||
|
void* hv_zalloc(size_t size);
|
||||||
|
void hv_free(void* ptr);
|
||||||
|
|
||||||
|
// 使用hv分配内存次数
|
||||||
|
long hv_alloc_cnt();
|
||||||
|
|
||||||
|
// 使用hv释放内存次数
|
||||||
|
long hv_free_cnt();
|
||||||
|
|
||||||
|
/* 字符串操作 */
|
||||||
|
// 字符串转大写
|
||||||
|
char* hv_strupper(char* str);
|
||||||
|
// 字符串转小写
|
||||||
|
char* hv_strlower(char* str);
|
||||||
|
// 字符串翻转
|
||||||
|
char* hv_strreverse(char* str);
|
||||||
|
|
||||||
|
// 判断字符串是否以xxx开头
|
||||||
|
bool hv_strstartswith(const char* str, const char* start);
|
||||||
|
|
||||||
|
// 判断字符串是否以xxx结尾
|
||||||
|
bool hv_strendswith(const char* str, const char* end);
|
||||||
|
|
||||||
|
// 判断字符串是否包含xxx
|
||||||
|
bool hv_strcontains(const char* str, const char* sub);
|
||||||
|
|
||||||
|
// 安全的strncpy
|
||||||
|
char* hv_strncpy(char* dest, const char* src, size_t n);
|
||||||
|
|
||||||
|
// 安全的strncat
|
||||||
|
char* hv_strncat(char* dest, const char* src, size_t n);
|
||||||
|
|
||||||
|
// 字符查找
|
||||||
|
char* hv_strnchr(const char* s, char c, size_t n);
|
||||||
|
|
||||||
|
// 查找最后一个点(通常用于提取文件后缀)
|
||||||
|
#define hv_strrchr_dot(str) strrchr(str, '.')
|
||||||
|
|
||||||
|
// 查找最后的路径(通常用于分离目录和文件)
|
||||||
|
char* hv_strrchr_dir(const char* filepath);
|
||||||
|
|
||||||
|
// 获取文件名(利用了上面的strrchr_dir)
|
||||||
|
const char* hv_basename(const char* filepath);
|
||||||
|
|
||||||
|
// 获取文件后缀(利用了上面的strrchr_dot)
|
||||||
|
const char* hv_suffixname(const char* filename);
|
||||||
|
|
||||||
|
/* 文件&目录 */
|
||||||
|
// mkdir -p: 创建目录
|
||||||
|
int hv_mkdir_p(const char* dir);
|
||||||
|
// rmdir -p: 删除目录
|
||||||
|
int hv_rmdir_p(const char* dir);
|
||||||
|
|
||||||
|
// 判断路径是否存在
|
||||||
|
bool hv_exists(const char* path);
|
||||||
|
|
||||||
|
// 判断是否是目录
|
||||||
|
bool hv_isdir(const char* path);
|
||||||
|
|
||||||
|
// 判断是否是文件
|
||||||
|
bool hv_isfile(const char* path);
|
||||||
|
|
||||||
|
// 判断是否是链接
|
||||||
|
bool hv_islink(const char* path);
|
||||||
|
|
||||||
|
// 获取文件大小
|
||||||
|
size_t hv_filesize(const char* filepath);
|
||||||
|
|
||||||
|
// 获取可执行文件绝对路径,例如/usr/local/bin/httpd
|
||||||
|
char* get_executable_path(char* buf, int size);
|
||||||
|
|
||||||
|
// 获取可执行文件所在目录,例如/usr/local/bin
|
||||||
|
char* get_executable_dir(char* buf, int size);
|
||||||
|
|
||||||
|
// 获取可执行文件名,例如httpd
|
||||||
|
char* get_executable_file(char* buf, int size);
|
||||||
|
|
||||||
|
// 获取运行目录,例如/home/www/html
|
||||||
|
char* get_run_dir(char* buf, int size);
|
||||||
|
|
||||||
|
// 返回一个随机数
|
||||||
|
int hv_rand(int min, int max);
|
||||||
|
|
||||||
|
// 返回一个随机字符串
|
||||||
|
char* hv_random_string(char *buf, int len);
|
||||||
|
|
||||||
|
// 1 y on yes true enable返回true(通常用于配置文件)
|
||||||
|
bool hv_getboolean(const char* str);
|
||||||
|
|
||||||
|
// 解析size字符串
|
||||||
|
// 1T2G3M4K5B => ?B
|
||||||
|
size_t hv_parse_size(const char* str);
|
||||||
|
|
||||||
|
// 解析时间字符串
|
||||||
|
// 1w2d3h4m5s => ?s
|
||||||
|
time_t hv_parse_time(const char* str);
|
||||||
|
|
||||||
|
// 解析url字符串
|
||||||
|
int hv_parse_url(hurl_t* stURL, const char* strURL);
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
单元测试代码见 [unittest/hbase_test.c](../../unittest/hbase_test.c)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user