Compare commits

53 Commits

Author SHA1 Message Date
19daab173c version 4.7.4 2025-07-31 20:56:32 +03:00
19f8f522b3 Fix multi piprocess wait 2025-07-31 20:55:33 +03:00
905d39c07b fix clang format and clear flag for read process out\err 2025-07-30 11:28:26 +03:00
9504792586 version 4.7.3 2025-07-17 11:17:53 +03:00
1b51d09c58 PIValueTree::child(PIStringList) fix 2025-07-17 11:16:47 +03:00
ed3d4c4217 PIJSON::new* now accept optional initial fields 2025-07-09 12:41:23 +03:00
7b52f6d70d fix get mtu (#186)
Reviewed-on: #186
2025-06-26 10:52:36 +03:00
19fe33383a Fix cmake module path (#185)
Если в cmake передаётся кастомная папка с cmake-модулями, например в toolchain файле, то pip перестаёт добавлять ./cmake в путь поиска модулей. Это приводит к ошибке `can't find PIPMacros.cmake`. Не  очень понимаю зачем так было сделано, поэтому просто убрал условие пустого CMAKE_MODULE_PATH.

Reviewed-on: #185
Co-authored-by: andrey.bychkov <andrey@signalmodelling.ru>
Co-committed-by: andrey.bychkov <andrey@signalmodelling.ru>
2025-06-26 10:52:04 +03:00
e57719c118 version 4.7.2
PIThreadPoolLoop reworked, now threads starts on constructor and immediately run after start()
2025-06-07 10:58:11 +03:00
edb077b400 PIThreadPoolLoopNW test 2025-06-03 20:15:00 +03:00
bad51db0c8 remove export 2025-05-18 18:53:28 +03:00
87ab4c4c28 version 4.7.1
PIHTTP::MessageConst code categories
PIHTTPClient can abort on program exit
2025-05-14 19:45:58 +03:00
8f3456a650 fix CurlThreadPool destroy logic 2025-05-14 19:29:07 +03:00
ce1aee1553 PIHTTP::MessageConst code categories
PIHTTPClient migrated to curl_multi_api
2025-05-14 16:21:38 +03:00
dfdc4b8bdc add overload for PIHTTPServer::register* for pointer to a member function 2025-04-30 15:07:25 +03:00
8a61cfe7ef new cmake 2025-04-29 21:50:17 +03:00
78f79d92aa PIOpenCL::Buffer::copyTo() with Buffer 2025-03-28 14:15:21 +03:00
f09fe03e0d workaround hangs on PIBroadcast::stopRead 2025-03-06 16:26:38 +03:00
8e18ec15c9 add PIBinaryLog::threadedReadRecord event (with full info) 2025-03-04 20:20:09 +03:00
4340f5444d add spaces for PICout operators 2025-02-27 21:26:29 +03:00
8e96750046 version 4.7.0
add PIEthernet socket options setReadBufferSize() and setWriteBufferSize()
add PIByteArray::dataAs
2025-02-06 11:13:43 +03:00
d01baffb0b PITimeMeasurer remove some API, add elapsedAndReset()
got rid off some warnings
2025-01-17 11:49:24 +03:00
82cda42e75 change last logic to PIThreadNotifier 2025-01-15 18:38:50 +03:00
5755d172cd fallback to min_sleep 2025-01-15 18:25:32 +03:00
0dd47f50a0 version 4.6.0
PIThreadNotifier::waitFor() new method
PIThread::waitForFinish() now use condvar to exit as soon as possible
2025-01-15 17:57:16 +03:00
60d2a83df5 android (maybe some other *nix) fix 2025-01-10 20:46:33 +03:00
7757ac10ec add PIP_BUILD_<MODULE> options for PIP build to force disabling modules 2025-01-09 17:36:40 +03:00
f334a6603f adopt for new MinGW 2025-01-06 12:55:44 +03:00
15548de79c version 4.5.0
PIThread::stopAndWait now returns bool
PIKbdListener on Linux now use piwaitevent_p and can immediately stop
new base method piZeroMemory, also migrate all "memset 0" to piZeroMemory
2024-12-29 11:48:24 +03:00
49713ddc57 PIThread now setup itself in thread func 2024-12-29 10:50:38 +03:00
0973379f53 now works 2024-12-26 16:19:33 +03:00
a3004491d6 no warning on terminate kbd 2024-12-26 16:18:13 +03:00
199a272eb8 now rude 2024-12-26 16:16:01 +03:00
855d1ca1b5 try to fix hang on exit by keyboard 2024-12-26 16:12:02 +03:00
64025e0399 PIThread now wait on _endThread() when starting is really done 2024-12-26 16:01:56 +03:00
6e5556969d fix for last commit 2024-12-25 19:37:55 +03:00
b50eeaef46 fix for last commit 2024-12-25 19:34:49 +03:00
ffc471359a fix thread name for linux 2024-12-25 19:30:15 +03:00
79007e7b4e PIString::arg() now ignore non-suitable %.
PIVector and PIDeque now use std::stable_sort
2024-12-07 12:57:48 +03:00
9e08b6ffc5 turn fuck off tests by default anyway 2024-12-03 15:41:34 +03:00
9b8a1583c2 add "--no-strip" flag to deploy_tool 2024-12-03 11:19:14 +03:00
cae264a77b forgot to implement PIHTTPClient headers 2024-11-28 13:13:08 +03:00
4f934fef35 PIHTTPClient fixes 2024-11-28 12:37:05 +03:00
3a159b0553 PIByteArray operators & | ^
PIDigest add BLAKE2 algorithms and HMAC
2024-11-27 18:27:51 +03:00
0c973f0216 add PIDigest with SHA and MD series 2024-11-27 14:40:39 +03:00
65d3168eb5 PICout::withExternalBufferAnd decomposed to PICout::withExternalBufferAndID and PICout::withExternalBufferAnd
PIString::toPercentageEncoding/fromPercentageEncoding
piStringify()
PIHTTPClient support arguments
some doc
2024-11-26 18:26:02 +03:00
12114b3e77 old curl fix 2024-11-25 16:02:40 +03:00
6f6b717354 pip_test 2024-11-25 15:53:12 +03:00
58b3fa64bc http server fix 2024-11-25 15:00:42 +03:00
1acaf24df9 PIHTTPServer basic auth works 2024-11-24 23:23:08 +03:00
c2c9822169 fix FindPIP.cmake 2024-11-23 17:55:59 +03:00
dff4f2b3a0 add http_client library, using libcurl
take out common http entities to http_common dir
2024-11-23 17:54:22 +03:00
bf9ad65ff0 take out "asize" from vector/dequeue to picontainers.h->calcNewSize()
minAlloc and maxPoTAlloc now can be override from CMake by PIP_CONTAINERS_MIN_ALLOC and PIP_CONTAINERS_MAX_POT_ALLOC variables
2024-11-21 20:15:18 +03:00
99 changed files with 5848 additions and 756 deletions

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@ _unsused
CMakeLists.txt.user*
/include
/release
/build*

View File

@@ -1,9 +1,12 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.13)
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
if (POLICY CMP0177)
cmake_policy(SET CMP0177 OLD)
endif()
project(PIP)
set(PIP_MAJOR 4)
set(PIP_MINOR 4)
set(PIP_REVISION 1)
set(PIP_MINOR 7)
set(PIP_REVISION 4)
set(PIP_SUFFIX )
set(PIP_COMPANY SHS)
set(PIP_DOMAIN org.SHS)
@@ -13,7 +16,7 @@ if (NOT DEFINED SHSTKPROJECT)
set(ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cmake-download/CMakeLists.txt"
"# This file was generated by PIP CMake, don`t edit it!
cmake_minimum_required(VERSION 2.8.2)
cmake_minimum_required(VERSION 3.13)
project(cmake-download NONE)
include(ExternalProject)
ExternalProject_Add(cmake
@@ -42,9 +45,7 @@ ExternalProject_Add(cmake
set(GIT_CMAKE_DIR "${CMAKE_CURRENT_BINARY_DIR}/cmake-src")
endif()
if ("x${CMAKE_MODULE_PATH}" STREQUAL "x")
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
if (NOT "x${GIT_CMAKE_DIR}" STREQUAL "x")
list(APPEND CMAKE_MODULE_PATH "${GIT_CMAKE_DIR}")
endif()
@@ -62,17 +63,11 @@ if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE
endif()
set(PIP_DLL_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "")
if (CMAKE_BUILD_TYPE MATCHES Debug)
set(PIP_BUILD_DEBUG ON)
else()
set(PIP_BUILD_DEBUG OFF)
endif()
# Options
option(ICU "ICU support for convert codepages" ${_ICU_DEFAULT})
option(STD_IOSTREAM "Building with std iostream operators support" OFF)
option(INTROSPECTION "Build with introspection" OFF)
option(TESTS "Build tests and perform their before install step" ${PIP_BUILD_DEBUG})
option(TESTS "Build tests and perform their before install step" OFF)
option(COVERAGE "Build project with coverage info" OFF)
set(PIP_UTILS 1)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
@@ -97,9 +92,11 @@ set(PIP_UTILS_LIST)
set(PIP_TESTS_LIST)
set(PIP_EXPORTS)
set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;client_server;cloud;lua;http_server")
set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;client_server;cloud;lua;http_client;http_server")
foreach(_m ${PIP_SRC_MODULES})
set(PIP_MSG_${_m} "no")
string(TOUPPER "${_m}" _mu)
option(PIP_BUILD_${_mu} "Build \"${_m}\" module" ON)
endforeach()
macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
@@ -118,7 +115,6 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
file(GLOB_RECURSE ASRC "${SOURCES}/*.cpp" "${SOURCES}/*.c")
list(APPEND CPPS ${ASRC})
endif()
#message("${NAME} HS = ${HS}")
list(APPEND HDRS ${HS})
list(APPEND PHDRS ${PHS})
@@ -374,6 +370,8 @@ pip_module(main "${LIBS_MAIN}" "PIP main library" "" "" "")
generate_export_header(pip)
list(APPEND HDRS "${CMAKE_CURRENT_BINARY_DIR}/pip_export.h")
file(GLOB_RECURSE _RM_HDRS "libs/main/digest/3rd/*.h")
list(REMOVE_ITEM HDRS ${_RM_HDRS})
foreach(_m ${PIP_SRC_MODULES})
set_target_properties(pip PROPERTIES DEFINE_SYMBOL pip_${_m}_EXPORTS)
generate_export_header(pip BASE_NAME "pip_${_m}")
@@ -381,142 +379,178 @@ foreach(_m ${PIP_SRC_MODULES})
endforeach()
set_target_properties(pip PROPERTIES DEFINE_SYMBOL pip_EXPORTS)
# Override containers minimum bytes allocation
if(NOT "x${PIP_CONTAINERS_MIN_ALLOC}" STREQUAL "x")
target_compile_definitions(pip PRIVATE "-DPIP_CONTAINERS_MIN_ALLOC=${PIP_CONTAINERS_MIN_ALLOC}")
message(STATUS "Attention: Override PIP_CONTAINERS_MIN_ALLOC = ${PIP_CONTAINERS_MIN_ALLOC}")
endif()
# Override containers maximum bytes for power of two expansion, may be bytes or X_KiB, or X_MiB
if(NOT "x${PIP_CONTAINERS_MAX_POT_ALLOC}" STREQUAL "x")
target_compile_definitions(pip PRIVATE "-DPIP_CONTAINERS_MAX_POT_ALLOC=${PIP_CONTAINERS_MAX_POT_ALLOC}")
message(STATUS "Attention: Override PIP_CONTAINERS_MAX_POT_ALLOC = ${PIP_CONTAINERS_MAX_POT_ALLOC}")
endif()
if (NOT CROSSTOOLS)
if (NOT PIP_FREERTOS)
if (PIP_BUILD_CONSOLE)
pip_module(console "" "PIP console support" "" "" "")
endif()
pip_module(console "" "PIP console support" "" "" "")
pip_find_lib(usb)
if(usb_FOUND)
pip_module(usb "usb" "PIP usb support" "" "" "")
if (PIP_BUILD_USB)
pip_find_lib(usb)
if(usb_FOUND)
pip_module(usb "usb" "PIP usb support" "" "" "")
endif()
endif()
pip_find_lib(zlib NAMES z zlib)
if(zlib_FOUND)
pip_module(compress "zlib" "PIP compression support" "" "" "")
if (PIP_BUILD_COMPRESS)
pip_find_lib(zlib NAMES z zlib)
if(zlib_FOUND)
pip_module(compress "zlib" "PIP compression support" "" "" "")
endif()
endif()
pip_find_lib(sodium)
if(sodium_FOUND)
pip_module(crypt "sodium" "PIP crypt support" "" "" "")
pip_module(client_server "pip_io_utils" "PIP client-server helper" "" "" "")
pip_module(cloud "pip_io_utils" "PIP cloud support" "" "" "")
if (PIP_BUILD_CRYPT)
pip_find_lib(sodium)
if(sodium_FOUND)
pip_module(crypt "sodium" "PIP crypt support" "" "" "")
pip_module(client_server "pip_io_utils" "PIP client-server helper" "" "" "")
pip_module(cloud "pip_io_utils" "PIP cloud support" "" "" "")
endif()
endif()
# Check if PIP support fftw3 for PIFFT using in math module
set(FFTW_LIB_NAME fftw3)
set(FFTW_LIB_SUFFIXES "" "f" "l" "q")
set(FFTW_LIB_SUFFIXES2 "" "-3")
set(FFTW_LIBS)
set(FFTW_ABS_LIBS)
set(CMAKE_REQUIRED_INCLUDES fftw3.h)
foreach(FFTW_S_ IN LISTS FFTW_LIB_SUFFIXES)
set(FFTW_BREAK false)
foreach(FFTW_S2_ IN LISTS FFTW_LIB_SUFFIXES2)
if(NOT FFTW_BREAK)
set(FFTW_CLN "${FFTW_LIB_NAME}${FFTW_S_}${FFTW_S2_}")
set(FFTW_CLNT "${FFTW_LIB_NAME}${FFTW_S_}_threads${FFTW_S2_}")
find_library(${FFTW_CLN}_LIBRARIES ${FFTW_CLN})
find_library(${FFTW_CLNT}_LIBRARIES ${FFTW_CLNT})
set(${FFTW_CLN}_FOUND FALSE)
set(${FFTW_CLNT}_FOUND FALSE)
if(${FFTW_CLN}_LIBRARIES)
set(${FFTW_CLN}_FOUND TRUE)
list(APPEND FFTW_LIBS "${FFTW_CLN}")
list(APPEND FFTW_ABS_LIBS "${${FFTW_CLN}_LIBRARIES}")
set(${FFTW_CLN}_CTS "${FFTW_CLN}")
if(${FFTW_CLNT}_FLIBRARIES)
set(${FFTW_CLNT}_FOUND TRUE)
list(APPEND FFTW_LIBS "${FFTW_CLNT}")
list(APPEND FFTW_ABS_LIBS "${${FFTW_CLNT}_LIBRARIES}")
list(APPEND ${FFTW_CLN}_CTS "${FFTW_CLNT}")
endif()
set(CMAKE_REQUIRED_LIBRARIES ${${FFTW_CLN}_CTS})
CHECK_FUNCTION_EXISTS(fftw${FFTW_S_}_make_planner_thread_safe ${FFTW_CLN}_TSFE)
add_definitions(-DPIP_FFTW${FFTW_S_})
if(${FFTW_CLN}_TSFE)
add_definitions(-DPIP_FFTW${FFTW_S_}_THREADSAFE)
else()
message(STATUS "Warning: PIFFTW${FFTW_S_}::preparePlan was not threadsafe")
if (PIP_BUILD_FFTW)
# Check if PIP support fftw3 for PIFFT using in math module
set(FFTW_LIB_NAME fftw3)
set(FFTW_LIB_SUFFIXES "" "f" "l" "q")
set(FFTW_LIB_SUFFIXES2 "" "-3")
set(FFTW_LIBS)
set(FFTW_ABS_LIBS)
set(CMAKE_REQUIRED_INCLUDES fftw3.h)
foreach(FFTW_S_ IN LISTS FFTW_LIB_SUFFIXES)
set(FFTW_BREAK false)
foreach(FFTW_S2_ IN LISTS FFTW_LIB_SUFFIXES2)
if(NOT FFTW_BREAK)
set(FFTW_CLN "${FFTW_LIB_NAME}${FFTW_S_}${FFTW_S2_}")
set(FFTW_CLNT "${FFTW_LIB_NAME}${FFTW_S_}_threads${FFTW_S2_}")
find_library(${FFTW_CLN}_LIBRARIES ${FFTW_CLN})
find_library(${FFTW_CLNT}_LIBRARIES ${FFTW_CLNT})
set(${FFTW_CLN}_FOUND FALSE)
set(${FFTW_CLNT}_FOUND FALSE)
if(${FFTW_CLN}_LIBRARIES)
set(${FFTW_CLN}_FOUND TRUE)
list(APPEND FFTW_LIBS "${FFTW_CLN}")
list(APPEND FFTW_ABS_LIBS "${${FFTW_CLN}_LIBRARIES}")
set(${FFTW_CLN}_CTS "${FFTW_CLN}")
if(${FFTW_CLNT}_FLIBRARIES)
set(${FFTW_CLNT}_FOUND TRUE)
list(APPEND FFTW_LIBS "${FFTW_CLNT}")
list(APPEND FFTW_ABS_LIBS "${${FFTW_CLNT}_LIBRARIES}")
list(APPEND ${FFTW_CLN}_CTS "${FFTW_CLNT}")
endif()
set(CMAKE_REQUIRED_LIBRARIES ${${FFTW_CLN}_CTS})
CHECK_FUNCTION_EXISTS(fftw${FFTW_S_}_make_planner_thread_safe ${FFTW_CLN}_TSFE)
add_definitions(-DPIP_FFTW${FFTW_S_})
if(${FFTW_CLN}_TSFE)
add_definitions(-DPIP_FFTW${FFTW_S_}_THREADSAFE)
else()
message(STATUS "Warning: PIFFTW${FFTW_S_}::preparePlan was not threadsafe")
endif()
endif()
endif()
endif()
endforeach()
endforeach()
endforeach()
if(FFTW_LIBS)
pip_module(fftw "${FFTW_LIBS}" "PIP FFTW support" "" "" "")
endif()
if (NOT "x${MINGW_INCLUDE}" STREQUAL "x")
list(APPEND CMAKE_INCLUDE_PATH "${MINGW_INCLUDE}")
endif()
find_package(OpenCL QUIET) #OpenCL_VERSION_STRING
if(OpenCL_FOUND)
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}")
if(APPLE)
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}/Headers")
if(FFTW_LIBS)
pip_module(fftw "${FFTW_LIBS}" "PIP FFTW support" "" "" "")
endif()
pip_module(opencl "OpenCL" "PIP OpenCL support" "${_opencl_inc}" "" " (${OpenCL_VERSION_STRING})")
endif()
if(sodium_FOUND)
pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)")
else()
pip_module(io_utils "" "PIP I/O support" "" "" "")
endif()
# Lua module
set(_lua_src_dir "${CMAKE_CURRENT_SOURCE_DIR}/3rd/lua")
set(_lua_bri_dir "${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd")
set(_lua_src_hdr "${_lua_src_dir}/lua.hpp" "${_lua_src_dir}/lua.h" "${_lua_src_dir}/luaconf.h" "${_lua_src_dir}/lualib.h")
pip_module(lua "" "PIP Lua support" "${_lua_src_dir};${_lua_bri_dir}" "${_lua_src_dir}" " (internal)")
target_include_directories(pip_lua PUBLIC "${_lua_src_dir}" "${_lua_bri_dir}")
if (WIN32)
target_compile_definitions(pip_lua PRIVATE LUA_BUILD_AS_DLL LUA_CORE)
endif()
list(APPEND HDR_DIRS "${_lua_bri_dir}/LuaBridge")
list(APPEND HDRS ${_lua_src_hdr})
# libmicrohttpd
find_library(microhttpd_LIBRARIES microhttpd HINTS "${MINGW_LIB}")
set(microhttpd_FOUND FALSE)
if (microhttpd_LIBRARIES)
set(microhttpd_FOUND TRUE)
set(_microhttpd_add_libs microhttpd)
if(WIN32)
if("${C_COMPILER}" STREQUAL "cl.exe")
else()
list(APPEND _microhttpd_add_libs ws2_32)
if (PIP_BUILD_OPENCL)
if (NOT "x${MINGW_INCLUDE}" STREQUAL "x")
list(APPEND CMAKE_INCLUDE_PATH "${MINGW_INCLUDE}")
endif()
find_package(OpenCL QUIET) #OpenCL_VERSION_STRING
if(OpenCL_FOUND)
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}")
if(APPLE)
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}/Headers")
endif()
pip_module(opencl "OpenCL" "PIP OpenCL support" "${_opencl_inc}" "" " (${OpenCL_VERSION_STRING})")
endif()
endif()
if (PIP_BUILD_IO_UTILS)
if(sodium_FOUND)
pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)")
else()
list(APPEND _microhttpd_add_libs dl)
find_library(tls_lib gnutls)
if (tls_lib)
set(gnutls_FOUND TRUE)
set(gnutls_LIBRARIES "${tls_lib}")
list(APPEND _microhttpd_add_libs gnutls)
endif()
if(DEFINED ENV{QNX_HOST})
list(APPEND _microhttpd_add_libs socket)
pip_module(io_utils "" "PIP I/O support" "" "" "")
endif()
endif()
if (PIP_BUILD_LUA)
# Lua module
set(_lua_src_dir "${CMAKE_CURRENT_SOURCE_DIR}/3rd/lua")
set(_lua_bri_dir "${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd")
set(_lua_src_hdr "${_lua_src_dir}/lua.hpp" "${_lua_src_dir}/lua.h" "${_lua_src_dir}/luaconf.h" "${_lua_src_dir}/lualib.h")
pip_module(lua "" "PIP Lua support" "${_lua_src_dir};${_lua_bri_dir}" "${_lua_src_dir}" " (internal)")
target_include_directories(pip_lua PUBLIC "${_lua_src_dir}" "${_lua_bri_dir}")
if (WIN32)
target_compile_definitions(pip_lua PRIVATE LUA_BUILD_AS_DLL LUA_CORE)
endif()
list(APPEND HDR_DIRS "${_lua_bri_dir}/LuaBridge")
list(APPEND HDRS ${_lua_src_hdr})
endif()
if (PIP_BUILD_HTTP_SERVER)
# libmicrohttpd
pip_find_lib(microhttpd HINTS "${MINGW_LIB}")
if (microhttpd_FOUND)
set(_microhttpd_add_libs microhttpd)
if(WIN32)
if("${C_COMPILER}" STREQUAL "cl.exe")
else()
list(APPEND _microhttpd_add_libs ws2_32)
endif()
else()
if (NOT DEFINED ANDROID_PLATFORM)
list(APPEND _microhttpd_add_libs pthread util)
list(APPEND _microhttpd_add_libs dl)
find_library(tls_lib gnutls)
if (tls_lib)
set(gnutls_FOUND TRUE)
set(gnutls_LIBRARIES "${tls_lib}")
list(APPEND _microhttpd_add_libs gnutls)
endif()
if(DEFINED ENV{QNX_HOST})
list(APPEND _microhttpd_add_libs socket)
else()
if (NOT DEFINED ANDROID_PLATFORM)
list(APPEND _microhttpd_add_libs pthread util)
endif()
endif()
endif()
#list(APPEND microhttpd_LIBRARIES "${_microhttpd_add_libs}")
pip_module(http_server "${_microhttpd_add_libs}" "PIP HTTP server" "" "" "")
endif()
#list(APPEND microhttpd_LIBRARIES "${_microhttpd_add_libs}")
pip_module(http_server "${_microhttpd_add_libs}" "PIP HTTP server" "" "" "")
endif()
if (PIP_BUILD_HTTP_CLIENT)
# libcurl
pip_find_lib(curl HINTS "${MINGW_LIB}")
if (curl_FOUND)
pip_module(http_client curl "PIP HTTP client" "" "" "")
endif()
endif()
# Test program
if(PIP_UTILS)
@@ -524,9 +558,9 @@ if (NOT CROSSTOOLS)
#target_link_libraries(pip_plugin pip)
if (NOT DEFINED ANDROID_PLATFORM)
if(microhttpd_FOUND)
if(microhttpd_FOUND AND curl_FOUND)
add_executable(pip_test "main.cpp")
target_link_libraries(pip_test pip pip_io_utils pip_client_server pip_http_server)
target_link_libraries(pip_test pip pip_io_utils pip_client_server pip_http_server pip_http_client)
if(sodium_FOUND)
add_executable(pip_cloud_test "main_picloud_test.cpp")
target_link_libraries(pip_cloud_test pip_cloud)
@@ -536,9 +570,19 @@ if (NOT CROSSTOOLS)
endif()
else()
pip_module(crypt "" "PIP crypt support" "" "" "")
pip_module(compress "" "PIP compression support" "" "" "")
pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)")
if (PIP_BUILD_CRYPT)
pip_module(crypt "" "PIP crypt support" "" "" "")
endif()
if (PIP_BUILD_COMPRESS)
pip_module(compress "" "PIP compression support" "" "" "")
endif()
if (PIP_BUILD_IO_UTILS)
pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)")
endif()
endif()
endif()
@@ -656,7 +700,7 @@ if ((NOT PIP_FREERTOS) AND (NOT CROSSTOOLS))
find_package(Doxygen)
if(DOXYGEN_FOUND)
set(DOXY_DEFINES "${PIP_EXPORTS}")
foreach (_m "console" "usb" "compress" "crypt" "client_server" "cloud" "fftw" "opencl" "io_utils" "lua")
foreach (_m "console" "usb" "compress" "crypt" "client_server" "cloud" "fftw" "opencl" "io_utils" "lua" "http_server" "http_client")
string(TOUPPER "${_m}" _mdef)
list(APPEND DOXY_DEFINES "PIP_${_mdef}_EXPORT")
endforeach()

View File

@@ -12,6 +12,7 @@ Create imported targets:
* PIP::ClientServer
* PIP::Cloud
* PIP::Lua
* PIP::HTTPClient
* PIP::HTTPServer
These targets include directories and depends on
@@ -24,10 +25,10 @@ include(SHSTKMacros)
shstk_set_find_dirs(PIP)
set(__libs "usb;crypt;console;fftw;compress;opencl;io_utils;client_server;cloud;lua;http_server")
set(__libs "usb;crypt;console;fftw;compress;opencl;io_utils;client_server;cloud;lua;http_client;http_server")
if (BUILDING_PIP)
#set(_libs "pip;pip_usb;pip_console;pip_crypt;pip_fftw;pip_compress;pip_opencl;pip_io_utils;pip_cloud;pip_lua;pip_http_server")
#set(_libs "pip;pip_usb;pip_console;pip_crypt;pip_fftw;pip_compress;pip_opencl;pip_io_utils;pip_cloud;pip_lua;pip_http_client;pip_http_server")
#set(_bins "pip_cmg;pip_rc;deploy_tool")
#get_target_property(_path pip BINARY_DIR)
#get_target_property(_path pip LIBRARY_OUTPUT_NAME)
@@ -97,6 +98,7 @@ set(__module_io_utils IOUtils )
set(__module_client_server ClientServer)
set(__module_cloud Cloud )
set(__module_lua Lua )
set(__module_http_client HTTPClient )
set(__module_http_server HTTPServer )
foreach (_l ${__libs})

View File

@@ -1,54 +1,57 @@
#include "pip.h"
//! [own]
inline PICout operator <<(PICout s, const PIByteArray & ba) {
s.space(); // insert space after previous output
s.quote(); // ONLY if you want to quoted your type
inline PICout operator<<(PICout s, const PIByteArray & ba) {
s.space(); // insert space after previous output
s.quote(); // ONLY if you want to quoted your type
s.saveAndSetControls(0); // clear all features and
// save them to stack,
// now it`s behavior similar to std::cout
// your output
for (uint i = 0; i < ba.size(); ++i)
s << ba[i];
s.restoreControls(); // restore features from stack
s.quote(); // ONLY if you want to quoted your type
s.quote(); // ONLY if you want to quoted your type
return s;
}
//! [own]
// clang-format off
void _() {
//! [0]
using namespace PICoutManipulators;
int a = 10, b = 32, c = 11;
piCout << a << Hex << b << Bin << c;
// 10 20 1011
piCout << "this" << "is" << Green << "green" << Default << "word";
piCout << "this"
<< "is" << Green << "green" << Default << "word";
// this is green word
PICout(AddSpaces | AddNewLine | AddQuotes) << Tab << "tab and" << "quotes";
PICout(AddSpaces | AddNewLine | AddQuotes) << Tab << "tab and"
<< "quotes";
// "tab and" "quotes"
//! [0]
}
// clang-format on
//! [notifier]
class A: public PIObject {
PIOBJECT(A)
public:
A() {}
EVENT_HANDLER2(void, pcf, int, id, PIString*, buff) {
piCout << "PICout(" << id << ") finished:" << (*buff);
}
EVENT_HANDLER2(void, pcf, int, id, PIString *, buff) { piCout << "PICout(" << id << ") finished:" << (*buff); }
};
int main() {
A a;
CONNECTU(PICout::Notifier::object(), finished, &a, pcf);
PIString buffer = "my buff:";
PICout(&buffer, 1) << "int 10 ->" << 10 << ", time ->" << PITime::current();
int my_id = PICout::registerExternalBufferID();
PICout::withExternalBufferAndID(&buffer, my_id) << "int 10 ->" << 10 << ", time ->" << PITime::current();
return 0;
}
// PICout( 1 ) finished: my buff:int 10 -> 10 , time -> PITime(14:07:09:000)

Binary file not shown.

View File

@@ -20,7 +20,7 @@
<context>
<name>PIFile</name>
<message>
<location filename="../libs/main/io_devices/pifile.cpp" line="299"/>
<location filename="../libs/main/io_devices/pifile.cpp" line="300"/>
<source>Downsize is not supported yet :-(</source>
<translation>Уменьшение размера не поддерживается</translation>
</message>
@@ -46,50 +46,50 @@
<context>
<name>PICrypt</name>
<message>
<location filename="../libs/crypt/picrypt.cpp" line="205"/>
<location filename="../libs/crypt/picrypt.cpp" line="187"/>
<source>internal error: bad hash size</source>
<translation>внутренняя ошибка: плохой размер хэша</translation>
</message>
<message>
<location filename="../libs/crypt/picrypt.cpp" line="39"/>
<location filename="../libs/crypt/picrypt.cpp" line="35"/>
<source>Error while initialize sodium!</source>
<translation>Ошибка инициализации sodium!</translation>
</message>
<message>
<location filename="../libs/crypt/picrypt.cpp" line="209"/>
<location filename="../libs/crypt/picrypt.cpp" line="190"/>
<source>invalid key size %1, should be %2, filled with zeros</source>
<translation>неверный размер ключа %1, должен быть %2, заполненный нулями</translation>
</message>
<message>
<location filename="../libs/crypt/picrypt.cpp" line="29"/>
<source>Warning: PICrypt is disabled, to enable install sodium library and rebuild pip</source>
<translation>Предупреждение: PICrypt неактивен, для активации установите библиотеку sodium и пересоберите PIP</translation>
<translation type="vanished">Предупреждение: PICrypt неактивен, для активации установите библиотеку sodium и пересоберите PIP</translation>
</message>
</context>
<context>
<name>PIBinLog</name>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="436"/>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="438"/>
<source>Read record error</source>
<translation>Ошибка чтения записи</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="432"/>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="434"/>
<source>End of BinLog file</source>
<translation>Конец BinLog файла</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="776"/>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="778"/>
<source>Error, can&apos;t open &quot;%1&quot;</source>
<translation>Ошибка, невозможно открыть &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="262"/>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="264"/>
<source>Creating directory &quot;%1&quot;</source>
<translation>Создание директории &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="785"/>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="787"/>
<source>Error, can&apos;t create &quot;%1&quot;</source>
<translation>Ошибка, невозможно создать &quot;%1&quot;</translation>
</message>
@@ -99,32 +99,32 @@
<translation>Ошибка, Файл пуст &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="789"/>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="791"/>
<source>Start join binlogs to &quot;%1&quot;</source>
<translation>Начало слияния логов в &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="514"/>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="516"/>
<source>BinLogFile has too old verion</source>
<translation>BinLogFile очень старой версии</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="513"/>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="515"/>
<source>BinLogFile has invalid version</source>
<translation>BinLogFile неверной версии</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="515"/>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="517"/>
<source>BinLogFile has too new version</source>
<translation>BinLogFile очень новой версии</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="386"/>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="388"/>
<source>Can&apos;t find record with id = %1</source>
<translation>Невозможно найти запись с ID = %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="803"/>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="805"/>
<source>Error, can&apos;t write to file &quot;%1&quot;</source>
<translation>Ошибка, невозможно записать в &quot;%1&quot;</translation>
</message>
@@ -139,12 +139,12 @@
<translation>Предупреждение: Пустой BinLog файл &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="825"/>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="827"/>
<source>Finish join binlogs, total time %1</source>
<translation>Завершение слияния логов, общее время %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="440"/>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="442"/>
<source>too small read buffer: %1, data size: %2</source>
<translation>слишком маленький буфер: %1, размер данных: %2</translation>
</message>
@@ -154,22 +154,22 @@
<translation>Ошибка: Невозможно записать заголовок в &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="319"/>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="321"/>
<source>Error: can`t write with id = 0! ID must be &gt; 0</source>
<translation>Ошибка: Невозможно записать с ID = 0! ID должен быть &gt; 0</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="495"/>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="497"/>
<source>BinLogFile signature is corrupted or invalid file</source>
<translation>Неверный заголовок BinLogFile, либо файл поврежден</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="295"/>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="297"/>
<source>Can&apos;t create new file, maybe path &quot;%1&quot; is invalid</source>
<translation>Невозможно создать новый файл, возможно путь &quot;%1&quot; неверен</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="286"/>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="288"/>
<source>Can&apos;t create new file, maybe LogDir &quot;%1&quot; is invalid</source>
<translation>Невозможно создать новый файл, возможно LogDir &quot;%1&quot; неверен</translation>
</message>
@@ -182,22 +182,22 @@
<context>
<name>PIOpenCL</name>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="509"/>
<location filename="../libs/opencl/piopencl.cpp" line="549"/>
<source>Error: empty range</source>
<translation>Ошибка: пустой диапазон</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="586"/>
<location filename="../libs/opencl/piopencl.cpp" line="626"/>
<source>setArgValue invalid index %1</source>
<translation>setArgValue неверный индекс %1</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="616"/>
<location filename="../libs/opencl/piopencl.cpp" line="656"/>
<source>bindArgValue invalid index %1</source>
<translation>bindArgValue неверный индекс %1</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="592"/>
<location filename="../libs/opencl/piopencl.cpp" line="632"/>
<source>setArgValue set scalar to &quot;%1 %2&quot;</source>
<translation>setArgValue устанавливается скаляр в &quot;%1 %2&quot;</translation>
</message>
@@ -207,7 +207,7 @@
<translation>Ошибка: Платформы OpenCL не найдены!</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="622"/>
<location filename="../libs/opencl/piopencl.cpp" line="662"/>
<source>bindArgValue set buffer to &quot;%1 %2&quot;</source>
<translation>bindArgValue устанавливается буфер в &quot;%1 %2&quot;</translation>
</message>
@@ -253,47 +253,47 @@
<context>
<name>PIString</name>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1774"/>
<location filename="../libs/main/text/pistring.cpp" line="1787"/>
<source>B</source>
<translation>Б</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1794"/>
<location filename="../libs/main/text/pistring.cpp" line="1807"/>
<source>EiB</source>
<translation>ЭиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1791"/>
<location filename="../libs/main/text/pistring.cpp" line="1804"/>
<source>GiB</source>
<translation>ГиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1789"/>
<location filename="../libs/main/text/pistring.cpp" line="1802"/>
<source>KiB</source>
<translation>КиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1790"/>
<location filename="../libs/main/text/pistring.cpp" line="1803"/>
<source>MiB</source>
<translation>МиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1793"/>
<location filename="../libs/main/text/pistring.cpp" line="1806"/>
<source>PiB</source>
<translation>ПиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1792"/>
<location filename="../libs/main/text/pistring.cpp" line="1805"/>
<source>TiB</source>
<translation>ТиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1796"/>
<location filename="../libs/main/text/pistring.cpp" line="1809"/>
<source>YiB</source>
<translation>ЙиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1795"/>
<location filename="../libs/main/text/pistring.cpp" line="1808"/>
<source>ZiB</source>
<translation>ЗиБ</translation>
</message>
@@ -301,17 +301,17 @@
<context>
<name>PIThread</name>
<message>
<location filename="../libs/main/thread/pithread.cpp" line="667"/>
<location filename="../libs/main/thread/pithread.cpp" line="668"/>
<source>Warning, terminate!</source>
<translation>Предупреждение, прекращение потока!</translation>
</message>
<message>
<location filename="../libs/main/thread/pithread.cpp" line="785"/>
<location filename="../libs/main/thread/pithread.cpp" line="781"/>
<source>Error: Can`t start new thread: %1</source>
<translation>Ошибка: Невозможно начать новый поток: %1</translation>
</message>
<message>
<location filename="../libs/main/thread/pithread.cpp" line="572"/>
<location filename="../libs/main/thread/pithread.cpp" line="573"/>
<source>[PIThread &quot;%1&quot;] Warning, terminate on destructor!</source>
<translation>[PIThread &quot;%1&quot;] Предупреждение, прекращение в деструкторе!</translation>
</message>
@@ -358,17 +358,17 @@
<context>
<name>PIEthernet</name>
<message>
<location filename="../libs/main/io_devices/piethernet.cpp" line="1233"/>
<location filename="../libs/main/io_devices/piethernet.cpp" line="1272"/>
<source>Can`t get interfaces: %1</source>
<translation>Невозможно получить интерфейсы: %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piethernet.cpp" line="903"/>
<location filename="../libs/main/io_devices/piethernet.cpp" line="942"/>
<source>Can`t accept new connection, %1</source>
<translation>Невозможно принять новое соединение, %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piethernet.cpp" line="1096"/>
<location filename="../libs/main/io_devices/piethernet.cpp" line="1135"/>
<source>Error allocating memory needed to call GetAdaptersInfo</source>
<translation>Ошибка выделения памяти для вызова GetAdaptersInfo</translation>
</message>
@@ -445,12 +445,12 @@
<context>
<name>PISystemTime</name>
<message>
<location filename="../libs/main/types/pisystemtime.cpp" line="335"/>
<location filename="../libs/main/types/pisystemtime.cpp" line="343"/>
<source>fromSystemTime() Warning: null frequency</source>
<translation>fromSystemTime() Предупреждение: нулевая частота</translation>
</message>
<message>
<location filename="../libs/main/types/pisystemtime.cpp" line="325"/>
<location filename="../libs/main/types/pisystemtime.cpp" line="333"/>
<source>toSystemTime() Warning: invalid hertz: %1</source>
<translation>toSystemTime() Предупреждение: неверная частота: %1</translation>
</message>
@@ -510,7 +510,7 @@
<context>
<name>PIStreamPacker</name>
<message>
<location filename="../libs/io_utils/pistreampacker.cpp" line="218"/>
<location filename="../libs/io_utils/pistreampacker.cpp" line="168"/>
<source>Warning! Not recommended to use with non-reliable device</source>
<translation>Предупреждение! Не рекомендуется использовать с ненадежными устройствами</translation>
</message>

View File

@@ -20,17 +20,19 @@
#include "piincludes_p.h"
#include "piliterals_time.h"
// clang-format off
#ifndef WINDOWS
# include <fcntl.h>
# include <sys/ioctl.h>
# include <termios.h>
#else
# include <wincon.h>
# include <wingdi.h>
# include <wincon.h>
# ifndef COMMON_LVB_UNDERSCORE
# define COMMON_LVB_UNDERSCORE 0x8000
# endif
#endif
// clang-format on
using namespace PIScreenTypes;

View File

@@ -23,7 +23,6 @@
#include "pisharedmemory.h"
#ifndef MICRO_PIP
# ifdef WINDOWS
# include <wincon.h>
# include <windows.h>
# include <wingdi.h>
# include <winuser.h>
@@ -148,7 +147,8 @@ void PITerminal::write(const PIByteArray & d) {
if (PRIVATE->fd == 0) return;
// ssize_t wrote = 0;
// wrote =
::write(PRIVATE->fd, d.data(), d.size_s());
auto _r = ::write(PRIVATE->fd, d.data(), d.size_s());
NO_UNUSED(_r);
// piCout << "wrote" << wrote << d;
# endif
# endif
@@ -346,8 +346,8 @@ void PITerminal::getCursor(int & x, int & y) {
int sz = 0;
PRIVATE->shm->read(&sz, 4);
# else
x = PRIVATE->cur_x;
y = PRIVATE->cur_y;
x = PRIVATE->cur_x;
y = PRIVATE->cur_y;
# endif
}
@@ -793,7 +793,7 @@ bool PITerminal::initialize() {
// SetHandleInformation(PRIVATE->pipe_in[1], HANDLE_FLAG_INHERIT, 0);
// SetHandleInformation(PRIVATE->hConBuf, HANDLE_FLAG_INHERIT, 0);
// GetStartupInfoA(&PRIVATE->si);
memset(&PRIVATE->si, 0, sizeof(PRIVATE->si));
piZeroMemory(PRIVATE->si);
PRIVATE->si.cb = sizeof(STARTUPINFO);
// PRIVATE->si.dwFlags |= STARTF_USESTDHANDLES;
PRIVATE->si.dwFlags |= STARTF_USESHOWWINDOW;
@@ -805,7 +805,7 @@ bool PITerminal::initialize() {
PRIVATE->si.dwXCountChars = 80;
PRIVATE->si.dwYCountChars = 24;
memset(&PRIVATE->pi, 0, sizeof(PRIVATE->pi));
piZeroMemory(PRIVATE->pi);
PIString shmh = PIString::fromNumber(randomi() % 10000);
PIString pname = "\\\\.\\pipe\\piterm" + shmh;
@@ -857,7 +857,7 @@ bool PITerminal::initialize() {
# else
# ifdef HAS_FORKPTY
char pty[256];
memset(pty, 0, 256);
piZeroMemory(pty, 256);
winsize ws;
ws.ws_col = dsize_x;
ws.ws_row = dsize_y;
@@ -934,7 +934,7 @@ void PITerminal::destroy() {
}
if (PRIVATE->pipe != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->pipe);
if (PRIVATE->hConBuf != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->hConBuf);
// piCout << "destroy" << size_y;
// piCout << "destroy" << size_y;
# else
# ifdef HAS_FORKPTY
if (PRIVATE->pid != 0) kill(PRIVATE->pid, SIGKILL);

View File

@@ -0,0 +1,96 @@
#include "curl_thread_pool_p.h"
#include "pihttpclient.h"
#include "pitime.h"
#include <curl/curl.h>
CurlThreadPool::CurlThreadPool() {
curl_global_init(CURL_GLOBAL_DEFAULT);
const int count = 10;
for (int i = 0; i < count; ++i) {
auto * t = new PIThread([this]() { threadFunc(); }, true);
threads << t;
}
}
CurlThreadPool::~CurlThreadPool() {
destroy();
// piCout << "~CurlThreadPool cleanup ...";
curl_global_cleanup();
// piCout << "~CurlThreadPool cleanup ok";
}
void CurlThreadPool::threadFunc() {
if (exiting) return;
// piCout << "threadFuncl w ...";
sem.acquire();
// piCout << "threadFuncl wdone";
if (exiting) return;
PIHTTPClient * c = nullptr;
{
auto cr = clients.getRef();
if (cr->isEmpty()) return;
c = cr->dequeue();
// piCout << "threadFuncl get c";
}
// piCout << "threadFuncl proc c";
procClient(c);
// piCout << "threadFuncl end";
}
void CurlThreadPool::procClient(PIHTTPClient * c) {
{ clients_in_proc.getRef()->append(c); }
if (c->init()) c->perform();
{ clients_in_proc.getRef()->removeOne(c); }
delete c;
}
void CurlThreadPool::registerClient(PIHTTPClient * c) {
clients.getRef()->enqueue(c);
sem.release();
// piCout << "registerClient";
}
CurlThreadPool * CurlThreadPool::instance() {
static CurlThreadPool ret;
return &ret;
}
void CurlThreadPool::destroy() {
// piCout << "~CurlThreadPool";
exiting = true;
for (auto * t: threads)
t->stop();
{
auto cr = clients.getRef();
for (auto c: *cr)
c->abort();
}
{
auto cr = clients_in_proc.getRef();
for (auto c: *cr)
c->abort();
}
// piCout << "~CurlThreadPool release ...";
sem.release(threads.size());
for (auto * t: threads) {
t->waitForFinish();
t->setDebug(false);
t->terminate();
}
// piCout << "~CurlThreadPool delete ...";
piDeleteAllAndClear(threads);
{
auto cr = clients.getRef();
for (auto c: *cr)
delete c;
}
// piCout << "~CurlThreadPool ok";
}

View File

@@ -0,0 +1,33 @@
#ifndef curl_thread_pool_p_H
#define curl_thread_pool_p_H
#include "piprotectedvariable.h"
#include "pisemaphore.h"
#include "pithread.h"
class PIHTTPClient;
class CurlThreadPool {
public:
void registerClient(PIHTTPClient * c);
static CurlThreadPool * instance();
private:
NO_COPY_CLASS(CurlThreadPool)
CurlThreadPool();
~CurlThreadPool();
void destroy();
void threadFunc();
void procClient(PIHTTPClient * c);
PIProtectedVariable<PIQueue<PIHTTPClient *>> clients;
PIProtectedVariable<PIVector<PIHTTPClient *>> clients_in_proc;
PISemaphore sem;
PIVector<PIThread *> threads;
std::atomic_bool exiting = {false};
};
#endif

View File

@@ -0,0 +1,294 @@
#include "pihttpclient.h"
#include "curl_thread_pool_p.h"
#include "piliterals_bytes.h"
#include "piliterals_string.h"
#include "pisystemtime.h"
#include <curl/curl.h>
#if !defined(CURL_WRITEFUNC_ERROR)
# define CURL_WRITEFUNC_ERROR 0xFFFFFFFF
#endif
int xfer_callback(void * ptr, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) {
return reinterpret_cast<PIHTTPClientBase *>(ptr)->__infoFunc(dltotal, dlnow, ultotal, ulnow);
}
int debug_callback(CURL * handle, curl_infotype type, char * data, size_t size, void * ptr) {
return reinterpret_cast<PIHTTPClientBase *>(ptr)->__debugFunc(type, data, size);
}
PRIVATE_DEFINITION_START(PIHTTPClient)
CURLM * multi = nullptr;
CURL * handle = nullptr;
curl_slist * header_list = nullptr;
bool isInit() const {
return multi && handle;
}
bool init() {
multi = curl_multi_init();
handle = curl_easy_init();
if (!multi || !handle) {
destroy();
return false;
}
return true;
}
void destroy() {
if (multi && handle) curl_multi_remove_handle(multi, handle);
if (header_list) curl_slist_free_all(header_list);
if (handle) curl_easy_cleanup(handle);
if (multi) curl_multi_cleanup(multi);
multi = nullptr;
handle = nullptr;
header_list = nullptr;
}
PRIVATE_DEFINITION_END(PIHTTPClient)
PIHTTPClient::PIHTTPClient() {}
PIHTTPClient::~PIHTTPClient() {}
bool PIHTTPClient::init() {
if (is_cancel) return false;
CurlThreadPool::instance();
if (!PRIVATE->init()) return false;
auto ait = request.arguments().makeIterator();
while (ait.next()) {
if (!url.contains('?'))
url.append('?');
else
url.append('&');
url.append(ait.key().toPercentageEncoding());
url.append('=');
url.append(ait.value().toPercentageEncoding());
}
headers.clear();
auto hit = request.headers().makeIterator();
while (hit.next()) {
headers << hit.key() + ": " + hit.value();
}
for (const auto & h: headers)
PRIVATE->header_list = curl_slist_append(PRIVATE->header_list, h.dataAscii());
curl_easy_setopt(PRIVATE->handle, CURLOPT_WRITEDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_READDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_XFERINFODATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_DEBUGDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_HEADERDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_WRITEFUNCTION, writeMemoryFunc);
curl_easy_setopt(PRIVATE->handle, CURLOPT_READFUNCTION, readMemoryFunc);
curl_easy_setopt(PRIVATE->handle, CURLOPT_XFERINFOFUNCTION, xfer_callback);
curl_easy_setopt(PRIVATE->handle, CURLOPT_DEBUGFUNCTION, debug_callback);
curl_easy_setopt(PRIVATE->handle, CURLOPT_HEADERFUNCTION, headerFunc);
curl_easy_setopt(PRIVATE->handle, CURLOPT_URL, url.dataUTF8());
curl_easy_setopt(PRIVATE->handle, CURLOPT_CUSTOMREQUEST, PIHTTP::methodName(request.method()));
curl_easy_setopt(PRIVATE->handle, CURLOPT_HTTPHEADER, PRIVATE->header_list);
curl_easy_setopt(PRIVATE->handle, CURLOPT_NOPROGRESS, 0L);
// curl_easy_setopt(PRIVATE->handle, CURLOPT_VERBOSE, 1L);
// curl_easy_setopt(PRIVATE->handle, CURLOPT_ERRORBUFFER, buffer_error.data());
curl_easy_setopt(PRIVATE->handle, CURLOPT_SSL_VERIFYPEER, 0L);
if (request.body().isNotEmpty()) {
curl_easy_setopt(PRIVATE->handle, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(PRIVATE->handle, CURLOPT_INFILESIZE_LARGE, static_cast<curl_off_t>(request.body().size()));
}
return true;
}
void PIHTTPClient::perform() {
if (!PRIVATE->isInit()) return;
if (!is_cancel) {
// piCout << "perform ...";
PITimeMeasurer tm;
// CURLcode res = curl_easy_perform(PRIVATE->handle);
curl_multi_add_handle(PRIVATE->multi, PRIVATE->handle);
int running_cnt = 1;
do {
CURLMcode mc = curl_multi_perform(PRIVATE->multi, &running_cnt);
// piCout << "curl_multi_perform" << mc << running_cnt;
if (!mc) /* wait for activity, timeout or "nothing" */
mc = curl_multi_poll(PRIVATE->multi, nullptr, 0, 50, nullptr);
if (mc || is_cancel) {
// piCout << "curl_multi_poll() failed";
break;
}
} while (running_cnt > 0 && !is_cancel);
if (is_cancel) {
if (on_abort) on_abort(reply);
PRIVATE->destroy();
return;
}
CURLMsg * m = nullptr;
CURLcode res = (CURLcode)-1;
do {
int msgq = 0;
m = curl_multi_info_read(PRIVATE->multi, &msgq);
if (m && (m->msg == CURLMSG_DONE)) {
res = m->data.result;
if (res == CURLE_OK) {
reply.setBody(std::move(buffer_out));
if (on_finish) on_finish(reply);
} else {
if (res == CURLE_ABORTED_BY_CALLBACK || is_cancel) {
// piCerr << "curl_easy_perform() failed:" << curl_easy_strerror(res);
if (on_abort) on_abort(reply);
} else {
last_error = curl_easy_strerror(res);
if (on_error) on_error(reply);
}
}
break;
}
} while (m && !is_cancel);
if (res == (CURLcode)-1) {
last_error = "CURL error";
if (on_error) on_error(reply);
}
// piCout << "done" << (int)res << "in" << tm.elapsed_m() << ", bytes" << buffer_out.size();
}
// piCout << last_error;
PRIVATE->destroy();
}
void PIHTTPClient::procHeaderLine(PIString & line) {
if (line.startsWith("HTTP"_a)) {
// HTTP/Версия КодСостояния Пояснение
line.cutLeft(5);
line.takeWord();
int code = line.takeWord().toInt();
// piCout << "code" << code;
reply.setCode(static_cast<PIHTTP::Code>(code));
return;
}
int ind = line.find(':');
if (ind < 0) return;
PIString hname = line.takeLeft(ind);
line.cutLeft(1).trim();
reply.addHeader(hname, line);
}
size_t PIHTTPClient::writeMemoryFunc(void * contents, size_t size, size_t nmemb, void * ptr) {
size_t bytes = size * nmemb;
// piCout << "writeMemoryFunc" << bytes;
auto client = reinterpret_cast<PIHTTPClient *>(ptr);
if (client->is_cancel) return CURL_WRITEFUNC_ERROR;
client->buffer_out.append(contents, bytes);
return bytes;
}
size_t PIHTTPClient::readMemoryFunc(void * contents, size_t size, size_t nmemb, void * ptr) {
size_t bytes = size * nmemb;
// piCout << "readMemoryFunc" << bytes;
auto client = reinterpret_cast<PIHTTPClient *>(ptr);
if (client->is_cancel) return CURL_READFUNC_ABORT;
const auto & buffer(client->request.body());
if (buffer.isEmpty()) return 0;
// piCout << bytes;
ssize_t ret = piClamp<ssize_t>(bytes, 0, buffer.size_s() - client->read_pos);
if (ret < 0) ret = 0;
if (ret > 0) memcpy(contents, buffer.data(client->read_pos), ret);
return ret;
}
size_t PIHTTPClient::headerFunc(char * contents, size_t size, size_t nmemb, void * ptr) {
size_t bytes = size * nmemb;
auto client = reinterpret_cast<PIHTTPClient *>(ptr);
if (client->is_cancel) return CURL_WRITEFUNC_ERROR;
PIString line = PIString::fromUTF8(contents, bytes).trim();
if (line.isNotEmpty()) client->procHeaderLine(line);
return bytes;
}
int PIHTTPClient::infoFunc(ssize_t dltotal, ssize_t dlnow, ssize_t ultotal, ssize_t ulnow) {
// piCout << "infoFunc" << dltotal << dlnow << ultotal << ulnow;
if (is_cancel) return 1;
return 0;
}
int PIHTTPClient::debugFunc(int type, char * data, size_t size) {
// piCout << "debugFunc" << type << PIString::fromUTF8(data, size);
return 0;
}
PIHTTPClient * PIHTTPClient::create(const PIString & url_, PIHTTP::Method method, const PIHTTP::MessageConst & req) {
PIHTTPClient * ret = new PIHTTPClient();
static_cast<PIHTTP::MessageConst &>(ret->request) = req;
ret->request.setMethod(method);
ret->reply.setMethod(method);
ret->url = url_;
return ret;
}
PIHTTPClient * PIHTTPClient::onFinish(std::function<void()> f) {
return onFinish([f](const PIHTTP::MessageConst &) { f(); });
}
PIHTTPClient * PIHTTPClient::onFinish(std::function<void(const PIHTTP::MessageConst &)> f) {
on_finish = f;
return this;
}
PIHTTPClient * PIHTTPClient::onError(std::function<void()> f) {
return onError([f](const PIHTTP::MessageConst &) { f(); });
}
PIHTTPClient * PIHTTPClient::onError(std::function<void(const PIHTTP::MessageConst &)> f) {
on_error = f;
return this;
}
PIHTTPClient * PIHTTPClient::onAbort(std::function<void()> f) {
return onAbort([f](const PIHTTP::MessageConst &) { f(); });
}
PIHTTPClient * PIHTTPClient::onAbort(std::function<void(const PIHTTP::MessageConst &)> f) {
on_abort = f;
return this;
}
void PIHTTPClient::start() {
CurlThreadPool::instance()->registerClient(this);
}
void PIHTTPClient::abort() {
is_cancel = true;
if (PRIVATE->isInit()) curl_multi_wakeup(PRIVATE->multi);
}
int PIHTTPClientBase::__infoFunc(ssize_t dltotal, ssize_t dlnow, ssize_t ultotal, ssize_t ulnow) {
return reinterpret_cast<PIHTTPClient *>(this)->infoFunc(dltotal, dlnow, ultotal, ulnow);
}
int PIHTTPClientBase::__debugFunc(int type, char * data, size_t size) {
return reinterpret_cast<PIHTTPClient *>(this)->debugFunc(type, data, size);
}

View File

@@ -1,4 +1,5 @@
#include "microhttpd_server.h"
#include "piliterals_bytes.h"
#include "piliterals_string.h"
#include "piliterals_time.h"
@@ -29,13 +30,23 @@
// clang-format on
struct MicrohttpdServerConnection {
bool ready();
int send_reply(const MicrohttpdServer::Reply & r);
int send_error();
using namespace PIHTTP;
bool done = false;
MicrohttpdServer::Method method = MicrohttpdServer::Method::Unknown;
struct BasicAuthCred {
bool exists = false;
PIString user;
PIString pass;
};
struct MicrohttpdServerConnection {
bool checkBasicAuth();
bool ready();
int sendReply(const MessageMutable & r);
BasicAuthCred getBasicAuthCred();
bool done = false, authorized = false;
Method method = Method::Unknown;
PIString path;
PIByteArray body;
PIMap<PIString, PIString> headers, args, post;
@@ -45,52 +56,85 @@ struct MicrohttpdServerConnection {
};
bool MicrohttpdServerConnection::checkBasicAuth() {
if (headers.contains(Header::Authorization)) {
auto ba_up = getBasicAuthCred();
bool ok = false; // server->callback_auth(ba_up.user, ba_up.pass);
if (server->callback_auth) ok = server->callback_auth(ba_up.user, ba_up.pass);
if (ok) {
authorized = true;
return true;
}
}
// piCout << "miss authorization";
sendReply(MessageMutable::fromCode(Code::Unauthorized)
.addHeader(Header::WWWAuthenticate, "Basic realm=\"%1\", charset=\"UTF-8\""_a.arg(server->realm))
.setBody(PIByteArray::fromAscii("Authorization required")));
// piCout << "answer sent";
return false;
}
bool MicrohttpdServerConnection::ready() {
if (!server) return false;
if (done) return true;
done = true;
MicrohttpdServer::Reply rep;
if (method == MicrohttpdServer::Method::Get) {
MessageMutable rep;
if (method == Method::Get) {
if (path == "/favicon.ico"_a) {
// piCout << "send favicon" << server->favicon.size() << "bytes";
rep.setBody(server->favicon);
send_reply(rep);
sendReply(rep);
return true;
}
}
// piCout << "ready" << (int)method << path;
MicrohttpdServer::Request req;
req.method = method;
req.path = path;
req.body = body;
req.headers = headers;
req.args = args;
rep.setCode(MHD_HTTP_BAD_REQUEST);
// piCout << "ready" << (int)method << path << body.size();
MessageMutable req;
req.setMethod(method);
req.setPath(path);
req.setBody(body);
req.headers() = headers;
req.arguments() = args;
rep.setCode(Code::BadRequest);
if (server->callback) rep = server->callback(req);
rep.addFixedHeaders();
send_reply(rep);
MicrohttpdServer::addFixedHeaders(rep);
sendReply(rep);
// piCout << "ready ok" << (int)rep.code() << rep.body().size();
return true;
}
int MicrohttpdServerConnection::send_reply(const MicrohttpdServer::Reply & r) {
MHD_Response * response = MHD_create_response_from_buffer(r.body.size(), (void *)r.body.data(), MHD_RESPMEM_MUST_COPY);
int MicrohttpdServerConnection::sendReply(const MessageMutable & r) {
MHD_Response * response = MHD_create_response_from_buffer(r.body().size(), (void *)r.body().data(), MHD_RESPMEM_MUST_COPY);
if (!response) {
// piCout << "null response" << r.body.size() << (void *)r.body.data();
return MHD_NO;
}
auto it = r.headers.makeIterator();
auto it = r.headers().makeIterator();
while (it.next())
MHD_add_response_header(response, it.key().dataAscii(), it.value().dataUTF8());
// piCout << "status" << r.code;
int ret = MHD_queue_response(connection, r.code, response);
int ret = MHD_queue_response(connection, static_cast<int>(r.code()), response);
MHD_destroy_response(response);
return ret;
}
int MicrohttpdServerConnection::send_error() {
return MHD_queue_response(connection, MHD_HTTP_BAD_REQUEST, MHD_create_response_from_buffer(0, nullptr, MHD_RESPMEM_MUST_COPY));
BasicAuthCred MicrohttpdServerConnection::getBasicAuthCred() {
BasicAuthCred ret;
char * p = nullptr;
auto u = MHD_basic_auth_get_username_password(connection, &p);
if (u) {
ret.user = PIString::fromUTF8(u);
ret.exists = true;
MHD_free(u);
}
if (p) {
ret.pass = PIString::fromUTF8(p);
ret.exists = true;
MHD_free(p);
}
return ret;
}
@@ -98,9 +142,9 @@ void log_callback(void * cls, const char * fmt, va_list ap) {
MicrohttpdServer * server = (MicrohttpdServer *)cls;
piCout << "log" << server;
if (!server) return;
char buffer[1024];
memset(buffer, 0, 1024);
std::vsnprintf(buffer, 1024, fmt, ap);
char buffer[1_KiB];
piZeroMemory(buffer, 1_KiB);
std::vsnprintf(buffer, 1_KiB, fmt, ap);
piCout << buffer;
}
@@ -150,38 +194,38 @@ int args_iterate(void * cls, MHD_ValueKind kind, const char * key, const char *
}
int answer_to_connection(void * cls,
MHD_Connection * connection,
const char * url,
const char * method,
const char * version,
const char * upload_data,
size_t * upload_data_size,
void ** con_cls) {
MicrohttpdServer * server = (MicrohttpdServer *)cls;
int answer_callback(void * cls,
MHD_Connection * connection,
const char * url,
const char * method,
const char * version,
const char * upload_data,
size_t * upload_data_size,
void ** con_cls) {
MicrohttpdServer * server = (MicrohttpdServer *)cls;
MicrohttpdServer::Method m = MicrohttpdServer::Method::Unknown;
Method m = Method::Unknown;
if (0 == strcmp(method, "GET"))
m = MicrohttpdServer::Method::Get;
m = Method::Get;
else if (0 == strcmp(method, "POST"))
m = MicrohttpdServer::Method::Post;
m = Method::Post;
else if (0 == strcmp(method, "HEAD"))
m = MicrohttpdServer::Method::Head;
m = Method::Head;
else if (0 == strcmp(method, "PUT"))
m = MicrohttpdServer::Method::Put;
m = Method::Put;
else if (0 == strcmp(method, "DELETE"))
m = MicrohttpdServer::Method::Delete;
m = Method::Delete;
else if (0 == strcmp(method, "CONNECT"))
m = MicrohttpdServer::Method::Connect;
m = Method::Connect;
else if (0 == strcmp(method, "OPTIONS"))
m = MicrohttpdServer::Method::Options;
m = Method::Options;
else if (0 == strcmp(method, "TRACE"))
m = MicrohttpdServer::Method::Trace;
m = Method::Trace;
else if (0 == strcmp(method, "PATCH"))
m = MicrohttpdServer::Method::Patch;
m = Method::Patch;
if (m == MicrohttpdServer::Method::Unknown) {
if (m == Method::Unknown) {
piCout << "[MicrohttpdServer]"
<< "Warning:"
<< "Unknown method!";
@@ -198,23 +242,27 @@ int answer_to_connection(void * cls,
conn->method = m;
MHD_get_connection_values(connection, MHD_HEADER_KIND, (MHD_KeyValueIterator)header_iterate, *con_cls);
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, (MHD_KeyValueIterator)args_iterate, *con_cls);
if (server->isBasicAuthEnabled() && !conn->authorized) {
if (!conn->checkBasicAuth()) return MHD_YES;
}
return MHD_YES;
}
if (m == MicrohttpdServer::Method::Unknown) {
return conn->send_error();
if (m == Method::Unknown) {
return conn->sendReply(MessageMutable::fromCode(Code::MethodNotAllowed));
}
if (*upload_data_size) {
if (!conn->postprocessor) {
conn->postprocessor = MHD_create_post_processor(connection, 65536, (MHD_PostDataIterator)iterate_post, (void *)conn);
conn->postprocessor = MHD_create_post_processor(connection, 64_KiB, (MHD_PostDataIterator)iterate_post, (void *)conn);
}
conn->body.append(upload_data, *upload_data_size);
MHD_post_process(conn->postprocessor, upload_data, *upload_data_size);
*upload_data_size = 0;
} else {
// qDebug() << "answer ok";
if (!conn->ready()) return conn->send_error();
if (!conn->ready()) return conn->sendReply(MessageMutable::fromCode(Code::InternalServerError));
}
return MHD_YES;
}
@@ -229,6 +277,7 @@ MicrohttpdServer::MicrohttpdServer() {
PRIVATE->daemon = nullptr;
opts[Option::ConnectionLimit] = FD_SETSIZE - 4;
opts[Option::ConnectionTimeout] = 0_s;
realm = "Restricted"_a;
}
@@ -263,7 +312,7 @@ bool MicrohttpdServer::listen(PINetworkAddress addr) {
key_pass = opts.value(Option::HTTPSKeyPassword).toByteArray();
if (key_pass.isNotEmpty()) key_pass.append(0);
sockaddr_in sa_addr;
memset(&sa_addr, 0, sizeof(sa_addr));
piZeroMemory(sa_addr);
sa_addr.sin_port = htons(addr.port());
sa_addr.sin_addr.s_addr = addr.ip();
sa_addr.sin_family = AF_INET;
@@ -283,7 +332,7 @@ bool MicrohttpdServer::listen(PINetworkAddress addr) {
addr.port(),
nullptr,
nullptr,
(MHD_AccessHandlerCallback)answer_to_connection,
(MHD_AccessHandlerCallback)answer_callback,
this,
MHD_OPTION_ARRAY,
options.data(),
@@ -305,34 +354,14 @@ void MicrohttpdServer::stop() {
}
void MicrohttpdServer::Reply::addHeader(const PIString & header, const PIString & value) {
headers[header] = value;
}
void MicrohttpdServer::Reply::removeHeader(const PIString & header) {
headers.remove(header);
}
void MicrohttpdServer::Reply::setBody(const PIByteArray & b) {
body = b;
}
void MicrohttpdServer::Reply::setCode(int c) {
code = c;
}
void MicrohttpdServer::Reply::addFixedHeaders() {
if (!headers.contains(MHD_HTTP_HEADER_CONTENT_TYPE)) {
if (body.isNotEmpty()) {
if (body.startsWith(PIByteArray::fromAscii("<!DOCTYPE html>")))
addHeader(MHD_HTTP_HEADER_CONTENT_TYPE, "text/html; charset=utf-8");
else if (body[0] == '[' || body[0] == '{')
addHeader(MHD_HTTP_HEADER_CONTENT_TYPE, "application/json; charset=utf-8");
void MicrohttpdServer::addFixedHeaders(MessageMutable & msg) {
if (!msg.headers().contains(Header::ContentType)) {
if (msg.body().isNotEmpty()) {
if (msg.body().startsWith(PIByteArray::fromAscii("<!DOCTYPE html>")))
msg.addHeader(Header::ContentType, "text/html; charset=utf-8");
else if (msg.body()[0] == '[' || msg.body()[0] == '{')
msg.addHeader(Header::ContentType, "application/json; charset=utf-8");
}
}
addHeader(MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, "*");
msg.addHeader(Header::AccessControlAllowOrigin, "*");
}

View File

@@ -4,29 +4,29 @@
PIHTTPServer::PIHTTPServer() {
setRequestCallback([this](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
MicrohttpdServer::Reply rep;
rep.setCode(404);
auto in_path = r.path.split("/");
setRequestCallback([this](const PIHTTP::MessageConst & r) -> PIHTTP::MessageMutable {
PIHTTP::MessageMutable reply;
reply.setCode(PIHTTP::Code::NotFound);
auto in_path = r.path().split("/");
in_path.removeAll("");
auto it = functions.makeReverseIterator();
bool found = false;
while (it.next()) {
if (it.value().function) {
if (it.value().method == r.method) {
if (it.value().method == r.method()) {
if (it.value().match(in_path)) {
rep = it.value().function(r);
reply = it.value().function(r);
found = true;
break;
}
}
}
}
if (!found && unhandled) rep = unhandled(r);
if (!found && unhandled) reply = unhandled(r);
auto hit = reply_headers.makeIterator();
while (hit.next())
rep.addHeader(hit.key(), hit.value());
return rep;
reply.addHeader(hit.key(), hit.value());
return reply;
});
}
@@ -36,8 +36,8 @@ PIHTTPServer::~PIHTTPServer() {
}
void PIHTTPServer::registerPath(const PIString & path, Method method, RequestFunction functor) {
auto & ep(functions[path + PIString::fromNumber((int)method)]);
void PIHTTPServer::registerPath(const PIString & path, PIHTTP::Method method, RequestFunction functor) {
auto & ep(functions[path + PIString::fromNumber(static_cast<int>(method))]);
ep.path = path.split("/");
ep.method = method;
ep.function = functor;
@@ -50,7 +50,7 @@ void PIHTTPServer::registerUnhandled(RequestFunction functor) {
}
void PIHTTPServer::unregisterPath(const PIString & path, Method method) {
void PIHTTPServer::unregisterPath(const PIString & path, PIHTTP::Method method) {
auto pl = path.split("/");
pl.removeAll("");
auto it = functions.makeIterator();

View File

@@ -240,8 +240,8 @@ void PIBroadcast::stopRead() {
if (isRunning()) stopAndWait();
PIMutexLocker ml(mcast_mutex);
for (auto * e: eth_mcast)
e->stopAndWait();
if (eth_lo) eth_lo->stopAndWait();
e->stopAndWait(5_s);
if (eth_lo) eth_lo->stopAndWait(5_s);
_started = false;
}

View File

@@ -179,7 +179,7 @@ PICout PILog::makePICout(PIObject * context, Level cat) {
if (context->name().isNotEmpty()) *buffer += " \"" + context->name() + "\"";
*buffer += "] ";
}
return PICout::withExternalBuffer(buffer, id_by_cat.value(cat), PICoutManipulators::AddSpaces);
return PICout::withExternalBufferAndID(buffer, id_by_cat.value(cat), PICoutManipulators::AddSpaces);
}

View File

@@ -405,7 +405,7 @@ float PISystemMonitor::calcThreadUsage(PISystemTime & t_new, PISystemTime & t_ol
ullong PISystemMonitor::totalRAM() {
#ifdef ESP_PLATFORM
multi_heap_info_t heap_info;
memset(&heap_info, 0, sizeof(multi_heap_info_t));
piZeroMemory(heap_info);
heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT);
return heap_info.total_allocated_bytes + heap_info.total_free_bytes;
#endif
@@ -416,7 +416,7 @@ ullong PISystemMonitor::totalRAM() {
ullong PISystemMonitor::freeRAM() {
#ifdef ESP_PLATFORM
multi_heap_info_t heap_info;
memset(&heap_info, 0, sizeof(multi_heap_info_t));
piZeroMemory(heap_info);
heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT);
return heap_info.total_free_bytes;
#endif
@@ -427,7 +427,7 @@ ullong PISystemMonitor::freeRAM() {
ullong PISystemMonitor::usedRAM() {
#ifdef ESP_PLATFORM
multi_heap_info_t heap_info;
memset(&heap_info, 0, sizeof(multi_heap_info_t));
piZeroMemory(heap_info);
heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT);
return heap_info.total_allocated_bytes;
#endif

View File

@@ -20,12 +20,15 @@
#include "piincludes_p.h"
#include "piliterals.h"
#include "piwaitevent_p.h"
// clang-format off
#ifndef WINDOWS
# include <termios.h>
#else
# include <wincon.h>
# include <wingdi.h>
# include <wincon.h>
#endif
// clang-format on
/** \class PIKbdListener
* \brief Keyboard console input listener
@@ -144,6 +147,7 @@ PRIVATE_DEFINITION_START(PIKbdListener)
int
#endif
ret;
PIWaitEvent event;
PRIVATE_DEFINITION_END(PIKbdListener)
@@ -157,11 +161,11 @@ PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread()
#else
tcgetattr(0, &PRIVATE->sterm);
#endif
is_active = true;
ret_func = slot;
kbddata_ = _d;
dbl_interval = 400;
PIKbdListener::exiting = exit_enabled = false;
ret_func = slot;
kbddata_ = _d;
dbl_interval = 400;
PRIVATE->event.create();
PIKbdListener::exiting = false;
if (startNow) start();
}
@@ -169,7 +173,7 @@ PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread()
PIKbdListener::~PIKbdListener() {
stop();
if (!waitForFinish(100_ms)) terminate();
end();
PRIVATE->event.destroy();
}
@@ -216,7 +220,8 @@ PIKbdListener::MouseButtons getButtons(DWORD v) {
void PIKbdListener::readKeyboard() {
ke.key = 0;
ke.modifiers = 0;
memset(rc, 0, 8);
char rc[8];
piZeroMemory(rc, 8);
#ifdef WINDOWS
INPUT_RECORD ir;
ReadConsoleInput(PRIVATE->hIn, &ir, 1, &(PRIVATE->ret));
@@ -403,6 +408,7 @@ void PIKbdListener::readKeyboard() {
}
#else
tcsetattr(0, TCSANOW, &PRIVATE->tterm);
if (!PRIVATE->event.wait(0)) return;
PRIVATE->ret = read(0, rc, 8);
/*piCout << "key" << PIString(rc).replaceAll("\e", "\\e");
for (int i = 0; i < PRIVATE->ret; ++i)
@@ -542,6 +548,13 @@ void PIKbdListener::readKeyboard() {
void PIKbdListener::stop() {
PIThread::stop();
PRIVATE->event.interrupt();
}
bool PIKbdListener::stopAndWait(PISystemTime timeout) {
stop();
return waitForFinish(timeout);
}

View File

@@ -29,10 +29,12 @@
#include "pithread.h"
#include "pitime.h"
#define WAIT_FOR_EXIT \
while (!PIKbdListener::exiting) \
piMSleep(PIP_MIN_MSLEEP * 5); \
if (PIKbdListener::instance()) PIKbdListener::instance()->stopAndWait();
#define WAIT_FOR_EXIT \
while (!PIKbdListener::exiting) \
piMSleep(PIP_MIN_MSLEEP * 5); \
if (PIKbdListener::instance()) { \
if (!PIKbdListener::instance()->stopAndWait(PISystemTime::fromSeconds(1))) PIKbdListener::instance()->terminate(); \
}
class PIP_EXPORT PIKbdListener: public PIThread {
@@ -182,6 +184,8 @@ public:
void stop();
bool stopAndWait(PISystemTime timeout = {});
//! Returns if keyboard listening is active (not running!)
bool isActive() { return is_active; }
@@ -252,9 +256,8 @@ private:
PRIVATE_DECLARATION(PIP_EXPORT)
KBFunc ret_func;
int exit_key;
bool exit_enabled, is_active;
bool exit_enabled = false, is_active = true;
void * kbddata_;
char rc[8];
double dbl_interval;
PITimeMeasurer tm_dbl;
KeyEvent ke;

View File

@@ -22,8 +22,21 @@
#include "piliterals_bytes.h"
const size_t minAlloc = 64;
const size_t maxPoTAlloc = 64_MiB;
#if defined(PIP_CONTAINERS_MIN_ALLOC)
# define ACTUAL_MIN_ALLOC PIP_CONTAINERS_MIN_ALLOC
#else
# define ACTUAL_MIN_ALLOC 64
#endif
#if defined(PIP_CONTAINERS_MAX_POT_ALLOC)
# define ACTUAL_MAX_POT_ALLOC PIP_CONTAINERS_MAX_POT_ALLOC
#else
# define ACTUAL_MAX_POT_ALLOC 64_MiB
#endif
const size_t minAlloc = ACTUAL_MIN_ALLOC;
const size_t maxPoTAlloc = ACTUAL_MAX_POT_ALLOC;
size_t _PIContainerConstantsBase::calcMinCountPoT(size_t szof) {

View File

@@ -89,6 +89,26 @@ public:
static const size_t ret = _PIContainerConstantsBase::calcStepAfterPoT(sizeof(T));
return ret;
}
static size_t calcNewSize(size_t old_size, size_t new_size) {
if (new_size == 0) return 0;
if (new_size < maxCountForPoT()) {
if (old_size * 2 >= new_size && old_size < new_size) {
return old_size * 2;
}
ssize_t t = minCountPoT();
new_size -= 1;
while (new_size >> t)
++t;
return (1 << t);
} else {
size_t ret = old_size;
while (ret < new_size)
ret += stepAfterPoT();
return ret;
}
return 0;
}
};

View File

@@ -1494,11 +1494,11 @@ public:
//! \~\details
//! \~english The order of equal elements is not guaranteed to be preserved.
//! Elements are compared using operator<.
//! Sorting provided by [std::sort](https://en.cppreference.com/w/cpp/algorithm/sort).
//! Sorting provided by [std::stable_sort](https://en.cppreference.com/w/cpp/algorithm/stable_sort).
//! Complexity `O(N·log(N))`.
//! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется.
//! Для сравнения элементов используется оператор `operator<`.
//! Для сортировки используется функция [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort).
//! Для сортировки используется функция [std::stable_sort](https://ru.cppreference.com/w/cpp/algorithm/stable_sort).
//! Сложность сортировки `O(N·log(N))`.
//! \~\code
//! PIDeque<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
@@ -1507,7 +1507,7 @@ public:
//! \endcode
//! \~\sa \a sort(std::function<bool(const T &a, const T &b)> comp)
inline PIDeque<T> & sort() {
std::sort(begin(), end());
std::stable_sort(begin(), end());
return *this;
}
@@ -1524,7 +1524,7 @@ public:
//! While the signature does not need to have const &, the function must not modify the objects passed to it.
//! The function must return `false` for identical elements,
//! otherwise, it will lead to undefined program behavior and memory errors.
//! Sorting provided by [std::sort](https://en.cppreference.com/w/cpp/algorithm/sort).
//! Sorting provided by [std::stable_sort](https://en.cppreference.com/w/cpp/algorithm/stable_sort).
//! Complexity `O(N·log(N))`.
//! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется.
//! Для сравнения элементов используется функция сравнения `comp`.
@@ -1532,7 +1532,7 @@ public:
//! второго. Сигнатура функции сравнения должна быть эквивалентна следующей: \code bool comp(const T &a, const T &b); \endcode Сигнатура
//! не обязана содержать const &, однако, функция не может изменять переданные объекты. Функция обязана возвращать `false` для
//! одинаковых элементов, иначе это приведёт к неопределённому поведению программы и ошибкам памяти. Для сортировки используется функция
//! [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort). Сложность сортировки `O(N·log(N))`.
//! [std::stable_sort](https://ru.cppreference.com/w/cpp/algorithm/stable_sort). Сложность сортировки `O(N·log(N))`.
//! \~\code
//! PIDeque<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
//! v.sort([](const int & a, const int & b){return a > b;});
@@ -1540,7 +1540,7 @@ public:
//! \endcode
//! \~\sa \a sort()
inline PIDeque<T> & sort(std::function<bool(const T & a, const T & b)> comp) {
std::sort(begin(), end(), comp);
std::stable_sort(begin(), end(), comp);
return *this;
}
@@ -2575,27 +2575,6 @@ private:
pid_data = nullptr;
}
inline size_t asize(ssize_t ss) {
if (ss <= 0) return 0;
size_t s = ss;
if (s < _PIContainerConstants<T>::maxCountForPoT()) {
if (pid_rsize * 2 >= s && pid_rsize < s) {
return pid_rsize * 2;
}
ssize_t t = _PIContainerConstants<T>::minCountPoT();
s -= 1;
while (s >> t)
++t;
return (1 << t);
} else {
size_t ret = pid_rsize;
while (ret < s)
ret += _PIContainerConstants<T>::stepAfterPoT();
return ret;
}
return 0;
}
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void newT(T * dst, const T * src, size_t s) {
PIINTROSPECTION_CONTAINER_USED(T, s)
@@ -2690,35 +2669,38 @@ private:
if (pid_start > 0) checkMove();
return;
}
pid_size = new_size;
const size_t as = asize(pid_start + new_size);
if (as != pid_rsize) {
pid_size = new_size;
const size_t new_rsize = _PIContainerConstants<T>::calcNewSize(pid_rsize, pid_start + new_size);
if (new_rsize != pid_rsize) {
PIINTROSPECTION_CONTAINER_ALLOC(T, (as - pid_rsize))
T * p_d = reinterpret_cast<T *>(realloc(reinterpret_cast<void *>(pid_data), as * sizeof(T)));
T * new_data = reinterpret_cast<T *>(realloc(reinterpret_cast<void *>(pid_data), new_rsize * sizeof(T)));
#ifndef NDEBUG
if (!p_d) {
if (!new_data) {
fprintf(stderr, "error with PIDeque<%s>::alloc\n", __PIP_TYPENAME__(T));
}
#endif
assert(p_d);
pid_data = p_d;
pid_rsize = as;
assert(new_data);
pid_data = new_data;
pid_rsize = new_rsize;
}
}
inline void alloc_backward(size_t new_size, ssize_t start_offset = 0) {
const size_t as = ssize_t(pid_start) + start_offset < 0 ? asize(pid_rsize - start_offset) : pid_rsize;
if (as > pid_rsize) {
T * td = reinterpret_cast<T *>(malloc(as * sizeof(T)));
const size_t ns = pid_start + as - pid_rsize;
const size_t new_rsize =
ssize_t(pid_start) + start_offset < 0 ? _PIContainerConstants<T>::calcNewSize(pid_rsize, pid_rsize - start_offset) : pid_rsize;
if (new_rsize > pid_rsize) {
T * tmp_data = reinterpret_cast<T *>(malloc(new_rsize * sizeof(T)));
const size_t new_start = pid_start + new_rsize - pid_rsize;
PIINTROSPECTION_CONTAINER_ALLOC(T, (as - pid_rsize))
if (pid_rsize > 0 && pid_data != 0) {
memcpy(reinterpret_cast<void *>(td + ns), reinterpret_cast<const void *>(pid_data + pid_start), pid_size * sizeof(T));
if (pid_rsize > 0 && pid_data) {
memcpy(reinterpret_cast<void *>(tmp_data + new_start),
reinterpret_cast<const void *>(pid_data + pid_start),
pid_size * sizeof(T));
dealloc();
}
pid_data = td;
pid_rsize = as;
pid_start = ns;
pid_data = tmp_data;
pid_rsize = new_rsize;
pid_start = new_start;
}
pid_start += start_offset;
pid_size = new_size;

View File

@@ -1420,11 +1420,11 @@ public:
//! \~\details
//! \~english The order of equal elements is not guaranteed to be preserved.
//! Elements are compared using operator<.
//! Sorting provided by [std::sort](https://en.cppreference.com/w/cpp/algorithm/sort).
//! Sorting provided by [std::stable_sort](https://en.cppreference.com/w/cpp/algorithm/stable_sort).
//! Complexity `O(N·log(N))`.
//! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется.
//! Для сравнения элементов используется оператор `operator<`.
//! Для сортировки используется функция [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort).
//! Для сортировки используется функция [std::stable_sort](https://ru.cppreference.com/w/cpp/algorithm/stable_sort).
//! Сложность сортировки `O(N·log(N))`.
//! \~\code
//! PIVector<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
@@ -1433,7 +1433,7 @@ public:
//! \endcode
//! \~\sa \a sort(std::function<bool(const T &a, const T &b)> comp)
inline PIVector<T> & sort() {
std::sort(begin(), end());
std::stable_sort(begin(), end());
return *this;
}
@@ -1450,7 +1450,7 @@ public:
//! While the signature does not need to have const &, the function must not modify the objects passed to it.
//! The function must return `false` for identical elements,
//! otherwise, it will lead to undefined program behavior and memory errors.
//! Sorting provided by [std::sort](https://en.cppreference.com/w/cpp/algorithm/sort).
//! Sorting provided by [std::stable_sort](https://en.cppreference.com/w/cpp/algorithm/stable_sort).
//! Complexity `O(N·log(N))`.
//! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется.
//! Для сравнения элементов используется функция сравнения `comp`.
@@ -1458,7 +1458,7 @@ public:
//! второго. Сигнатура функции сравнения должна быть эквивалентна следующей: \code bool comp(const T &a, const T &b); \endcode Сигнатура
//! не обязана содержать const &, однако, функция не может изменять переданные объекты. Функция обязана возвращать `false` для
//! одинаковых элементов, иначе это приведёт к неопределённому поведению программы и ошибкам памяти. Для сортировки используется функция
//! [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort). Сложность сортировки `O(N·log(N))`.
//! [std::stable_sort](https://ru.cppreference.com/w/cpp/algorithm/stable_sort). Сложность сортировки `O(N·log(N))`.
//! \~\code
//! PIVector<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
//! v.sort([](const int & a, const int & b){return a > b;});
@@ -1466,7 +1466,7 @@ public:
//! \endcode
//! \~\sa \a sort()
inline PIVector<T> & sort(std::function<bool(const T & a, const T & b)> comp) {
std::sort(begin(), end(), comp);
std::stable_sort(begin(), end(), comp);
return *this;
}
@@ -2459,26 +2459,6 @@ private:
piv_data = nullptr;
}
inline size_t asize(size_t s) {
if (s == 0) return 0;
if (s < _PIContainerConstants<T>::maxCountForPoT()) {
if (piv_rsize * 2 >= s && piv_rsize < s) {
return piv_rsize * 2;
}
ssize_t t = _PIContainerConstants<T>::minCountPoT();
s -= 1;
while (s >> t)
++t;
return (1 << t);
} else {
size_t ret = piv_rsize;
while (ret < s)
ret += _PIContainerConstants<T>::stepAfterPoT();
return ret;
}
return 0;
}
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void newT(T * dst, const T * src, size_t s) {
PIINTROSPECTION_CONTAINER_USED(T, s)
@@ -2566,19 +2546,19 @@ private:
piv_size = new_size;
return;
}
piv_size = new_size;
const size_t as = asize(new_size);
if (as == piv_rsize) return;
piv_size = new_size;
const size_t new_rsize = _PIContainerConstants<T>::calcNewSize(piv_rsize, new_size);
if (new_rsize == piv_rsize) return;
PIINTROSPECTION_CONTAINER_ALLOC(T, (as - piv_rsize))
T * p_d = reinterpret_cast<T *>(realloc(reinterpret_cast<void *>(piv_data), as * sizeof(T)));
T * new_data = reinterpret_cast<T *>(realloc(reinterpret_cast<void *>(piv_data), new_rsize * sizeof(T)));
#ifndef NDEBUG
if (!p_d) {
if (!new_data) {
fprintf(stderr, "error with PIVector<%s>::alloc\n", __PIP_TYPENAME__(T));
}
#endif
assert(p_d);
piv_data = p_d;
piv_rsize = as;
assert(new_data);
piv_data = new_data;
piv_rsize = new_rsize;
}
T * piv_data = nullptr;

View File

@@ -46,6 +46,7 @@
#include <atomic>
#include <cassert>
#include <cstddef>
#include <cstdio>
#include <functional>
#include <initializer_list>
#include <limits>
@@ -558,6 +559,23 @@ inline uint piHash(const ldouble & v) {
return piHashData((const uchar *)&v, sizeof(v));
}
//! \~\brief
//! \~english Zero "size" bytes by address "ptr".
//! \~russian Зануляет "size" байт по адресу "ptr".
inline void piZeroMemory(void * ptr, size_t size) {
memset(ptr, 0, size);
}
//! \~\brief
//! \~english Zero variable "v" memory.
//! \~russian Зануляет память переменной "v".
template<typename T>
inline void piZeroMemory(T & v) {
piZeroMemory(&v, sizeof(v));
}
//! \~\brief
//! \~english Call \b delete on each "container" element.
//! \~russian Вызывает \b delete на каждый элемент "container".

View File

@@ -28,7 +28,6 @@
# include <locale>
#endif
#ifdef WINDOWS
# include <wincon.h>
# include <windows.h>
# include <wingdi.h>
# define COMMON_LVB_UNDERSCORE 0x8000
@@ -208,7 +207,7 @@ PICout::~PICout() {
PICout::__mutex__().unlock();
}
if (buffer_) {
((NotifierObject *)Notifier::object())->finished(id_, buffer_);
if (id_ >= 0) ((NotifierObject *)Notifier::object())->finished(id_, buffer_);
} else {
getStdStream(stream_).flush();
}
@@ -748,7 +747,12 @@ bool PICout::isOutputDeviceActive(PICout::OutputDevice d) {
}
PICout PICout::withExternalBuffer(PIString * buffer, int id, PIFlags<PICoutManipulators::PICoutControl> controls) {
PICout PICout::withExternalBuffer(PIString * buffer, PIFlags<PICoutManipulators::PICoutControl> controls) {
return withExternalBufferAndID(buffer, -1, controls);
}
PICout PICout::withExternalBufferAndID(PIString * buffer, int id, PIFlags<PICoutManipulators::PICoutControl> controls) {
PICout c(controls);
c.buffer_ = buffer;
c.id_ = id;

View File

@@ -30,15 +30,24 @@
#ifdef DOXYGEN
//! \~english Macro used for conditional (piDebug) output to PICout
//! \~russian Макрос для условного (piDebug) вывода в PICout
//! \~english Macro used for conditional (piDebug) output to PICout(StdOut)
//! \~russian Макрос для условного (piDebug) вывода в PICout(StdOut)
# define piCout
//! \~english Macro used for conditional (piDebug) output to PICout(StdErr)
//! \~russian Макрос для условного (piDebug) вывода в PICout(StdErr)
# define piCerr
//! \relatesalso PIObject
//! \~english Macro used for conditional (piDebug && PIObject::debug()) output to PICout for subclasses of PIObject
//! \~russian Макрос для условного (piDebug && PIObject::debug()) вывода в PICout для наследников PIObject
//! \~english Macro used for conditional (piDebug && PIObject::debug()) output to PICout(StdOut) for subclasses of PIObject
//! \~russian Макрос для условного (piDebug && PIObject::debug()) вывода в PICout(StdOut) для наследников PIObject
# define piCoutObj
//! \relatesalso PIObject
//! \~english Macro used for conditional (piDebug && PIObject::debug()) output to PICout(StdErr) for subclasses of PIObject
//! \~russian Макрос для условного (piDebug && PIObject::debug()) вывода в PICout(StdErr) для наследников PIObject
# define piCerrObj
#else
# define piCout PICout(piDebug, PICoutStdStream::StdOut)
# define piCoutObj \
@@ -375,15 +384,19 @@ public:
static bool isOutputDeviceActive(OutputDevice d);
//! \~english Construct with external buffer.
//! \~russian Конструктор с внешним буфером.
static PICout withExternalBuffer(PIString * buffer,
PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::AddSpaces);
//! \~english Construct with external buffer and ID "id". See \a Notifier for details
//! \~russian Конструктор с внешним буфером и ID "id". Подробнее \a Notifier
static PICout withExternalBuffer(PIString * buffer,
int id = 0,
PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::AddSpaces |
PICoutManipulators::AddNewLine);
static PICout withExternalBufferAndID(PIString * buffer,
int id,
PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::DefaultControls);
//! \~english Returns unique external buffer ID for later use in \a withExternalBuffer()
//! \~russian Возвращает уникальный ID для внешнего буфера для дальнейшего использования в \a withExternalBuffer()
//! \~english Returns unique external buffer ID for later use in \a withExternalBufferAndID()
//! \~russian Возвращает уникальный ID для внешнего буфера для дальнейшего использования в \a withExternalBufferAndID()
static int registerExternalBufferID();
static PIMutex & __mutex__();
@@ -397,7 +410,7 @@ private:
static OutputDevices devs;
PRIVATE_DECLARATION(PIP_EXPORT)
bool first_out_ = true, is_copy_ = false, format_changed_ = false, actve_ = true;
int int_base_ = 10, win_attr_ = 0, id_ = 0;
int int_base_ = 10, win_attr_ = 0, id_ = -1;
PIString * buffer_ = nullptr;
PICoutManipulators::PICoutControls ctrl_ = PICoutManipulators::DefaultControls;
PICoutStdStream stream_ = PICoutStdStream::StdOut;

View File

@@ -167,7 +167,7 @@ PIInit::PIInit() {
for (l = 0; l < MAX_PATH; ++l)
if (cpinfo.CodePageName[l] == '\0' || cpinfo.CodePageName[l] == ' ') break;
__sysoemname__ = new char[256];
memset(__sysoemname__, 0, 256);
piZeroMemory(__sysoemname__, 256);
memcpy(__sysoemname__, "ibm-", 4);
memcpy(&(__sysoemname__[4]), cpinfo.CodePageName, l);
# else
@@ -190,7 +190,7 @@ PIInit::PIInit() {
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &__pi_mac_clock);
# endif
char cbuff[1024];
memset(cbuff, 0, 1024);
piZeroMemory(cbuff, 1024);
if (gethostname(cbuff, 1023) == 0) {
sinfo->hostname = cbuff;
}
@@ -210,7 +210,7 @@ PIInit::PIInit() {
wchar_t ** argv_ = CommandLineToArgvW(GetCommandLineW(), &argc_);
if (argc_ > 0 && argv_ != 0) sinfo->execCommand = argv_[0];
LocalFree(argv_);
memset(cbuff, 0, 1024);
piZeroMemory(cbuff, 1024);
ulong unlen = 1023;
if (GetUserNameA(cbuff, &unlen) != 0) sinfo->user = cbuff;
# else // WINDOWS
@@ -219,7 +219,7 @@ PIInit::PIInit() {
if (ps)
sinfo->user = ps->pw_name;
else {
memset(cbuff, 0, 1024);
piZeroMemory(cbuff, 1024);
char * l = getlogin();
if (l) sinfo->user = l;
}

View File

@@ -46,7 +46,7 @@ void PIWaitEvent::create() {
}
#else
for (int i = 0; i < 3; ++i)
memset(&(fds[i]), 0, sizeof(fds[i]));
piZeroMemory(fds[i]);
if (::pipe(pipe_fd) < 0) {
piCout << "Error with pipe:" << errorString();
} else {
@@ -129,7 +129,8 @@ void PIWaitEvent::interrupt() {
#ifdef WINDOWS
SetEvent(event);
#else
::write(pipe_fd[WriteEnd], "", 1);
auto _r = ::write(pipe_fd[WriteEnd], "", 1);
NO_UNUSED(_r);
#endif
}

View File

@@ -0,0 +1,160 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#ifndef BLAKE2_IMPL_H
#define BLAKE2_IMPL_H
#include <stdint.h>
#include <string.h>
#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
#if defined(_MSC_VER)
#define BLAKE2_INLINE __inline
#elif defined(__GNUC__)
#define BLAKE2_INLINE __inline__
#else
#define BLAKE2_INLINE
#endif
#else
#define BLAKE2_INLINE inline
#endif
static BLAKE2_INLINE uint32_t load32( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
uint32_t w;
memcpy(&w, src, sizeof w);
return w;
#else
const uint8_t *p = ( const uint8_t * )src;
return (( uint32_t )( p[0] ) << 0) |
(( uint32_t )( p[1] ) << 8) |
(( uint32_t )( p[2] ) << 16) |
(( uint32_t )( p[3] ) << 24) ;
#endif
}
static BLAKE2_INLINE uint64_t load64( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
uint64_t w;
memcpy(&w, src, sizeof w);
return w;
#else
const uint8_t *p = ( const uint8_t * )src;
return (( uint64_t )( p[0] ) << 0) |
(( uint64_t )( p[1] ) << 8) |
(( uint64_t )( p[2] ) << 16) |
(( uint64_t )( p[3] ) << 24) |
(( uint64_t )( p[4] ) << 32) |
(( uint64_t )( p[5] ) << 40) |
(( uint64_t )( p[6] ) << 48) |
(( uint64_t )( p[7] ) << 56) ;
#endif
}
static BLAKE2_INLINE uint16_t load16( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
uint16_t w;
memcpy(&w, src, sizeof w);
return w;
#else
const uint8_t *p = ( const uint8_t * )src;
return ( uint16_t )((( uint32_t )( p[0] ) << 0) |
(( uint32_t )( p[1] ) << 8));
#endif
}
static BLAKE2_INLINE void store16( void *dst, uint16_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
memcpy(dst, &w, sizeof w);
#else
uint8_t *p = ( uint8_t * )dst;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w;
#endif
}
static BLAKE2_INLINE void store32( void *dst, uint32_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
memcpy(dst, &w, sizeof w);
#else
uint8_t *p = ( uint8_t * )dst;
p[0] = (uint8_t)(w >> 0);
p[1] = (uint8_t)(w >> 8);
p[2] = (uint8_t)(w >> 16);
p[3] = (uint8_t)(w >> 24);
#endif
}
static BLAKE2_INLINE void store64( void *dst, uint64_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
memcpy(dst, &w, sizeof w);
#else
uint8_t *p = ( uint8_t * )dst;
p[0] = (uint8_t)(w >> 0);
p[1] = (uint8_t)(w >> 8);
p[2] = (uint8_t)(w >> 16);
p[3] = (uint8_t)(w >> 24);
p[4] = (uint8_t)(w >> 32);
p[5] = (uint8_t)(w >> 40);
p[6] = (uint8_t)(w >> 48);
p[7] = (uint8_t)(w >> 56);
#endif
}
static BLAKE2_INLINE uint64_t load48( const void *src )
{
const uint8_t *p = ( const uint8_t * )src;
return (( uint64_t )( p[0] ) << 0) |
(( uint64_t )( p[1] ) << 8) |
(( uint64_t )( p[2] ) << 16) |
(( uint64_t )( p[3] ) << 24) |
(( uint64_t )( p[4] ) << 32) |
(( uint64_t )( p[5] ) << 40) ;
}
static BLAKE2_INLINE void store48( void *dst, uint64_t w )
{
uint8_t *p = ( uint8_t * )dst;
p[0] = (uint8_t)(w >> 0);
p[1] = (uint8_t)(w >> 8);
p[2] = (uint8_t)(w >> 16);
p[3] = (uint8_t)(w >> 24);
p[4] = (uint8_t)(w >> 32);
p[5] = (uint8_t)(w >> 40);
}
static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c )
{
return ( w >> c ) | ( w << ( 32 - c ) );
}
static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c )
{
return ( w >> c ) | ( w << ( 64 - c ) );
}
/* prevents compiler optimizing out memset() */
static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n)
{
static void *(*const volatile memset_v)(void *, int, size_t) = &memset;
memset_v(v, 0, n);
}
#endif

View File

@@ -0,0 +1,195 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#ifndef BLAKE2_H
#define BLAKE2_H
#include <stddef.h>
#include <stdint.h>
#if defined(_MSC_VER)
#define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop))
#else
#define BLAKE2_PACKED(x) x __attribute__((packed))
#endif
#if defined(__cplusplus)
extern "C" {
#endif
enum blake2s_constant
{
BLAKE2S_BLOCKBYTES = 64,
BLAKE2S_OUTBYTES = 32,
BLAKE2S_KEYBYTES = 32,
BLAKE2S_SALTBYTES = 8,
BLAKE2S_PERSONALBYTES = 8
};
enum blake2b_constant
{
BLAKE2B_BLOCKBYTES = 128,
BLAKE2B_OUTBYTES = 64,
BLAKE2B_KEYBYTES = 64,
BLAKE2B_SALTBYTES = 16,
BLAKE2B_PERSONALBYTES = 16
};
typedef struct blake2s_state__
{
uint32_t h[8];
uint32_t t[2];
uint32_t f[2];
uint8_t buf[BLAKE2S_BLOCKBYTES];
size_t buflen;
size_t outlen;
uint8_t last_node;
} blake2s_state;
typedef struct blake2b_state__
{
uint64_t h[8];
uint64_t t[2];
uint64_t f[2];
uint8_t buf[BLAKE2B_BLOCKBYTES];
size_t buflen;
size_t outlen;
uint8_t last_node;
} blake2b_state;
typedef struct blake2sp_state__
{
blake2s_state S[8][1];
blake2s_state R[1];
uint8_t buf[8 * BLAKE2S_BLOCKBYTES];
size_t buflen;
size_t outlen;
} blake2sp_state;
typedef struct blake2bp_state__
{
blake2b_state S[4][1];
blake2b_state R[1];
uint8_t buf[4 * BLAKE2B_BLOCKBYTES];
size_t buflen;
size_t outlen;
} blake2bp_state;
BLAKE2_PACKED(struct blake2s_param__
{
uint8_t digest_length; /* 1 */
uint8_t key_length; /* 2 */
uint8_t fanout; /* 3 */
uint8_t depth; /* 4 */
uint32_t leaf_length; /* 8 */
uint32_t node_offset; /* 12 */
uint16_t xof_length; /* 14 */
uint8_t node_depth; /* 15 */
uint8_t inner_length; /* 16 */
/* uint8_t reserved[0]; */
uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */
uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */
});
typedef struct blake2s_param__ blake2s_param;
BLAKE2_PACKED(struct blake2b_param__
{
uint8_t digest_length; /* 1 */
uint8_t key_length; /* 2 */
uint8_t fanout; /* 3 */
uint8_t depth; /* 4 */
uint32_t leaf_length; /* 8 */
uint32_t node_offset; /* 12 */
uint32_t xof_length; /* 16 */
uint8_t node_depth; /* 17 */
uint8_t inner_length; /* 18 */
uint8_t reserved[14]; /* 32 */
uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */
uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */
});
typedef struct blake2b_param__ blake2b_param;
typedef struct blake2xs_state__
{
blake2s_state S[1];
blake2s_param P[1];
} blake2xs_state;
typedef struct blake2xb_state__
{
blake2b_state S[1];
blake2b_param P[1];
} blake2xb_state;
/* Padded structs result in a compile-time error */
enum {
BLAKE2_DUMMY_1 = 1/(int)(sizeof(blake2s_param) == BLAKE2S_OUTBYTES),
BLAKE2_DUMMY_2 = 1/(int)(sizeof(blake2b_param) == BLAKE2B_OUTBYTES)
};
/* Streaming API */
int blake2s_init( blake2s_state *S, size_t outlen );
int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen );
int blake2s_init_param( blake2s_state *S, const blake2s_param *P );
int blake2s_update( blake2s_state *S, const void *in, size_t inlen );
int blake2s_final( blake2s_state *S, void *out, size_t outlen );
int blake2b_init( blake2b_state *S, size_t outlen );
int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen );
int blake2b_init_param( blake2b_state *S, const blake2b_param *P );
int blake2b_update( blake2b_state *S, const void *in, size_t inlen );
int blake2b_final( blake2b_state *S, void *out, size_t outlen );
int blake2sp_init( blake2sp_state *S, size_t outlen );
int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen );
int blake2sp_update( blake2sp_state *S, const void *in, size_t inlen );
int blake2sp_final( blake2sp_state *S, void *out, size_t outlen );
int blake2bp_init( blake2bp_state *S, size_t outlen );
int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen );
int blake2bp_update( blake2bp_state *S, const void *in, size_t inlen );
int blake2bp_final( blake2bp_state *S, void *out, size_t outlen );
/* Variable output length API */
int blake2xs_init( blake2xs_state *S, const size_t outlen );
int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen );
int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen );
int blake2xs_final(blake2xs_state *S, void *out, size_t outlen);
int blake2xb_init( blake2xb_state *S, const size_t outlen );
int blake2xb_init_key( blake2xb_state *S, const size_t outlen, const void *key, size_t keylen );
int blake2xb_update( blake2xb_state *S, const void *in, size_t inlen );
int blake2xb_final(blake2xb_state *S, void *out, size_t outlen);
/* Simple API */
int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2xs( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2xb( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
/* This is simply an alias for blake2b */
int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
#if defined(__cplusplus)
}
#endif
#endif

View File

@@ -0,0 +1,379 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
static const uint64_t blake2b_IV[8] =
{
0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
};
static const uint8_t blake2b_sigma[12][16] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
};
static void blake2b_set_lastnode( blake2b_state *S )
{
S->f[1] = (uint64_t)-1;
}
/* Some helper functions, not necessarily useful */
static int blake2b_is_lastblock( const blake2b_state *S )
{
return S->f[0] != 0;
}
static void blake2b_set_lastblock( blake2b_state *S )
{
if( S->last_node ) blake2b_set_lastnode( S );
S->f[0] = (uint64_t)-1;
}
static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc )
{
S->t[0] += inc;
S->t[1] += ( S->t[0] < inc );
}
static void blake2b_init0( blake2b_state *S )
{
size_t i;
memset( S, 0, sizeof( blake2b_state ) );
for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i];
}
/* init xors IV with input parameter block */
int blake2b_init_param( blake2b_state *S, const blake2b_param *P )
{
const uint8_t *p = ( const uint8_t * )( P );
size_t i;
blake2b_init0( S );
/* IV XOR ParamBlock */
for( i = 0; i < 8; ++i )
S->h[i] ^= load64( p + sizeof( S->h[i] ) * i );
S->outlen = P->digest_length;
return 0;
}
int blake2b_init( blake2b_state *S, size_t outlen )
{
blake2b_param P[1];
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
P->digest_length = (uint8_t)outlen;
P->key_length = 0;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store32( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = 0;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2b_init_param( S, P );
}
int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen )
{
blake2b_param P[1];
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store32( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = 0;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
if( blake2b_init_param( S, P ) < 0 ) return -1;
{
uint8_t block[BLAKE2B_BLOCKBYTES];
memset( block, 0, BLAKE2B_BLOCKBYTES );
memcpy( block, key, keylen );
blake2b_update( S, block, BLAKE2B_BLOCKBYTES );
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
#define G(r,i,a,b,c,d) \
do { \
a = a + b + m[blake2b_sigma[r][2*i+0]]; \
d = rotr64(d ^ a, 32); \
c = c + d; \
b = rotr64(b ^ c, 24); \
a = a + b + m[blake2b_sigma[r][2*i+1]]; \
d = rotr64(d ^ a, 16); \
c = c + d; \
b = rotr64(b ^ c, 63); \
} while(0)
#define ROUND(r) \
do { \
G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
G(r,2,v[ 2],v[ 6],v[10],v[14]); \
G(r,3,v[ 3],v[ 7],v[11],v[15]); \
G(r,4,v[ 0],v[ 5],v[10],v[15]); \
G(r,5,v[ 1],v[ 6],v[11],v[12]); \
G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
} while(0)
static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] )
{
uint64_t m[16];
uint64_t v[16];
size_t i;
for( i = 0; i < 16; ++i ) {
m[i] = load64( block + i * sizeof( m[i] ) );
}
for( i = 0; i < 8; ++i ) {
v[i] = S->h[i];
}
v[ 8] = blake2b_IV[0];
v[ 9] = blake2b_IV[1];
v[10] = blake2b_IV[2];
v[11] = blake2b_IV[3];
v[12] = blake2b_IV[4] ^ S->t[0];
v[13] = blake2b_IV[5] ^ S->t[1];
v[14] = blake2b_IV[6] ^ S->f[0];
v[15] = blake2b_IV[7] ^ S->f[1];
ROUND( 0 );
ROUND( 1 );
ROUND( 2 );
ROUND( 3 );
ROUND( 4 );
ROUND( 5 );
ROUND( 6 );
ROUND( 7 );
ROUND( 8 );
ROUND( 9 );
ROUND( 10 );
ROUND( 11 );
for( i = 0; i < 8; ++i ) {
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
}
}
#undef G
#undef ROUND
int blake2b_update( blake2b_state *S, const void *pin, size_t inlen )
{
const unsigned char * in = (const unsigned char *)pin;
if( inlen > 0 )
{
size_t left = S->buflen;
size_t fill = BLAKE2B_BLOCKBYTES - left;
if( inlen > fill )
{
S->buflen = 0;
memcpy( S->buf + left, in, fill ); /* Fill buffer */
blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
blake2b_compress( S, S->buf ); /* Compress */
in += fill; inlen -= fill;
while(inlen > BLAKE2B_BLOCKBYTES) {
blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
blake2b_compress( S, in );
in += BLAKE2B_BLOCKBYTES;
inlen -= BLAKE2B_BLOCKBYTES;
}
}
memcpy( S->buf + S->buflen, in, inlen );
S->buflen += inlen;
}
return 0;
}
int blake2b_final( blake2b_state *S, void *out, size_t outlen )
{
uint8_t buffer[BLAKE2B_OUTBYTES] = {0};
size_t i;
if( out == NULL || outlen < S->outlen )
return -1;
if( blake2b_is_lastblock( S ) )
return -1;
blake2b_increment_counter( S, S->buflen );
blake2b_set_lastblock( S );
memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */
blake2b_compress( S, S->buf );
for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */
store64( buffer + sizeof( S->h[i] ) * i, S->h[i] );
memcpy( out, buffer, S->outlen );
secure_zero_memory(buffer, sizeof(buffer));
return 0;
}
/* inlen, at least, should be uint64_t. Others can be size_t. */
int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
{
blake2b_state S[1];
/* Verify parameters */
if ( NULL == in && inlen > 0 ) return -1;
if ( NULL == out ) return -1;
if( NULL == key && keylen > 0 ) return -1;
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
if( keylen > BLAKE2B_KEYBYTES ) return -1;
if( keylen > 0 )
{
if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1;
}
else
{
if( blake2b_init( S, outlen ) < 0 ) return -1;
}
blake2b_update( S, ( const uint8_t * )in, inlen );
blake2b_final( S, out, outlen );
return 0;
}
int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) {
return blake2b(out, outlen, in, inlen, key, keylen);
}
#if defined(SUPERCOP)
int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen )
{
return blake2b( out, BLAKE2B_OUTBYTES, in, inlen, NULL, 0 );
}
#endif
#if defined(BLAKE2B_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2B_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step;
for( i = 0; i < BLAKE2B_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
/* Test simple API */
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2B_OUTBYTES];
blake2b( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES );
if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) {
for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
uint8_t hash[BLAKE2B_OUTBYTES];
blake2b_state S;
uint8_t * p = buf;
size_t mlen = i;
int err = 0;
if( (err = blake2b_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2b_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2b_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2b_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -0,0 +1,359 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#if defined(_OPENMP)
#include <omp.h>
#endif
#include "blake2.h"
#include "blake2-impl.h"
#define PARALLELISM_DEGREE 4
/*
blake2b_init_param defaults to setting the expecting output length
from the digest_length parameter block field.
In some cases, however, we do not want this, as the output length
of these instances is given by inner_length instead.
*/
static int blake2bp_init_leaf_param( blake2b_state *S, const blake2b_param *P )
{
int err = blake2b_init_param(S, P);
S->outlen = P->inner_length;
return err;
}
static int blake2bp_init_leaf( blake2b_state *S, size_t outlen, size_t keylen, uint64_t offset )
{
blake2b_param P[1];
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, offset );
store32( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = BLAKE2B_OUTBYTES;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2bp_init_leaf_param( S, P );
}
static int blake2bp_init_root( blake2b_state *S, size_t outlen, size_t keylen )
{
blake2b_param P[1];
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store32( &P->xof_length, 0 );
P->node_depth = 1;
P->inner_length = BLAKE2B_OUTBYTES;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2b_init_param( S, P );
}
int blake2bp_init( blake2bp_state *S, size_t outlen )
{
size_t i;
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
S->outlen = outlen;
if( blake2bp_init_root( S->R, outlen, 0 ) < 0 )
return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2bp_init_leaf( S->S[i], outlen, 0, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
return 0;
}
int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen )
{
size_t i;
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
if( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
S->outlen = outlen;
if( blake2bp_init_root( S->R, outlen, keylen ) < 0 )
return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2bp_init_leaf( S->S[i], outlen, keylen, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
{
uint8_t block[BLAKE2B_BLOCKBYTES];
memset( block, 0, BLAKE2B_BLOCKBYTES );
memcpy( block, key, keylen );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S->S[i], block, BLAKE2B_BLOCKBYTES );
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
int blake2bp_update( blake2bp_state *S, const void *pin, size_t inlen )
{
const unsigned char * in = (const unsigned char *)pin;
size_t left = S->buflen;
size_t fill = sizeof( S->buf ) - left;
size_t i;
if( left && inlen >= fill )
{
memcpy( S->buf + left, in, fill );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S->S[i], S->buf + i * BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES );
in += fill;
inlen -= fill;
left = 0;
}
#if defined(_OPENMP)
#pragma omp parallel shared(S), num_threads(PARALLELISM_DEGREE)
#else
for( i = 0; i < PARALLELISM_DEGREE; ++i )
#endif
{
#if defined(_OPENMP)
size_t i = omp_get_thread_num();
#endif
size_t inlen__ = inlen;
const unsigned char *in__ = ( const unsigned char * )in;
in__ += i * BLAKE2B_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES )
{
blake2b_update( S->S[i], in__, BLAKE2B_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
}
}
in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES );
inlen %= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
if( inlen > 0 )
memcpy( S->buf + left, in, inlen );
S->buflen = left + inlen;
return 0;
}
int blake2bp_final( blake2bp_state *S, void *out, size_t outlen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2B_OUTBYTES];
size_t i;
if(out == NULL || outlen < S->outlen) {
return -1;
}
for( i = 0; i < PARALLELISM_DEGREE; ++i )
{
if( S->buflen > i * BLAKE2B_BLOCKBYTES )
{
size_t left = S->buflen - i * BLAKE2B_BLOCKBYTES;
if( left > BLAKE2B_BLOCKBYTES ) left = BLAKE2B_BLOCKBYTES;
blake2b_update( S->S[i], S->buf + i * BLAKE2B_BLOCKBYTES, left );
}
blake2b_final( S->S[i], hash[i], BLAKE2B_OUTBYTES );
}
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S->R, hash[i], BLAKE2B_OUTBYTES );
return blake2b_final( S->R, out, S->outlen );
}
int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2B_OUTBYTES];
blake2b_state S[PARALLELISM_DEGREE][1];
blake2b_state FS[1];
size_t i;
/* Verify parameters */
if ( NULL == in && inlen > 0 ) return -1;
if ( NULL == out ) return -1;
if( NULL == key && keylen > 0 ) return -1;
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
if( keylen > BLAKE2B_KEYBYTES ) return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2bp_init_leaf( S[i], outlen, keylen, i ) < 0 ) return -1;
S[PARALLELISM_DEGREE - 1]->last_node = 1; /* mark last node */
if( keylen > 0 )
{
uint8_t block[BLAKE2B_BLOCKBYTES];
memset( block, 0, BLAKE2B_BLOCKBYTES );
memcpy( block, key, keylen );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S[i], block, BLAKE2B_BLOCKBYTES );
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
}
#if defined(_OPENMP)
#pragma omp parallel shared(S,hash), num_threads(PARALLELISM_DEGREE)
#else
for( i = 0; i < PARALLELISM_DEGREE; ++i )
#endif
{
#if defined(_OPENMP)
size_t i = omp_get_thread_num();
#endif
size_t inlen__ = inlen;
const unsigned char *in__ = ( const unsigned char * )in;
in__ += i * BLAKE2B_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES )
{
blake2b_update( S[i], in__, BLAKE2B_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
}
if( inlen__ > i * BLAKE2B_BLOCKBYTES )
{
const size_t left = inlen__ - i * BLAKE2B_BLOCKBYTES;
const size_t len = left <= BLAKE2B_BLOCKBYTES ? left : BLAKE2B_BLOCKBYTES;
blake2b_update( S[i], in__, len );
}
blake2b_final( S[i], hash[i], BLAKE2B_OUTBYTES );
}
if( blake2bp_init_root( FS, outlen, keylen ) < 0 )
return -1;
FS->last_node = 1; /* Mark as last node */
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( FS, hash[i], BLAKE2B_OUTBYTES );
return blake2b_final( FS, out, outlen );;
}
#if defined(BLAKE2BP_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2B_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step;
for( i = 0; i < BLAKE2B_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
/* Test simple API */
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2B_OUTBYTES];
blake2bp( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES );
if( 0 != memcmp( hash, blake2bp_keyed_kat[i], BLAKE2B_OUTBYTES ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) {
for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
uint8_t hash[BLAKE2B_OUTBYTES];
blake2bp_state S;
uint8_t * p = buf;
size_t mlen = i;
int err = 0;
if( (err = blake2bp_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2bp_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2bp_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2bp_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2bp_keyed_kat[i], BLAKE2B_OUTBYTES)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -0,0 +1,367 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
static const uint32_t blake2s_IV[8] =
{
0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
};
static const uint8_t blake2s_sigma[10][16] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
};
static void blake2s_set_lastnode( blake2s_state *S )
{
S->f[1] = (uint32_t)-1;
}
/* Some helper functions, not necessarily useful */
static int blake2s_is_lastblock( const blake2s_state *S )
{
return S->f[0] != 0;
}
static void blake2s_set_lastblock( blake2s_state *S )
{
if( S->last_node ) blake2s_set_lastnode( S );
S->f[0] = (uint32_t)-1;
}
static void blake2s_increment_counter( blake2s_state *S, const uint32_t inc )
{
S->t[0] += inc;
S->t[1] += ( S->t[0] < inc );
}
static void blake2s_init0( blake2s_state *S )
{
size_t i;
memset( S, 0, sizeof( blake2s_state ) );
for( i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i];
}
/* init2 xors IV with input parameter block */
int blake2s_init_param( blake2s_state *S, const blake2s_param *P )
{
const unsigned char *p = ( const unsigned char * )( P );
size_t i;
blake2s_init0( S );
/* IV XOR ParamBlock */
for( i = 0; i < 8; ++i )
S->h[i] ^= load32( &p[i * 4] );
S->outlen = P->digest_length;
return 0;
}
/* Sequential blake2s initialization */
int blake2s_init( blake2s_state *S, size_t outlen )
{
blake2s_param P[1];
/* Move interval verification here? */
if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1;
P->digest_length = (uint8_t)outlen;
P->key_length = 0;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store16( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = 0;
/* memset(P->reserved, 0, sizeof(P->reserved) ); */
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2s_init_param( S, P );
}
int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen )
{
blake2s_param P[1];
if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1;
if ( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1;
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store16( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = 0;
/* memset(P->reserved, 0, sizeof(P->reserved) ); */
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
if( blake2s_init_param( S, P ) < 0 ) return -1;
{
uint8_t block[BLAKE2S_BLOCKBYTES];
memset( block, 0, BLAKE2S_BLOCKBYTES );
memcpy( block, key, keylen );
blake2s_update( S, block, BLAKE2S_BLOCKBYTES );
secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
#define G(r,i,a,b,c,d) \
do { \
a = a + b + m[blake2s_sigma[r][2*i+0]]; \
d = rotr32(d ^ a, 16); \
c = c + d; \
b = rotr32(b ^ c, 12); \
a = a + b + m[blake2s_sigma[r][2*i+1]]; \
d = rotr32(d ^ a, 8); \
c = c + d; \
b = rotr32(b ^ c, 7); \
} while(0)
#define ROUND(r) \
do { \
G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
G(r,2,v[ 2],v[ 6],v[10],v[14]); \
G(r,3,v[ 3],v[ 7],v[11],v[15]); \
G(r,4,v[ 0],v[ 5],v[10],v[15]); \
G(r,5,v[ 1],v[ 6],v[11],v[12]); \
G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
} while(0)
static void blake2s_compress( blake2s_state *S, const uint8_t in[BLAKE2S_BLOCKBYTES] )
{
uint32_t m[16];
uint32_t v[16];
size_t i;
for( i = 0; i < 16; ++i ) {
m[i] = load32( in + i * sizeof( m[i] ) );
}
for( i = 0; i < 8; ++i ) {
v[i] = S->h[i];
}
v[ 8] = blake2s_IV[0];
v[ 9] = blake2s_IV[1];
v[10] = blake2s_IV[2];
v[11] = blake2s_IV[3];
v[12] = S->t[0] ^ blake2s_IV[4];
v[13] = S->t[1] ^ blake2s_IV[5];
v[14] = S->f[0] ^ blake2s_IV[6];
v[15] = S->f[1] ^ blake2s_IV[7];
ROUND( 0 );
ROUND( 1 );
ROUND( 2 );
ROUND( 3 );
ROUND( 4 );
ROUND( 5 );
ROUND( 6 );
ROUND( 7 );
ROUND( 8 );
ROUND( 9 );
for( i = 0; i < 8; ++i ) {
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
}
}
#undef G
#undef ROUND
int blake2s_update( blake2s_state *S, const void *pin, size_t inlen )
{
const unsigned char * in = (const unsigned char *)pin;
if( inlen > 0 )
{
size_t left = S->buflen;
size_t fill = BLAKE2S_BLOCKBYTES - left;
if( inlen > fill )
{
S->buflen = 0;
memcpy( S->buf + left, in, fill ); /* Fill buffer */
blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
blake2s_compress( S, S->buf ); /* Compress */
in += fill; inlen -= fill;
while(inlen > BLAKE2S_BLOCKBYTES) {
blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES);
blake2s_compress( S, in );
in += BLAKE2S_BLOCKBYTES;
inlen -= BLAKE2S_BLOCKBYTES;
}
}
memcpy( S->buf + S->buflen, in, inlen );
S->buflen += inlen;
}
return 0;
}
int blake2s_final( blake2s_state *S, void *out, size_t outlen )
{
uint8_t buffer[BLAKE2S_OUTBYTES] = {0};
size_t i;
if( out == NULL || outlen < S->outlen )
return -1;
if( blake2s_is_lastblock( S ) )
return -1;
blake2s_increment_counter( S, ( uint32_t )S->buflen );
blake2s_set_lastblock( S );
memset( S->buf + S->buflen, 0, BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */
blake2s_compress( S, S->buf );
for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */
store32( buffer + sizeof( S->h[i] ) * i, S->h[i] );
memcpy( out, buffer, outlen );
secure_zero_memory(buffer, sizeof(buffer));
return 0;
}
int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
{
blake2s_state S[1];
/* Verify parameters */
if ( NULL == in && inlen > 0 ) return -1;
if ( NULL == out ) return -1;
if ( NULL == key && keylen > 0) return -1;
if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
if( keylen > BLAKE2S_KEYBYTES ) return -1;
if( keylen > 0 )
{
if( blake2s_init_key( S, outlen, key, keylen ) < 0 ) return -1;
}
else
{
if( blake2s_init( S, outlen ) < 0 ) return -1;
}
blake2s_update( S, ( const uint8_t * )in, inlen );
blake2s_final( S, out, outlen );
return 0;
}
#if defined(SUPERCOP)
int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen )
{
return blake2s( out, BLAKE2S_OUTBYTES, in, inlen, NULL, 0 );
}
#endif
#if defined(BLAKE2S_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2S_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step;
for( i = 0; i < BLAKE2S_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
/* Test simple API */
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2S_OUTBYTES];
blake2s( hash, BLAKE2S_OUTBYTES, buf, i, key, BLAKE2S_KEYBYTES );
if( 0 != memcmp( hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) {
for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
uint8_t hash[BLAKE2S_OUTBYTES];
blake2s_state S;
uint8_t * p = buf;
size_t mlen = i;
int err = 0;
if( (err = blake2s_init_key(&S, BLAKE2S_OUTBYTES, key, BLAKE2S_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2s_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2s_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2s_final(&S, hash, BLAKE2S_OUTBYTES)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -0,0 +1,359 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#if defined(_OPENMP)
#include <omp.h>
#endif
#include "blake2.h"
#include "blake2-impl.h"
#define PARALLELISM_DEGREE 8
/*
blake2sp_init_param defaults to setting the expecting output length
from the digest_length parameter block field.
In some cases, however, we do not want this, as the output length
of these instances is given by inner_length instead.
*/
static int blake2sp_init_leaf_param( blake2s_state *S, const blake2s_param *P )
{
int err = blake2s_init_param(S, P);
S->outlen = P->inner_length;
return err;
}
static int blake2sp_init_leaf( blake2s_state *S, size_t outlen, size_t keylen, uint64_t offset )
{
blake2s_param P[1];
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, offset );
store16( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = BLAKE2S_OUTBYTES;
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2sp_init_leaf_param( S, P );
}
static int blake2sp_init_root( blake2s_state *S, size_t outlen, size_t keylen )
{
blake2s_param P[1];
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store16( &P->xof_length, 0 );
P->node_depth = 1;
P->inner_length = BLAKE2S_OUTBYTES;
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2s_init_param( S, P );
}
int blake2sp_init( blake2sp_state *S, size_t outlen )
{
size_t i;
if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
S->outlen = outlen;
if( blake2sp_init_root( S->R, outlen, 0 ) < 0 )
return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2sp_init_leaf( S->S[i], outlen, 0, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
return 0;
}
int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen )
{
size_t i;
if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
if( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
S->outlen = outlen;
if( blake2sp_init_root( S->R, outlen, keylen ) < 0 )
return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2sp_init_leaf( S->S[i], outlen, keylen, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
{
uint8_t block[BLAKE2S_BLOCKBYTES];
memset( block, 0, BLAKE2S_BLOCKBYTES );
memcpy( block, key, keylen );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S->S[i], block, BLAKE2S_BLOCKBYTES );
secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
int blake2sp_update( blake2sp_state *S, const void *pin, size_t inlen )
{
const unsigned char * in = (const unsigned char *)pin;
size_t left = S->buflen;
size_t fill = sizeof( S->buf ) - left;
size_t i;
if( left && inlen >= fill )
{
memcpy( S->buf + left, in, fill );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES );
in += fill;
inlen -= fill;
left = 0;
}
#if defined(_OPENMP)
#pragma omp parallel shared(S), num_threads(PARALLELISM_DEGREE)
#else
for( i = 0; i < PARALLELISM_DEGREE; ++i )
#endif
{
#if defined(_OPENMP)
size_t i = omp_get_thread_num();
#endif
size_t inlen__ = inlen;
const unsigned char *in__ = ( const unsigned char * )in;
in__ += i * BLAKE2S_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
{
blake2s_update( S->S[i], in__, BLAKE2S_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
}
}
in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES );
inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
if( inlen > 0 )
memcpy( S->buf + left, in, inlen );
S->buflen = left + inlen;
return 0;
}
int blake2sp_final( blake2sp_state *S, void *out, size_t outlen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
size_t i;
if(out == NULL || outlen < S->outlen) {
return -1;
}
for( i = 0; i < PARALLELISM_DEGREE; ++i )
{
if( S->buflen > i * BLAKE2S_BLOCKBYTES )
{
size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES;
if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES;
blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left );
}
blake2s_final( S->S[i], hash[i], BLAKE2S_OUTBYTES );
}
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S->R, hash[i], BLAKE2S_OUTBYTES );
return blake2s_final( S->R, out, S->outlen );
}
int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
blake2s_state S[PARALLELISM_DEGREE][1];
blake2s_state FS[1];
size_t i;
/* Verify parameters */
if ( NULL == in && inlen > 0 ) return -1;
if ( NULL == out ) return -1;
if ( NULL == key && keylen > 0) return -1;
if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
if( keylen > BLAKE2S_KEYBYTES ) return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2sp_init_leaf( S[i], outlen, keylen, i ) < 0 ) return -1;
S[PARALLELISM_DEGREE - 1]->last_node = 1; /* mark last node */
if( keylen > 0 )
{
uint8_t block[BLAKE2S_BLOCKBYTES];
memset( block, 0, BLAKE2S_BLOCKBYTES );
memcpy( block, key, keylen );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S[i], block, BLAKE2S_BLOCKBYTES );
secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
}
#if defined(_OPENMP)
#pragma omp parallel shared(S,hash), num_threads(PARALLELISM_DEGREE)
#else
for( i = 0; i < PARALLELISM_DEGREE; ++i )
#endif
{
#if defined(_OPENMP)
size_t i = omp_get_thread_num();
#endif
size_t inlen__ = inlen;
const unsigned char *in__ = ( const unsigned char * )in;
in__ += i * BLAKE2S_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
{
blake2s_update( S[i], in__, BLAKE2S_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
}
if( inlen__ > i * BLAKE2S_BLOCKBYTES )
{
const size_t left = inlen__ - i * BLAKE2S_BLOCKBYTES;
const size_t len = left <= BLAKE2S_BLOCKBYTES ? left : BLAKE2S_BLOCKBYTES;
blake2s_update( S[i], in__, len );
}
blake2s_final( S[i], hash[i], BLAKE2S_OUTBYTES );
}
if( blake2sp_init_root( FS, outlen, keylen ) < 0 )
return -1;
FS->last_node = 1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( FS, hash[i], BLAKE2S_OUTBYTES );
return blake2s_final( FS, out, outlen );
}
#if defined(BLAKE2SP_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2S_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step;
for( i = 0; i < BLAKE2S_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
/* Test simple API */
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2S_OUTBYTES];
blake2sp( hash, BLAKE2S_OUTBYTES, buf, i, key, BLAKE2S_KEYBYTES );
if( 0 != memcmp( hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) {
for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
uint8_t hash[BLAKE2S_OUTBYTES];
blake2sp_state S;
uint8_t * p = buf;
size_t mlen = i;
int err = 0;
if( (err = blake2sp_init_key(&S, BLAKE2S_OUTBYTES, key, BLAKE2S_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2sp_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2sp_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2sp_final(&S, hash, BLAKE2S_OUTBYTES)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -0,0 +1,241 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2016, JP Aumasson <jeanphilippe.aumasson@gmail.com>.
Copyright 2016, Samuel Neves <sneves@dei.uc.pt>.
You may use this under the terms of the CC0, the OpenSSL Licence, or
the Apache Public License 2.0, at your option. The terms of these
licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
int blake2xb_init( blake2xb_state *S, const size_t outlen ) {
return blake2xb_init_key(S, outlen, NULL, 0);
}
int blake2xb_init_key( blake2xb_state *S, const size_t outlen, const void *key, size_t keylen)
{
if ( outlen == 0 || outlen > 0xFFFFFFFFUL ) {
return -1;
}
if (NULL != key && keylen > BLAKE2B_KEYBYTES) {
return -1;
}
if (NULL == key && keylen > 0) {
return -1;
}
/* Initialize parameter block */
S->P->digest_length = BLAKE2B_OUTBYTES;
S->P->key_length = keylen;
S->P->fanout = 1;
S->P->depth = 1;
store32( &S->P->leaf_length, 0 );
store32( &S->P->node_offset, 0 );
store32( &S->P->xof_length, outlen );
S->P->node_depth = 0;
S->P->inner_length = 0;
memset( S->P->reserved, 0, sizeof( S->P->reserved ) );
memset( S->P->salt, 0, sizeof( S->P->salt ) );
memset( S->P->personal, 0, sizeof( S->P->personal ) );
if( blake2b_init_param( S->S, S->P ) < 0 ) {
return -1;
}
if (keylen > 0) {
uint8_t block[BLAKE2B_BLOCKBYTES];
memset(block, 0, BLAKE2B_BLOCKBYTES);
memcpy(block, key, keylen);
blake2b_update(S->S, block, BLAKE2B_BLOCKBYTES);
secure_zero_memory(block, BLAKE2B_BLOCKBYTES);
}
return 0;
}
int blake2xb_update( blake2xb_state *S, const void *in, size_t inlen ) {
return blake2b_update( S->S, in, inlen );
}
int blake2xb_final( blake2xb_state *S, void *out, size_t outlen) {
blake2b_state C[1];
blake2b_param P[1];
uint32_t xof_length = load32(&S->P->xof_length);
uint8_t root[BLAKE2B_BLOCKBYTES];
size_t i;
if (NULL == out) {
return -1;
}
/* outlen must match the output size defined in xof_length, */
/* unless it was -1, in which case anything goes except 0. */
if(xof_length == 0xFFFFFFFFUL) {
if(outlen == 0) {
return -1;
}
} else {
if(outlen != xof_length) {
return -1;
}
}
/* Finalize the root hash */
if (blake2b_final(S->S, root, BLAKE2B_OUTBYTES) < 0) {
return -1;
}
/* Set common block structure values */
/* Copy values from parent instance, and only change the ones below */
memcpy(P, S->P, sizeof(blake2b_param));
P->key_length = 0;
P->fanout = 0;
P->depth = 0;
store32(&P->leaf_length, BLAKE2B_OUTBYTES);
P->inner_length = BLAKE2B_OUTBYTES;
P->node_depth = 0;
for (i = 0; outlen > 0; ++i) {
const size_t block_size = (outlen < BLAKE2B_OUTBYTES) ? outlen : BLAKE2B_OUTBYTES;
/* Initialize state */
P->digest_length = block_size;
store32(&P->node_offset, i);
blake2b_init_param(C, P);
/* Process key if needed */
blake2b_update(C, root, BLAKE2B_OUTBYTES);
if (blake2b_final(C, (uint8_t *)out + i * BLAKE2B_OUTBYTES, block_size) < 0 ) {
return -1;
}
outlen -= block_size;
}
secure_zero_memory(root, sizeof(root));
secure_zero_memory(P, sizeof(P));
secure_zero_memory(C, sizeof(C));
/* Put blake2xb in an invalid state? cf. blake2s_is_lastblock */
return 0;
}
int blake2xb(void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen)
{
blake2xb_state S[1];
/* Verify parameters */
if (NULL == in && inlen > 0)
return -1;
if (NULL == out)
return -1;
if (NULL == key && keylen > 0)
return -1;
if (keylen > BLAKE2B_KEYBYTES)
return -1;
if (outlen == 0)
return -1;
/* Initialize the root block structure */
if (blake2xb_init_key(S, outlen, key, keylen) < 0) {
return -1;
}
/* Absorb the input message */
blake2xb_update(S, in, inlen);
/* Compute the root node of the tree and the final hash using the counter construction */
return blake2xb_final(S, out, outlen);
}
#if defined(BLAKE2XB_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2B_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step, outlen;
for( i = 0; i < BLAKE2B_KEYBYTES; ++i ) {
key[i] = ( uint8_t )i;
}
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) {
buf[i] = ( uint8_t )i;
}
/* Testing length of outputs rather than inputs */
/* (Test of input lengths mostly covered by blake2b tests) */
/* Test simple API */
for( outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen )
{
uint8_t hash[BLAKE2_KAT_LENGTH] = {0};
if( blake2xb( hash, outlen, buf, BLAKE2_KAT_LENGTH, key, BLAKE2B_KEYBYTES ) < 0 ) {
goto fail;
}
if( 0 != memcmp( hash, blake2xb_keyed_kat[outlen-1], outlen ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) {
for (outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen) {
uint8_t hash[BLAKE2_KAT_LENGTH];
blake2xb_state S;
uint8_t * p = buf;
size_t mlen = BLAKE2_KAT_LENGTH;
int err = 0;
if( (err = blake2xb_init_key(&S, outlen, key, BLAKE2B_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2xb_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2xb_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2xb_final(&S, hash, outlen)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2xb_keyed_kat[outlen-1], outlen)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -0,0 +1,239 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2016, JP Aumasson <jeanphilippe.aumasson@gmail.com>.
Copyright 2016, Samuel Neves <sneves@dei.uc.pt>.
You may use this under the terms of the CC0, the OpenSSL Licence, or
the Apache Public License 2.0, at your option. The terms of these
licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
int blake2xs_init( blake2xs_state *S, const size_t outlen ) {
return blake2xs_init_key(S, outlen, NULL, 0);
}
int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen )
{
if ( outlen == 0 || outlen > 0xFFFFUL ) {
return -1;
}
if (NULL != key && keylen > BLAKE2S_KEYBYTES) {
return -1;
}
if (NULL == key && keylen > 0) {
return -1;
}
/* Initialize parameter block */
S->P->digest_length = BLAKE2S_OUTBYTES;
S->P->key_length = keylen;
S->P->fanout = 1;
S->P->depth = 1;
store32( &S->P->leaf_length, 0 );
store32( &S->P->node_offset, 0 );
store16( &S->P->xof_length, outlen );
S->P->node_depth = 0;
S->P->inner_length = 0;
memset( S->P->salt, 0, sizeof( S->P->salt ) );
memset( S->P->personal, 0, sizeof( S->P->personal ) );
if( blake2s_init_param( S->S, S->P ) < 0 ) {
return -1;
}
if (keylen > 0) {
uint8_t block[BLAKE2S_BLOCKBYTES];
memset(block, 0, BLAKE2S_BLOCKBYTES);
memcpy(block, key, keylen);
blake2s_update(S->S, block, BLAKE2S_BLOCKBYTES);
secure_zero_memory(block, BLAKE2S_BLOCKBYTES);
}
return 0;
}
int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen ) {
return blake2s_update( S->S, in, inlen );
}
int blake2xs_final(blake2xs_state *S, void *out, size_t outlen) {
blake2s_state C[1];
blake2s_param P[1];
uint16_t xof_length = load16(&S->P->xof_length);
uint8_t root[BLAKE2S_BLOCKBYTES];
size_t i;
if (NULL == out) {
return -1;
}
/* outlen must match the output size defined in xof_length, */
/* unless it was -1, in which case anything goes except 0. */
if(xof_length == 0xFFFFUL) {
if(outlen == 0) {
return -1;
}
} else {
if(outlen != xof_length) {
return -1;
}
}
/* Finalize the root hash */
if (blake2s_final(S->S, root, BLAKE2S_OUTBYTES) < 0) {
return -1;
}
/* Set common block structure values */
/* Copy values from parent instance, and only change the ones below */
memcpy(P, S->P, sizeof(blake2s_param));
P->key_length = 0;
P->fanout = 0;
P->depth = 0;
store32(&P->leaf_length, BLAKE2S_OUTBYTES);
P->inner_length = BLAKE2S_OUTBYTES;
P->node_depth = 0;
for (i = 0; outlen > 0; ++i) {
const size_t block_size = (outlen < BLAKE2S_OUTBYTES) ? outlen : BLAKE2S_OUTBYTES;
/* Initialize state */
P->digest_length = block_size;
store32(&P->node_offset, i);
blake2s_init_param(C, P);
/* Process key if needed */
blake2s_update(C, root, BLAKE2S_OUTBYTES);
if (blake2s_final(C, (uint8_t *)out + i * BLAKE2S_OUTBYTES, block_size) < 0) {
return -1;
}
outlen -= block_size;
}
secure_zero_memory(root, sizeof(root));
secure_zero_memory(P, sizeof(P));
secure_zero_memory(C, sizeof(C));
/* Put blake2xs in an invalid state? cf. blake2s_is_lastblock */
return 0;
}
int blake2xs(void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen)
{
blake2xs_state S[1];
/* Verify parameters */
if (NULL == in && inlen > 0)
return -1;
if (NULL == out)
return -1;
if (NULL == key && keylen > 0)
return -1;
if (keylen > BLAKE2S_KEYBYTES)
return -1;
if (outlen == 0)
return -1;
/* Initialize the root block structure */
if (blake2xs_init_key(S, outlen, key, keylen) < 0) {
return -1;
}
/* Absorb the input message */
blake2xs_update(S, in, inlen);
/* Compute the root node of the tree and the final hash using the counter construction */
return blake2xs_final(S, out, outlen);
}
#if defined(BLAKE2XS_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2S_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step, outlen;
for( i = 0; i < BLAKE2S_KEYBYTES; ++i ) {
key[i] = ( uint8_t )i;
}
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) {
buf[i] = ( uint8_t )i;
}
/* Testing length of outputs rather than inputs */
/* (Test of input lengths mostly covered by blake2s tests) */
/* Test simple API */
for( outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen )
{
uint8_t hash[BLAKE2_KAT_LENGTH] = {0};
if( blake2xs( hash, outlen, buf, BLAKE2_KAT_LENGTH, key, BLAKE2S_KEYBYTES ) < 0 ) {
goto fail;
}
if( 0 != memcmp( hash, blake2xs_keyed_kat[outlen-1], outlen ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) {
for (outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen) {
uint8_t hash[BLAKE2_KAT_LENGTH];
blake2xs_state S;
uint8_t * p = buf;
size_t mlen = BLAKE2_KAT_LENGTH;
int err = 0;
if( (err = blake2xs_init_key(&S, outlen, key, BLAKE2S_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2xs_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2xs_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2xs_final(&S, hash, outlen)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2xs_keyed_kat[outlen-1], outlen)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -0,0 +1,153 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pidigest.h"
#include "pidigest_blake2_p.h"
#include "pidigest_md2_p.h"
#include "pidigest_md4_p.h"
#include "pidigest_md5_p.h"
#include "pidigest_sha1_p.h"
#include "pidigest_sha2_p.h"
int PIDigest::hashLength(Type type) {
switch (type) {
case Type::MD2: return 16;
case Type::MD4: return 16;
case Type::MD5: return 16;
case Type::SHA1: return 20;
case Type::SHA2_224: return 28;
case Type::SHA2_256: return 32;
case Type::SHA2_384: return 48;
case Type::SHA2_512: return 64;
case Type::SHA2_512_224: return 28;
case Type::SHA2_512_256: return 32;
case Type::BLAKE2s_128: return 16;
case Type::BLAKE2s_160: return 20;
case Type::BLAKE2s_224: return 28;
case Type::BLAKE2s_256: return 32;
case Type::BLAKE2b_128: return 16;
case Type::BLAKE2b_160: return 20;
case Type::BLAKE2b_224: return 28;
case Type::BLAKE2b_256: return 32;
case Type::BLAKE2b_384: return 48;
case Type::BLAKE2b_512: return 64;
default: break;
}
return 0;
}
int PIDigest::blockLength(Type type) {
switch (type) {
case Type::MD2: return 16;
case Type::MD4:
case Type::MD5: return 64;
case Type::SHA1: return 64;
case Type::SHA2_224:
case Type::SHA2_256: return 64;
case Type::SHA2_384:
case Type::SHA2_512:
case Type::SHA2_512_224:
case Type::SHA2_512_256: return 128;
case Type::BLAKE2s_128:
case Type::BLAKE2s_160:
case Type::BLAKE2s_224:
case Type::BLAKE2s_256: return 64;
case Type::BLAKE2b_128:
case Type::BLAKE2b_160:
case Type::BLAKE2b_224:
case Type::BLAKE2b_256:
case Type::BLAKE2b_384:
case Type::BLAKE2b_512: return 128;
default: break;
}
return 0;
}
PIConstChars PIDigest::typeName(Type type) {
switch (type) {
case Type::MD2: return "MD2";
case Type::MD4: return "MD4";
case Type::MD5: return "MD5";
case Type::SHA1: return "SHA1";
case Type::SHA2_224: return "SHA2_224";
case Type::SHA2_256: return "SHA2_256";
case Type::SHA2_384: return "SHA2_384";
case Type::SHA2_512: return "SHA2_512";
case Type::SHA2_512_224: return "SHA2_512_224";
case Type::SHA2_512_256: return "SHA2_512_256";
case Type::BLAKE2s_128: return "BLAKE2s_128";
case Type::BLAKE2s_160: return "BLAKE2s_160";
case Type::BLAKE2s_224: return "BLAKE2s_224";
case Type::BLAKE2s_256: return "BLAKE2s_256";
case Type::BLAKE2b_128: return "BLAKE2b_128";
case Type::BLAKE2b_160: return "BLAKE2b_160";
case Type::BLAKE2b_224: return "BLAKE2b_224";
case Type::BLAKE2b_256: return "BLAKE2b_256";
case Type::BLAKE2b_384: return "BLAKE2b_384";
case Type::BLAKE2b_512: return "BLAKE2b_512";
default: break;
}
return "Unknown";
}
PIByteArray PIDigest::calculate(const PIByteArray & msg, Type type) {
switch (type) {
case Type::MD2: return MD2::md2(msg);
case Type::MD4: return MD4::md4(msg);
case Type::MD5: return MD5::md5(msg);
case Type::SHA1: return SHA1::sha1(msg);
case Type::SHA2_224: return SHA2::sha2xx(msg, SHA2::initial_224, 28);
case Type::SHA2_256: return SHA2::sha2xx(msg, SHA2::initial_256, 32);
case Type::SHA2_384: return SHA2::sha5xx(msg, SHA2::initial_384, 48);
case Type::SHA2_512: return SHA2::sha5xx(msg, SHA2::initial_512, 64);
case Type::SHA2_512_224: return SHA2::sha5xx(msg, SHA2::initial_512_224, 28);
case Type::SHA2_512_256: return SHA2::sha5xx(msg, SHA2::initial_512_256, 32);
case Type::BLAKE2s_128: return BLAKE2::blake2s(msg, 16);
case Type::BLAKE2s_160: return BLAKE2::blake2s(msg, 20);
case Type::BLAKE2s_224: return BLAKE2::blake2s(msg, 28);
case Type::BLAKE2s_256: return BLAKE2::blake2s(msg, 32);
case Type::BLAKE2b_128: return BLAKE2::blake2b(msg, 16);
case Type::BLAKE2b_160: return BLAKE2::blake2b(msg, 20);
case Type::BLAKE2b_224: return BLAKE2::blake2b(msg, 28);
case Type::BLAKE2b_256: return BLAKE2::blake2b(msg, 32);
case Type::BLAKE2b_384: return BLAKE2::blake2b(msg, 48);
case Type::BLAKE2b_512: return BLAKE2::blake2b(msg, 64);
default: break;
}
return {};
}
PIByteArray PIDigest::HMAC(const PIByteArray & msg, const PIByteArray & key, Type type) {
int b = PIDigest::blockLength(type);
auto ipad = PIByteArray(b, uchar(0x36));
auto opad = PIByteArray(b, uchar(0x5C));
PIByteArray k0;
if (key.size_s() > b)
k0 = PIDigest::calculate(key, type);
else
k0 = key;
k0.resize(b);
return PIDigest::calculate((k0 ^ opad).append(PIDigest::calculate((k0 ^ ipad).append(msg), type)), type);
}

View File

@@ -0,0 +1,72 @@
/*! \file pidigest.h
* \ingroup Core
* \~\brief
* \~english Digest algorithms
* \~russian Алгоритмы хэш-сумм
*
* \~\details
* \~english
* This file implements several common-usage hash algorithms
* \~russian
* Этот файл реализует несколько распространенных алгоритмов хэширования
*/
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pidigest_h
#define pidigest_h
#include "pibytearray.h"
#include "piconstchars.h"
class PIP_EXPORT PIDigest {
public:
enum class Type {
SHA1,
SHA2_224,
SHA2_256,
SHA2_384,
SHA2_512,
SHA2_512_224,
SHA2_512_256,
MD2,
MD4,
MD5,
BLAKE2s_128,
BLAKE2s_160,
BLAKE2s_224,
BLAKE2s_256,
BLAKE2b_128,
BLAKE2b_160,
BLAKE2b_224,
BLAKE2b_256,
BLAKE2b_384,
BLAKE2b_512,
Count,
};
static int hashLength(Type type);
static int blockLength(Type type);
static PIConstChars typeName(Type type);
static PIByteArray calculate(const PIByteArray & msg, Type type);
static PIByteArray HMAC(const PIByteArray & msg, const PIByteArray & key, PIDigest::Type type);
};
#endif

View File

@@ -0,0 +1,64 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pidigest_blake2_p.h"
#include "3rd/BLAKE2/blake2.h"
PIByteArray BLAKE2::blake2s(const PIByteArray & in, int out_bytes) {
PIByteArray ret(out_bytes);
::blake2s(ret.data(), ret.size(), in.data(), in.size(), nullptr, 0);
return ret;
}
PIByteArray BLAKE2::blake2b(const PIByteArray & in, int out_bytes) {
PIByteArray ret(out_bytes);
::blake2b(ret.data(), ret.size(), in.data(), in.size(), nullptr, 0);
return ret;
}
PIByteArray BLAKE2::blake2sp(const PIByteArray & in, int out_bytes) {
PIByteArray ret(out_bytes);
::blake2sp(ret.data(), ret.size(), in.data(), in.size(), nullptr, 0);
return ret;
}
PIByteArray BLAKE2::blake2bp(const PIByteArray & in, int out_bytes) {
PIByteArray ret(out_bytes);
::blake2bp(ret.data(), ret.size(), in.data(), in.size(), nullptr, 0);
return ret;
}
PIByteArray BLAKE2::blake2xs(const PIByteArray & in, int out_bytes) {
PIByteArray ret(out_bytes);
::blake2xs(ret.data(), ret.size(), in.data(), in.size(), nullptr, 0);
return ret;
}
PIByteArray BLAKE2::blake2xb(const PIByteArray & in, int out_bytes) {
PIByteArray ret(out_bytes);
::blake2xb(ret.data(), ret.size(), in.data(), in.size(), nullptr, 0);
return ret;
}

View File

@@ -0,0 +1,35 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pidigest_blake2_h
#define pidigest_blake2_h
#include "pibytearray.h"
class BLAKE2 {
public:
static PIByteArray blake2s(const PIByteArray & in, int out_bytes);
static PIByteArray blake2b(const PIByteArray & in, int out_bytes);
static PIByteArray blake2sp(const PIByteArray & in, int out_bytes);
static PIByteArray blake2bp(const PIByteArray & in, int out_bytes);
static PIByteArray blake2xs(const PIByteArray & in, int out_bytes);
static PIByteArray blake2xb(const PIByteArray & in, int out_bytes);
};
#endif

View File

@@ -0,0 +1,88 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pidigest_md2_p.h"
PIByteArray MD2::md2(const PIByteArray & in) {
constexpr int part_size = 16;
static constexpr uchar S[] = {
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147,
43, 217, 188, 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, 23, 229, 18, 190, 78, 196, 214,
218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34,
95, 33, 128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, 181, 209,
215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105,
52, 64, 126, 15, 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, 44, 83, 13, 110, 133, 40,
132, 9, 211, 223, 205, 244, 65, 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74,
120, 136, 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, 166, 119,
114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20};
PIByteArray msg = in;
int add_l = part_size - (msg.size() % part_size);
if (add_l <= 0) add_l += part_size;
for (int i = 0; i < add_l; ++i)
msg.append(uchar(add_l));
int parts = msg.size_s() / part_size;
// piCout << "add" << add_l << "=" << (in.size() + add_l) << msg.size() << parts;
uchar cs[16];
for (int i = 0; i < 16; ++i)
cs[i] = 0;
uchar l = 0;
for (int p = 0; p < parts; ++p) {
uchar * mb = (uchar *)msg.data(p * part_size);
for (int j = 0; j < 16; ++j) {
uchar c = mb[j];
cs[j] = cs[j] ^ S[c ^ l];
l = cs[j];
}
}
msg.append(cs, 16);
++parts;
uchar x[48];
for (int i = 0; i < 48; ++i)
x[i] = 0;
for (int p = 0; p < parts; ++p) {
uchar * mb = (uchar *)msg.data(p * part_size);
for (int j = 0; j < 16; ++j) {
uchar c = mb[j];
cs[j] = cs[j] ^ S[c ^ l];
l = cs[j];
}
for (int j = 0; j < 16; ++j) {
x[16 + j] = mb[j];
x[32 + j] = (x[16 + j] ^ x[j]);
}
uchar t = 0;
for (int j = 0; j < 18; ++j) {
for (int k = 0; k < 48; ++k) {
t = x[k] = (x[k] ^ S[t]);
}
t = (t + j) % 256;
}
}
return PIByteArray(x, 16);
}

View File

@@ -0,0 +1,30 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pidigest_md2_h
#define pidigest_md2_h
#include "pibytearray.h"
class MD2 {
public:
static PIByteArray md2(const PIByteArray & in);
};
#endif

View File

@@ -0,0 +1,127 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pidigest_md4_p.h"
template<typename T>
inline T rotate_u(T v, int bits) {
return (v << bits) | (v >> ((sizeof(T) * 8) - bits));
}
#define F(X, Y, Z) (((X) & (Y)) | ((~(X)) & (Z)))
#define G(X, Y, Z) (((X) & (Y)) | ((X) & (Z)) | ((Y) & (Z)))
#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
#define MD4ROUND1(a, b, c, d, x, s) \
a += F(b, c, d) + x; \
a = rotate_u(a, s);
#define MD4ROUND2(a, b, c, d, x, s) \
a += G(b, c, d) + x + 0x5A827999u; \
a = rotate_u(a, s);
#define MD4ROUND3(a, b, c, d, x, s) \
a += H(b, c, d) + x + 0x6ED9EBA1u; \
a = rotate_u(a, s);
PIByteArray MD4::md4(const PIByteArray & in) {
constexpr int part_size = 64;
uint32_t a = piChangedEndian(0x01234567u);
uint32_t b = piChangedEndian(0x89ABCDEFu);
uint32_t c = piChangedEndian(0xFEDCBA98u);
uint32_t d = piChangedEndian(0x76543210u);
uint64_t l = in.size() * 8;
PIByteArray msg = in;
int add_l = (part_size - 8) - (msg.size() % (part_size));
if (add_l <= 0) add_l += part_size;
msg.append(0x80);
for (int i = 1; i < add_l; ++i)
msg.append(0x0);
msg << l;
int parts = msg.size_s() / part_size;
// piCout << l << "add" << add_l << "=" << (in.size() + add_l + sizeof(l)) << msg.size() << parts;
for (int p = 0; p < parts; ++p) {
uint32_t * mw = (uint32_t *)msg.data(p * part_size);
// piCout << PIByteArray(w, 64);
uint32_t a0 = a;
uint32_t b0 = b;
uint32_t c0 = c;
uint32_t d0 = d;
MD4ROUND1(a, b, c, d, mw[0], 3);
MD4ROUND1(d, a, b, c, mw[1], 7);
MD4ROUND1(c, d, a, b, mw[2], 11);
MD4ROUND1(b, c, d, a, mw[3], 19);
MD4ROUND1(a, b, c, d, mw[4], 3);
MD4ROUND1(d, a, b, c, mw[5], 7);
MD4ROUND1(c, d, a, b, mw[6], 11);
MD4ROUND1(b, c, d, a, mw[7], 19);
MD4ROUND1(a, b, c, d, mw[8], 3);
MD4ROUND1(d, a, b, c, mw[9], 7);
MD4ROUND1(c, d, a, b, mw[10], 11);
MD4ROUND1(b, c, d, a, mw[11], 19);
MD4ROUND1(a, b, c, d, mw[12], 3);
MD4ROUND1(d, a, b, c, mw[13], 7);
MD4ROUND1(c, d, a, b, mw[14], 11);
MD4ROUND1(b, c, d, a, mw[15], 19);
MD4ROUND2(a, b, c, d, mw[0], 3);
MD4ROUND2(d, a, b, c, mw[4], 5);
MD4ROUND2(c, d, a, b, mw[8], 9);
MD4ROUND2(b, c, d, a, mw[12], 13);
MD4ROUND2(a, b, c, d, mw[1], 3);
MD4ROUND2(d, a, b, c, mw[5], 5);
MD4ROUND2(c, d, a, b, mw[9], 9);
MD4ROUND2(b, c, d, a, mw[13], 13);
MD4ROUND2(a, b, c, d, mw[2], 3);
MD4ROUND2(d, a, b, c, mw[6], 5);
MD4ROUND2(c, d, a, b, mw[10], 9);
MD4ROUND2(b, c, d, a, mw[14], 13);
MD4ROUND2(a, b, c, d, mw[3], 3);
MD4ROUND2(d, a, b, c, mw[7], 5);
MD4ROUND2(c, d, a, b, mw[11], 9);
MD4ROUND2(b, c, d, a, mw[15], 13);
MD4ROUND3(a, b, c, d, mw[0], 3);
MD4ROUND3(d, a, b, c, mw[8], 9);
MD4ROUND3(c, d, a, b, mw[4], 11);
MD4ROUND3(b, c, d, a, mw[12], 15);
MD4ROUND3(a, b, c, d, mw[2], 3);
MD4ROUND3(d, a, b, c, mw[10], 9);
MD4ROUND3(c, d, a, b, mw[6], 11);
MD4ROUND3(b, c, d, a, mw[14], 15);
MD4ROUND3(a, b, c, d, mw[1], 3);
MD4ROUND3(d, a, b, c, mw[9], 9);
MD4ROUND3(c, d, a, b, mw[5], 11);
MD4ROUND3(b, c, d, a, mw[13], 15);
MD4ROUND3(a, b, c, d, mw[3], 3);
MD4ROUND3(d, a, b, c, mw[11], 9);
MD4ROUND3(c, d, a, b, mw[7], 11);
MD4ROUND3(b, c, d, a, mw[15], 15);
a += a0;
b += b0;
c += c0;
d += d0;
}
PIByteArray ret;
ret << a << b << c << d;
return ret;
}

View File

@@ -0,0 +1,30 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pidigest_md4_h
#define pidigest_md4_h
#include "pibytearray.h"
class MD4 {
public:
static PIByteArray md4(const PIByteArray & in);
};
#endif

View File

@@ -0,0 +1,93 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pidigest_md5_p.h"
template<typename T>
inline T rotate_u(T v, int bits) {
return (v << bits) | (v >> ((sizeof(T) * 8) - bits));
}
PIByteArray MD5::md5(const PIByteArray & in) {
constexpr int part_size = 64;
static constexpr uint32_t K[64] = {
0xD76AA478u, 0xE8C7B756u, 0x242070DBu, 0xC1BDCEEEu, 0xF57C0FAFu, 0x4787C62Au, 0xA8304613u, 0xFD469501u, 0x698098D8u, 0x8B44F7AFu,
0xFFFF5BB1u, 0x895CD7BEu, 0x6B901122u, 0xFD987193u, 0xA679438Eu, 0x49B40821u, 0xF61E2562u, 0xC040B340u, 0x265E5A51u, 0xE9B6C7AAu,
0xD62F105Du, 0x02441453u, 0xD8A1E681u, 0xE7D3FBC8u, 0x21E1CDE6u, 0xC33707D6u, 0xF4D50D87u, 0x455A14EDu, 0xA9E3E905u, 0xFCEFA3F8u,
0x676F02D9u, 0x8D2A4C8Au, 0xFFFA3942u, 0x8771F681u, 0x6D9D6122u, 0xFDE5380Cu, 0xA4BEEA44u, 0x4BDECFA9u, 0xF6BB4B60u, 0xBEBFBC70u,
0x289B7EC6u, 0xEAA127FAu, 0xD4EF3085u, 0x04881D05u, 0xD9D4D039u, 0xE6DB99E5u, 0x1FA27CF8u, 0xC4AC5665u, 0xF4292244u, 0x432AFF97u,
0xAB9423A7u, 0xFC93A039u, 0x655B59C3u, 0x8F0CCC92u, 0xFFEFF47Du, 0x85845DD1u, 0x6FA87E4Fu, 0xFE2CE6E0u, 0xA3014314u, 0x4E0811A1u,
0xF7537E82u, 0xBD3AF235u, 0x2AD7D2BBu, 0xEB86D391u};
static constexpr uint32_t s[64] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9,
14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21};
uint32_t a0 = 0x67452301u;
uint32_t b0 = 0xefcdab89u;
uint32_t c0 = 0x98badcfeu;
uint32_t d0 = 0x10325476u;
uint64_t l = in.size() * 8;
PIByteArray msg = in;
int add_l = (part_size - 8) - (msg.size() % (part_size));
if (add_l <= 0) add_l += part_size;
msg.append(0x80);
for (int i = 1; i < add_l; ++i)
msg.append(0x0);
msg << l;
int parts = msg.size_s() / part_size;
// piCout << l << "add" << add_l << "=" << (in.size() + add_l + sizeof(l)) << msg.size() << parts;
for (int p = 0; p < parts; ++p) {
uint32_t * mw = (uint32_t *)msg.data(p * part_size);
uint32_t A = a0;
uint32_t B = b0;
uint32_t C = c0;
uint32_t D = d0;
for (int i = 0; i < 64; ++i) {
uint32_t F = 0, g = 0;
if (i >= 0 && i <= 15) {
F = (B & C) | ((~B) & D);
g = i;
} else if (i >= 16 && i <= 31) {
F = (D & B) | ((~D) & C);
g = (5 * i + 1) % 16;
} else if (i >= 32 && i <= 47) {
F = B ^ C ^ D;
g = (3 * i + 5) % 16;
} else if (i >= 48 && i <= 63) {
F = C ^ (B | (~D));
g = (7 * i) % 16;
}
F = F + A + K[i] + mw[g];
A = D;
D = C;
C = B;
B = B + rotate_u(F, s[i]);
}
a0 = a0 + A;
b0 = b0 + B;
c0 = c0 + C;
d0 = d0 + D;
}
PIByteArray ret;
ret << a0 << b0 << c0 << d0;
return ret;
}

View File

@@ -0,0 +1,30 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pidigest_md5_h
#define pidigest_md5_h
#include "pibytearray.h"
class MD5 {
public:
static PIByteArray md5(const PIByteArray & in);
};
#endif

View File

@@ -0,0 +1,98 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pidigest_sha1_p.h"
template<typename T>
inline T rotate_u(T v, int bits) {
return (v << bits) | (v >> ((sizeof(T) * 8) - bits));
}
template<typename T>
inline T shift_u(T v, int bits) {
return v << bits;
}
PIByteArray SHA1::sha1(const PIByteArray & in) {
constexpr int part_size = 64;
constexpr int rounds = 80;
uint32_t h0 = 0x67452301u;
uint32_t h1 = 0xEFCDAB89u;
uint32_t h2 = 0x98BADCFEu;
uint32_t h3 = 0x10325476u;
uint32_t h4 = 0xC3D2E1F0u;
uint64_t l = in.size() * 8;
PIByteArray msg = in;
int add_l = (part_size - 8) - (msg.size() % (part_size));
if (add_l <= 0) add_l += part_size;
msg.append(0x80);
for (int i = 1; i < add_l; ++i)
msg.append(0x0);
msg << piChangedEndian(l);
int parts = msg.size_s() / part_size;
// piCout << l << "add" << add_l << "=" << (in.size() + add_l + sizeof(l)) << msg.size() << parts;
uint32_t w[80];
for (int p = 0; p < parts; ++p) {
uint32_t * mw = (uint32_t *)msg.data(p * part_size);
for (int i = 0; i < 16; ++i)
w[i] = piChangedEndian(mw[i]);
for (int i = 16; i < 80; ++i) {
w[i] = rotate_u((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
}
uint32_t a = h0;
uint32_t b = h1;
uint32_t c = h2;
uint32_t d = h3;
uint32_t e = h4;
uint32_t f = 0;
uint32_t k = 0;
uint32_t t = 0;
for (int i = 0; i < rounds; ++i) {
if (i >= 0 && i <= 19) {
f = (b & c) | ((~b) & d);
k = 0x5A827999;
} else if (i >= 20 && i <= 39) {
f = b ^ c ^ d;
k = 0x6ED9EBA1;
} else if (i >= 40 && i <= 59) {
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
} else if (i >= 60 && i <= 79) {
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
t = rotate_u(a, 5) + f + e + k + w[i];
e = d;
d = c;
c = rotate_u(b, 30);
b = a;
a = t;
}
h0 += a;
h1 += b;
h2 += c;
h3 += d;
h4 += e;
}
PIByteArray ret;
ret << piChangedEndian(h0) << piChangedEndian(h1) << piChangedEndian(h2) << piChangedEndian(h3) << piChangedEndian(h4);
return ret;
}

View File

@@ -0,0 +1,30 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pidigest_sha1_h
#define pidigest_sha1_h
#include "pibytearray.h"
class SHA1 {
public:
static PIByteArray sha1(const PIByteArray & in);
};
#endif

View File

@@ -0,0 +1,240 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pidigest_sha2_p.h"
const uint32_t SHA2::initial_224[8] =
{0xC1059ED8u, 0x367CD507u, 0x3070DD17u, 0xF70E5939u, 0xFFC00B31u, 0x68581511u, 0x64F98FA7u, 0xBEFA4FA4u};
const uint32_t SHA2::initial_256[8] =
{0x6A09E667u, 0xBB67AE85u, 0x3C6EF372u, 0xA54FF53Au, 0x510E527Fu, 0x9B05688Cu, 0x1F83D9ABu, 0x5BE0CD19u};
const uint64_t SHA2::initial_384[8] = {0xCBBB9D5DC1059ED8U,
0x629A292A367CD507U,
0x9159015A3070DD17U,
0x152FECD8F70E5939U,
0x67332667FFC00B31U,
0x8EB44A8768581511U,
0xDB0C2E0D64F98FA7U,
0x47B5481DBEFA4FA4U};
const uint64_t SHA2::initial_512[8] = {0X6A09E667F3BCC908U,
0XBB67AE8584CAA73BU,
0X3C6EF372FE94F82BU,
0XA54FF53A5F1D36F1U,
0X510E527FADE682D1U,
0X9B05688C2B3E6C1FU,
0X1F83D9ABFB41BD6BU,
0X5BE0CD19137E2179U};
const uint64_t SHA2::initial_512_256[8] = {0x22312194FC2BF72CU,
0x9F555FA3C84C64C2U,
0x2393B86B6F53B151U,
0x963877195940EABDU,
0x96283EE2A88EFFE3U,
0xBE5E1E2553863992U,
0x2B0199FC2C85B8AAU,
0x0EB72DDC81C52CA2U};
const uint64_t SHA2::initial_512_224[8] = {0x8C3D37C819544DA2U,
0x73E1996689DCD4D6U,
0x1DFAB7AE32FF9C82U,
0x679DD514582F9FCFU,
0x0F6D2B697BD44DA8U,
0x77E36F7304C48942U,
0x3F9D85A86A1D36C8U,
0x1112E6AD91D692A1U};
template<typename T>
inline T rotate_u(T v, int bits) {
return (v >> bits) | (v << ((sizeof(T) * 8) - bits));
}
template<typename T>
inline T shift_u(T v, int bits) {
return v >> bits;
}
PIByteArray SHA2::sha2xx(const PIByteArray & in, const uint32_t * initial, int out_bytes) {
constexpr int part_size = 64;
constexpr int rounds = 64;
static constexpr uint32_t k[part_size] = {
0x428A2F98u, 0x71374491u, 0xB5C0FBCFu, 0xE9B5DBA5u, 0x3956C25Bu, 0x59F111F1u, 0x923F82A4u, 0xAB1C5ED5u, 0xD807AA98u, 0x12835B01u,
0x243185BEu, 0x550C7DC3u, 0x72BE5D74u, 0x80DEB1FEu, 0x9BDC06A7u, 0xC19BF174u, 0xE49B69C1u, 0xEFBE4786u, 0x0FC19DC6u, 0x240CA1CCu,
0x2DE92C6Fu, 0x4A7484AAu, 0x5CB0A9DCu, 0x76F988DAu, 0x983E5152u, 0xA831C66Du, 0xB00327C8u, 0xBF597FC7u, 0xC6E00BF3u, 0xD5A79147u,
0x06CA6351u, 0x14292967u, 0x27B70A85u, 0x2E1B2138u, 0x4D2C6DFCu, 0x53380D13u, 0x650A7354u, 0x766A0ABBu, 0x81C2C92Eu, 0x92722C85u,
0xA2BFE8A1u, 0xA81A664Bu, 0xC24B8B70u, 0xC76C51A3u, 0xD192E819u, 0xD6990624u, 0xF40E3585u, 0x106AA070u, 0x19A4C116u, 0x1E376C08u,
0x2748774Cu, 0x34B0BCB5u, 0x391C0CB3u, 0x4ED8AA4Au, 0x5B9CCA4Fu, 0x682E6FF3u, 0x748F82EEu, 0x78A5636Fu, 0x84C87814u, 0x8CC70208u,
0x90BEFFFAu, 0xA4506CEBu, 0xBEF9A3F7u, 0xC67178F2u};
uint32_t h0 = initial[0];
uint32_t h1 = initial[1];
uint32_t h2 = initial[2];
uint32_t h3 = initial[3];
uint32_t h4 = initial[4];
uint32_t h5 = initial[5];
uint32_t h6 = initial[6];
uint32_t h7 = initial[7];
uint64_t l = in.size() * 8;
PIByteArray msg = in;
int add_l = (part_size - 8) - (msg.size() % (part_size));
if (add_l <= 0) add_l += part_size;
msg.append(0x80);
for (int i = 1; i < add_l; ++i)
msg.append(0x0);
msg << piChangedEndian(l);
int parts = msg.size_s() / part_size;
// piCout << l << "add" << add_l << "=" << (in.size() + add_l + sizeof(l)) << msg.size() << parts;
uint32_t w[64];
for (int p = 0; p < parts; ++p) {
uint32_t * mw = (uint32_t *)msg.data(p * part_size);
for (int i = 0; i < 16; ++i)
w[i] = piChangedEndian(mw[i]);
for (int i = 16; i < 64; ++i) {
uint32_t s0 = rotate_u(w[i - 15], 7) ^ rotate_u(w[i - 15], 18) ^ shift_u(w[i - 15], 3);
uint32_t s1 = rotate_u(w[i - 2], 17) ^ rotate_u(w[i - 2], 19) ^ shift_u(w[i - 2], 10);
w[i] = w[i - 16] + s0 + w[i - 7] + s1;
}
uint32_t a = h0;
uint32_t b = h1;
uint32_t c = h2;
uint32_t d = h3;
uint32_t e = h4;
uint32_t f = h5;
uint32_t g = h6;
uint32_t h = h7;
for (int i = 0; i < rounds; ++i) {
uint32_t S1 = rotate_u(e, 6) ^ rotate_u(e, 11) ^ rotate_u(e, 25);
uint32_t ch = (e & f) ^ (~e & g);
uint32_t t1 = h + S1 + ch + k[i] + w[i];
uint32_t S0 = rotate_u(a, 2) ^ rotate_u(a, 13) ^ rotate_u(a, 22);
uint32_t maj = (a & b) ^ (a & c) ^ (b & c);
uint32_t t2 = S0 + maj;
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
h0 += a;
h1 += b;
h2 += c;
h3 += d;
h4 += e;
h5 += f;
h6 += g;
h7 += h;
}
PIByteArray ret;
ret << piChangedEndian(h0) << piChangedEndian(h1) << piChangedEndian(h2) << piChangedEndian(h3) << piChangedEndian(h4)
<< piChangedEndian(h5) << piChangedEndian(h6) << piChangedEndian(h7);
ret.resize(out_bytes);
return ret;
}
PIByteArray SHA2::sha5xx(const PIByteArray & in, const uint64_t * initial, int out_bytes) {
constexpr int part_size = 128;
constexpr int rounds = 80;
static constexpr uint64_t k[80] = {
0X428A2F98D728AE22U, 0X7137449123EF65CDU, 0XB5C0FBCFEC4D3B2FU, 0XE9B5DBA58189DBBCU, 0X3956C25BF348B538U, 0X59F111F1B605D019U,
0X923F82A4AF194F9BU, 0XAB1C5ED5DA6D8118U, 0XD807AA98A3030242U, 0X12835B0145706FBEU, 0X243185BE4EE4B28CU, 0X550C7DC3D5FFB4E2U,
0X72BE5D74F27B896FU, 0X80DEB1FE3B1696B1U, 0X9BDC06A725C71235U, 0XC19BF174CF692694U, 0XE49B69C19EF14AD2U, 0XEFBE4786384F25E3U,
0X0FC19DC68B8CD5B5U, 0X240CA1CC77AC9C65U, 0X2DE92C6F592B0275U, 0X4A7484AA6EA6E483U, 0X5CB0A9DCBD41FBD4U, 0X76F988DA831153B5U,
0X983E5152EE66DFABU, 0XA831C66D2DB43210U, 0XB00327C898FB213FU, 0XBF597FC7BEEF0EE4U, 0XC6E00BF33DA88FC2U, 0XD5A79147930AA725U,
0X06CA6351E003826FU, 0X142929670A0E6E70U, 0X27B70A8546D22FFCU, 0X2E1B21385C26C926U, 0X4D2C6DFC5AC42AEDU, 0X53380D139D95B3DFU,
0X650A73548BAF63DEU, 0X766A0ABB3C77B2A8U, 0X81C2C92E47EDAEE6U, 0X92722C851482353BU, 0XA2BFE8A14CF10364U, 0XA81A664BBC423001U,
0XC24B8B70D0F89791U, 0XC76C51A30654BE30U, 0XD192E819D6EF5218U, 0XD69906245565A910U, 0XF40E35855771202AU, 0X106AA07032BBD1B8U,
0X19A4C116B8D2D0C8U, 0X1E376C085141AB53U, 0X2748774CDF8EEB99U, 0X34B0BCB5E19B48A8U, 0X391C0CB3C5C95A63U, 0X4ED8AA4AE3418ACBU,
0X5B9CCA4F7763E373U, 0X682E6FF3D6B2B8A3U, 0X748F82EE5DEFB2FCU, 0X78A5636F43172F60U, 0X84C87814A1F0AB72U, 0X8CC702081A6439ECU,
0X90BEFFFA23631E28U, 0XA4506CEBDE82BDE9U, 0XBEF9A3F7B2C67915U, 0XC67178F2E372532BU, 0XCA273ECEEA26619CU, 0XD186B8C721C0C207U,
0XEADA7DD6CDE0EB1EU, 0XF57D4F7FEE6ED178U, 0X06F067AA72176FBAU, 0X0A637DC5A2C898A6U, 0X113F9804BEF90DAEU, 0X1B710B35131C471BU,
0X28DB77F523047D84U, 0X32CAAB7B40C72493U, 0X3C9EBE0A15C9BEBCU, 0X431D67C49C100D4CU, 0X4CC5D4BECB3E42B6U, 0X597F299CFC657E2AU,
0X5FCB6FAB3AD6FAECU, 0X6C44198C4A475817U};
uint64_t h0 = initial[0];
uint64_t h1 = initial[1];
uint64_t h2 = initial[2];
uint64_t h3 = initial[3];
uint64_t h4 = initial[4];
uint64_t h5 = initial[5];
uint64_t h6 = initial[6];
uint64_t h7 = initial[7];
uint64_t l = in.size() * 8;
PIByteArray msg = in;
int add_l = (part_size - 8) - (msg.size() % (part_size));
if (add_l <= 0) add_l += part_size;
msg.append(0x80);
for (int i = 1; i < add_l; ++i)
msg.append(0x0);
msg << piChangedEndian(l);
int parts = msg.size_s() / part_size;
// piCout << l << "add" << add_l << "=" << (in.size() + add_l + sizeof(l)) << msg.size() << parts;
uint64_t w[80];
for (int p = 0; p < parts; ++p) {
uint64_t * mw = (uint64_t *)msg.data(p * part_size);
for (int i = 0; i < 16; ++i)
w[i] = piChangedEndian(mw[i]);
for (int i = 16; i < 80; ++i) {
uint64_t s0 = rotate_u(w[i - 15], 1) ^ rotate_u(w[i - 15], 8) ^ shift_u(w[i - 15], 7);
uint64_t s1 = rotate_u(w[i - 2], 19) ^ rotate_u(w[i - 2], 61) ^ shift_u(w[i - 2], 6);
w[i] = w[i - 16] + s0 + w[i - 7] + s1;
}
uint64_t a = h0;
uint64_t b = h1;
uint64_t c = h2;
uint64_t d = h3;
uint64_t e = h4;
uint64_t f = h5;
uint64_t g = h6;
uint64_t h = h7;
for (int i = 0; i < rounds; ++i) {
uint64_t S1 = rotate_u(e, 14) ^ rotate_u(e, 18) ^ rotate_u(e, 41);
uint64_t ch = (e & f) ^ (~e & g);
uint64_t t1 = h + S1 + ch + k[i] + w[i];
uint64_t S0 = rotate_u(a, 28) ^ rotate_u(a, 34) ^ rotate_u(a, 39);
uint64_t maj = (a & b) ^ (a & c) ^ (b & c);
uint64_t t2 = S0 + maj;
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
h0 += a;
h1 += b;
h2 += c;
h3 += d;
h4 += e;
h5 += f;
h6 += g;
h7 += h;
}
PIByteArray ret;
ret << piChangedEndian(h0) << piChangedEndian(h1) << piChangedEndian(h2) << piChangedEndian(h3) << piChangedEndian(h4)
<< piChangedEndian(h5) << piChangedEndian(h6) << piChangedEndian(h7);
ret.resize(out_bytes);
return ret;
}

View File

@@ -0,0 +1,39 @@
/*
PIP - Platform Independent Primitives
Digest algorithms
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pidigest_sha2_h
#define pidigest_sha2_h
#include "pibytearray.h"
class SHA2 {
public:
static const uint32_t initial_224[8];
static const uint32_t initial_256[8];
static const uint64_t initial_384[8];
static const uint64_t initial_512[8];
static const uint64_t initial_512_256[8];
static const uint64_t initial_512_224[8];
static PIByteArray sha2xx(const PIByteArray & in, const uint32_t * initial, int out_bytes);
static PIByteArray sha5xx(const PIByteArray & in, const uint64_t * initial, int out_bytes);
};
#endif

View File

@@ -0,0 +1,63 @@
#ifndef pihttpclient_h
#define pihttpclient_h
#include "pihttptypes.h"
#include "pip_http_client_export.h"
#include "pistringlist.h"
class PIHTTPClientBase {
public:
int __infoFunc(ssize_t dltotal, ssize_t dlnow, ssize_t ultotal, ssize_t ulnow);
int __debugFunc(int type, char * data, size_t size);
};
class PIP_HTTP_CLIENT_EXPORT PIHTTPClient: private PIHTTPClientBase {
friend class PIHTTPClientBase;
friend class CurlThreadPool;
public:
static PIHTTPClient * create(const PIString & url, PIHTTP::Method method = PIHTTP::Method::Get, const PIHTTP::MessageConst & req = {});
PIHTTPClient * onFinish(std::function<void()> f);
PIHTTPClient * onFinish(std::function<void(const PIHTTP::MessageConst &)> f);
PIHTTPClient * onError(std::function<void()> f);
PIHTTPClient * onError(std::function<void(const PIHTTP::MessageConst &)> f);
PIHTTPClient * onAbort(std::function<void()> f);
PIHTTPClient * onAbort(std::function<void(const PIHTTP::MessageConst &)> f);
void start();
void abort();
PIString lastError() const { return last_error; }
private:
NO_COPY_CLASS(PIHTTPClient)
PIHTTPClient();
virtual ~PIHTTPClient();
PRIVATE_DECLARATION(PIP_HTTP_CLIENT_EXPORT)
bool init();
void perform();
void procHeaderLine(PIString & line);
static size_t writeMemoryFunc(void * contents, size_t size, size_t nmemb, void * ptr);
static size_t readMemoryFunc(void * contents, size_t size, size_t nmemb, void * ptr);
static size_t headerFunc(char * contents, size_t size, size_t nmemb, void * ptr);
int infoFunc(ssize_t dltotal, ssize_t dlnow, ssize_t ultotal, ssize_t ulnow);
int debugFunc(int type, char * data, size_t size);
PIString url;
PIString last_error;
PIStringList headers;
PIByteArray buffer_out;
PIHTTP::MessageMutable request, reply;
std::atomic_bool is_cancel = {false};
ssize_t read_pos = 0;
std::function<void(const PIHTTP::MessageConst &)> on_finish, on_error, on_abort;
};
#endif

View File

@@ -0,0 +1,54 @@
/*
PIP - Platform Independent Primitives
Module includes
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//! \defgroup HTTPServer HTTPServer
//! \~\brief
//! \~english HTTP client
//! \~russian HTTP сервер
//!
//! \~\details
//! \~english \section cmake_module_HTTPServer Building with CMake
//! \~russian \section cmake_module_HTTPServer Сборка с использованием CMake
//!
//! \~\code
//! find_package(PIP REQUIRED)
//! target_link_libraries([target] PIP::HTTPServer)
//! \endcode
//!
//! \~english \par Common
//! \~russian \par Общее
//!
//! \~english
//! These files provides HTTP server based on libmicrohttpd
//!
//! \~russian
//! Эти файлы обеспечивают HTTP сервер, основанный на libmicrohttpd
//!
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//!
#ifndef pihttpclientmodule_H
#define pihttpclientmodule_H
#include "pihttpclient.h"
#endif

View File

@@ -0,0 +1,328 @@
#ifndef pihttpconstants_h
#define pihttpconstants_h
namespace PIHTTP {
enum class Method {
Unknown,
Get,
Head,
Post,
Put,
Delete,
Connect,
Options,
Trace,
Patch
};
enum class Code {
Unknown = -1,
Continue = 100,
SwitchingProtocols = 101,
Processing = 102,
EarlyHints = 103,
Ok = 200,
Created = 201,
Accepted = 202,
NonAuthoritativeInformation = 203,
NoContent = 204,
ResetContent = 205,
PartialContent = 206,
MultiStatus = 207,
AlreadyReported = 208,
IMUsed = 226,
MultipleChoices = 300,
MovedPermanently = 301,
Found = 302,
SeeOther = 303,
NotModified = 304,
UseProxy = 305,
SwitchProxy = 306,
TemporaryRedirect = 307,
PermanentRedirect = 308,
BadRequest = 400,
Unauthorized = 401,
PaymentRequired = 402,
Forbidden = 403,
NotFound = 404,
MethodNotAllowed = 405,
NotAcceptable = 406,
ProxyAuthenticationRequired = 407,
RequestTimeout = 408,
Conflict = 409,
Gone = 410,
LengthRequired = 411,
PreconditionFailed = 412,
ContentTooLarge = 413,
UriTooLong = 414,
UnsupportedMediaType = 415,
RangeNotSatisfiable = 416,
ExpectationFailed = 417,
MisdirectedRequest = 421,
UnprocessableContent = 422,
Locked = 423,
FailedDependency = 424,
TooEarly = 425,
UpgradeRequired = 426,
PreconditionRequired = 428,
TooManyRequests = 429,
RequestHeaderFieldsTooLarge = 431,
RetryWith = 449,
BlockedByWindowsParentalControls = 450,
UnavailableForLegalReasons = 451,
InternalServerError = 500,
NotImplemented = 501,
BadGateway = 502,
ServiceUnavailable = 503,
GatewayTimeout = 504,
HttpVersionNotSupported = 505,
VariantAlsoNegotiates = 506,
InsufficientStorage = 507,
LoopDetected = 508,
NotExtended = 510,
BandwidthLimitExceeded = 509,
NetworkAuthenticationRequired = 511,
};
namespace Header {
constexpr static char Accept[] = "Accept";
constexpr static char AcceptCharset[] = "Accept-Charset";
constexpr static char AcceptEncoding[] = "Accept-Encoding";
constexpr static char AcceptLanguage[] = "Accept-Language";
constexpr static char AcceptRanges[] = "Accept-Ranges";
constexpr static char Age[] = "Age";
constexpr static char Allow[] = "Allow";
constexpr static char AuthenticationInfo[] = "Authentication-Info";
constexpr static char Authorization[] = "Authorization";
constexpr static char CacheControl[] = "Cache-Control";
constexpr static char Close[] = "Close";
constexpr static char Connection[] = "Connection";
constexpr static char ContentEncoding[] = "Content-Encoding";
constexpr static char ContentLanguage[] = "Content-Language";
constexpr static char ContentLength[] = "Content-Length";
constexpr static char ContentLocation[] = "Content-Location";
constexpr static char ContentRange[] = "Content-Range";
constexpr static char ContentType[] = "Content-Type";
constexpr static char Date[] = "Date";
constexpr static char ETag[] = "ETag";
constexpr static char Expect[] = "Expect";
constexpr static char Expires[] = "Expires";
constexpr static char From[] = "From";
constexpr static char Host[] = "Host";
constexpr static char IfMatch[] = "If-Match";
constexpr static char IfModifiedSince[] = "If-Modified-Since";
constexpr static char IfNoneMatch[] = "If-None-Match";
constexpr static char IfRange[] = "If-Range";
constexpr static char IfUnmodifiedSince[] = "If-Unmodified-Since";
constexpr static char LastModified[] = "Last-Modified";
constexpr static char Location[] = "Location";
constexpr static char MaxForwards[] = "Max-Forwards";
constexpr static char MimeVersion[] = "MIME-Version";
constexpr static char Pragma[] = "Pragma";
constexpr static char ProxyAuthenticate[] = "Proxy-Authenticate";
constexpr static char ProxyAuthenticationInfo[] = "Proxy-Authentication-Info";
constexpr static char ProxyAuthorization[] = "Proxy-Authorization";
constexpr static char Range[] = "Range";
constexpr static char Referer[] = "Referer";
constexpr static char RetryAfter[] = "Retry-After";
constexpr static char Server[] = "Server";
constexpr static char TE[] = "TE";
constexpr static char Trailer[] = "Trailer";
constexpr static char TransferEncoding[] = "Transfer-Encoding";
constexpr static char Upgrade[] = "Upgrade";
constexpr static char UserAgent[] = "User-Agent";
constexpr static char Vary[] = "Vary";
constexpr static char Via[] = "Via";
constexpr static char WWWAuthenticate[] = "WWW-Authenticate";
constexpr static char Asterisk[] = "*";
constexpr static char AIM[] = "A-IM";
constexpr static char AcceptAdditions[] = "Accept-Additions";
constexpr static char AcceptCH[] = "Accept-CH";
constexpr static char AcceptDatetime[] = "Accept-Datetime";
constexpr static char AcceptFeatures[] = "Accept-Features";
constexpr static char AcceptPatch[] = "Accept-Patch";
constexpr static char AcceptPost[] = "Accept-Post";
constexpr static char AcceptSignature[] = "Accept-Signature";
constexpr static char AccessControlAllowCredentials[] = "Access-Control-Allow-Credentials";
constexpr static char AccessControlAllowHeaders[] = "Access-Control-Allow-Headers";
constexpr static char AccessControlAllowMethods[] = "Access-Control-Allow-Methods";
constexpr static char AccessControlAllowOrigin[] = "Access-Control-Allow-Origin";
constexpr static char AccessControlExposeHeaders[] = "Access-Control-Expose-Headers";
constexpr static char AccessControlMaxAge[] = "Access-Control-Max-Age";
constexpr static char AccessControlRequestHeaders[] = "Access-Control-Request-Headers";
constexpr static char AccessControlRequestMethod[] = "Access-Control-Request-Method";
constexpr static char ALPN[] = "ALPN";
constexpr static char AltSvc[] = "Alt-Svc";
constexpr static char AltUsed[] = "Alt-Used";
constexpr static char Alternates[] = "Alternates";
constexpr static char ApplyToRedirectRef[] = "Apply-To-Redirect-Ref";
constexpr static char AuthenticationControl[] = "Authentication-Control";
constexpr static char CacheStatus[] = "Cache-Status";
constexpr static char CalManagedID[] = "Cal-Managed-ID";
constexpr static char CalDAVTimezones[] = "CalDAV-Timezones";
constexpr static char CapsuleProtocol[] = "Capsule-Protocol";
constexpr static char CDNCacheControl[] = "CDN-Cache-Control";
constexpr static char CDNLoop[] = "CDN-Loop";
constexpr static char CertNotAfter[] = "Cert-Not-After";
constexpr static char CertNotBefore[] = "Cert-Not-Before";
constexpr static char ClearSiteData[] = "Clear-Site-Data";
constexpr static char ClientCert[] = "Client-Cert";
constexpr static char ClientCertChain[] = "Client-Cert-Chain";
constexpr static char ContentDigest[] = "Content-Digest";
constexpr static char ContentDisposition[] = "Content-Disposition";
constexpr static char ContentID[] = "Content-ID";
constexpr static char ContentSecurityPolicy[] = "Content-Security-Policy";
constexpr static char ContentSecurityPolicyReportOnly[] = "Content-Security-Policy-Report-Only";
constexpr static char Cookie[] = "Cookie";
constexpr static char CrossOriginEmbedderPolicy[] = "Cross-Origin-Embedder-Policy";
constexpr static char CrossOriginEmbedderPolicyReportOnly[] = "Cross-Origin-Embedder-Policy-Report-Only";
constexpr static char CrossOriginOpenerPolicy[] = "Cross-Origin-Opener-Policy";
constexpr static char CrossOriginOpenerPolicyReportOnly[] = "Cross-Origin-Opener-Policy-Report-Only";
constexpr static char CrossOriginResourcePolicy[] = "Cross-Origin-Resource-Policy";
constexpr static char DASL[] = "DASL";
constexpr static char DAV[] = "DAV";
constexpr static char DeltaBase[] = "Delta-Base";
constexpr static char Depth[] = "Depth";
constexpr static char Destination[] = "Destination";
constexpr static char DifferentialID[] = "Differential-ID";
constexpr static char DPoP[] = "DPoP";
constexpr static char DPoPNonce[] = "DPoP-Nonce";
constexpr static char EarlyData[] = "Early-Data";
constexpr static char ExpectCT[] = "Expect-CT";
constexpr static char Forwarded[] = "Forwarded";
constexpr static char Hobareg[] = "Hobareg";
constexpr static char If[] = "If";
constexpr static char IfScheduleTagMatch[] = "If-Schedule-Tag-Match";
constexpr static char IM[] = "IM";
constexpr static char IncludeReferredTokenBindingID[] = "Include-Referred-Token-Binding-ID";
constexpr static char KeepAlive[] = "Keep-Alive";
constexpr static char Label[] = "Label";
constexpr static char LastEventID[] = "Last-Event-ID";
constexpr static char Link[] = "Link";
constexpr static char LockToken[] = "Lock-Token";
constexpr static char MementoDatetime[] = "Memento-Datetime";
constexpr static char Meter[] = "Meter";
constexpr static char Negotiate[] = "Negotiate";
constexpr static char NEL[] = "NEL";
constexpr static char ODataEntityid[] = "OData-EntityId";
constexpr static char ODataIsolation[] = "OData-Isolation";
constexpr static char ODataMaxversion[] = "OData-MaxVersion";
constexpr static char ODataVersion[] = "OData-Version";
constexpr static char OptionalWWWAuthenticate[] = "Optional-WWW-Authenticate";
constexpr static char OrderingType[] = "Ordering-Type";
constexpr static char Origin[] = "Origin";
constexpr static char OriginAgentCluster[] = "Origin-Agent-Cluster";
constexpr static char OSCORE[] = "OSCORE";
constexpr static char OSLCCoreVersion[] = "OSLC-Core-Version";
constexpr static char Overwrite[] = "Overwrite";
constexpr static char PingFrom[] = "Ping-From";
constexpr static char PingTo[] = "Ping-To";
constexpr static char Position[] = "Position";
constexpr static char Prefer[] = "Prefer";
constexpr static char PreferenceApplied[] = "Preference-Applied";
constexpr static char Priority[] = "Priority";
constexpr static char ProxyStatus[] = "Proxy-Status";
constexpr static char PublicKeyPins[] = "Public-Key-Pins";
constexpr static char PublicKeyPinsReportOnly[] = "Public-Key-Pins-Report-Only";
constexpr static char RedirectRef[] = "Redirect-Ref";
constexpr static char Refresh[] = "Refresh";
constexpr static char ReplayNonce[] = "Replay-Nonce";
constexpr static char ReprDigest[] = "Repr-Digest";
constexpr static char ScheduleReply[] = "Schedule-Reply";
constexpr static char ScheduleTag[] = "Schedule-Tag";
constexpr static char SecPurpose[] = "Sec-Purpose";
constexpr static char SecTokenBinding[] = "Sec-Token-Binding";
constexpr static char SecWebsocketAccept[] = "Sec-WebSocket-Accept";
constexpr static char SecWebsocketExtensions[] = "Sec-WebSocket-Extensions";
constexpr static char SecWebsocketKey[] = "Sec-WebSocket-Key";
constexpr static char SecWebsocketProtocol[] = "Sec-WebSocket-Protocol";
constexpr static char SecWebsocketVersion[] = "Sec-WebSocket-Version";
constexpr static char ServerTiming[] = "Server-Timing";
constexpr static char SetCookie[] = "Set-Cookie";
constexpr static char Signature[] = "Signature";
constexpr static char SignatureInput[] = "Signature-Input";
constexpr static char SLUG[] = "SLUG";
constexpr static char Soapaction[] = "SoapAction";
constexpr static char StatusURI[] = "Status-URI";
constexpr static char StrictTransportSecurity[] = "Strict-Transport-Security";
constexpr static char Sunset[] = "Sunset";
constexpr static char SurrogateCapability[] = "Surrogate-Capability";
constexpr static char SurrogateControl[] = "Surrogate-Control";
constexpr static char TCN[] = "TCN";
constexpr static char Timeout[] = "Timeout";
constexpr static char Topic[] = "Topic";
constexpr static char Traceparent[] = "Traceparent";
constexpr static char Tracestate[] = "Tracestate";
constexpr static char TTL[] = "TTL";
constexpr static char Urgency[] = "Urgency";
constexpr static char VariantVary[] = "Variant-Vary";
constexpr static char WantContentDigest[] = "Want-Content-Digest";
constexpr static char WantReprDigest[] = "Want-Repr-Digest";
constexpr static char XContentTypeOptions[] = "X-Content-Type-Options";
constexpr static char XFrameOptions[] = "X-Frame-Options";
constexpr static char AmpCacheTransform[] = "AMP-Cache-Transform";
constexpr static char ConfigurationContext[] = "Configuration-Context";
constexpr static char EDIINTFeatures[] = "EDIINT-Features";
constexpr static char Isolation[] = "Isolation";
constexpr static char PermissionsPolicy[] = "Permissions-Policy";
constexpr static char RepeatabilityClientID[] = "Repeatability-Client-ID";
constexpr static char RepeatabilityFirstSent[] = "Repeatability-First-Sent";
constexpr static char RepeatabilityRequestID[] = "Repeatability-Request-ID";
constexpr static char RepeatabilityResult[] = "Repeatability-Result";
constexpr static char ReportingEndpoints[] = "Reporting-Endpoints";
constexpr static char SecGPC[] = "Sec-GPC";
constexpr static char TimingAllowOrigin[] = "Timing-Allow-Origin";
constexpr static char CPEPInfo[] = "C-PEP-Info";
constexpr static char ProtocolInfo[] = "Protocol-Info";
constexpr static char ProtocolQuery[] = "Protocol-Query";
constexpr static char AccessControl[] = "Access-Control";
constexpr static char CExt[] = "C-Ext";
constexpr static char CMan[] = "C-Man";
constexpr static char COpt[] = "C-Opt";
constexpr static char CPEP[] = "C-PEP";
constexpr static char ContentBase[] = "Content-Base";
constexpr static char ContentMD5[] = "Content-MD5";
constexpr static char ContentScriptType[] = "Content-Script-Type";
constexpr static char ContentStyleType[] = "Content-Style-Type";
constexpr static char ContentVersion[] = "Content-Version";
constexpr static char Cookie2[] = "Cookie2";
constexpr static char DefaultStyle[] = "Default-Style";
constexpr static char DerivedFrom[] = "Derived-From";
constexpr static char Digest[] = "Digest";
constexpr static char Ext[] = "Ext";
constexpr static char Getprofile[] = "GetProfile";
constexpr static char HTTP2Settings[] = "HTTP2-Settings";
constexpr static char Man[] = "Man";
constexpr static char MethodCheck[] = "Method-Check";
constexpr static char MethodCheckExpires[] = "Method-Check-Expires";
constexpr static char Opt[] = "Opt";
constexpr static char P3P[] = "P3P";
constexpr static char PEP[] = "PEP";
constexpr static char PepInfo[] = "Pep-Info";
constexpr static char PICSLabel[] = "PICS-Label";
constexpr static char Profileobject[] = "ProfileObject";
constexpr static char Protocol[] = "Protocol";
constexpr static char ProtocolRequest[] = "Protocol-Request";
constexpr static char ProxyFeatures[] = "Proxy-Features";
constexpr static char ProxyInstruction[] = "Proxy-Instruction";
constexpr static char Public[] = "Public";
constexpr static char RefererRoot[] = "Referer-Root";
constexpr static char Safe[] = "Safe";
constexpr static char SecurityScheme[] = "Security-Scheme";
constexpr static char SetCookie2[] = "Set-Cookie2";
constexpr static char Setprofile[] = "SetProfile";
constexpr static char URI[] = "URI";
constexpr static char WantDigest[] = "Want-Digest";
constexpr static char Warning[] = "Warning";
}; // namespace Header
}; // namespace PIHTTP
#endif

View File

@@ -0,0 +1,109 @@
#include "pihttptypes.h"
const char * PIHTTP::methodName(Method m) {
switch (m) {
case Method::Get: return "GET";
case Method::Head: return "HEAD";
case Method::Post: return "POST";
case Method::Put: return "PUT";
case Method::Delete: return "DELETE";
case Method::Connect: return "CONNECT";
case Method::Options: return "OPTIONS";
case Method::Trace: return "TRACE";
case Method::Patch: return "PATCH";
default: break;
};
return "UNKNOWN";
}
// PIHTTP::MessageConst
bool PIHTTP::MessageConst::isCodeInformational() const {
return (int)code() >= 100 && (int)code() < 200;
}
bool PIHTTP::MessageConst::isCodeSuccess() const {
return (int)code() >= 200 && (int)code() < 300;
}
bool PIHTTP::MessageConst::isCodeRedirection() const {
return (int)code() >= 300 && (int)code() < 400;
}
bool PIHTTP::MessageConst::isCodeClientError() const {
return (int)code() >= 400 && (int)code() < 500;
}
bool PIHTTP::MessageConst::isCodeServerError() const {
return (int)code() >= 500 && (int)code() < 600;
}
// PIHTTP::MessageMutable
PIHTTP::MessageMutable & PIHTTP::MessageMutable::addHeader(const PIString & header, const PIString & value) {
m_headers[header] = value;
return *this;
}
PIHTTP::MessageMutable & PIHTTP::MessageMutable::removeHeader(const PIString & header) {
m_headers.remove(header);
return *this;
}
PIHTTP::MessageMutable & PIHTTP::MessageMutable::addArgument(const PIString & arg, const PIString & value) {
m_arguments[arg] = value;
return *this;
}
PIHTTP::MessageMutable & PIHTTP::MessageMutable::removeArgument(const PIString & arg) {
m_arguments.remove(arg);
return *this;
}
PIHTTP::MessageMutable & PIHTTP::MessageMutable::setMethod(Method m) {
m_method = m;
return *this;
}
PIHTTP::MessageMutable & PIHTTP::MessageMutable::setCode(Code c) {
m_code = c;
return *this;
}
PIHTTP::MessageMutable & PIHTTP::MessageMutable::setPath(PIString p) {
m_path = std::move(p);
return *this;
}
PIHTTP::MessageMutable & PIHTTP::MessageMutable::setBody(PIByteArray b) {
m_body = std::move(b);
return *this;
}
PIHTTP::MessageMutable PIHTTP::MessageMutable::fromCode(Code c) {
PIHTTP::MessageMutable ret;
ret.setCode(c);
return ret;
}
PIHTTP::MessageMutable PIHTTP::MessageMutable::fromMethod(Method m) {
PIHTTP::MessageMutable ret;
ret.setMethod(m);
return ret;
}

View File

@@ -0,0 +1,63 @@
#ifndef pihttptypes_h
#define pihttptypes_h
#include "pihttpconstants.h"
#include "pip_export.h"
#include "pistringlist.h"
namespace PIHTTP {
class PIP_EXPORT MessageConst {
public:
PIHTTP::Method method() const { return m_method; }
PIHTTP::Code code() const { return m_code; }
bool isCodeInformational() const;
bool isCodeSuccess() const;
bool isCodeRedirection() const;
bool isCodeClientError() const;
bool isCodeServerError() const;
bool isCodeError() const { return isCodeClientError() || isCodeServerError(); }
const PIString & path() const { return m_path; }
PIStringList pathList() const { return m_path.split('/').removeAll({}); }
const PIByteArray & body() const { return m_body; }
const PIMap<PIString, PIString> & headers() const { return m_headers; }
const PIMap<PIString, PIString> & arguments() const { return m_arguments; }
protected:
PIHTTP::Method m_method = PIHTTP::Method::Unknown;
PIHTTP::Code m_code = PIHTTP::Code::Ok;
PIString m_path;
PIByteArray m_body;
PIMap<PIString, PIString> m_headers;
PIMap<PIString, PIString> m_arguments;
};
class PIP_EXPORT MessageMutable: public MessageConst {
public:
MessageMutable & setMethod(PIHTTP::Method m);
MessageMutable & setCode(PIHTTP::Code c);
MessageMutable & setPath(PIString p);
MessageMutable & setBody(PIByteArray b);
const PIMap<PIString, PIString> & headers() const { return m_headers; }
const PIMap<PIString, PIString> & arguments() const { return m_arguments; }
PIMap<PIString, PIString> & headers() { return m_headers; }
MessageMutable & addHeader(const PIString & header, const PIString & value);
MessageMutable & removeHeader(const PIString & header);
PIMap<PIString, PIString> & arguments() { return m_arguments; }
MessageMutable & addArgument(const PIString & arg, const PIString & value);
MessageMutable & removeArgument(const PIString & arg);
static MessageMutable fromCode(PIHTTP::Code c);
static MessageMutable fromMethod(PIHTTP::Method m);
};
PIP_EXPORT const char * methodName(Method m);
}; // namespace PIHTTP
#endif

View File

@@ -1,7 +1,7 @@
#ifndef MICROHTTPD_SERVER_P_H
#define MICROHTTPD_SERVER_P_H
#include "pibase.h"
#include "pihttptypes.h"
#include "piobject.h"
#include "pip_http_server_export.h"
@@ -15,18 +15,6 @@ public:
MicrohttpdServer();
virtual ~MicrohttpdServer();
enum class Method {
Unknown,
Get,
Head,
Post,
Put,
Delete,
Connect,
Options,
Trace,
Patch
};
enum class Option {
ConnectionLimit, // uint
ConnectionTimeout, // uint, sec
@@ -36,30 +24,6 @@ public:
HTTPSKeyPassword // const char * to passwd for key.pem
};
struct PIP_HTTP_SERVER_EXPORT Request {
MicrohttpdServer::Method method;
PIString path;
PIByteArray body;
PIMap<PIString, PIString> headers;
PIMap<PIString, PIString> args;
};
class PIP_HTTP_SERVER_EXPORT Reply {
friend struct MicrohttpdServerConnection;
public:
void addHeader(const PIString & header, const PIString & value);
void removeHeader(const PIString & header);
void setBody(const PIByteArray & b);
void setCode(int c);
private:
void addFixedHeaders();
int code = 200;
PIByteArray body;
PIMap<PIString, PIString> headers;
};
void setOption(Option o, PIVariant v);
void setFavicon(const PIByteArray & im);
@@ -68,14 +32,25 @@ public:
bool isListen() const;
void stop();
void setRequestCallback(std::function<Reply(Request)> c) { callback = c; }
void enableBasicAuth() { setBasicAuthEnabled(true); }
void disableBasicAuth() { setBasicAuthEnabled(false); }
void setBasicAuthEnabled(bool yes) { use_basic_auth = yes; }
bool isBasicAuthEnabled() const { return use_basic_auth; }
void setBasicAuthRealm(const PIString & r) { realm = r; }
void setRequestCallback(std::function<PIHTTP::MessageMutable(const PIHTTP::MessageConst &)> c) { callback = c; }
void setBasicAuthCallback(std::function<bool(const PIString &, const PIString &)> c) { callback_auth = c; }
private:
static void addFixedHeaders(PIHTTP::MessageMutable & msg);
PRIVATE_DECLARATION(PIP_HTTP_SERVER_EXPORT)
PIByteArray favicon;
PIString realm;
PIMap<Option, PIVariant> opts;
std::function<Reply(Request)> callback;
std::function<PIHTTP::MessageMutable(const PIHTTP::MessageConst &)> callback;
std::function<bool(const PIString &, const PIString &)> callback_auth;
std::atomic_bool use_basic_auth = {false};
PIByteArray mem_key, mem_cert, key_pass;
};

View File

@@ -10,13 +10,24 @@ public:
PIHTTPServer();
virtual ~PIHTTPServer();
using RequestFunction = std::function<MicrohttpdServer::Reply(const MicrohttpdServer::Request &)>;
using RequestFunction = std::function<PIHTTP::MessageMutable(const PIHTTP::MessageConst &)>;
void registerPath(const PIString & path, MicrohttpdServer::Method method, RequestFunction functor);
void registerPath(const PIString & path, PIHTTP::Method method, RequestFunction functor);
template<typename T>
void
registerPath(const PIString & path, PIHTTP::Method method, T * o, PIHTTP::MessageMutable (T::*function)(const PIHTTP::MessageConst &)) {
registerPath(path, method, [o, function](const PIHTTP::MessageConst & m) { return (o->*function)(m); });
}
void registerUnhandled(RequestFunction functor);
void unregisterPath(const PIString & path, MicrohttpdServer::Method method);
template<typename T>
void registerUnhandled(T * o, PIHTTP::MessageMutable (T::*function)(const PIHTTP::MessageConst &)) {
registerUnhandled([o, function](const PIHTTP::MessageConst & m) { return (o->*function)(m); });
}
void unregisterPath(const PIString & path, PIHTTP::Method method);
void unregisterPath(const PIString & path);
// void registerBasicAuth() {}
void addReplyHeader(const PIString & name, const PIString & value) { reply_headers[name] = value; }
void removeReplyHeader(const PIString & name) { reply_headers.remove(name); }
void clearReplyHeaders() { reply_headers.clear(); }
@@ -25,7 +36,7 @@ private:
struct Endpoint {
bool match(const PIStringList & in_path) const;
PIStringList path;
MicrohttpdServer::Method method = MicrohttpdServer::Method::Unknown;
PIHTTP::Method method = PIHTTP::Method::Unknown;
RequestFunction function;
};
PIMap<PIString, PIString> reply_headers;

View File

@@ -181,6 +181,7 @@ bool PIBinaryLog::threadedRead(const uchar * readed, ssize_t size) {
is_thread_ok = false;
logmutex.lock();
const PISystemTime lastrec_timestamp = lastrecord.timestamp;
const int lastrec_id = lastrecord.id;
logmutex.unlock();
PISystemTime pt;
double delay;
@@ -248,7 +249,8 @@ bool PIBinaryLog::threadedRead(const uchar * readed, ssize_t size) {
break;
default: return false;
}
bool res = PIIODevice::threadedRead(readed, size);
bool res = PIIODevice::threadedRead(readed, size);
threadedReadRecord(PIByteArray(readed, size), lastrec_id, lastrec_timestamp);
is_thread_ok = true;
return res;
}

View File

@@ -327,6 +327,7 @@ public:
EVENT(fileError);
EVENT1(newFile, const PIString &, filename);
EVENT1(posChanged, int, pos);
EVENT3(threadedReadRecord, PIByteArray, data, int, id, PISystemTime, time);
//! Get binlog info and statistic
static BinLogInfo getLogInfo(const PIString & path);

View File

@@ -326,7 +326,7 @@ PIVector<PIFile::FileInfo> PIDir::entries() {
}
} else {
WIN32_FIND_DATAA fd;
memset(&fd, 0, sizeof(fd));
piZeroMemory(fd);
p += "\\*";
void * hf = FindFirstFileA((LPCSTR)(p.data()), &fd);
if (!hf) return l;
@@ -335,7 +335,7 @@ PIVector<PIFile::FileInfo> PIDir::entries() {
PIString fn(fd.cFileName);
if (fn == "..") hdd = true;
l << PIFile::fileInfo(dp + fn);
memset(&fd, 0, sizeof(fd));
piZeroMemory(fd);
} while (FindNextFileA(hf, &fd) != 0);
FindClose(hf);
l.sort(sort_compare);
@@ -440,7 +440,7 @@ PIDir PIDir::current() {
char rc[1024];
#endif
#ifdef WINDOWS
memset(rc, 0, 1024);
piZeroMemory(rc, 1024);
if (GetCurrentDirectory(1024, (LPTSTR)rc) == 0) return PIString();
PIString ret(rc);
ret.replaceAll("\\", PIDir::separator);
@@ -463,13 +463,13 @@ PIDir PIDir::home() {
#endif
#ifdef WINDOWS
rc = new char[1024];
memset(rc, 0, 1024);
piZeroMemory(rc, 1024);
if (ExpandEnvironmentStrings((LPCTSTR) "%HOMEPATH%", (LPTSTR)rc, 1024) == 0) {
delete[] rc;
return PIDir();
}
PIString hp(rc);
memset(rc, 0, 1024);
piZeroMemory(rc, 1024);
if (ExpandEnvironmentStrings((LPCTSTR) "%HOMEDRIVE%", (LPTSTR)rc, 1024) == 0) {
delete[] rc;
return PIDir();
@@ -495,7 +495,7 @@ PIDir PIDir::temporary() {
char * rc = nullptr;
#ifdef WINDOWS
rc = new char[1024];
memset(rc, 0, 1024);
piZeroMemory(rc, 1024);
int ret = GetTempPath(1024, (LPTSTR)rc);
if (ret == 0) {
delete[] rc;

View File

@@ -163,6 +163,30 @@ PIEthernet::~PIEthernet() {
}
void PIEthernet::setReadTimeout(PISystemTime tm) {
setProperty("readTimeout", tm);
applyTimeouts();
}
void PIEthernet::setWriteTimeout(PISystemTime tm) {
setProperty("writeTimeout", tm);
applyTimeouts();
}
void PIEthernet::setReadBufferSize(int bytes) {
rcv_buf = bytes;
applyBuffers();
}
void PIEthernet::setWriteBufferSize(int bytes) {
snd_buf = bytes;
applyBuffers();
}
void PIEthernet::construct() {
// piCout << " PIEthernet" << uint(this);
setOption(BlockingWrite);
@@ -211,6 +235,7 @@ void PIEthernet::init() {
}
applyParameters();
applyTimeouts();
applyBuffers();
applyOptInt(IPPROTO_IP, IP_TTL, TTL());
// piCoutObj << "inited" << path();
}
@@ -272,7 +297,7 @@ bool PIEthernet::openDevice() {
// if (type() == TCP_Client)
// connecting_ = true;
if (type() != UDP || mode() == PIIODevice::WriteOnly) return true;
memset(&PRIVATE->addr_, 0, sizeof(PRIVATE->addr_));
piZeroMemory(PRIVATE->addr_);
PRIVATE->addr_.sin_family = AF_INET;
PRIVATE->addr_.sin_port = htons(addr_r.port());
if (params[PIEthernet::Broadcast])
@@ -296,6 +321,7 @@ bool PIEthernet::openDevice() {
while (!mcast_queue.isEmpty())
joinMulticastGroup(mcast_queue.dequeue());
applyTimeouts();
applyBuffers();
applyOptInt(IPPROTO_IP, IP_TTL, TTL());
addr_lr.clear();
return true;
@@ -338,9 +364,22 @@ void PIEthernet::applyTimeouts() {
}
void PIEthernet::applyBuffers() {
if (sock < 0) return;
if (rcv_buf > 0) ethSetsockoptInt(sock, SOL_SOCKET, SO_RCVBUF, rcv_buf);
if (snd_buf > 0) {
if (sock_s != sock) {
ethSetsockoptInt(sock_s, SOL_SOCKET, SO_SNDBUF, snd_buf);
} else {
ethSetsockoptInt(sock, SOL_SOCKET, SO_SNDBUF, snd_buf);
}
}
}
void PIEthernet::applyTimeout(int fd, int opt, PISystemTime tm) {
if (fd == 0) return;
// piCoutObj << "setReadIsBlocking" << yes;
// piCoutObj << "setReadIsBlocking" << yes;
#ifdef WINDOWS
DWORD _tm = tm.toMilliseconds();
#else
@@ -377,7 +416,7 @@ bool PIEthernet::joinMulticastGroup(const PIString & group) {
#else
struct ip_mreq mreq;
#endif
memset(&mreq, 0, sizeof(mreq));
piZeroMemory(mreq);
#ifdef LINUX
// mreq.imr_address.s_addr = INADDR_ANY;
/*PIEthernet::InterfaceList il = interfaces();
@@ -423,7 +462,7 @@ bool PIEthernet::leaveMulticastGroup(const PIString & group) {
#else
struct ip_mreq mreq;
#endif
memset(&mreq, 0, sizeof(mreq));
piZeroMemory(mreq);
if (params[PIEthernet::Broadcast])
#ifndef LWIP
mreq.imr_address.s_addr = INADDR_ANY;
@@ -454,7 +493,7 @@ bool PIEthernet::connect(bool threaded) {
if (connected_) return false;
if (sock == -1) init();
if (sock == -1) return false;
memset(&PRIVATE->addr_, 0, sizeof(PRIVATE->addr_));
piZeroMemory(PRIVATE->addr_);
addr_r.set(path());
PRIVATE->addr_.sin_port = htons(addr_r.port());
PRIVATE->addr_.sin_addr.s_addr = addr_r.ip();
@@ -492,7 +531,7 @@ bool PIEthernet::listen(bool threaded) {
}
listen_threaded = server_bounded = false;
addr_r.set(path());
memset(&PRIVATE->addr_, 0, sizeof(PRIVATE->addr_));
piZeroMemory(PRIVATE->addr_);
PRIVATE->addr_.sin_port = htons(addr_r.port());
PRIVATE->addr_.sin_addr.s_addr = addr_r.ip();
PRIVATE->addr_.sin_family = AF_INET;
@@ -618,7 +657,7 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) {
case TCP_Client:
if (connecting_) {
addr_r.set(path());
memset(&PRIVATE->addr_, 0, sizeof(PRIVATE->addr_));
piZeroMemory(PRIVATE->addr_);
PRIVATE->addr_.sin_port = htons(addr_r.port());
PRIVATE->addr_.sin_addr.s_addr = addr_r.ip();
PRIVATE->addr_.sin_family = AF_INET;
@@ -704,7 +743,7 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) {
if (rs > 0) received(read_to, rs);
return rs;
case UDP: {
memset(&PRIVATE->raddr_, 0, sizeof(PRIVATE->raddr_));
piZeroMemory(PRIVATE->raddr_);
// piCoutObj << "read from" << path() << "...";
#ifdef WINDOWS
long wr = waitForEvent(PRIVATE->event, FD_READ | FD_CLOSE);
@@ -765,7 +804,7 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) {
// piCout << "[PIEth] write to" << ip_s << ":" << port_s << "ok";
case TCP_Client: {
if (connecting_) {
memset(&PRIVATE->addr_, 0, sizeof(PRIVATE->addr_));
piZeroMemory(PRIVATE->addr_);
addr_r.set(path());
PRIVATE->addr_.sin_port = htons(addr_r.port());
PRIVATE->addr_.sin_addr.s_addr = addr_r.ip();
@@ -962,7 +1001,7 @@ long PIEthernet::waitForEvent(PIWaitEvent & event, long mask) {
// DWORD wr = WSAWaitForMultipleEvents(1, &(PRIVATE->read_event), FALSE, WSA_INFINITE, TRUE);
// if (wr == WSA_WAIT_EVENT_0) {
WSANETWORKEVENTS events;
memset(&events, 0, sizeof(events));
piZeroMemory(events);
WSAEnumNetworkEvents(sock, event.getEvent(), &events);
// piCoutObj << "wait result" << events.lNetworkEvents;
return events.lNetworkEvents;
@@ -1204,9 +1243,12 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
# else
if (s != -1) {
struct ifreq ir;
strcpy(ir.ifr_name, cif->ifa_name);
memset(&ir, 0, sizeof(ir));
strncpy(ir.ifr_name, cif->ifa_name, sizeof(ir.ifr_name));
if (ioctl(s, SIOCGIFHWADDR, &ir) == 0) {
ci.mac = macFromBytes(PIByteArray(ir.ifr_hwaddr.sa_data, 6));
}
if (ioctl(s, SIOCGIFMTU, &ir) == 0) {
ci.mtu = ir.ifr_mtu;
}
}
@@ -1245,7 +1287,7 @@ PINetworkAddress PIEthernet::interfaceAddress(const PIString & interface_) {
return PINetworkAddress();
#else
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
piZeroMemory(ifr);
strcpy(ifr.ifr_name, interface_.dataAscii());
int s = ::socket(AF_INET, SOCK_DGRAM, 0);
ioctl(s, SIOCGIFADDR, &ifr);

View File

@@ -180,10 +180,17 @@ public:
PISystemTime writeTimeout() const { return property("writeTimeout").toSystemTime(); }
//! Set timeout for read
void setReadTimeout(PISystemTime tm) { setProperty("readTimeout", tm); }
void setReadTimeout(PISystemTime tm);
//! Set timeout for write
void setWriteTimeout(PISystemTime tm) { setProperty("writeTimeout", tm); }
void setWriteTimeout(PISystemTime tm);
//! Set socket receive buffer size
void setReadBufferSize(int bytes);
//! Set socket send buffer size
void setWriteBufferSize(int bytes);
//! Returns TTL (Time To Live)
@@ -318,10 +325,10 @@ public:
//! Network interface descriptor
struct PIP_EXPORT Interface {
//! System index
int index;
int index = -1;
//! MTU
int mtu;
int mtu = 0;
//! System name
PIString name;
@@ -344,6 +351,9 @@ public:
//! Flags of interface
InterfaceFlags flags;
//! Returns if interface is active
bool isValid() const { return name.isNotEmpty(); }
//! Returns if interface is active
bool isActive() const { return flags[PIEthernet::ifActive]; }
@@ -477,11 +487,12 @@ protected:
bool closeDevice() override;
void closeSocket(int & sd);
void applyTimeouts();
void applyBuffers();
void applyTimeout(int fd, int opt, PISystemTime tm);
void applyOptInt(int level, int opt, int val);
PRIVATE_DECLARATION(PIP_EXPORT)
int sock = -1, sock_s = -1;
int sock = -1, sock_s = -1, rcv_buf = 0, snd_buf = 0;
std::atomic_bool connected_ = {false}, connecting_ = {false}, listen_threaded = {false}, server_bounded = {false};
bool is_server_client = false;
mutable PINetworkAddress addr_r, addr_s, addr_lr;

View File

@@ -263,7 +263,8 @@ PIByteArray PIFile::readAll(bool forceRead) {
if (s < 0) return a;
a.resize(s);
seekToBegin();
fread(a.data(), 1, s, PRIVATE->fd);
auto _r = fread(a.data(), 1, s, PRIVATE->fd);
NO_UNUSED(_r);
seek(cp);
if (s >= 0) a.resize(s);
return a;
@@ -492,7 +493,7 @@ PIFile::FileInfo PIFile::fileInfo(const PIString & path) {
}
if (!hFile) return ret;
BY_HANDLE_FILE_INFORMATION fi;
memset(&fi, 0, sizeof(fi));
piZeroMemory(fi);
if (GetFileInformationByHandle(hFile, &fi) != 0) {
LARGE_INTEGER filesize;
filesize.LowPart = filesize.HighPart = 0;
@@ -515,12 +516,12 @@ PIFile::FileInfo PIFile::fileInfo(const PIString & path) {
CloseHandle(hFile);
#else
_stat_struct_ fs;
memset(&fs, 0, sizeof(fs));
piZeroMemory(fs);
_stat_call_(path.data(), &fs);
int mode = fs.st_mode;
ret.size = fs.st_size;
ret.id_user = fs.st_uid;
ret.id_group = fs.st_gid;
int mode = fs.st_mode;
ret.size = fs.st_size;
ret.id_user = fs.st_uid;
ret.id_group = fs.st_gid;
# ifdef ANDROID
ret.time_access = PIDateTime::fromSystemTime(PISystemTime(fs.st_atime, fs.st_atime_nsec));
ret.time_modification = PIDateTime::fromSystemTime(PISystemTime(fs.st_mtime, fs.st_mtime_nsec));
@@ -541,10 +542,10 @@ PIFile::FileInfo PIFile::fileInfo(const PIString & path) {
# endif
# endif
# ifndef MICRO_PIP
ret.perm_user = FileInfo::Permissions((mode & S_IRUSR) == S_IRUSR, (mode & S_IWUSR) == S_IWUSR, (mode & S_IXUSR) == S_IXUSR);
ret.perm_group = FileInfo::Permissions((mode & S_IRGRP) == S_IRGRP, (mode & S_IWGRP) == S_IWGRP, (mode & S_IXGRP) == S_IXGRP);
ret.perm_other = FileInfo::Permissions((mode & S_IROTH) == S_IROTH, (mode & S_IWOTH) == S_IWOTH, (mode & S_IXOTH) == S_IXOTH);
memset(&fs, 0, sizeof(fs));
ret.perm_user = FileInfo::Permissions((mode & S_IRUSR) == S_IRUSR, (mode & S_IWUSR) == S_IWUSR, (mode & S_IXUSR) == S_IXUSR);
ret.perm_group = FileInfo::Permissions((mode & S_IRGRP) == S_IRGRP, (mode & S_IWGRP) == S_IWGRP, (mode & S_IXGRP) == S_IXGRP);
ret.perm_other = FileInfo::Permissions((mode & S_IROTH) == S_IROTH, (mode & S_IWOTH) == S_IWOTH, (mode & S_IXOTH) == S_IXOTH);
piZeroMemory(fs);
_stat_link_(path.data(), &fs);
mode &= ~S_IFLNK;
mode |= S_IFLNK & fs.st_mode;

View File

@@ -877,7 +877,7 @@ ssize_t PISerial::readDevice(void * read_to, ssize_t max_size) {
close();
return 0;
}
memset(&(PRIVATE->overlap), 0, sizeof(PRIVATE->overlap));
piZeroMemory(PRIVATE->overlap);
PRIVATE->overlap.hEvent = PRIVATE->event.getEvent();
PRIVATE->readed = 0;
ReadFile(PRIVATE->hCom, read_to, max_size, NULL, &(PRIVATE->overlap));
@@ -924,7 +924,7 @@ ssize_t PISerial::writeDevice(const void * data, ssize_t max_size) {
DWORD wrote(0);
// piCoutObj << "send ..." << max_size;// << ": " << PIString((char*)data, max_size);
sending = true;
memset(&(PRIVATE->overlap_write), 0, sizeof(PRIVATE->overlap_write));
piZeroMemory(PRIVATE->overlap_write);
PRIVATE->overlap_write.hEvent = PRIVATE->event_write.getEvent();
WriteFile(PRIVATE->hCom, data, max_size, NULL, &(PRIVATE->overlap_write));
if (PRIVATE->event_write.wait()) {
@@ -1160,7 +1160,7 @@ PIVector<PISerial::DeviceInfo> PISerial::availableDevicesInfo(bool test) {
const HDEVINFO dis = SetupDiGetClassDevs(&(guids[i]), NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (dis == INVALID_HANDLE_VALUE) continue;
SP_DEVINFO_DATA did;
memset(&did, 0, sizeof(did));
piZeroMemory(did);
did.cbSize = sizeof(did);
DWORD index = 0;
while (SetupDiEnumDeviceInfo(dis, index++, &did)) {

View File

@@ -136,7 +136,10 @@ bool PISharedMemory::openDevice() {
PRIVATE->owner = true;
// piCoutObj << "created" << fd;
}
if (fd >= 0) ftruncate(fd, dsize);
if (fd >= 0) {
auto _r = ftruncate(fd, dsize);
NO_UNUSED(_r);
}
PRIVATE->data = mmap(0, dsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
::close(fd);
if (PRIVATE->data == MAP_FAILED) {

View File

@@ -179,6 +179,7 @@ public:
//! \~russian Перегруженный оператор для вывода координат в \a PICout.
template<typename Type>
PICout operator<<(PICout & s, const PILine<Type> & v) {
s.space();
s.saveAndSetControls(0);
s << "Line{" << v.p0 << ", " << v.p1 << "}";
s.restoreControls();

View File

@@ -771,6 +771,8 @@ inline std::ostream & operator<<(std::ostream & s, const PIMathMatrixT<Rows, Col
//! \return непечатанная в консоль \a PICout.
template<uint Rows, uint Cols, typename Type>
inline PICout operator<<(PICout s, const PIMathMatrixT<Rows, Cols, Type> & m) {
s.space();
s.saveAndSetControls(0);
s << "{";
for (uint r = 0; r < Rows; ++r) {
for (uint c = 0; c < Cols; ++c) {
@@ -780,6 +782,7 @@ inline PICout operator<<(PICout s, const PIMathMatrixT<Rows, Cols, Type> & m) {
if (r < Rows - 1) s << PICoutManipulators::NewLine << " ";
}
s << "}";
s.restoreControls();
return s;
}
@@ -1465,6 +1468,8 @@ inline std::ostream & operator<<(std::ostream & s, const PIMathMatrix<Type> & m)
//! \return непечатанная в консоль \a PICout.
template<typename Type>
inline PICout operator<<(PICout s, const PIMathMatrix<Type> & m) {
s.space();
s.saveAndSetControls(0);
s << "Matrix{";
for (uint r = 0; r < m.rows(); ++r) {
for (uint c = 0; c < m.cols(); ++c) {
@@ -1474,6 +1479,7 @@ inline PICout operator<<(PICout s, const PIMathMatrix<Type> & m) {
if (r < m.rows() - 1) s << PICoutManipulators::NewLine << " ";
}
s << "}";
s.restoreControls();
return s;
}

View File

@@ -333,12 +333,15 @@ inline PIMathVectorT<Size, Type> operator*(const Type & x, const PIMathVectorT<S
template<uint Size, typename Type>
inline PICout operator<<(PICout s, const PIMathVectorT<Size, Type> & v) {
s.space();
s.saveAndSetControls(0);
s << "Vector{";
PIMV_FOR {
s << v[i];
if (i < Size - 1) s << ", ";
}
s << "}";
s.restoreControls();
return s;
}
@@ -611,12 +614,15 @@ inline std::ostream & operator<<(std::ostream & s, const PIMathVector<Type> & v)
template<typename Type>
inline PICout operator<<(PICout s, const PIMathVector<Type> & v) {
s.space();
s.saveAndSetControls(0);
s << "Vector{";
for (uint i = 0; i < v.size(); ++i) {
s << v[i];
if (i < v.size() - 1) s << ", ";
}
s << "}";
s.restoreControls();
return s;
}

View File

@@ -154,6 +154,7 @@ public:
//! \~russian Перегруженный оператор для вывода координат в \a PICout.
template<typename Type>
PICout operator<<(PICout & s, const PIPoint<Type> & v) {
s.space();
s.saveAndSetControls(0);
s << "Point{" << v.x << ", " << v.y << "}";
s.restoreControls();

View File

@@ -360,6 +360,7 @@ private:
template<typename Type>
PICout operator<<(PICout & s, const PIRect<Type> & v) {
s.space();
s.saveAndSetControls(0);
s << "Rect{" << v.bottomLeft() << ":" << v.width() << "x" << v.height() << "}";
s.restoreControls();

View File

@@ -228,9 +228,11 @@ public:
void copyToContainer();
void copyTo(void * data);
void copyTo(void * data, int elements_count, int elements_offset = 0);
void copyTo(Buffer * buffer, int elements_count = -1, int elements_from_offset = 0, int elements_to_offset = 0);
void copyFromContainer();
void copyFrom(void * data);
void copyFrom(void * data, int elements_count, int elements_offset = 0);
void copyFrom(Buffer * buffer, int elements_count = -1, int elements_from_offset = 0, int elements_to_offset = 0);
uint elementsCount() const { return elements; }
private:
@@ -244,6 +246,7 @@ public:
void zero();
bool init();
void * containerData();
static void copy(Buffer * buffer_from, Buffer * buffer_to, int elements_count, int elements_from_offset, int elements_to_offset);
Context * context_;
Direction dir;
Container type;

View File

@@ -26,6 +26,7 @@
#include "picontainersmodule.h"
#include "picoremodule.h"
#include "picryptmodule.h"
#include "pidigest.h"
#include "pigeomodule.h"
#include "pihttpservermodule.h"
#include "piiodevicesmodule.h"

View File

@@ -204,16 +204,21 @@
//!
PIJSON PIJSON::newObject() {
PIJSON PIJSON::newObject(const PIVariantMap & fields) {
PIJSON ret;
ret.c_type = Object;
auto it = fields.makeIterator();
while (it.next())
ret[it.key()] = it.value();
return ret;
}
PIJSON PIJSON::newArray() {
PIJSON PIJSON::newArray(const PIVariantVector & fields) {
PIJSON ret;
ret.c_type = Array;
for (const auto & i: fields)
ret << i;
return ret;
}
@@ -325,6 +330,15 @@ PIJSON & PIJSON::operator<<(const PIJSON & element) {
}
PIJSON & PIJSON::operator<<(const PIVariant & element) {
c_type = Array;
PIJSON e;
e = element;
c_array << e;
return *this;
}
PIJSON & PIJSON::operator=(const PIJSON & v) {
c_type = v.c_type;
c_value = v.c_value;

View File

@@ -160,6 +160,10 @@ public:
//! \~russian Устанавливает тип элемента в \a PIJSON::Array и добавляет элемент в массив.
PIJSON & operator<<(const PIJSON & element);
//! \~english Set element type to \a PIJSON::Array and add element to the end of array.
//! \~russian Устанавливает тип элемента в \a PIJSON::Array и добавляет элемент в массив.
PIJSON & operator<<(const PIVariant & value);
//! \~english Returns element from map with key "key" if type is \a PIJSON::Object, otherwise returns invalid %PIJSON.
//! \~russian Возвращает элемент из словаря по ключу "key" если тип \a PIJSON::Object, иначе возвращает недействительный %PIJSON.
@@ -183,8 +187,8 @@ public:
//! \~russian Разбирает текстовое представление JSON "str" и возвращает его корневой элемент.
static PIJSON fromJSON(PIString str);
static PIJSON newObject();
static PIJSON newArray();
static PIJSON newObject(const PIVariantMap & fields = {});
static PIJSON newArray(const PIVariantVector & fields = {});
static PIJSON newString(const PIString & v = PIString());
private:

View File

@@ -171,13 +171,10 @@ void PIProcess::startProc(bool detached) {
if (g_in) PRIVATE->tf_in = freopen(f_in.path().data(), "r", stdin);
if (g_out) PRIVATE->tf_out = freopen(f_out.path().data(), "w", stdout);
if (g_err) PRIVATE->tf_err = freopen(f_err.path().data(), "w", stderr);
# ifndef WINDOWS
if (!wd.isEmpty())
if (!chdir(wd.data())) piCoutObj << "Error while set working directory";
# endif
# ifdef WINDOWS
GetStartupInfoA(&(PRIVATE->si));
memset(&(PRIVATE->pi), 0, sizeof(PRIVATE->pi));
piZeroMemory(PRIVATE->pi);
if (CreateProcessA(0, // No module name (use command line)
a, // Command line
0, // Process handle not inheritable
@@ -196,128 +193,150 @@ void PIProcess::startProc(bool detached) {
}
CloseHandle(PRIVATE->pi.hThread);
CloseHandle(PRIVATE->pi.hProcess);
} else
} else {
piCoutObj << "\"CreateProcess\" error: %1"_tr("PIProcess").arg(errorString());
# else
// cout << "exec " << tf_in << ", " << tf_out << ", " << tf_err << endl;
if (execve(str.data(), (char * const *)argscc, (char * const *)envcc) < 0)
piCoutObj << "\"execve" << str << args << "\" error :" << errorString();
}
else {
piMinSleep();
// cout << "wait" << endl;
if (!detached) {
wait(&exit_code);
pid_ = 0;
if (!detached) PRIVATE->pid = pid_;
// cout << "wait done" << endl;
}
}
# endif
if (!detached) execFinished(str, exit_code);
is_exec = false;
# ifdef WINDOWS
delete[] a;
}
# endif
# ifndef WINDOWS
if (!wd.isEmpty()) {
if (!chdir(wd.data())) piCoutObj << "Error while set working directory";
}
// cout << "exec " << tf_in << ", " << tf_out << ", " << tf_err << endl;
if (execve(str.data(), (char * const *)argscc, (char * const *)envcc) < 0) {
piCoutObj << "\"execve" << str << args << "\" error :" << errorString();
}
} else {
piMinSleep();
// cout << "wait" << endl;
if (!detached) {
waitpid(pid_, &exit_code, 0);
pid_ = 0;
if (!detached) PRIVATE->pid = pid_;
// cout << "wait done" << endl;
}
}
void PIProcess::terminate() {
# endif
if (!detached) execFinished(str, exit_code);
is_exec = false;
# ifdef WINDOWS
if (is_exec)
if (!TerminateProcess(PRIVATE->pi.hProcess, 0)) return;
PRIVATE->pi.dwProcessId = 0;
delete[] a;
# endif
}
PIByteArray PIProcess::readFile(PIFile & f, bool clear)
{
f.open(PIIODevice::ReadOnly);
const auto ret = f.readAll();
if (clear) {
f.clear();
}
return ret;
}
void PIProcess::terminate() {
# ifdef WINDOWS
if (is_exec)
if (!TerminateProcess(PRIVATE->pi.hProcess, 0)) return;
PRIVATE->pi.dwProcessId = 0;
# else
if (is_exec) kill(PRIVATE->pid, SIGKILL);
PRIVATE->pid = 0;
# endif
}
}
bool PIProcess::waitForFinish() {
return PIThread::waitForFinish(1_m);
}
bool PIProcess::waitForFinish() {
return PIThread::waitForFinish(1_m);
}
void PIProcess::execIndependent(const PIString & program, const PIStringList & args_) {
PIProcess p;
p.args << program << args_;
p.startProc(true);
}
void PIProcess::execIndependent(const PIString & program, const PIStringList & args_) {
PIProcess p;
p.args << program << args_;
p.startProc(true);
}
int PIProcess::pID() const {
int PIProcess::pID() const {
# ifdef WINDOWS
return PRIVATE->pi.dwProcessId;
return PRIVATE->pi.dwProcessId;
# else
return PRIVATE->pid;
# endif
}
}
PIByteArray PIProcess::readOutput(bool clear) {
return readFile(f_out, clear);
}
PIByteArray PIProcess::readError(bool clear) {
return readFile(f_err, clear);
}
int PIProcess::currentPID() {
int PIProcess::currentPID() {
# ifdef WINDOWS
return GetCurrentProcessId();
return GetCurrentProcessId();
# else
return getpid();
# endif
}
PIStringList PIProcess::currentEnvironment() {
PIStringList l;
int i = 0;
while (environ[i] != 0) {
l << environ[i];
++i;
}
return l;
}
PIStringList PIProcess::currentEnvironment() {
PIStringList l;
int i = 0;
while (environ[i] != 0) {
l << environ[i];
++i;
}
return l;
}
void PIProcess::run() {
startProc(false);
}
void PIProcess::run() {
startProc(false);
}
void PIProcess::removeEnvironmentVariable(const PIString & variable) {
PIString s;
for (int i = 0; i < env.size_s(); ++i) {
s = env[i];
if (s.left(s.find("=")).trimmed() == variable) {
env.remove(i);
--i;
}
void PIProcess::removeEnvironmentVariable(const PIString & variable) {
PIString s;
for (int i = 0; i < env.size_s(); ++i) {
s = env[i];
if (s.left(s.find("=")).trimmed() == variable) {
env.remove(i);
--i;
}
}
}
void PIProcess::setEnvironmentVariable(const PIString & variable, const PIString & value) {
PIString s, v;
for (int i = 0; i < env.size_s(); ++i) {
s = env[i];
v = s.left(s.find("=")).trimmed();
if (v == variable) {
env[i] = v + "=" + value;
return;
}
void PIProcess::setEnvironmentVariable(const PIString & variable, const PIString & value) {
PIString s, v;
for (int i = 0; i < env.size_s(); ++i) {
s = env[i];
v = s.left(s.find("=")).trimmed();
if (v == variable) {
env[i] = v + "=" + value;
return;
}
env << variable + "=" + value;
}
env << variable + "=" + value;
}
PIString PIProcess::getEnvironmentVariable(const PIString & variable) {
PIStringList env_ = currentEnvironment();
PIString s, v;
for (int i = 0; i < env_.size_s(); ++i) {
s = env_[i];
v = s.left(s.find("=")).trimmed();
if (v == variable) {
return s.right(s.size() - 1 - s.find("=")).trimmed();
}
PIString PIProcess::getEnvironmentVariable(const PIString & variable) {
PIStringList env_ = currentEnvironment();
PIString s, v;
for (int i = 0; i < env_.size_s(); ++i) {
s = env_[i];
v = s.left(s.find("=")).trimmed();
if (v == variable) {
return s.right(s.size() - 1 - s.find("=")).trimmed();
}
return PIString();
}
return PIString();
}
#endif // MICRO_PIP

View File

@@ -99,18 +99,11 @@ public:
//! \~english Returns all attached execution output stream
//! \~russian
PIByteArray readOutput() {
f_out.open(PIIODevice::ReadOnly);
return f_out.readAll();
}
PIByteArray readOutput(bool clear = false);
//! \~english Returns all attached execution error stream
//! \~russian
PIByteArray readError() {
f_err.open(PIIODevice::ReadOnly);
return f_err.readAll();
}
PIByteArray readError(bool clear = false);
//! \~english Returns current attached execution environment
//! \~russian
@@ -227,6 +220,7 @@ private:
void run() override;
void exec_();
void startProc(bool detached);
PIByteArray readFile(PIFile & f, bool clear);
PRIVATE_DECLARATION(PIP_EXPORT)
PIStringList args, env;

View File

@@ -54,7 +54,7 @@ PIStringList PISystemInfo::mountRoots() {
# ifdef LINUX
PIString s_df, s_m;
char in[1024];
memset(in, 0, 1024);
piZeroMemory(in, 1024);
FILE * fp = popen("mount -l", "r");
PIStringList tl;
if (fp) {
@@ -129,7 +129,7 @@ PIVector<PISystemInfo::MountInfo> PISystemInfo::mountInfo(bool ignore_cache) {
#ifdef LINUX
PIString s_df, s_m;
char in[1024];
memset(in, 0, 1024);
piZeroMemory(in, 1024);
// piCout << "mountInfo 0";
FILE * fp = popen("df -B1", "r");
PIStringList l_df;
@@ -141,7 +141,7 @@ PIVector<PISystemInfo::MountInfo> PISystemInfo::mountInfo(bool ignore_cache) {
fp = 0;
}
// piCout << "mountInfo 1";
memset(in, 0, 1024);
piZeroMemory(in, 1024);
fp = popen("mount -l", "r");
PIStringList tl;
if (fp) {

View File

@@ -73,7 +73,7 @@ ushort charFromCodepage(const char * c, int size, const char * codepage, int * t
return buffer;
# else
mbstate_t state;
memset(&state, 0, sizeof(state));
piZeroMemory(state);
wchar_t wc;
ret = mbrtowc(&wc, c, size, &state);
// printf("mbtowc = %d\n", ret);
@@ -369,7 +369,7 @@ PICout operator<<(PICout s, const PIChar & v) {
UConverter * cc = ucnv_open(__syslocname__, &e);
if (cc) {
char uc[8];
memset(uc, 0, 8);
piZeroMemory(uc, 8);
e = (UErrorCode)0;
ucnv_fromUChars(cc, uc, 8, (const UChar *)(&v.ch), 1, &e);
ucnv_close(cc);

View File

@@ -178,7 +178,7 @@ T toDecimal(const PIString & s) {
#define pisprintf(f, v) \
char ch[256]; \
memset(ch, 0, 256); \
piZeroMemory(ch, 256); \
snprintf(ch, 256, f, v); \
return PIStringAscii(ch);
@@ -492,7 +492,8 @@ void PIString::buildData(const char * cp) const {
std::string u8str = ucs2conv.to_bytes((char16_t *)d.data(), (char16_t *)d.data() + d.size());
data_ = (char *)malloc(u8str.size() + 1);
strcpy(data_, u8str.c_str());
data_size_ = u8str.size();
data_[u8str.size()] = '\0';
data_size_ = u8str.size();
# endif
#endif
}
@@ -536,7 +537,7 @@ PIString PIString::minArgPlaceholder() {
bool ok = false;
tmp = mid(i + 1, j - i - 1);
int cur = tmp.toInt(10, &ok);
if (!ok) continue;
if (!ok || tmp.isEmpty()) continue;
if (min < 0 || min > cur) {
min = cur;
ret = tmp;
@@ -1810,6 +1811,46 @@ PIString & PIString::setReadableSize(llong bytes) {
}
PIString PIString::toPercentageEncoding() const {
static const PIString valid = "-._~"_a;
PIString ret;
PIByteArray utf8;
bool ok = false;
for (const auto & c: *this) {
ok = false;
if (c.isAscii()) {
if (c.isAlpha() || c.isDigit())
ok = true;
else if (valid.contains(c))
ok = true;
}
if (ok) {
ret.append(c);
} else {
utf8 = PIString(c).toUTF8();
for (auto u: utf8)
ret.append('%').append(PIString::fromNumber(u, 16).expandLeftTo(2, '0'));
}
}
return ret;
}
PIString PIString::fromPercentageEncoding(const PIString & in) {
PIByteArray utf8;
PIChar c;
for (int i = 0; i < in.size_s(); ++i) {
c = in[i];
if (c == '%') {
utf8 << static_cast<uchar>(in.mid(i + 1, 2).toInt(16));
i += 2;
} else
utf8 << static_cast<uchar>(c.toAscii());
}
return PIString::fromUTF8(utf8);
}
PIString & PIString::arg(const PIString & v) {
auto ph = minArgPlaceholder();
if (!ph.isEmpty()) replaceAll(ph, v);

View File

@@ -1687,6 +1687,10 @@ public:
PIString & setReadableSize(llong bytes);
//! \~english Returns [percentage-encoded](https://en.wikipedia.org/wiki/Percent-encoding) string.
//! \~russian Возвращает [URL-кодированную](https://ru.wikipedia.org/wiki/URL) строку.
PIString toPercentageEncoding() const;
//! \~english Replace all occurances like "%1", "%2", ... with lowest value to "v" and returns this string.
//! \~russian Заменяет все вхождения типа "%1", "%2", ... с наименьшим значением на "v" и возвращает эту строку.
//! \~\details
@@ -1906,6 +1910,10 @@ public:
//! \~\sa PIString::setReadableSize()
static PIString readableSize(llong bytes);
//! \~english Returns string from [percentage-encoded](https://en.wikipedia.org/wiki/Percent-encoding) "in".
//! \~russian Возвращает строку из [URL-кодированной](https://ru.wikipedia.org/wiki/URL)"in".
static PIString fromPercentageEncoding(const PIString & in);
//! \~english Swaps string `str` other with this string.
//! \~russian Меняет строку `str` с этой строкой.
//! \~\details
@@ -2020,4 +2028,15 @@ inline void piSwap(PIString & f, PIString & s) {
f.swap(s);
}
//! \~english Returns string representation of \"v\", using PICout operator<<(T)
//! \~russian Возвращает строковое представление \"v\", используя PICout operator<<(T)
template<typename T>
inline PIString piStringify(const T & v) {
PIString ret;
PICout::withExternalBuffer(&ret) << v;
return ret;
}
#endif // PISTRING_H

View File

@@ -58,7 +58,7 @@ PIConditionVariable::PIConditionVariable() {
# if !defined(MAC_OS)
pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
# endif
memset(&(PRIVATE->nativeHandle), 0, sizeof(PRIVATE->nativeHandle));
piZeroMemory(PRIVATE->nativeHandle);
pthread_cond_init(&PRIVATE->nativeHandle, &condattr);
#endif
}

View File

@@ -209,10 +209,10 @@ void PIMutex::init() {
PRIVATE->mutex = xSemaphoreCreateMutex();
#else
pthread_mutexattr_t attr;
memset(&attr, 0, sizeof(attr));
piZeroMemory(attr);
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
memset(&(PRIVATE->mutex), 0, sizeof(PRIVATE->mutex));
piZeroMemory(PRIVATE->mutex);
pthread_mutex_init(&(PRIVATE->mutex), &attr);
pthread_mutexattr_destroy(&attr);
#endif

View File

@@ -21,6 +21,7 @@
#include "piincludes_p.h"
#include "piintrospection_threads.h"
#include "piliterals_time.h"
#include "pitime.h"
#include "pitranslator.h"
#ifndef MICRO_PIP
@@ -651,9 +652,9 @@ bool PIThread::startOnce(std::function<void()> func) {
}
void PIThread::stopAndWait(PISystemTime timeout) {
bool PIThread::stopAndWait(PISystemTime timeout) {
stop();
waitForFinish(timeout);
return waitForFinish(timeout);
}
@@ -736,9 +737,10 @@ bool PIThread::_startThread(void * func) {
#ifdef FREERTOS
if (xTaskCreate((__THREAD_FUNC_RET__(*)(void *))func,
((PIString &)name().elided(15, 0.4f).resize(15, PIChar('\0'))).dataAscii(), // A name just for humans
128, // This stack size can be checked & adjusted by reading the Stack Highwater
auto name_ba = createThreadName();
if (xTaskCreate((__THREAD_FUNC_RET__ (*)(void *))func,
(const char *)name_ba.data(), // A name just for humans
128, // This stack size can be checked & adjusted by reading the Stack Highwater
this,
priority_,
&PRIVATE->thread) == pdPASS) {
@@ -750,12 +752,12 @@ bool PIThread::_startThread(void * func) {
if (PRIVATE->thread) CloseHandle(PRIVATE->thread);
# ifdef CC_GCC
PRIVATE->thread = (void *)_beginthreadex(0, 0, (__THREAD_FUNC_RET__(*)(void *))func, this, 0, 0);
PRIVATE->thread = (void *)_beginthreadex(0, 0, (__THREAD_FUNC_RET__ (*)(void *))func, this, CREATE_SUSPENDED, 0);
# else
PRIVATE->thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)func, this, 0, 0);
PRIVATE->thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)func, this, CREATE_SUSPENDED, 0);
# endif
if (PRIVATE->thread != 0) {
setPriority(priority_);
ResumeThread(PRIVATE->thread);
return true;
}
@@ -764,17 +766,11 @@ bool PIThread::_startThread(void * func) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
int ret = pthread_create(&PRIVATE->thread, &attr, (__THREAD_FUNC_RET__(*)(void *))func, this);
// PICout(PICoutManipulators::DefaultControls) << "pthread_create" << PRIVATE->thread;
int ret = pthread_create(&PRIVATE->thread, &attr, (__THREAD_FUNC_RET__ (*)(void *))func, this);
pthread_attr_destroy(&attr);
// PICout(PICoutManipulators::DefaultControls) << "pthread_create" << PRIVATE->thread;
// piCout << "started" << PRIVATE->thread;
if (ret == 0) {
# ifdef MAC_OS
pthread_setname_np(((PIString &)name().elided(15, 0.4f).resize(15, PIChar('\0'))).dataAscii());
pthread_threadid_np(PRIVATE->thread, (__uint64_t *)&tid_);
# else
pthread_setname_np(PRIVATE->thread, ((PIString &)name().elided(15, 0.4f).resize(15, PIChar('\0'))).dataAscii());
# endif
setPriority(priority_);
return true;
}
@@ -796,7 +792,7 @@ void PIThread::setPriority(PIThread::Priority prior) {
# ifndef WINDOWS
// PICout(PICoutManipulators::DefaultControls) << "setPriority" << PRIVATE->thread;
int policy_ = 0;
memset(&(PRIVATE->sparam), 0, sizeof(PRIVATE->sparam));
piZeroMemory(PRIVATE->sparam);
pthread_getschedparam(PRIVATE->thread, &policy_, &(PRIVATE->sparam));
PRIVATE->sparam.
# ifndef LINUX
@@ -807,7 +803,6 @@ void PIThread::setPriority(PIThread::Priority prior) {
= priority2System(priority_);
pthread_setschedparam(PRIVATE->thread, policy_, &(PRIVATE->sparam));
# else
if (!running_ || (PRIVATE->thread == 0)) return;
SetThreadPriority(PRIVATE->thread, priority2System(priority_));
# endif
#endif // FREERTOS
@@ -833,28 +828,16 @@ bool PIThread::waitForFinish(PISystemTime timeout) {
// timeout_msecs;
if (!running_) return true;
if (timeout.isNull()) {
while (running_) {
piMinSleep();
#ifdef WINDOWS
if (!isExists(PRIVATE->thread)) {
unlock();
return true;
}
#endif
for (;;) {
if (_waitForFinish(PISystemTime::fromMilliseconds(PIP_MIN_MSLEEP))) break;
}
return true;
}
tmf_.reset();
while (running_ && tmf_.elapsed() < timeout) {
piMinSleep();
#ifdef WINDOWS
if (!isExists(PRIVATE->thread)) {
unlock();
return true;
}
#endif
PITimeMeasurer tm;
while (tm.elapsed() < timeout) {
if (_waitForFinish(PISystemTime::fromMilliseconds(PIP_MIN_MSLEEP))) return true;
}
return tmf_.elapsed() < timeout;
return tm.elapsed() < timeout;
}
@@ -865,10 +848,10 @@ bool PIThread::waitForStart(PISystemTime timeout) {
piMinSleep();
return true;
}
tms_.reset();
while (!running_ && tms_.elapsed() < timeout)
PITimeMeasurer tm;
while (!running_ && tm.elapsed() < timeout)
piMinSleep();
return tms_.elapsed() < timeout;
return tm.elapsed() < timeout;
}
@@ -885,6 +868,8 @@ void PIThread::_beginThread() {
#ifdef LINUX
tid_ = gettid();
#endif
setPriority(priority_);
setThreadName();
PIINTROSPECTION_THREAD_START(this);
REGISTER_THREAD(this);
running_ = true;
@@ -899,8 +884,8 @@ void PIThread::_runThread() {
PIINTROSPECTION_THREAD_RUN(this);
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "lock" << "...";
if (lockRun) thread_mutex.lock();
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "lock" << "ok";
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "run" << "...";
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "lock" << "ok";
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "run" << "...";
#ifdef PIP_INTROSPECTION
PITimeMeasurer _tm;
#endif
@@ -923,6 +908,7 @@ void PIThread::_endThread() {
PIScopeExitCall ec([this] {
terminating = running_ = false;
tid_ = -1;
state_notifier.notify();
});
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "...";
stopped();
@@ -947,8 +933,8 @@ void PIThread::_endThread() {
#elif defined(FREERTOS)
PRIVATE->thread = 0;
#else
// pthread_detach(PRIVATE->thread);
PRIVATE->thread = 0;
ec.callAndCancel();
pthread_exit(0);
#endif
}
@@ -964,10 +950,10 @@ void PIThread::__thread_func__() {
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "wait" << "...";
PIINTROSPECTION_THREAD_WAIT(this);
if (delay_.isNotNull()) {
tmr_.reset();
PITimeMeasurer tm;
double sl(0.);
while (1) {
sl = piMind(delay_.toMilliseconds() - tmr_.elapsed_m(), PIP_MIN_MSLEEP);
sl = piMind(delay_.toMilliseconds() - tm.elapsed_m(), PIP_MIN_MSLEEP);
if (terminating) break;
if (sl <= 0.) break;
piMSleep(sl);
@@ -1063,3 +1049,40 @@ void PIThread::runOnce(std::function<void()> func, const PIString & name) {
#endif
t->startOnce();
}
PIByteArray PIThread::createThreadName(int size) const {
PIString tname = name().simplified();
tname.elide(size - 1, 0.4f).resize(size - 1, PIChar('\0'));
PIByteArray ret = tname.toAscii();
ret.resize(size);
ret.back() = 0;
return ret;
}
void PIThread::setThreadName() {
#ifndef WINDOWS
auto name_ba = createThreadName();
# ifdef MAC_OS
pthread_setname_np((const char *)name_ba.data());
pthread_threadid_np(PRIVATE->thread, (__uint64_t *)&tid_);
# else
pthread_setname_np(PRIVATE->thread, (const char *)name_ba.data());
# endif
#endif
}
bool PIThread::_waitForFinish(PISystemTime max_tm) {
if (!running_) return true;
state_notifier.waitFor(max_tm);
if (!running_) return true;
#ifdef WINDOWS
if (!isExists(PRIVATE->thread)) {
unlock();
return true;
}
#endif
return false;
}

View File

@@ -29,6 +29,7 @@
#include "piinit.h"
#include "pimutex.h"
#include "piobject.h"
#include "pithreadnotifier.h"
class PIThread;
@@ -143,15 +144,13 @@ public:
EVENT_HANDLER0(void, stop);
EVENT_HANDLER0(void, terminate);
//! \~english Stop thread and wait for finish.
//! \~russian Останавливает поток и ожидает завершения.
void stopAndWait(int timeout_ms) DEPRECATEDM("use waitForStart(PISystemTime)") {
stopAndWait(PISystemTime::fromMilliseconds(timeout_ms));
bool stopAndWait(int timeout_ms) DEPRECATEDM("use stopAndWait(PISystemTime)") {
return stopAndWait(PISystemTime::fromMilliseconds(timeout_ms));
}
//! \~english Stop thread and wait for finish.
//! \~russian Останавливает поток и ожидает завершения.
void stopAndWait(PISystemTime timeout = {});
//! \~english Stop thread and wait for finish. Returns \b false if timeout expired.
//! \~russian Останавливает поток и ожидает завершения. Возвращает \b false если таймаут истек.
bool stopAndWait(PISystemTime timeout = {});
//! \~english Set common data passed to external function
//! \~russian Устанавливает данные, передаваемые в функцию потока
@@ -194,8 +193,8 @@ public:
return waitForStart(PISystemTime::fromMilliseconds(timeout_msecs));
}
//! \~english Wait for thread finish
//! \~russian Ожидает завершения потока
//! \~english Wait for thread finish. Returns \b false if timeout expired.
//! \~russian Ожидает завершения потока. Возвращает \b false если таймаут истек.
bool waitForFinish(PISystemTime timeout = {});
bool waitForFinish(int timeout_msecs) DEPRECATEDM("use waitForFinish(PISystemTime)") {
return waitForFinish(PISystemTime::fromMilliseconds(timeout_msecs));
@@ -289,9 +288,9 @@ protected:
llong tid_ = -1;
void * data_ = nullptr;
mutable PIMutex thread_mutex;
PITimeMeasurer tmf_, tms_, tmr_;
PIThread::Priority priority_ = piNormal;
ThreadFunc ret_func = nullptr;
PIThreadNotifier state_notifier;
PRIVATE_DECLARATION(PIP_EXPORT)
private:
@@ -299,6 +298,10 @@ private:
void _beginThread();
void _runThread();
void _endThread();
bool _waitForFinish(PISystemTime max_tm);
PIByteArray createThreadName(int size = 16) const;
void setThreadName();
};

View File

@@ -115,6 +115,19 @@ void PIThreadNotifier::wait() {
}
bool PIThreadNotifier::waitFor(PISystemTime timeout) {
bool ret = false;
m.lock();
if (cnt == 0) v.waitFor(m, timeout);
if (cnt > 0) {
cnt--;
ret = true;
}
m.unlock();
return ret;
}
//! \~\details
//! \~english
//! If many threads waiting, then notify randomly one.\n

View File

@@ -37,6 +37,11 @@ public:
//! \~russian Начать ожидание, продолжает когда другой поток вызовет \a notify()
void wait();
//! \~english Start waiting no longer than "timeout", return \b true if other thread call \a notify(), \b false if timeout expired
//! \~russian Начать ожидание не дольше чем "timeout", возвращает \b true когда другой поток вызовал \a notify(), \b false если таймаут
//! истек
bool waitFor(PISystemTime timeout);
//! \~english Notify one waiting thread, which waiting on \a wait() function
//! \~russian Уведомить один из ожидающих потоков, которые висят на методе \a wait()
void notify();

View File

@@ -106,16 +106,29 @@
PIThreadPoolLoop::PIThreadPoolLoop(int thread_cnt) {
if (thread_cnt <= 0) thread_cnt = piMaxi(1, PISystemInfo::instance()->processorsCount);
piForTimes(thread_cnt) {
auto * t = new PIThread();
auto * t = new PIThread([this]() {
while (true) {
sem_exec.acquire();
if (is_destroy) return;
int cc = counter.fetch_add(1);
func(cc);
sem_done.release();
}
});
threads << t;
}
for (auto * t: threads)
t->start();
// piCout << "PIThreadPoolLoop" << proc_cnt << "threads";
}
PIThreadPoolLoop::~PIThreadPoolLoop() {
for (auto * t: threads) {
is_destroy = true;
for (auto * t: threads)
t->stop();
sem_exec.release(threads.size());
for (auto * t: threads) {
if (!t->waitForFinish(100_ms)) t->terminate();
delete t;
}
@@ -127,20 +140,19 @@ void PIThreadPoolLoop::setFunction(std::function<void(int)> f) {
}
void PIThreadPoolLoop::wait() {
// piCout << "wait" << wait_count;
if (wait_count <= 0) return;
sem_done.acquire(wait_count);
wait_count = 0;
// piCout << "wait done";
}
void PIThreadPoolLoop::start(int index_start, int index_count) {
counter = index_start;
int end = index_start + index_count;
for (auto * t: threads)
t->start([this, end, t]() {
while (1) {
int cc = counter.fetch_add(1);
if (cc >= end) {
t->stop();
return;
}
func(cc);
}
});
counter = index_start;
wait_count = index_count;
sem_exec.release(index_count);
}
@@ -154,9 +166,3 @@ void PIThreadPoolLoop::exec(int index_start, int index_count, std::function<void
setFunction(f);
exec(index_start, index_count);
}
void PIThreadPoolLoop::wait() {
for (auto * t: threads)
t->waitForFinish();
}

View File

@@ -26,6 +26,7 @@
#ifndef PITHREADPOOLLOOP_H
#define PITHREADPOOLLOOP_H
#include "pisemaphore.h"
#include "pivector.h"
class PIThread;
@@ -83,7 +84,9 @@ public:
private:
PIVector<PIThread *> threads;
std::function<void(int)> func;
std::atomic_int counter = {0};
PISemaphore sem_exec, sem_done;
std::atomic_bool is_destroy = {false};
std::atomic_int counter = {0}, wait_count = {0};
};

View File

@@ -492,6 +492,11 @@ public:
//! По умолчанию указывает на начало массива.
inline const uchar * data(size_t index = 0) const { return d.data(index); }
template<typename T>
inline T dataAs(size_t index = 0) {
return *(T *)d.data(index);
}
//! \~english Clear array, remove all elements.
//! \~russian Очищает массив, удаляет все элементы.
//! \~\details
@@ -1238,6 +1243,39 @@ inline bool operator!=(const PIByteArray & v0, const PIByteArray & v1) {
return true;
}
//! \relatesalso PIByteArray
//! \~english Returns bit-wise "and". If non-equal size, then returns empty %PIByteArray.
//! \~russian Возвращает по-битовое "и" Если размеры не совпадают, возвращает пустой %PIByteArray.
inline PIByteArray operator&(const PIByteArray & v0, const PIByteArray & v1) {
if (v0.size() != v1.size()) return {};
PIByteArray ret(v0.size(), 0);
for (uint i = 0; i < v0.size(); ++i)
ret[i] = v0[i] & v1[i];
return ret;
}
//! \relatesalso PIByteArray
//! \~english Returns bit-wise "or". If non-equal size, then returns empty %PIByteArray.
//! \~russian Возвращает по-битовое "или" Если размеры не совпадают, возвращает пустой %PIByteArray.
inline PIByteArray operator|(const PIByteArray & v0, const PIByteArray & v1) {
if (v0.size() != v1.size()) return {};
PIByteArray ret(v0.size(), 0);
for (uint i = 0; i < v0.size(); ++i)
ret[i] = v0[i] | v1[i];
return ret;
}
//! \relatesalso PIByteArray
//! \~english Returns bit-wise "xor". If non-equal size, then returns empty %PIByteArray.
//! \~russian Возвращает по-битовое "исключающее или" Если размеры не совпадают, возвращает пустой %PIByteArray.
inline PIByteArray operator^(const PIByteArray & v0, const PIByteArray & v1) {
if (v0.size() != v1.size()) return {};
PIByteArray ret(v0.size(), 0);
for (uint i = 0; i < v0.size(); ++i)
ret[i] = v0[i] ^ v1[i];
return ret;
}
#ifdef PIP_STD_IOSTREAM
//! \relatesalso PIByteArray \brief Output to std::ostream operator
inline std::ostream & operator<<(std::ostream & s, const PIByteArray & ba);

View File

@@ -324,7 +324,7 @@ PIString PIDateTime::toString(const PIString & format) const {
time_t PIDateTime::toSecondSinceEpoch() const {
tm pt;
memset(&pt, 0, sizeof(pt));
piZeroMemory(pt);
pt.tm_sec = seconds;
pt.tm_min = minutes;
pt.tm_hour = hours;

View File

@@ -317,6 +317,14 @@ PISystemTime PITimeMeasurer::elapsed() const {
}
PISystemTime PITimeMeasurer::elapsedAndReset() {
auto ct = PISystemTime::current(true);
auto ret = ct - t_st;
t_st = ct;
return ret;
}
// PISystemTime::Frequency
PISystemTime PISystemTime::Frequency::toSystemTime() const {

View File

@@ -501,43 +501,24 @@ public:
//! \~russian Возвращает в PISystemTime время, прошедшее с последнего вызова \a reset(), либо создания измерителя.
PISystemTime elapsed() const;
double reset_time_n() const { return t_st.toNanoseconds(); }
double reset_time_u() const { return t_st.toMicroseconds(); }
double reset_time_m() const { return t_st.toMilliseconds(); }
double reset_time_s() const { return t_st.toSeconds(); }
//! \~\brief
//! \~english Returns PISystemTime elapsed from last \a reset() execution or from timer measurer creation and call \a reset().
//! \~russian Возвращает в PISystemTime время, прошедшее с последнего вызова \a reset(), либо создания измерителя, и вызывает \a
//! reset().
PISystemTime elapsedAndReset();
//! \~\brief
//! \~english Returns time mark of last \a reset() execution or timer measurer creation.
//! \~russian Возвращает отметку времени последнего вызова \a reset(), либо создания измерителя.
PISystemTime reset_time() { return t_st; }
PISystemTime reset_time() DEPRECATEDM("use PISystemTime::resetTime()") { return t_st; }
//! \~\brief
//! \~english Returns nanoseconds representation of current system time.
//! \~russian Возвращает в наносекундах системное время.
static double elapsed_system_n() { return PISystemTime::current(true).toNanoseconds(); }
//! \~\brief
//! \~english Returns microseconds representation of current system time.
//! \~russian Возвращает в микросекундах системное время.
static double elapsed_system_u() { return PISystemTime::current(true).toMicroseconds(); }
//! \~\brief
//! \~english Returns milliseconds representation of current system time.
//! \~russian Возвращает в милисекундах системное время.
static double elapsed_system_m() { return PISystemTime::current(true).toMilliseconds(); }
//! \~\brief
//! \~english Returns seconds representation of current system time.
//! \~russian Возвращает в секундах системное время.
static double elapsed_system_s() { return PISystemTime::current(true).toSeconds(); }
//! \~\brief
//! \~english Returns time mark of current system time.
//! \~russian Возвращает системное время.
static PISystemTime elapsed_system() { return PISystemTime::current(true); }
//! \~english Returns time mark of last \a reset() execution or timer measurer creation.
//! \~russian Возвращает отметку времени последнего вызова \a reset(), либо создания измерителя.
PISystemTime resetTime() const { return t_st; }
private:
PISystemTime t_st, t_cur;
PISystemTime t_st;
};
#endif // PITIME_H

View File

@@ -54,6 +54,14 @@ inline void piSleep(double secs) {
piUSleep(int(secs * 1000000.));
} // on !Windows consider constant "usleep" offset
//! \ingroup Types
//! \brief
//! \~english Precise sleep for "t" time
//! \~russian Точно ожидает время "t"
inline void piSleep(PISystemTime t) {
t.sleep();
}
//! \ingroup Types
//! \~english Shortest available on current system sleep
//! \~russian Наименее возможное для данной системы по длительности ожидание

View File

@@ -183,7 +183,7 @@ const PIValueTree & PIValueTree::child(const PIStringList & path) const {
if (_is_null || path.isEmpty()) return *this;
const PIValueTree * ret = &child(path[0]);
for (int i = 1; i < path.size_s(); ++i)
ret = &child(path[i]);
ret = &(ret->child(path[i]));
return *ret;
}

View File

@@ -240,11 +240,17 @@ PIOpenCL::Program * PIOpenCL::Context::createProgram(const PIString & source, co
if (error) (*error) = "Empty program!";
return 0;
}
PIString src_text = PRIVATE->complex_src + source;
const char * csrc = src_text.dataAscii();
size_t src_size = src_text.size();
cl_int ret = 0;
cl_program prog = clCreateProgramWithSource(PRIVATE->context, 1, &csrc, &src_size, &ret);
static PIString double_ext = "#ifdef cl_khr_fp64\n\
#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n\
#elif defined(cl_amd_fp64)\n\
#pragma OPENCL EXTENSION cl_amd_fp64 : enable\n\
#else\n\
#endif\n";
PIString src_text = PRIVATE->complex_src + double_ext + source;
const char * csrc = src_text.dataAscii();
size_t src_size = src_text.size();
cl_int ret = 0;
cl_program prog = clCreateProgramWithSource(PRIVATE->context, 1, &csrc, &src_size, &ret);
if (ret != 0) {
piCout << "[PIOpenCL::Context]"
<< "clCreateProgramWithSource error" << ret;
@@ -429,6 +435,11 @@ void PIOpenCL::Buffer::copyTo(void * data, int elements_count, int elements_offs
}
void PIOpenCL::Buffer::copyTo(Buffer * buffer, int elements_count, int elements_from_offset, int elements_to_offset) {
copy(this, buffer, elements_count, elements_from_offset, elements_to_offset);
}
void PIOpenCL::Buffer::copyFromContainer() {
if (!PRIVATE->buffer || !container) return;
copyFrom(containerData());
@@ -445,12 +456,12 @@ void PIOpenCL::Buffer::copyFrom(void * data) {
}
void PIOpenCL::Buffer::copyFrom(void * data, int elements_count, int elements_offset) {
void PIOpenCL::Buffer::copyFrom(void * data, int elements_count, int elements_from_offset) {
if (!PRIVATE->buffer) return;
cl_int ret = clEnqueueWriteBuffer(context_->PRIVATEWB->queue,
PRIVATE->buffer,
CL_TRUE,
elements_offset * def.size(),
elements_from_offset * def.size(),
elements_count * def.size(),
data,
0,
@@ -463,6 +474,35 @@ void PIOpenCL::Buffer::copyFrom(void * data, int elements_count, int elements_of
}
void PIOpenCL::Buffer::copyFrom(Buffer * buffer, int elements_count, int elements_from_offset, int elements_to_offset) {
copy(buffer, this, elements_count, elements_to_offset, elements_from_offset);
}
void PIOpenCL::Buffer::copy(Buffer * buffer_from,
Buffer * buffer_to,
int elements_count,
int elements_from_offset,
int elements_to_offset) {
if (!buffer_from || !buffer_to) return;
if (!buffer_from->PRIVATEWB->buffer || !buffer_to->PRIVATEWB->buffer) return;
if (elements_count < 0) elements_count = piMini(buffer_from->elements, buffer_to->elements);
cl_int ret = clEnqueueCopyBuffer(buffer_from->context_->PRIVATEWB->queue,
buffer_from->PRIVATEWB->buffer,
buffer_to->PRIVATEWB->buffer,
elements_from_offset * buffer_from->def.size(),
elements_to_offset * buffer_to->def.size(),
elements_count * buffer_from->def.size(),
0,
nullptr,
nullptr);
if (ret != 0) {
piCout << "[PIOpenCL::Buffer]"
<< "clEnqueueCopyBuffer error" << ret;
}
}
PIOpenCL::Program::Program() {
// piCout << "new program" << this;
zero();
@@ -548,7 +588,7 @@ void PIOpenCL::Kernel::zero() {
bool PIOpenCL::Kernel::init() {
char kname[1024];
memset(kname, 0, 1024);
piZeroMemory(kname, 1024);
cl_int ret = 0;
ret = clGetKernelInfo(PRIVATE->kernel, CL_KERNEL_FUNCTION_NAME, 1024, kname, 0);
if (ret != 0) {
@@ -655,14 +695,14 @@ void PIOpenCL::KernelArg::init(void * _k, uint index) {
cl_kernel k = (cl_kernel)_k;
cl_int ret = 0;
char nm[1024];
memset(nm, 0, 1024);
piZeroMemory(nm, 1024);
ret = clGetKernelArgInfo(k, index, CL_KERNEL_ARG_TYPE_NAME, 1024, nm, 0);
if (ret != 0) {
piCout << "[PIOpenCL::Kernel]"
<< "clGetKernelArgInfo(CL_KERNEL_ARG_TYPE_NAME) error" << ret;
}
type_name = nm;
memset(nm, 0, 1024);
piZeroMemory(nm, 1024);
ret = clGetKernelArgInfo(k, index, CL_KERNEL_ARG_NAME, 1024, nm, 0);
if (ret != 0) {
piCout << "[PIOpenCL::Kernel]"

219
main.cpp
View File

@@ -1,27 +1,226 @@
#include "libs/http_client/curl_thread_pool_p.h"
#include "pidigest.h"
#include "pihttpclient.h"
#include "pip.h"
using namespace PICoutManipulators;
using namespace PIHTTP;
PIKbdListener kbd;
const char * pageTitle = "<!DOCTYPE html>"
"<html>"
"<body>"
"<h1>Title</h1>"
"</body>"
"</html>";
class PIThreadPoolLoopNW {
public:
PIThreadPoolLoopNW(int thread_cnt = -1) {
if (thread_cnt <= 0) thread_cnt = piMaxi(1, PISystemInfo::instance()->processorsCount);
piForTimes(thread_cnt) {
auto * t = new PIThread([this]() {
while (true) {
sem_exec.acquire();
if (is_destroy) return;
int cc = counter.fetch_add(1);
func(cc);
sem_done.release();
}
});
threads << t;
}
for (auto * t: threads)
t->start();
// piCout << "PIThreadPoolLoop" << proc_cnt << "threads";
}
virtual ~PIThreadPoolLoopNW() {
is_destroy = true;
for (auto * t: threads)
t->stop();
sem_exec.release(threads.size());
for (auto * t: threads) {
if (!t->waitForFinish(100_ms)) t->terminate();
delete t;
}
}
void setFunction(std::function<void(int)> f) { func = f; }
void wait() {
// piCout << "wait" << wait_count;
if (wait_count <= 0) return;
sem_done.acquire(wait_count);
wait_count = 0;
// piCout << "wait done";
}
void start(int index_start, int index_count) {
counter = index_start;
wait_count = index_count;
sem_exec.release(index_count);
}
void exec(int index_start, int index_count) {
start(index_start, index_count);
wait();
}
void exec(int index_start, int index_count, std::function<void(int)> f) {
setFunction(f);
exec(index_start, index_count);
}
private:
PIVector<PIThread *> threads;
std::function<void(int)> func;
PISemaphore sem_exec, sem_done;
std::atomic_bool is_destroy = {false};
std::atomic_int counter = {0}, wait_count = {0};
};
// PIKbdListener kbd;
PIVector<int> vec;
int main(int argc, char * argv[]) {
vec.resize(16);
vec.fill([](int i) { return i; });
piCout << vec;
PIThreadPoolLoop tpl(8);
tpl.setFunction([](int i) { vec[i]++; });
const int count = 10000;
PITimeMeasurer tm;
piForTimes(count) {
tpl.exec(0, 16);
}
// tpl.exec(0, 16);
auto el = tm.elapsed().toMilliseconds();
piCout << "el" << el << "ms," << (el / count * 1000) << "us per round";
// tpl.wait();
piCout << vec;
return 0;
/*piForTimes(10) {
PIThread t;
t.setName("thread____");
t.startOnce([]() {
// piCout << "thread";
piMSleep(2.);
});
PITimeMeasurer tm;
t.stopAndWait();
auto el = tm.elapsed();
piCout << el.toMilliseconds();
}
return 0;*/
/*auto src = PIByteArray::fromAscii("The quick brown fox jumps over the lazy dog");
auto key = PIByteArray::fromAscii("key");
PIStringList tnl;
int max_size = 0;
for (int t = 0; t < (int)PIDigest::Type::C ount; ++t) {
tnl << PIDigest::typeName((PIDigest::Type)t);
max_size = piMaxi(max_size, tnl.back().size_s());
}
PIByteArray hs;
piCout << PIString::fromAscii(src);
for (int t = 0; t < (int)PIDigest::Type::Count; ++t) {
hs = PIDigest::calculate(src, (PIDigest::Type)t);
piCout << tnl[t].expandLeftTo(max_size, ' ') << "->" << hs.toHex();
}
for (int t = 0; t < (int)PIDigest::Type::Count; ++t) {
const int bench_count = 100000;
PITimeMeasurer tm;
piForTimes(bench_count) {
hs = PIDigest::calculate(src, (PIDigest::Type)t);
}
auto el = tm.elapsed();
piCout << tnl[t].expandLeftTo(max_size, ' ') << "time" << el.toMilliseconds();
}
// src.clear();
// crypto_hash_sha512(sout.data(), src.data(), src.size());
// piCout << "sod:" << sout.toHex();
// piCout << "512:" << sha5xx(src, initial_512, 64).toHex();
return 0;*/
/*PIHTTPServer server;
server.listen({"127.0.0.1:7777"});
// server.setBasicAuthRealm("pip");
// server.setBasicAuthEnabled(true);
// server.setBasicAuthCallback([](const PIString & u, const PIString & p) -> bool {
// piCout << "basic auth" << u << p;
// return (u == "u" && p == "p");
// });
server.registerPath("sendMessage", Method::Post, [](const PIHTTP::MessageConst & msg) -> PIHTTP::MessageMutable {
return MessageMutable().setCode(Code::Accepted);
});
server.registerUnhandled([](const PIHTTP::MessageConst & msg) -> PIHTTP::MessageMutable {
PIHTTP::MessageMutable ret;
piCout << "server rec:\n\tpath: %1\n\tmethod: %2\n\targs: %3\n\theaders: %4\n\tbody: %5\n"_a.arg(msg.path())
.arg(PIHTTP::methodName(msg.method()))
.arg(piStringify(msg.arguments()))
.arg(PIStringList(msg.headers().map<PIString>([](PIString k, PIString v) { return k + " = " + v; })).join("\n\t\t "))
.arg(PIString::fromUTF8(msg.body()));
ret.setCode(PIHTTP::Code::BadRequest);
ret.setBody(PIByteArray::fromAscii("hello client! 0123456789"));
piSleep(5.);
return ret;
});
kbd.waitForFinish();
return 0;*/
/*PIHTTP::MessageMutable req;
req.setBody(PIByteArray::fromAscii("hello server!")).addArgument("a0", "val.0").addArgument("a~r1", "знач,1"_u8);
auto * c = PIHTTPClient::create("http://u:p@127.0.0.1:7777/api", PIHTTP::Method::Get, req);
c->onFinish([](PIHTTP::MessageConst msg) {
piCout << "client rec:\n\tpath: %1\n\tmethod: %2\n\targs: %3\n\theaders: %4\n\tbody: %5\n"_a.arg(msg.path())
.arg(PIHTTP::methodName(msg.method()))
.arg(piStringify(msg.arguments()))
.arg(
PIStringList(msg.headers().map<PIString>([](PIString k, PIString v) { return k + " = " + v; })).join("\n\t\t
")) .arg(PIString::fromUTF8(msg.body()));
})
->onError([c](PIHTTP::MessageConst r) {
piCout << "error" << (int)r.code();
piCout << "msg" << c->lastError();
})
->onAbort([c](PIHTTP::MessageConst r) {
piCout << "abort" << (int)r.code();
piCout << "msg" << c->lastError();
})
->start();*/
auto * c = PIHTTPClient::create(
PIString("127.0.0.1:7777/%1").arg("sendMessag"),
Method::Post,
MessageMutable().addHeader(Header::ContentType, "application/json").setBody(PIByteArray::fromAscii("{hello}")));
c->onFinish([](const PIHTTP::MessageConst & msg) { piCout << "message finish" << (int)msg.code() << PIString::fromUTF8(msg.body()); })
->onError([c](const PIHTTP::MessageConst & msg) { piCout << "message error" << c->lastError(); })
->onAbort([c](const PIHTTP::MessageConst & msg) { piCout << "aborted"; })
->start();
piMSleep(1000);
// CurlThreadPool::instance()->destroy();
// kbd.enableExitCapture();
// WAIT_FOR_EXIT
// kbd.stopAndWait();
// server.stop();
c->abort();
piMSleep(10);
return 0;
// piCout << PIString::readableSize(PISystemMonitor::usedRAM());
PIVector<int> vi;
/*PIVector<int> vi;
piForTimes(10) {
piSleep(2.);
vi.enlarge(1000000);
piCout << "now" << vi.size() << vi.capacity();
}
piSleep(5.);
piSleep(5.);*/
/*kbd.enableExitCapture();
PIHTTPServer server;
@@ -71,7 +270,7 @@ int main(int argc, char * argv[]) {
piCout << " body" << r.body;
piCout << "";
rep.setBody(PIByteArray::fromAscii("[{\"value1\": true, \"value2\": \"ыекштп\"}]"));
return rep;
return rep;
});*/
/*piCout << "start" << server.isListen();

View File

@@ -45,7 +45,7 @@ void usage() {
}
PIString confDir() {
PIString pisdConfDir() {
return
#ifdef WINDOWS
PIDir::home().path() + "/AppData/Local"
@@ -74,7 +74,7 @@ int main(int argc, char * argv[]) {
}
PINetworkAddress addr = PINetworkAddress("0.0.0.0", 10101);
PIString conf_path = confDir();
PIString conf_path = pisdConfDir();
PIDir::make(conf_path);
conf_path += "/picloud.conf";
uint max_connections = 1000;

View File

@@ -40,7 +40,7 @@ void setCommands() {
cmd_copydir = "cp -rf ";
ign_err_suffix = " 2> /dev/null";
# ifdef MAC_OS
qplatforms = "cocoa";
qplatforms = "cocoa";
# else
qplatforms = "xcb,wayland";
# endif
@@ -90,6 +90,7 @@ void usage() {
piCout << "--dpkg-workdir <d> " << Green << "- dpkg \"admindir\" path, default \"\"";
piCout << "--name-tool <path> " << Green << "- \"install_name_tool\" path, default \"install_name_tool\"";
piCout << "--strip <path> " << Green << "- \"strip\" path, default \"strip\"";
piCout << "--no-strip " << Green << "- disable strip (save debug info)";
piCout << "--rpath " << Green << "- set rpath for copied files using \"patchelf\"";
piCout << "-d <depth> " << Green << "- maximum dependepcies depth, default 8";
piCout << "";
@@ -205,7 +206,7 @@ PIString execute(const PIString & cmd) {
if (fp) {
const int sz = 256;
char in[sz];
memset(in, 0, sz);
piZeroMemory(in, sz);
while (true) {
int r = fread(in, 1, sz, fp);
if (r <= 0) break;
@@ -380,7 +381,8 @@ void copyWildcard(const PIString & from, const PIString & to) {
PIFile::FileInfo fi(from);
system(("robocopy \"" + fi.dir() + "\" \"" + to + "\" \"" + fi.name() + "\" /E /NJH /NJS /NP /NDL /NS /NC /NFL 1> NUL").data());
#else
system((cmd_copy + from + " \"" + to + "/\"" + cmd_suffix).data());
auto _r = system((cmd_copy + from + " \"" + to + "/\"" + cmd_suffix).data());
NO_UNUSED(_r);
#endif
}
@@ -597,6 +599,7 @@ int main(int argc, char * argv[]) {
cli.addArgument("name-tool", PIChar('\0'), true);
cli.addArgument("rpath", PIChar('\0'));
cli.addArgument("strip", PIChar('\0'), true);
cli.addArgument("no-strip", PIChar('\0'), false);
cli.addArgument("Dpkg", true);
cli.addArgument("dpkg-workdir", PIChar('\0'), true);
cli.addArgument("depth", true);
@@ -625,6 +628,7 @@ int main(int argc, char * argv[]) {
rpath = cli.hasArgument("rpath");
if (nametool.isEmpty()) nametool = "install_name_tool";
if (strip.isEmpty()) strip = "strip";
if (cli.hasArgument("no-strip")) strip.clear();
dpkg = cli.argumentValue("Dpkg");
dpkg_workdir = cli.argumentValue("dpkg-workdir");
#ifdef WINDOWS
@@ -794,11 +798,14 @@ int main(int argc, char * argv[]) {
if (need_cp) {
piCout << "copy" << l;
if (!fake) {
system((cmd_copy + "\"" + l + "\" \"" + out_dir + "\"" + cmd_suffix).data());
if (!otool.isEmpty()) // Apple
system((strip + " -S \"" + out_dir + fi.name() + "\"").data());
else
system((strip + " --strip-unneeded \"" + out_dir + fi.name() + "\"").data());
auto _r = system((cmd_copy + "\"" + l + "\" \"" + out_dir + "\"" + cmd_suffix).data());
if (strip.isNotEmpty()) {
if (!otool.isEmpty()) // Apple
_r = system((strip + " -S \"" + out_dir + fi.name() + "\"").data());
else
_r = system((strip + " --strip-unneeded \"" + out_dir + fi.name() + "\"").data());
}
NO_UNUSED(_r);
}
}
}
@@ -807,7 +814,10 @@ int main(int argc, char * argv[]) {
PIString fd = findLib(f);
if (!fd.isEmpty()) {
piCout << "copy framework" << f;
if (!fake) system((cmd_copydir + "\"" + fd + "\" \"" + out_dir + "\"" + cmd_suffix).data());
if (!fake) {
auto _r = system((cmd_copydir + "\"" + fd + "\" \"" + out_dir + "\"" + cmd_suffix).data());
NO_UNUSED(_r);
}
} else
miss_frameworks << f;
}

View File

@@ -31,8 +31,10 @@ int main(int argc, char * argv[]) {
# include "piscreentypes.h"
# include "pisharedmemory.h"
# include <wincon.h>
// clang-format off
# include <wingdi.h>
# include <wincon.h>
// clang-format on
PIVector<PIVector<PIScreenTypes::Cell>> cells;
@@ -125,7 +127,7 @@ void readConsole(int x, int y, int w, int h) {
bs.X = w;
bs.Y = h;
bc.X = bc.Y = 0;
memset(chars, 0, w * h * sizeof(CHAR_INFO));
piZeroMemory(chars, w * h * sizeof(CHAR_INFO));
ReadConsoleOutput(console, chars, bs, bc, &(sbi.srWindow));
for (int i = 0; i < h; ++i)
for (int j = 0; j < w; ++j)
@@ -249,9 +251,9 @@ int main(int argc, char * argv[]) {
// piCout << "start";
STARTUPINFOA si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
memset(&sbi, 0, sizeof(sbi));
piZeroMemory(si);
piZeroMemory(pi);
piZeroMemory(sbi);
PIString shmh, pname;
if (argc > 1) shmh = argv[1];
if (argc > 2) pname = argv[2];

View File

@@ -421,11 +421,12 @@ int main(int argc, char * argv[]) {
if (sapp) CONNECTU(sapp, messageReceived, menu, messageFromApp);
if (cli.hasArgument("silent")) {
PICout::setOutputDevices(PICout::Console);
PIKbdListener ls;
PIKbdListener ls(0, 0, false);
ls.enableExitCapture(PIKbdListener::F10);
ls.start();
WAIT_FOR_EXIT
ls.stopAndWait();
while (!PIKbdListener::exiting)
piMSleep(PIP_MIN_MSLEEP * 5);
if (!ls.stopAndWait(1_s)) ls.terminate();
} else {
screen->start();
screen->waitForFinish();