Add:libhv open source code.
This commit is contained in:
parent
2d0bf0ff64
commit
44a74ac4aa
3
external/CMakeLists.txt
vendored
3
external/CMakeLists.txt
vendored
|
@ -2,6 +2,7 @@
|
|||
add_subdirectory(sqlite3/sqlite-3430000)
|
||||
add_subdirectory(goahead-5.2.0)
|
||||
|
||||
# ================= httpserver ================= #
|
||||
find_program(M4 m4)
|
||||
if(NOT M4)
|
||||
message("m4 not found. Install before continuing.")
|
||||
|
@ -15,5 +16,7 @@ if(NOT RAGEL)
|
|||
WORKING_DIRECTORY ${EXTERNAL_SOURCE_PATH}/gtest/)
|
||||
endif()
|
||||
add_subdirectory(httpserver.h-master/src)
|
||||
# ================= httpserver end ================= #
|
||||
|
||||
add_subdirectory(cJSON-1.7.17)
|
||||
add_subdirectory(libhv/libhv-1.3.2)
|
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
|
||||
```
|
281
external/libhv/libhv-1.3.2/CMakeLists.txt
vendored
Normal file
281
external/libhv/libhv-1.3.2/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,281 @@
|
|||
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)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${LIBDIR})
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${LIBDIR})
|
||||
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)
|
111
external/libhv/libhv-1.3.2/docs/cn/hlog.md
vendored
Normal file
111
external/libhv/libhv-1.3.2/docs/cn/hlog.md
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
日志
|
||||
|
||||
```c
|
||||
|
||||
// 标准输出日志
|
||||
void stdout_logger(int loglevel, const char* buf, int len);
|
||||
|
||||
// 标准错误日志
|
||||
void stderr_logger(int loglevel, const char* buf, int len);
|
||||
|
||||
// 文件日志
|
||||
void file_logger(int loglevel, const char* buf, int len);
|
||||
|
||||
// 网络日志(定义在event/nlog.h头文件里)
|
||||
// void network_logger(int loglevel, const char* buf, int len);
|
||||
|
||||
// 创建日志器
|
||||
logger_t* logger_create();
|
||||
|
||||
// 销毁日志器
|
||||
void logger_destroy(logger_t* logger);
|
||||
|
||||
// 设置日志处理器
|
||||
void logger_set_handler(logger_t* logger, logger_handler fn);
|
||||
|
||||
// 设置日志等级
|
||||
void logger_set_level(logger_t* logger, int level);
|
||||
// level = [VERBOSE,DEBUG,INFO,WARN,ERROR,FATAL,SILENT]
|
||||
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
|
||||
* %% %
|
||||
*/
|
||||
void logger_set_format(logger_t* logger, const char* format);
|
||||
|
||||
// 设置日志缓存大小
|
||||
void logger_set_max_bufsize(logger_t* logger, unsigned int bufsize);
|
||||
|
||||
// 启用日志颜色
|
||||
void logger_enable_color(logger_t* logger, int on);
|
||||
|
||||
// 日志打印
|
||||
int logger_print(logger_t* logger, int level, const char* fmt, ...);
|
||||
|
||||
// 设置日志文件
|
||||
void logger_set_file(logger_t* logger, const char* filepath);
|
||||
|
||||
// 设置日志文件大小
|
||||
void logger_set_max_filesize(logger_t* logger, unsigned long long filesize);
|
||||
// 16, 16M, 16MB
|
||||
void logger_set_max_filesize_by_str(logger_t* logger, const char* filesize);
|
||||
|
||||
// 设置日志文件保留天数
|
||||
void logger_set_remain_days(logger_t* logger, int days);
|
||||
|
||||
// 启用每次写日志文件立即刷新到磁盘(即每次都调用fsync,会增加IO耗时,影响性能)
|
||||
void logger_enable_fsync(logger_t* logger, int on);
|
||||
|
||||
// 刷新缓存到磁盘(如对日志文件实时性有必要的,可使用定时器定时刷新到磁盘)
|
||||
void logger_fsync(logger_t* logger);
|
||||
|
||||
// 获取当前日志文件路径
|
||||
const char* logger_get_cur_file(logger_t* logger);
|
||||
|
||||
// hlog: 默认的日志器
|
||||
logger_t* hv_default_logger();
|
||||
|
||||
// 销毁默认的日志器
|
||||
void hv_destroy_default_logger(void);
|
||||
|
||||
// 对默认日志器hlog的一些便利操作宏
|
||||
#define hlog hv_default_logger()
|
||||
#define hlog_destory() hv_destroy_default_logger()
|
||||
/* 禁用hv的默认日志 */
|
||||
#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]\n", ## __VA_ARGS__, __FILENAME__, __LINE__, __FUNCTION__)
|
||||
#define hlogi(fmt, ...) logger_print(hlog, LOG_LEVEL_INFO, fmt " [%s:%d:%s]\n", ## __VA_ARGS__, __FILENAME__, __LINE__, __FUNCTION__)
|
||||
#define hlogw(fmt, ...) logger_print(hlog, LOG_LEVEL_WARN, fmt " [%s:%d:%s]\n", ## __VA_ARGS__, __FILENAME__, __LINE__, __FUNCTION__)
|
||||
#define hloge(fmt, ...) logger_print(hlog, LOG_LEVEL_ERROR, fmt " [%s:%d:%s]\n", ## __VA_ARGS__, __FILENAME__, __LINE__, __FUNCTION__)
|
||||
#define hlogf(fmt, ...) logger_print(hlog, LOG_LEVEL_FATAL, fmt " [%s:%d:%s]\n", ## __VA_ARGS__, __FILENAME__, __LINE__, __FUNCTION__)
|
||||
|
||||
```
|
||||
|
||||
测试代码见 [examples/hloop_test.c](../../examples/hloop_test.c)
|
636
external/libhv/libhv-1.3.2/docs/cn/hloop.md
vendored
Normal file
636
external/libhv/libhv-1.3.2/docs/cn/hloop.md
vendored
Normal file
|
@ -0,0 +1,636 @@
|
|||
事件循环和IO多路复用机制介绍
|
||||
|
||||
事件循环是`libevent、libev、libuv、libhv`这类网络库里最核心的概念,即在事件循环里处理IO读写事件、定时器事件、自定义事件等各种事件;<br>
|
||||
IO多路复用即在一个IO线程监听多个fd,如最早期的`select`、后来的`poll`,`linux的epoll`、`windows的iocp`、`bsd的kqueue`、`solaris的port`等,都属于IO多路复用机制。<br>
|
||||
非阻塞NIO搭配IO多路复用机制就是高并发的钥匙。<br>
|
||||
`libhv`下的`event`模块正是封装了多种平台的IO多路复用机制,提供了统一的事件接口,是`libhv`的核心模块。<br>
|
||||
|
||||
`hloop.h`: 事件循环模块对外头文件。<br>
|
||||
|
||||
```c
|
||||
|
||||
// 事件结构体
|
||||
struct hevent_s {
|
||||
hloop_t* loop; // 事件所属循环
|
||||
hevent_type_e event_type; // 事件类型
|
||||
uint64_t event_id; // 事件ID
|
||||
hevent_cb cb; // 事件回调
|
||||
void* userdata; // 用户数据
|
||||
void* privdata; // 私有数据
|
||||
struct hevent_s* pending_next; // 指向下一个事件,用于实现事件队列
|
||||
int priority; // 事件优先级
|
||||
};
|
||||
|
||||
// 设置事件ID
|
||||
#define hevent_set_id(ev, id) ((hevent_t*)(ev))->event_id = id
|
||||
// 设置事件回调
|
||||
#define hevent_set_cb(ev, cb) ((hevent_t*)(ev))->cb = cb
|
||||
// 设置事件优先级
|
||||
#define hevent_set_priority(ev, prio) ((hevent_t*)(ev))->priority = prio
|
||||
// 设置事件用户数据
|
||||
#define hevent_set_userdata(ev, udata) ((hevent_t*)(ev))->userdata = (void*)udata
|
||||
|
||||
// 获取事件所属循环
|
||||
#define hevent_loop(ev) (((hevent_t*)(ev))->loop)
|
||||
// 获取事件类型
|
||||
#define hevent_type(ev) (((hevent_t*)(ev))->event_type)
|
||||
// 获取事件ID
|
||||
#define hevent_id(ev) (((hevent_t*)(ev))->event_id)
|
||||
// 获取事件回调
|
||||
#define hevent_cb(ev) (((hevent_t*)(ev))->cb)
|
||||
// 获取事件优先级
|
||||
#define hevent_priority(ev) (((hevent_t*)(ev))->priority)
|
||||
// 获取事件用户数据
|
||||
#define hevent_userdata(ev) (((hevent_t*)(ev))->userdata)
|
||||
|
||||
// hidle_t、htimer_t、hio_t皆是继承自hevent_t,继承上面的数据成员和函数方法
|
||||
|
||||
// 新建事件循环
|
||||
hloop_t* hloop_new(int flags DEFAULT(HLOOP_FLAG_AUTO_FREE));
|
||||
|
||||
// 释放事件循环
|
||||
void hloop_free(hloop_t** pp);
|
||||
|
||||
// 运行事件循环
|
||||
int hloop_run(hloop_t* loop);
|
||||
|
||||
// 停止事件循环
|
||||
int hloop_stop(hloop_t* loop);
|
||||
|
||||
// 暂停事件循环
|
||||
int hloop_pause(hloop_t* loop);
|
||||
|
||||
// 继续事件循环
|
||||
int hloop_resume(hloop_t* loop);
|
||||
|
||||
// 唤醒事件循环
|
||||
int hloop_wakeup(hloop_t* loop);
|
||||
|
||||
// 返回事件循环状态
|
||||
hloop_status_e hloop_status(hloop_t* loop);
|
||||
|
||||
// 更新事件循环里的时间
|
||||
void hloop_update_time(hloop_t* loop);
|
||||
|
||||
// 返回事件循环里记录的时间
|
||||
uint64_t hloop_now(hloop_t* loop); // s
|
||||
uint64_t hloop_now_ms(hloop_t* loop); // ms
|
||||
uint64_t hloop_now_us(hloop_t* loop); // us
|
||||
|
||||
// 返回事件循环所在进程ID
|
||||
long hloop_pid(hloop_t* loop);
|
||||
|
||||
// 返回事件循环所在线程ID
|
||||
long hloop_tid(hloop_t* loop);
|
||||
|
||||
// 返回事件循环的循环次数
|
||||
uint64_t hloop_count(hloop_t* loop);
|
||||
|
||||
// 返回事件循环里激活的IO事件数量
|
||||
uint32_t hloop_nios(hloop_t* loop);
|
||||
|
||||
// 返回事件循环里激活的定时器事件数量
|
||||
uint32_t hloop_ntimers(hloop_t* loop);
|
||||
|
||||
// 返回事件循环里激活的空闲事件数量
|
||||
uint32_t hloop_nidles(hloop_t* loop);
|
||||
|
||||
// 返回事件循环里激活的事件数量
|
||||
uint32_t hloop_nactives(hloop_t* loop);
|
||||
|
||||
// 设置事件循环的用户数据
|
||||
void hloop_set_userdata(hloop_t* loop, void* userdata);
|
||||
|
||||
// 获取事件循环的用户数据
|
||||
void* hloop_userdata(hloop_t* loop);
|
||||
|
||||
// 投递事件
|
||||
void hloop_post_event(hloop_t* loop, hevent_t* ev);
|
||||
|
||||
// 添加空闲事件
|
||||
hidle_t* hidle_add(hloop_t* loop, hidle_cb cb, uint32_t repeat DEFAULT(INFINITE));
|
||||
|
||||
// 删除空闲事件
|
||||
void hidle_del(hidle_t* idle);
|
||||
|
||||
// 添加超时定时器
|
||||
htimer_t* htimer_add(hloop_t* loop, htimer_cb cb, uint32_t timeout_ms, uint32_t repeat DEFAULT(INFINITE));
|
||||
|
||||
// 添加时间定时器
|
||||
htimer_t* htimer_add_period(hloop_t* loop, htimer_cb cb,
|
||||
int8_t minute DEFAULT(0), int8_t hour DEFAULT(-1), int8_t day DEFAULT(-1),
|
||||
int8_t week DEFAULT(-1), int8_t month DEFAULT(-1), uint32_t repeat DEFAULT(INFINITE));
|
||||
|
||||
// 删除定时器
|
||||
void htimer_del(htimer_t* timer);
|
||||
|
||||
// 重置定时器
|
||||
void htimer_reset(htimer_t* timer, uint32_t timeout_ms DEFAULT(0));
|
||||
|
||||
// 返回IO多路复用引擎 (select、poll、epoll、etc.)
|
||||
const char* hio_engine();
|
||||
|
||||
// 获取IO对象
|
||||
hio_t* hio_get(hloop_t* loop, int fd);
|
||||
|
||||
// 添加IO读写事件
|
||||
int hio_add(hio_t* io, hio_cb cb, int events DEFAULT(HV_READ));
|
||||
|
||||
// 删除IO读写事件
|
||||
int hio_del(hio_t* io, int events DEFAULT(HV_RDWR));
|
||||
|
||||
// 将IO对象从当前所属事件循环中剥离
|
||||
void hio_detach(/*hloop_t* loop,*/ hio_t* io);
|
||||
|
||||
// 将IO对象关联到新的事件循环
|
||||
void hio_attach(hloop_t* loop, hio_t* io);
|
||||
|
||||
// hio_detach 和 hio_attach 的示例代码见 examples/multi-thread/one-acceptor-multi-workers.c
|
||||
/*
|
||||
void new_conn_event(hevent_t* ev) {
|
||||
hloop_t* loop = ev->loop;
|
||||
hio_t* io = (hio_t*)hevent_userdata(ev);
|
||||
// 关联到新的worker事件循环
|
||||
hio_attach(loop, io);
|
||||
}
|
||||
|
||||
void on_accpet(hio_t* io) {
|
||||
// 从acceptor所在事件循环中剥离
|
||||
hio_detach(io);
|
||||
|
||||
// 将新的连接按照负载均衡策略分发到worker线程
|
||||
hloop_t* worker_loop = get_one_loop();
|
||||
hevent_t ev;
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.loop = worker_loop;
|
||||
ev.cb = new_conn_event;
|
||||
ev.userdata = io;
|
||||
hloop_post_event(worker_loop, &ev);
|
||||
}
|
||||
*/
|
||||
|
||||
// 判断fd是否存在于事件循环
|
||||
bool hio_exists(hloop_t* loop, int fd);
|
||||
|
||||
// 返回一个唯一标示ID
|
||||
uint32_t hio_id (hio_t* io);
|
||||
|
||||
// 返回文件描述符
|
||||
int hio_fd (hio_t* io);
|
||||
|
||||
// 返回错误码
|
||||
int hio_error (hio_t* io);
|
||||
|
||||
// 返回添加的事件
|
||||
int hio_events (hio_t* io);
|
||||
|
||||
// 获取返回的事件
|
||||
int hio_revents (hio_t* io);
|
||||
|
||||
// 返回IO类型
|
||||
hio_type_e hio_type (hio_t* io);
|
||||
|
||||
// 返回本地地址
|
||||
struct sockaddr* hio_localaddr(hio_t* io);
|
||||
|
||||
// 返回对端地址
|
||||
struct sockaddr* hio_peeraddr (hio_t* io);
|
||||
|
||||
// 设置上下文
|
||||
void hio_set_context(hio_t* io, void* ctx);
|
||||
|
||||
// 获取上下文
|
||||
void* hio_context(hio_t* io);
|
||||
|
||||
// 是否已打开
|
||||
bool hio_is_opened(hio_t* io);
|
||||
|
||||
// 是否已连接
|
||||
bool hio_is_connected(hio_t* io);
|
||||
|
||||
// 是否已关闭
|
||||
bool hio_is_closed(hio_t* io);
|
||||
|
||||
// 设置读缓存
|
||||
void hio_set_readbuf(hio_t* io, void* buf, size_t len);
|
||||
|
||||
// 获取读缓存
|
||||
hio_readbuf_t* hio_get_readbuf(hio_t* io);
|
||||
|
||||
// 设置最大读缓存
|
||||
void hio_set_max_read_bufsize (hio_t* io, uint32_t size);
|
||||
|
||||
// 设置最大写缓存
|
||||
void hio_set_max_write_bufsize(hio_t* io, uint32_t size);
|
||||
|
||||
// 获取当前写缓存大小
|
||||
size_t hio_write_bufsize(hio_t* io);
|
||||
|
||||
// 判断是否写完成
|
||||
#define hio_write_is_complete(io) (hio_write_bufsize(io) == 0)
|
||||
|
||||
// 获取最后读的时间
|
||||
uint64_t hio_last_read_time(hio_t* io); // ms
|
||||
|
||||
// 获取最后写的时间
|
||||
uint64_t hio_last_write_time(hio_t* io); // ms
|
||||
|
||||
// 设置accept回调
|
||||
void hio_setcb_accept (hio_t* io, haccept_cb accept_cb);
|
||||
// 设置连接回调
|
||||
void hio_setcb_connect (hio_t* io, hconnect_cb connect_cb);
|
||||
// 设置读回调
|
||||
void hio_setcb_read (hio_t* io, hread_cb read_cb);
|
||||
// 设置写回调
|
||||
void hio_setcb_write (hio_t* io, hwrite_cb write_cb);
|
||||
// 设置关闭回调
|
||||
void hio_setcb_close (hio_t* io, hclose_cb close_cb);
|
||||
|
||||
// 获取accept回调
|
||||
haccept_cb hio_getcb_accept(hio_t* io);
|
||||
// 获取连接回调
|
||||
hconnect_cb hio_getcb_connect(hio_t* io);
|
||||
// 获取读回调
|
||||
hread_cb hio_getcb_read(hio_t* io);
|
||||
// 获取写回调
|
||||
hwrite_cb hio_getcb_write(hio_t* io);
|
||||
// 获取关闭回调
|
||||
hclose_cb hio_getcb_close(hio_t* io);
|
||||
|
||||
// 开启SSL/TLS加密通信
|
||||
int hio_enable_ssl(hio_t* io);
|
||||
// 是否SSL/TLS加密通信
|
||||
bool hio_is_ssl(hio_t* io);
|
||||
// 设置SSL
|
||||
int hio_set_ssl (hio_t* io, hssl_t ssl);
|
||||
// 设置SSL_CTX
|
||||
int hio_set_ssl_ctx(hio_t* io, hssl_ctx_t ssl_ctx);
|
||||
// 新建SSL_CTX
|
||||
int hio_new_ssl_ctx(hio_t* io, hssl_ctx_opt_t* opt);
|
||||
// 获取SSL
|
||||
hssl_t hio_get_ssl(hio_t* io);
|
||||
// 获取SSL_CTX
|
||||
hssl_ctx_t hio_get_ssl_ctx(hio_t* io);
|
||||
// 设置主机名
|
||||
int hio_set_hostname(hio_t* io, const char* hostname);
|
||||
// 获取主机名
|
||||
const char* hio_get_hostname(hio_t* io);
|
||||
|
||||
// 设置连接超时
|
||||
void hio_set_connect_timeout(hio_t* io, int timeout_ms DEFAULT(HIO_DEFAULT_CONNECT_TIMEOUT));
|
||||
// 设置关闭超时 (说明:非阻塞写队列非空时,需要等待写完成再关闭)
|
||||
void hio_set_close_timeout(hio_t* io, int timeout_ms DEFAULT(HIO_DEFAULT_CLOSE_TIMEOUT));
|
||||
// 设置读超时 (一段时间没有数据到来便自动关闭连接)
|
||||
void hio_set_read_timeout(hio_t* io, int timeout_ms);
|
||||
// 设置写超时 (一段时间没有数据发送便自动关闭连接)
|
||||
void hio_set_write_timeout(hio_t* io, int timeout_ms);
|
||||
// 设置keepalive超时 (一段时间没有数据收发便自动关闭连接)
|
||||
void hio_set_keepalive_timeout(hio_t* io, int timeout_ms DEFAULT(HIO_DEFAULT_KEEPALIVE_TIMEOUT));
|
||||
|
||||
// 设置心跳 (定时发送心跳包)
|
||||
typedef void (*hio_send_heartbeat_fn)(hio_t* io);
|
||||
void hio_set_heartbeat(hio_t* io, int interval_ms, hio_send_heartbeat_fn fn);
|
||||
|
||||
// 接收连接
|
||||
// hio_add(io, HV_READ) => accept => haccept_cb
|
||||
int hio_accept (hio_t* io);
|
||||
|
||||
// 连接
|
||||
// connect => hio_add(io, HV_WRITE) => hconnect_cb
|
||||
int hio_connect(hio_t* io);
|
||||
|
||||
// 读
|
||||
// hio_add(io, HV_READ) => read => hread_cb
|
||||
int hio_read (hio_t* io);
|
||||
|
||||
// 开始读
|
||||
#define hio_read_start(io) hio_read(io)
|
||||
|
||||
// 停止读
|
||||
#define hio_read_stop(io) hio_del(io, HV_READ)
|
||||
|
||||
// 读一次
|
||||
// hio_read_start => hread_cb => hio_read_stop
|
||||
int hio_read_once (hio_t* io);
|
||||
|
||||
// 读取直到指定长度
|
||||
// hio_read_once => hread_cb(len)
|
||||
int hio_read_until_length(hio_t* io, unsigned int len);
|
||||
|
||||
// 读取直到遇到分隔符
|
||||
// hio_read_once => hread_cb(...delim)
|
||||
int hio_read_until_delim (hio_t* io, unsigned char delim);
|
||||
|
||||
// 读取一行
|
||||
#define hio_readline(io) hio_read_until_delim(io, '\n')
|
||||
|
||||
// 读取字符串
|
||||
#define hio_readstring(io) hio_read_until_delim(io, '\0')
|
||||
|
||||
// 读取N个字节
|
||||
#define hio_readbytes(io, len) hio_read_until_length(io, len)
|
||||
#define hio_read_until(io, len) hio_read_until_length(io, len)
|
||||
|
||||
// 写
|
||||
// hio_try_write => hio_add(io, HV_WRITE) => write => hwrite_cb
|
||||
int hio_write (hio_t* io, const void* buf, size_t len);
|
||||
|
||||
// 关闭
|
||||
// hio_del(io, HV_RDWR) => close => hclose_cb
|
||||
int hio_close (hio_t* io);
|
||||
|
||||
// 异步关闭 (投递一个close事件)
|
||||
// NOTE: hloop_post_event(hio_close_event)
|
||||
int hio_close_async(hio_t* io);
|
||||
|
||||
//------------------高等级的接口-------------------------------------------
|
||||
// 读
|
||||
// hio_get -> hio_set_readbuf -> hio_setcb_read -> hio_read
|
||||
hio_t* hread (hloop_t* loop, int fd, void* buf, size_t len, hread_cb read_cb);
|
||||
// 写
|
||||
// hio_get -> hio_setcb_write -> hio_write
|
||||
hio_t* hwrite (hloop_t* loop, int fd, const void* buf, size_t len, hwrite_cb write_cb DEFAULT(NULL));
|
||||
// 关闭
|
||||
// hio_get -> hio_close
|
||||
void hclose (hloop_t* loop, int fd);
|
||||
|
||||
// tcp
|
||||
// 接收连接
|
||||
// hio_get -> hio_setcb_accept -> hio_accept
|
||||
hio_t* haccept (hloop_t* loop, int listenfd, haccept_cb accept_cb);
|
||||
// 连接
|
||||
// hio_get -> hio_setcb_connect -> hio_connect
|
||||
hio_t* hconnect (hloop_t* loop, int connfd, hconnect_cb connect_cb);
|
||||
// 接收
|
||||
// hio_get -> hio_set_readbuf -> hio_setcb_read -> hio_read
|
||||
hio_t* hrecv (hloop_t* loop, int connfd, void* buf, size_t len, hread_cb read_cb);
|
||||
// 发送
|
||||
// hio_get -> hio_setcb_write -> hio_write
|
||||
hio_t* hsend (hloop_t* loop, int connfd, const void* buf, size_t len, hwrite_cb write_cb DEFAULT(NULL));
|
||||
|
||||
// udp
|
||||
// 设置IO类型
|
||||
void hio_set_type(hio_t* io, hio_type_e type);
|
||||
// 设置本地地址
|
||||
void hio_set_localaddr(hio_t* io, struct sockaddr* addr, int addrlen);
|
||||
// 设置对端地址
|
||||
void hio_set_peeraddr (hio_t* io, struct sockaddr* addr, int addrlen);
|
||||
// 接收
|
||||
// hio_get -> hio_set_readbuf -> hio_setcb_read -> hio_read
|
||||
hio_t* hrecvfrom (hloop_t* loop, int sockfd, void* buf, size_t len, hread_cb read_cb);
|
||||
// 发送
|
||||
// hio_get -> hio_setcb_write -> hio_write
|
||||
hio_t* hsendto (hloop_t* loop, int sockfd, const void* buf, size_t len, hwrite_cb write_cb DEFAULT(NULL));
|
||||
|
||||
//-----------------顶层的接口---------------------------------------------
|
||||
// 创建socket套接字,返回IO对象
|
||||
// @hio_create_socket: socket -> bind -> listen
|
||||
// sockaddr_set_ipport -> socket -> hio_get(loop, sockfd) ->
|
||||
// side == HIO_SERVER_SIDE ? bind ->
|
||||
// type & HIO_TYPE_SOCK_STREAM ? listen ->
|
||||
hio_t* hio_create_socket(hloop_t* loop, const char* host, int port,
|
||||
hio_type_e type DEFAULT(HIO_TYPE_TCP),
|
||||
hio_side_e side DEFAULT(HIO_SERVER_SIDE));
|
||||
|
||||
// @tcp_server: hio_create_socket(loop, host, port, HIO_TYPE_TCP, HIO_SERVER_SIDE) -> hio_setcb_accept -> hio_accept
|
||||
// 创建TCP服务,示例代码见 examples/tcp_echo_server.c
|
||||
hio_t* hloop_create_tcp_server (hloop_t* loop, const char* host, int port, haccept_cb accept_cb);
|
||||
|
||||
// @tcp_client: hio_create_socket(loop, host, port, HIO_TYPE_TCP, HIO_CLIENT_SIDE) -> hio_setcb_connect -> hio_setcb_close -> hio_connect
|
||||
// 创建TCP客户端,示例代码见 examples/nc.c
|
||||
hio_t* hloop_create_tcp_client (hloop_t* loop, const char* host, int port, hconnect_cb connect_cb, hclose_cb close_cb);
|
||||
|
||||
// @ssl_server: hio_create_socket(loop, host, port, HIO_TYPE_SSL, HIO_SERVER_SIDE) -> hio_setcb_accept -> hio_accept
|
||||
// 创建SSL服务端,示例代码见 examples/tcp_echo_server.c => #define TEST_SSL 1
|
||||
hio_t* hloop_create_ssl_server (hloop_t* loop, const char* host, int port, haccept_cb accept_cb);
|
||||
|
||||
// @ssl_client: hio_create_socket(loop, host, port, HIO_TYPE_SSL, HIO_CLIENT_SIDE) -> hio_setcb_connect -> hio_setcb_close -> hio_connect
|
||||
// 创建SSL客户端,示例代码见 examples/nc.c => #define TEST_SSL 1
|
||||
hio_t* hloop_create_ssl_client (hloop_t* loop, const char* host, int port, hconnect_cb connect_cb, hclose_cb close_cb);
|
||||
|
||||
// @udp_server: hio_create_socket(loop, host, port, HIO_TYPE_UDP, HIO_SERVER_SIDE)
|
||||
// 创建UDP服务端,示例代码见 examples/udp_echo_server.c
|
||||
hio_t* hloop_create_udp_server (hloop_t* loop, const char* host, int port);
|
||||
|
||||
// @udp_server: hio_create_socket(loop, host, port, HIO_TYPE_UDP, HIO_CLIENT_SIDE)
|
||||
// 创建UDP客户端,示例代码见 examples/nc.c
|
||||
hio_t* hloop_create_udp_client (hloop_t* loop, const char* host, int port);
|
||||
|
||||
//-----------------转发---------------------------------------------
|
||||
// hio_read(io)
|
||||
// hio_read(io->upstream_io)
|
||||
void hio_read_upstream(hio_t* io);
|
||||
// on_write(io) -> hio_write_is_complete(io) -> hio_read(io->upstream_io)
|
||||
void hio_read_upstream_on_write_complete(hio_t* io, const void* buf, int writebytes);
|
||||
// hio_write(io->upstream_io, buf, bytes)
|
||||
void hio_write_upstream(hio_t* io, void* buf, int bytes);
|
||||
// hio_close(io->upstream_io)
|
||||
void hio_close_upstream(hio_t* io);
|
||||
|
||||
// io1->upstream_io = io2;
|
||||
// io2->upstream_io = io1;
|
||||
// 建立转发,示例代码见 examples/socks5_proxy_server.c
|
||||
void hio_setup_upstream(hio_t* io1, hio_t* io2);
|
||||
|
||||
// @return io->upstream_io
|
||||
hio_t* hio_get_upstream(hio_t* io);
|
||||
|
||||
// @tcp_upstream: hio_create_socket -> hio_setup_upstream -> hio_connect -> on_connect -> hio_read_upstream
|
||||
// @return upstream_io
|
||||
// 建立TCP转发,示例代码见 examples/tcp_proxy_server.c
|
||||
hio_t* hio_setup_tcp_upstream(hio_t* io, const char* host, int port, int ssl DEFAULT(0));
|
||||
// 建立SSL转发
|
||||
#define hio_setup_ssl_upstream(io, host, port) hio_setup_tcp_upstream(io, host, port, 1)
|
||||
|
||||
// @udp_upstream: hio_create_socket -> hio_setup_upstream -> hio_read_upstream
|
||||
// @return upstream_io
|
||||
// 建立UDP转发,示例代码见 examples/udp_proxy_server.c
|
||||
hio_t* hio_setup_udp_upstream(hio_t* io, const char* host, int port);
|
||||
|
||||
//-----------------拆包---------------------------------------------
|
||||
// 拆包模式
|
||||
typedef enum {
|
||||
UNPACK_MODE_NONE = 0,
|
||||
UNPACK_BY_FIXED_LENGTH = 1, // 固定长度拆包,不建议
|
||||
UNPACK_BY_DELIMITER = 2, // 根据分隔符拆包,适用于文本协议
|
||||
UNPACK_BY_LENGTH_FIELD = 3, // 根据头部长度字段拆包,适用于二进制协议
|
||||
} unpack_mode_e;
|
||||
|
||||
// 拆包设置
|
||||
typedef struct unpack_setting_s {
|
||||
unpack_mode_e mode; // 拆包模式
|
||||
unsigned int package_max_length; // 最大的包长
|
||||
union {
|
||||
// UNPACK_BY_FIXED_LENGTH: 固定长度拆包设置
|
||||
struct {
|
||||
unsigned int fixed_length; // 固定长度
|
||||
};
|
||||
// UNPACK_BY_DELIMITER: 分隔符拆包设置
|
||||
struct {
|
||||
unsigned char delimiter[PACKAGE_MAX_DELIMITER_BYTES]; // 分隔符
|
||||
unsigned short delimiter_bytes; // 分隔符所占字节数
|
||||
};
|
||||
/*
|
||||
* UNPACK_BY_LENGTH_FIELD: 头部长度字段拆包设置
|
||||
*
|
||||
* 包长 = 头部长度 + 数据长度 + 调整长度
|
||||
* package_len = head_len + body_len + length_adjustment
|
||||
*
|
||||
* if (length_field_coding == ENCODE_BY_VARINT) head_len = body_offset + varint_bytes - length_field_bytes;
|
||||
* else head_len = body_offset;
|
||||
*
|
||||
* 注意:头部长度字段的值仅代表数据长度,不包括头部本身长度,
|
||||
* 如果你的头部长度字段代表总包长,那么应该将length_adjustment设置为负的头部长度
|
||||
* length_field stores body length, exclude head length,
|
||||
* if length_field = head_len + body_len, then length_adjustment should be set to -head_len.
|
||||
*
|
||||
*/
|
||||
struct {
|
||||
unsigned short body_offset; // 到数据的偏移,通常等于头部长度
|
||||
unsigned short length_field_offset; // 长度字段偏移
|
||||
unsigned short length_field_bytes; // 长度字段所占字节数
|
||||
short length_adjustment; // 调整长度
|
||||
unpack_coding_e length_field_coding; // 长度字段编码方式
|
||||
};
|
||||
};
|
||||
} unpack_setting_t;
|
||||
|
||||
/*
|
||||
* 拆包示例代码见 examples/jsonrpc examples/protorpc
|
||||
*
|
||||
* 注意:多个IO对象的unpack_setting_t可能是一样的,所有hio_t里仅保存了unpack_setting_t的指针,
|
||||
* unpack_setting_t的生命周期应该被调用者所保证,不应该使用局部变量。
|
||||
*/
|
||||
|
||||
// 设置拆包
|
||||
void hio_set_unpack(hio_t* io, unpack_setting_t* setting);
|
||||
// 取消拆包设置
|
||||
void hio_unset_unpack(hio_t* io);
|
||||
|
||||
// 拆包设置示例:
|
||||
/*
|
||||
|
||||
// FTP协议通过\r\n分割符拆包
|
||||
unpack_setting_t ftp_unpack_setting;
|
||||
memset(&ftp_unpack_setting, 0, sizeof(unpack_setting_t));
|
||||
ftp_unpack_setting.package_max_length = DEFAULT_PACKAGE_MAX_LENGTH;
|
||||
ftp_unpack_setting.mode = UNPACK_BY_DELIMITER;
|
||||
ftp_unpack_setting.delimiter[0] = '\r';
|
||||
ftp_unpack_setting.delimiter[1] = '\n';
|
||||
ftp_unpack_setting.delimiter_bytes = 2;
|
||||
|
||||
// MQTT协议通过头部长度字段拆包,头部长度字段使用了varint编码
|
||||
unpack_setting_t mqtt_unpack_setting = {
|
||||
.mode = UNPACK_BY_LENGTH_FIELD,
|
||||
.package_max_length = DEFAULT_PACKAGE_MAX_LENGTH,
|
||||
.body_offset = 2,
|
||||
.length_field_offset = 1,
|
||||
.length_field_bytes = 1,
|
||||
.length_field_coding = ENCODE_BY_VARINT,
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
//-----------------重连----------------------------------------
|
||||
// 重连设置
|
||||
typedef struct reconn_setting_s {
|
||||
uint32_t min_delay; // ms 重连最小延时
|
||||
uint32_t max_delay; // ms 重连最大延时
|
||||
uint32_t cur_delay; // ms 当前延时
|
||||
/*
|
||||
* @delay_policy: 延时策略
|
||||
* 0: fixed 固定延时
|
||||
* min_delay=3s => 3,3,3...
|
||||
* 1: linear 线性增长延时
|
||||
* min_delay=3s max_delay=10s => 3,6,9,10,10...
|
||||
* other: exponential 指数增长延时
|
||||
* min_delay=3s max_delay=60s delay_policy=2 => 3,6,12,24,48,60,60...
|
||||
*/
|
||||
uint32_t delay_policy; // 延时策略
|
||||
uint32_t max_retry_cnt; // 最大重试次数
|
||||
uint32_t cur_retry_cnt; // 当前重试次数
|
||||
} reconn_setting_t;
|
||||
|
||||
// 重连设置初始化
|
||||
void reconn_setting_init(reconn_setting_t* reconn);
|
||||
|
||||
// 重连设置重置
|
||||
void reconn_setting_reset(reconn_setting_t* reconn);
|
||||
|
||||
// 增加重试次数并判断是否未超过最大重试次数
|
||||
bool reconn_setting_can_retry(reconn_setting_t* reconn);
|
||||
|
||||
// 计算当前重连延时
|
||||
uint32_t reconn_setting_calc_delay(reconn_setting_t* reconn);
|
||||
|
||||
//-----------------负载均衡-------------------------------------
|
||||
// 负载均衡策略枚举
|
||||
typedef enum {
|
||||
LB_RoundRobin, // 轮询
|
||||
LB_Random, // 随机
|
||||
LB_LeastConnections,// 最少连接数
|
||||
LB_IpHash, // IP hash
|
||||
LB_UrlHash, // URL hash
|
||||
} load_balance_e;
|
||||
|
||||
//-----------------可靠UDP---------------------------------------------
|
||||
// 关闭可靠UDP
|
||||
int hio_close_rudp(hio_t* io, struct sockaddr* peeraddr DEFAULT(NULL));
|
||||
|
||||
// KCP设置
|
||||
typedef struct kcp_setting_s {
|
||||
// ikcp_create(conv, ...)
|
||||
unsigned int conv;
|
||||
// ikcp_nodelay(kcp, nodelay, interval, fastresend, nocwnd)
|
||||
int nodelay;
|
||||
int interval;
|
||||
int fastresend;
|
||||
int nocwnd;
|
||||
// ikcp_wndsize(kcp, sndwnd, rcvwnd)
|
||||
int sndwnd;
|
||||
int rcvwnd;
|
||||
// ikcp_setmtu(kcp, mtu)
|
||||
int mtu;
|
||||
// ikcp_update
|
||||
int update_interval;
|
||||
} kcp_setting_t;
|
||||
|
||||
// KCP 正常模式
|
||||
HV_INLINE void kcp_setting_init_with_normal_mode(kcp_setting_t* setting);
|
||||
|
||||
// KCP fast模式
|
||||
void kcp_setting_init_with_fast_mode(kcp_setting_t* setting);
|
||||
|
||||
// KCP fast2模式
|
||||
void kcp_setting_init_with_fast2_mode(kcp_setting_t* setting);
|
||||
|
||||
// KCP fast3模式
|
||||
void kcp_setting_init_with_fast3_mode(kcp_setting_t* setting);
|
||||
|
||||
// 设置KCP,示例代码见 examples/udp_echo_server.c => #define TEST_KCP 1
|
||||
int hio_set_kcp(hio_t* io, kcp_setting_t* setting DEFAULT(NULL));
|
||||
|
||||
```
|
||||
|
||||
示例代码:
|
||||
|
||||
- 事件循环: [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)
|
||||
- TCP客户端: [examples/tcp_client_test.c](../../examples/tcp_client_test.c)
|
||||
- UDP回显服务: [examples/udp_echo_server.c](../../examples/udp_echo_server.c)
|
||||
- UDP代理服务: [examples/udp_proxy_server.c](../../examples/udp_proxy_server.c)
|
||||
- 网络客户端: [examples/nc](../../examples/nc.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)
|
||||
- protobufRPC示例: [examples/protorpc](../../examples/protorpc)
|
||||
|
||||
多进程/多线程模式示例代码:
|
||||
|
||||
- 多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)
|
105
external/libhv/libhv-1.3.2/echo-servers/asio_echo.cpp
vendored
Normal file
105
external/libhv/libhv-1.3.2/echo-servers/asio_echo.cpp
vendored
Normal file
|
@ -0,0 +1,105 @@
|
|||
//
|
||||
// async_tcp_echo_server.cpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
class session {
|
||||
public:
|
||||
session(boost::asio::io_service& io_service) :
|
||||
socket_(io_service) {
|
||||
}
|
||||
|
||||
tcp::socket& socket() {
|
||||
return socket_;
|
||||
}
|
||||
|
||||
void start() {
|
||||
socket_.async_read_some(boost::asio::buffer(data_, max_length),
|
||||
boost::bind(&session::handle_read, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void handle_read(const boost::system::error_code& error,
|
||||
size_t bytes_transferred) {
|
||||
if (!error) {
|
||||
boost::asio::async_write(socket_, boost::asio::buffer(data_,
|
||||
bytes_transferred), boost::bind(&session::handle_write,
|
||||
this, boost::asio::placeholders::error));
|
||||
} else {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
void handle_write(const boost::system::error_code& error) {
|
||||
if (!error) {
|
||||
socket_.async_read_some(boost::asio::buffer(data_, max_length),
|
||||
boost::bind(&session::handle_read, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
} else {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
tcp::socket socket_;
|
||||
enum {
|
||||
max_length = 1024
|
||||
};
|
||||
char data_[max_length];
|
||||
};
|
||||
|
||||
class server {
|
||||
public:
|
||||
server(boost::asio::io_service& io_service, short port) :
|
||||
io_service_(io_service), acceptor_(io_service, tcp::endpoint(tcp::v4(),
|
||||
port)) {
|
||||
session* new_session = new session(io_service_);
|
||||
acceptor_.async_accept(new_session->socket(), boost::bind(
|
||||
&server::handle_accept, this, new_session,
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
void handle_accept(session* new_session,
|
||||
const boost::system::error_code& error) {
|
||||
if (!error) {
|
||||
new_session->start();
|
||||
new_session = new session(io_service_);
|
||||
acceptor_.async_accept(new_session->socket(), boost::bind(
|
||||
&server::handle_accept, this, new_session,
|
||||
boost::asio::placeholders::error));
|
||||
} else {
|
||||
delete new_session;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
boost::asio::io_service& io_service_;
|
||||
tcp::acceptor acceptor_;
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
printf("Usage: cmd port\n");
|
||||
return -10;
|
||||
}
|
||||
int port = atoi(argv[1]);
|
||||
|
||||
boost::asio::io_service io_service;
|
||||
server s(io_service, port);
|
||||
io_service.run();
|
||||
|
||||
return 0;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user