├── .editorconfig ├── .gitattributes ├── .gitignore ├── CHANGES.md ├── CMakeLists.txt ├── Doxyfile.in ├── LICENSE.txt ├── README.md ├── cmake ├── dmitigr.cmake ├── dmitigr_base.cmake ├── dmitigr_cpplipa-config.cmake ├── dmitigr_cpplipa.cmake ├── dmitigr_cpplipa_libraries.cmake.in ├── dmitigr_cpplipa_libraries_all.cmake ├── dmitigr_fcgi.cmake ├── dmitigr_fs.cmake ├── dmitigr_librarian.cmake ├── dmitigr_math.cmake ├── dmitigr_net.cmake ├── dmitigr_os.cmake ├── dmitigr_rnd.cmake └── dmitigr_util.cmake ├── doc ├── base │ └── README.md ├── fcgi │ ├── README.md │ └── dmitigr_fcgi_overview.violet.html └── util │ └── README.md ├── src ├── base │ ├── assert.hpp │ ├── base.hpp │ ├── errc.hpp │ ├── errctg.hpp │ └── exceptions.hpp ├── dll.hpp.in ├── fcgi │ ├── basics.cpp │ ├── basics.hpp │ ├── connection.hpp │ ├── dll.hpp │ ├── exceptions.hpp │ ├── fcgi.cpp │ ├── fcgi.hpp │ ├── lib_version.cpp │ ├── lib_version.hpp │ ├── listener.cpp │ ├── listener.hpp │ ├── listener_options.cpp │ ├── listener_options.hpp │ ├── server_connection.cpp │ ├── server_connection.hpp │ ├── server_connection_stacked.cpp │ ├── streambuf.cpp │ ├── streambuf.hpp │ ├── streams.cpp │ ├── streams.hpp │ ├── types_fwd.hpp │ ├── version.hpp │ └── version.rc ├── fs │ ├── filesystem.hpp │ ├── fs.hpp │ └── misc.hpp ├── lib.cpp.in ├── lib_version.cpp.in ├── lib_version.hpp.in ├── math │ ├── alignment.hpp │ ├── exceptions.hpp │ ├── interval.hpp │ ├── math.hpp │ ├── statistic.hpp │ └── version.hpp ├── net │ ├── address.hpp │ ├── basics.hpp │ ├── client.hpp │ ├── conversions.hpp │ ├── descriptor.hpp │ ├── endpoint.hpp │ ├── errctg.hpp │ ├── exceptions.hpp │ ├── last_error.hpp │ ├── listener.hpp │ ├── net.hpp │ ├── socket.hpp │ ├── types_fwd.hpp │ ├── util.hpp │ └── version.hpp ├── os │ ├── environment.hpp │ ├── error.hpp │ ├── exceptions.hpp │ ├── last_error.hpp │ ├── os.hpp │ ├── pid.hpp │ ├── types_fwd.hpp │ ├── version.hpp │ └── windows.hpp ├── rnd │ ├── exceptions.hpp │ ├── number.hpp │ ├── rnd.hpp │ ├── string.hpp │ ├── uuid.hpp │ └── version.hpp ├── util │ ├── contract.hpp │ ├── diagnostic.hpp │ ├── endianness.hpp │ ├── enum_bitmask.hpp │ ├── memory.hpp │ └── util.hpp ├── version.hpp.in └── version.rc.in └── test ├── fcgi ├── fcgi-hello.cpp ├── fcgi-hellomt.cpp ├── fcgi-largesend.cpp └── fcgi-overload.cpp ├── math └── math-unit-test.cpp ├── net └── net-unit-net.cpp ├── rnd └── rnd-uuid.cpp └── util └── util-diag.cpp /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.{cpp,hpp,txt,md}] 8 | charset = utf-8 9 | 10 | [*.{cpp,hpp}] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | doc/fcgi/dmitigr_fcgi_overview.violet.html binary 3 | doc/pgfe/dmitigr_pgfe_overview.violet.html binary 4 | test/mulf/mulf-form-data*.txt text eol=crlf 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.[oa] 3 | *.exe 4 | *.[ip]db 5 | *.ilk 6 | *.obj 7 | *bld* 8 | *build* 9 | .DS_Store 10 | BROWSE 11 | .idea 12 | .vs 13 | 14 | cmake-build-* 15 | 16 | _private 17 | doxygen 18 | Doxyfile 19 | tool/cpplipa_*deps.sh 20 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | # Fcgi Release Notes 2 | 3 | ## [Unreleased] 4 | 5 | [Unreleased]: https://github.com/dmitigr/fcgi/compare/v1.0.0...HEAD 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FastCGI implementation in C++ {#mainpage} 2 | 3 | `dmitigr::fcgi` - is a [FastCGI] protocol implementation written in C++. 4 | 5 | ## Hello, World 6 | 7 | ```cpp 8 | #include 9 | #include 10 | 11 | int main() 12 | { 13 | namespace fcgi = dmitigr::fcgi; 14 | try { 15 | const auto port = 9000; 16 | const auto backlog = 64; 17 | fcgi::Listener server{fcgi::Listener_options{"0.0.0.0", port, backlog}}; 18 | server.listen(); 19 | while (true) { 20 | if (const auto conn = server.accept()) { 21 | conn->out() << "Content-Type: text/plain" << fcgi::crlfcrlf; 22 | conn->out() << "Hello from dmitigr::fcgi!"; 23 | } 24 | } 25 | } catch (const std::exception& e) { 26 | std::cerr << "Oops: " << e.what() << std::endl; 27 | return 1; 28 | } 29 | } 30 | ``` 31 | 32 | ## Hello, Multithreaded World 33 | 34 | ```cpp 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | namespace { 41 | 42 | constexpr std::size_t pool_size{64}; 43 | 44 | } // namespace 45 | 46 | int main() 47 | { 48 | namespace fcgi = dmitigr::fcgi; 49 | try { 50 | const auto serve = [](auto* const server) 51 | { 52 | while (true) { 53 | const auto conn = server->accept(); 54 | conn->out() << "Content-Type: text/plain" << fcgi::crlfcrlf; 55 | conn->out() << "Hello from dmitigr::fcgi!"; 56 | conn->close(); // Optional. 57 | } 58 | }; 59 | 60 | const auto port = 9000; 61 | const auto backlog = 64; 62 | std::clog << "Multi-threaded FastCGI server started:\n" 63 | << " port = " << port << "\n" 64 | << " backlog = " << backlog << "\n" 65 | << " thread pool size = " << pool_size << std::endl; 66 | 67 | fcgi::Listener server{fcgi::Listener_options{"0.0.0.0", port, backlog}}; 68 | server.listen(); 69 | std::vector threads(pool_size); 70 | for (auto& t : threads) 71 | t = std::thread{serve, &server}; 72 | 73 | for (auto& t : threads) 74 | t.join(); 75 | 76 | server.close(); // Optional. 77 | } catch (const std::exception& e) { 78 | std::cerr << "error: " << e.what() << std::endl; 79 | return 1; 80 | } 81 | } 82 | ``` 83 | 84 | ## Usage 85 | 86 | ### Quick usage as header-only library 87 | 88 | Copy the contents of the `src` directory to a project directory which is under 89 | an include path of a compiler, for example, `src/3rdparty/dmitigr`. 90 | 91 | Create `hello.cpp`: 92 | 93 | ```C++ 94 | #include "dmitigr/fcgi/fcgi.hpp" 95 | 96 | int main() 97 | { 98 | // Application code here... 99 | } 100 | ``` 101 | 102 | Compile `hello.cpp`: 103 | 104 | ``` 105 | g++ -std=c++17 -ohello hello.cpp 106 | ``` 107 | 108 | ### Quick usage with CMake 109 | 110 | Create build directory, configure, build and install: 111 | 112 | ``` 113 | cd fcgi 114 | mkdir build && cd build 115 | cmake .. 116 | cmake --build . 117 | sudo cmake --install . 118 | ``` 119 | 120 | Create `hello/hello.cpp`: 121 | 122 | ```C++ 123 | #include "dmitigr/fcgi/fcgi.hpp" 124 | 125 | int main() 126 | { 127 | // Application code here... 128 | } 129 | ``` 130 | 131 | Create `hello/CMakeLists.txt`: 132 | 133 | ```cmake 134 | cmake_minimum_required(VERSION 3.16) 135 | project(foo) 136 | find_package(dmitigr_cpplipa REQUIRED COMPONENTS fcgi) 137 | set(CMAKE_CXX_STANDARD 17) 138 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 139 | add_executable(hello hello.cpp) 140 | target_link_libraries(hello dmitigr_fcgi) 141 | ``` 142 | 143 | Compile `hello/hello.cpp`: 144 | 145 | ``` 146 | mkdir hello/build && cd hello/build 147 | cmake .. 148 | cmake --build . 149 | ``` 150 | 151 | ### Advanced usage 152 | 153 | For more details please, see [usage section][dmitigr_cpplipa_usage] for hints 154 | how to link `dmitigr::fcgi`. 155 | 156 | [dmitigr_cpplipa_usage]: https://github.com/dmitigr/cpplipa.git#usage 157 | 158 | [FastCGI]: https://en.wikipedia.org/wiki/FastCGI 159 | -------------------------------------------------------------------------------- /cmake/dmitigr.cmake: -------------------------------------------------------------------------------- 1 | # -*- cmake -*- 2 | # 3 | # Copyright 2022 Dmitry Igrishin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | function(dmitigr_append_cppfs libraries) 18 | if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 19 | if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9") 20 | list(APPEND ${libraries} stdc++fs) 21 | endif() 22 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 23 | if (DMITIGR_CPPLIPA_CLANG_USE_LIBCPP) 24 | if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "7") 25 | list(APPEND ${libraries} c++experimental) 26 | elseif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9") 27 | list(APPEND ${libraries} c++fs) 28 | endif() 29 | endif() 30 | endif() 31 | set(${libraries} ${${libraries}} PARENT_SCOPE) 32 | endfunction() 33 | 34 | function(dmitigr_capitalize_string str outvar) 35 | string(TOUPPER "${str}" STR) 36 | string(SUBSTRING "${STR}" 0 1 S) 37 | string(SUBSTRING "${str}" 1 -1 tr) 38 | set(${outvar} "${S}${tr}" PARENT_SCOPE) 39 | endfunction() 40 | 41 | function(dmitigr_get_version in_string out_major out_minor out_patch) 42 | string(REGEX MATCHALL "[0-9]+" ver "${in_string}") 43 | list(GET ver 0 major) 44 | list(GET ver 1 minor) 45 | list(GET ver 2 patch) 46 | set(${out_major} ${major} PARENT_SCOPE) 47 | set(${out_minor} ${minor} PARENT_SCOPE) 48 | set(${out_patch} ${patch} PARENT_SCOPE) 49 | endfunction() 50 | -------------------------------------------------------------------------------- /cmake/dmitigr_base.cmake: -------------------------------------------------------------------------------- 1 | # -*- cmake -*- 2 | # 3 | # Copyright 2022 Dmitry Igrishin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # ------------------------------------------------------------------------------ 18 | # Info 19 | # ------------------------------------------------------------------------------ 20 | 21 | dmitigr_cpplipa_set_library_info(base 0 0 0 "Base stuff") 22 | 23 | # ------------------------------------------------------------------------------ 24 | # Sources 25 | # ------------------------------------------------------------------------------ 26 | 27 | set(dmitigr_base_headers 28 | assert.hpp 29 | errc.hpp 30 | errctg.hpp 31 | exceptions.hpp 32 | ) 33 | -------------------------------------------------------------------------------- /cmake/dmitigr_cpplipa-config.cmake: -------------------------------------------------------------------------------- 1 | # -*- cmake -*- 2 | # 3 | # Copyright 2022 Dmitry Igrishin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | function(dmitigr_cpplipa_load_with_deps component) 18 | # Loading the component's dependencies 19 | foreach(dep ${dmitigr_cpplipa_${component}_deps}) 20 | dmitigr_cpplipa_load_with_deps(${dep}) 21 | endforeach() 22 | 23 | # Loading the component 24 | string(REGEX MATCH "(shared|static|interface)$" suffix "${component}") 25 | if(NOT suffix) 26 | if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/dmitigr_${component}_shared-config.cmake) 27 | set(suffix "shared") 28 | elseif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/dmitigr_${component}_static-config.cmake) 29 | set(suffix "static") 30 | elseif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/dmitigr_${component}_interface-config.cmake) 31 | set(suffix "interface") 32 | endif() 33 | set(component "${component}_${suffix}") 34 | endif() 35 | set(config_file "${CMAKE_CURRENT_LIST_DIR}/dmitigr_${component}-config.cmake") 36 | if(EXISTS ${config_file}) 37 | include(${config_file}) 38 | else() 39 | message(FATAL_ERROR "No configuration files for dmitigr_${component} found") 40 | endif() 41 | endfunction() 42 | 43 | # ------------------------------------------------------------------------------ 44 | 45 | include(${CMAKE_CURRENT_LIST_DIR}/dmitigr_cpplipa_libraries.cmake) 46 | include(${CMAKE_CURRENT_LIST_DIR}/dmitigr_cpplipa_libraries_all.cmake) 47 | 48 | if(NOT dmitigr_cpplipa_FIND_COMPONENTS) 49 | set(dmitigr_cpplipa_FIND_COMPONENTS ${dmitigr_cpplipa_libraries}) 50 | endif() 51 | 52 | foreach(component ${dmitigr_cpplipa_FIND_COMPONENTS}) 53 | dmitigr_cpplipa_load_with_deps(${component}) 54 | endforeach() 55 | -------------------------------------------------------------------------------- /cmake/dmitigr_cpplipa.cmake: -------------------------------------------------------------------------------- 1 | # -*- cmake -*- 2 | # 3 | # Copyright 2022 Dmitry Igrishin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # The following variables are taken into account for any library: 18 | # dmitigr_${lib}_target_link_libraries_${suff} 19 | # dmitigr_${lib}_target_compile_definitions_${suff} 20 | # dmitigr_${lib}_target_include_directories_${suff} 21 | # where ${suff} - public|private|interface 22 | # 23 | # The following variables are taken into account for any test: 24 | # dmitigr_${lib}_test_${test}_target_link_libraries 25 | # dmitigr_${lib}_test_${test}_target_compile_definitions 26 | 27 | include(${CMAKE_CURRENT_LIST_DIR}/dmitigr_cpplipa_libraries_all.cmake) 28 | 29 | # ------------------------------------------------------------------------------ 30 | # Source type list 31 | # ------------------------------------------------------------------------------ 32 | 33 | set(dmitigr_cpplipa_source_types 34 | headers 35 | build_only_sources 36 | implementations 37 | cmake_sources 38 | cmake_unpreprocessed 39 | transunits) 40 | 41 | # ------------------------------------------------------------------------------ 42 | # Dependency related stuff 43 | # ------------------------------------------------------------------------------ 44 | 45 | function(dmitigr_cpplipa_get_deps res_var lib) 46 | foreach(dep ${dmitigr_cpplipa_${lib}_deps}) 47 | # Getting dependencies of dep 48 | dmitigr_cpplipa_get_deps(dep_deps ${dep}) 49 | 50 | # Adding dependencies of dep to the result 51 | foreach(d ${dep_deps}) 52 | if (NOT ${d} IN_LIST result) 53 | list(APPEND result ${d}) 54 | endif() 55 | endforeach() 56 | 57 | # Adding dep itself to the result 58 | if (NOT ${dep} IN_LIST result) 59 | list(APPEND result ${dep}) 60 | endif() 61 | endforeach() 62 | 63 | set(${res_var} ${result} PARENT_SCOPE) 64 | endfunction() 65 | 66 | # ------------------------------------------------------------------------------ 67 | # Target compile options 68 | # ------------------------------------------------------------------------------ 69 | 70 | function(dmitigr_cpplipa_target_compile_options t) 71 | if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 72 | target_compile_options(${t} PRIVATE 73 | -pedantic 74 | -Wall 75 | -Wextra 76 | # -Winline 77 | -Winit-self 78 | -Wuninitialized 79 | -Wmaybe-uninitialized 80 | -Woverloaded-virtual 81 | -Wsuggest-override 82 | -Wlogical-op 83 | -Wswitch) 84 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 85 | target_compile_options(${t} PRIVATE 86 | -pedantic 87 | -Weverything 88 | -Wno-c++98-compat 89 | -Wno-c++98-compat-pedantic 90 | -Wno-documentation-unknown-command 91 | -Wno-disabled-macro-expansion 92 | -Wno-weak-vtables 93 | -Wno-ctad-maybe-unsupported 94 | -Wno-padded 95 | -Wno-exit-time-destructors 96 | -Wno-global-constructors 97 | -Wno-covered-switch-default 98 | -Wno-switch-enum # but -Wswitch still active! 99 | -Wno-unused-private-field 100 | -Wno-reserved-id-macro 101 | ) 102 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 103 | target_compile_options(${t} PRIVATE 104 | /W4 105 | /Zc:throwingNew,referenceBinding,noexceptTypes 106 | /errorReport:none 107 | /nologo 108 | /utf-8) 109 | endif() 110 | endfunction() 111 | 112 | # ------------------------------------------------------------------------------ 113 | 114 | macro(dmitigr_cpplipa_set_library_info lib 115 | version_major version_minor version_patch description) 116 | if((${version_major} LESS 0) 117 | OR (${version_minor} LESS 0) OR (${version_patch} LESS 0)) 118 | message(FATAL_ERROR "Invalid version of ${lib} specified") 119 | endif() 120 | 121 | set(dmitigr_${lib}_name "${lib}") 122 | string(TOUPPER "${lib}" dmitigr_${lib}_NAME) 123 | 124 | string(SUBSTRING "${lib}" 0 1 n) 125 | string(TOUPPER "${n}" N) 126 | string(SUBSTRING "${lib}" 1 -1 ame) 127 | set(dmitigr_${lib}_Name "${N}${ame}") 128 | 129 | set(dmitigr_${lib}_version_major "${version_major}") 130 | set(dmitigr_${lib}_version_minor "${version_minor}") 131 | set(dmitigr_${lib}_version_patch "${version_patch}") 132 | math(EXPR dmitigr_${lib}_version_major_hi "(${version_major} >> 16) & 0x0000ffff" OUTPUT_FORMAT DECIMAL) 133 | math(EXPR dmitigr_${lib}_version_major_lo "(${version_major}) & 0x0000ffff" OUTPUT_FORMAT DECIMAL) 134 | math(EXPR dmitigr_${lib}_version_minor_hi "(${version_minor} >> 16) & 0x0000ffff" OUTPUT_FORMAT DECIMAL) 135 | math(EXPR dmitigr_${lib}_version_minor_lo "(${version_minor}) & 0x0000ffff" OUTPUT_FORMAT DECIMAL) 136 | 137 | set(dmitigr_${lib}_description "${description}") 138 | set(dmitigr_${lib}_internal_name "dmitigr_${lib}") 139 | set(dmitigr_${lib}_product_name "Dmitigr ${dmitigr_${lib}_Name}") 140 | endmacro() 141 | 142 | # ------------------------------------------------------------------------------ 143 | 144 | macro(dmitigr_cpplipa_set_library_info_lib_variables lib) 145 | set(dmitigr_lib_name ${dmitigr_${lib}_name}) 146 | set(dmitigr_lib_NAME ${dmitigr_${lib}_NAME}) 147 | set(dmitigr_lib_Name ${dmitigr_${lib}_Name}) 148 | set(dmitigr_lib_version_major ${dmitigr_${lib}_version_major}) 149 | set(dmitigr_lib_version_minor ${dmitigr_${lib}_version_minor}) 150 | set(dmitigr_lib_version_patch ${dmitigr_${lib}_version_patch}) 151 | set(dmitigr_lib_version_major_hi ${dmitigr_${lib}_version_major_hi}) 152 | set(dmitigr_lib_version_major_lo ${dmitigr_${lib}_version_major_lo}) 153 | set(dmitigr_lib_version_minor_hi ${dmitigr_${lib}_version_minor_hi}) 154 | set(dmitigr_lib_version_minor_lo ${dmitigr_${lib}_version_minor_lo}) 155 | set(dmitigr_lib_description ${dmitigr_${lib}_description}) 156 | set(dmitigr_lib_internal_name ${dmitigr_${lib}_internal_name}) 157 | set(dmitigr_lib_product_name ${dmitigr_${lib}_product_name}) 158 | endmacro() 159 | -------------------------------------------------------------------------------- /cmake/dmitigr_cpplipa_libraries.cmake.in: -------------------------------------------------------------------------------- 1 | # -*- cmake -*- 2 | # 3 | # Copyright 2022 Dmitry Igrishin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set(dmitigr_cpplipa_libraries "@dmitigr_cpplipa_libraries@") 18 | -------------------------------------------------------------------------------- /cmake/dmitigr_cpplipa_libraries_all.cmake: -------------------------------------------------------------------------------- 1 | # -*- cmake -*- 2 | # 3 | # Copyright 2022 Dmitry Igrishin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # ------------------------------------------------------------------------------ 18 | # Library list 19 | # ------------------------------------------------------------------------------ 20 | 21 | set(dmitigr_cpplipa_libraries_all 22 | # Level 0 (base level) 23 | base 24 | # Level 1 25 | algo concur dt fs hsh math os que rajson rnd str ttpl util uv 26 | # Level 2 27 | mulf net prg sqlixx url 28 | # Level 3 29 | jrpc ws wscl 30 | # Level 4 31 | fcgi http pgfe 32 | # Level 5 33 | web 34 | ) 35 | 36 | # ------------------------------------------------------------------------------ 37 | # Dependency lists 38 | # ------------------------------------------------------------------------------ 39 | 40 | # Third-parties 41 | set(dmitigr_cpplipa_3rdparty_uwebsockets_deps 3rdparty_usockets) 42 | 43 | # Level 1 44 | set(dmitigr_cpplipa_algo_deps base) 45 | set(dmitigr_cpplipa_concur_deps base) 46 | set(dmitigr_cpplipa_dt_deps base) 47 | set(dmitigr_cpplipa_fs_deps) 48 | set(dmitigr_cpplipa_hsh_deps) 49 | set(dmitigr_cpplipa_math_deps base) 50 | set(dmitigr_cpplipa_os_deps base) 51 | set(dmitigr_cpplipa_que_deps) 52 | set(dmitigr_cpplipa_rajson_deps base fs 3rdparty_rapidjson) 53 | set(dmitigr_cpplipa_rnd_deps base) 54 | set(dmitigr_cpplipa_str_deps base) 55 | set(dmitigr_cpplipa_ttpl_deps base) 56 | set(dmitigr_cpplipa_util_deps base) 57 | set(dmitigr_cpplipa_uv_deps base) 58 | # Level 2 59 | set(dmitigr_cpplipa_mulf_deps base str) 60 | set(dmitigr_cpplipa_net_deps base fs os util) 61 | set(dmitigr_cpplipa_prg_deps base fs os rajson str) 62 | set(dmitigr_cpplipa_sqlixx_deps base fs) 63 | set(dmitigr_cpplipa_url_deps base str) 64 | # Level 3 65 | set(dmitigr_cpplipa_jrpc_deps base algo math rajson str) 66 | set(dmitigr_cpplipa_ws_deps base fs net 3rdparty_uwebsockets) 67 | set(dmitigr_cpplipa_wscl_deps base net 3rdparty_uwsc) 68 | # Level 4 69 | set(dmitigr_cpplipa_fcgi_deps base fs math net) 70 | set(dmitigr_cpplipa_http_deps base dt net str) 71 | set(dmitigr_cpplipa_pgfe_deps base fs net str util) 72 | # Level 5 73 | set(dmitigr_cpplipa_web_deps base fcgi fs http jrpc mulf str ttpl) 74 | -------------------------------------------------------------------------------- /cmake/dmitigr_fcgi.cmake: -------------------------------------------------------------------------------- 1 | # -*- cmake -*- 2 | # 3 | # Copyright 2022 Dmitry Igrishin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # ------------------------------------------------------------------------------ 18 | # Info 19 | # ------------------------------------------------------------------------------ 20 | 21 | dmitigr_cpplipa_set_library_info(fcgi 1 0 0 "FastCGI library") 22 | 23 | # ------------------------------------------------------------------------------ 24 | # Sources 25 | # ------------------------------------------------------------------------------ 26 | 27 | set(dmitigr_fcgi_headers 28 | basics.hpp 29 | connection.hpp 30 | exceptions.hpp 31 | listener.hpp 32 | listener_options.hpp 33 | server_connection.hpp 34 | streambuf.hpp 35 | streams.hpp 36 | types_fwd.hpp 37 | ) 38 | 39 | set(dmitigr_fcgi_implementations 40 | basics.cpp 41 | listener.cpp 42 | listener_options.cpp 43 | server_connection.cpp 44 | server_connection_stacked.cpp 45 | streambuf.cpp 46 | streams.cpp 47 | ) 48 | 49 | # ------------------------------------------------------------------------------ 50 | # Tests 51 | # ------------------------------------------------------------------------------ 52 | 53 | if(DMITIGR_CPPLIPA_TESTS) 54 | set(dmitigr_fcgi_tests hello hellomt largesend overload) 55 | set(dmitigr_fcgi_tests_target_link_libraries dmitigr_base dmitigr_rnd) 56 | if(UNIX) 57 | list(APPEND dmitigr_fcgi_tests_target_link_libraries pthread) 58 | endif() 59 | endif() 60 | -------------------------------------------------------------------------------- /cmake/dmitigr_fs.cmake: -------------------------------------------------------------------------------- 1 | # -*- cmake -*- 2 | # 3 | # Copyright 2022 Dmitry Igrishin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # ------------------------------------------------------------------------------ 18 | # Info 19 | # ------------------------------------------------------------------------------ 20 | 21 | dmitigr_cpplipa_set_library_info(fs 0 0 0 "Standard filesystem extensions") 22 | 23 | # ------------------------------------------------------------------------------ 24 | # Sources 25 | # ------------------------------------------------------------------------------ 26 | 27 | set(dmitigr_fs_headers 28 | filesystem.hpp 29 | misc.hpp 30 | ) 31 | 32 | # ------------------------------------------------------------------------------ 33 | # Dependencies 34 | # ------------------------------------------------------------------------------ 35 | 36 | dmitigr_append_cppfs(dmitigr_fs_target_link_libraries_interface) 37 | -------------------------------------------------------------------------------- /cmake/dmitigr_librarian.cmake: -------------------------------------------------------------------------------- 1 | # -*- cmake -*- 2 | # 3 | # Copyright 2022 Dmitry Igrishin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Find specified include directories and libraries. 18 | # 19 | # This module uses the following variables: 20 | # 21 | # dmitigr_librarian_lib - the library to find. It used as path suffix of include path. 22 | # ${dmitigr_librarian_lib}_include_names - names of the headers to find 23 | # ${dmitigr_librarian_lib}_library_names - names of the libraries to find 24 | # ${dmitigr_librarian_lib}_FIND_REQUIRED - True or False 25 | # 26 | # This module defines the following variables: 27 | # 28 | # ${dmitigr_librarian_lib}_INCLUDE_DIRS - include directories 29 | # ${dmitigr_librarian_lib}_LIBRARIES - suggested libraries to link 30 | # ${dmitigr_librarian_lib}_FOUND - True if ${dmitigr_librarian_lib} libraries are found 31 | 32 | set(${dmitigr_librarian_lib}_FOUND False) 33 | 34 | find_path(${dmitigr_librarian_lib}_INCLUDE_DIRS 35 | NAMES ${${dmitigr_librarian_lib}_include_names}) 36 | if(${dmitigr_librarian_lib}_INCLUDE_DIRS) 37 | if(${dmitigr_librarian_lib}_library_names) 38 | find_library(${dmitigr_librarian_lib}_LIBRARIES 39 | NAMES ${${dmitigr_librarian_lib}_library_names}) 40 | if(${dmitigr_librarian_lib}_LIBRARIES) 41 | set(${dmitigr_librarian_lib}_FOUND True) 42 | endif() 43 | endif() 44 | endif() 45 | 46 | if(${dmitigr_librarian_lib}_FIND_REQUIRED) 47 | if(NOT ${dmitigr_librarian_lib}_FOUND) 48 | message(FATAL_ERROR "Could not find ${dmitigr_librarian_lib} library") 49 | endif() 50 | endif() 51 | -------------------------------------------------------------------------------- /cmake/dmitigr_math.cmake: -------------------------------------------------------------------------------- 1 | # -*- cmake -*- 2 | # 3 | # Copyright 2022 Dmitry Igrishin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # ------------------------------------------------------------------------------ 18 | # Info 19 | # ------------------------------------------------------------------------------ 20 | 21 | dmitigr_cpplipa_set_library_info(math 0 0 0 "Math stuff") 22 | 23 | # ------------------------------------------------------------------------------ 24 | # Sources 25 | # ------------------------------------------------------------------------------ 26 | 27 | set(dmitigr_math_headers 28 | alignment.hpp 29 | exceptions.hpp 30 | interval.hpp 31 | statistic.hpp 32 | ) 33 | 34 | # ------------------------------------------------------------------------------ 35 | # Tests 36 | # ------------------------------------------------------------------------------ 37 | 38 | if(DMITIGR_CPPLIPA_TESTS) 39 | set(dmitigr_math_tests test) 40 | set(dmitigr_math_tests_target_link_libraries dmitigr_base) 41 | endif() 42 | -------------------------------------------------------------------------------- /cmake/dmitigr_net.cmake: -------------------------------------------------------------------------------- 1 | # -*- cmake -*- 2 | # 3 | # Copyright 2022 Dmitry Igrishin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # ------------------------------------------------------------------------------ 18 | # Info 19 | # ------------------------------------------------------------------------------ 20 | 21 | dmitigr_cpplipa_set_library_info(net 0 0 0 "Networking") 22 | 23 | # ------------------------------------------------------------------------------ 24 | # Sources 25 | # ------------------------------------------------------------------------------ 26 | 27 | set(dmitigr_net_headers 28 | address.hpp 29 | basics.hpp 30 | client.hpp 31 | conversions.hpp 32 | descriptor.hpp 33 | endpoint.hpp 34 | errctg.hpp 35 | exceptions.hpp 36 | last_error.hpp 37 | listener.hpp 38 | socket.hpp 39 | types_fwd.hpp 40 | util.hpp 41 | ) 42 | 43 | set(dmitigr_net_implementations 44 | ) 45 | 46 | # ------------------------------------------------------------------------------ 47 | # Dependencies 48 | # ------------------------------------------------------------------------------ 49 | 50 | if (WIN32) 51 | if (CMAKE_SYSTEM_NAME MATCHES MSYS|MinGW|Cygwin AND CMAKE_CXX_COMPILER_ID MATCHES GNU|Clang) 52 | list(APPEND dmitigr_net_target_link_libraries_interface libws2_32.a) 53 | else() 54 | list(APPEND dmitigr_net_target_link_libraries_interface Ws2_32.lib) 55 | endif() 56 | endif() 57 | 58 | # ------------------------------------------------------------------------------ 59 | # Tests 60 | # ------------------------------------------------------------------------------ 61 | 62 | if(DMITIGR_CPPLIPA_TESTS) 63 | if(UNIX AND NOT CMAKE_SYSTEM_NAME MATCHES MSYS|MinGW|Cygwin) 64 | set(dmitigr_net_tests net) 65 | set(dmitigr_net_tests_target_link_libraries dmitigr_base) 66 | endif() 67 | endif() 68 | -------------------------------------------------------------------------------- /cmake/dmitigr_os.cmake: -------------------------------------------------------------------------------- 1 | # -*- cmake -*- 2 | # 3 | # Copyright 2022 Dmitry Igrishin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # ------------------------------------------------------------------------------ 18 | # Info 19 | # ------------------------------------------------------------------------------ 20 | 21 | dmitigr_cpplipa_set_library_info(os 0 0 0 "OS basics") 22 | 23 | # ------------------------------------------------------------------------------ 24 | # Sources 25 | # ------------------------------------------------------------------------------ 26 | 27 | set(dmitigr_os_headers 28 | environment.hpp 29 | error.hpp 30 | exceptions.hpp 31 | last_error.hpp 32 | pid.hpp 33 | types_fwd.hpp 34 | ) 35 | 36 | set(dmitigr_os_implementations 37 | ) 38 | 39 | if (WIN32) 40 | list(APPEND dmitigr_os_headers windows.hpp) 41 | endif() 42 | -------------------------------------------------------------------------------- /cmake/dmitigr_rnd.cmake: -------------------------------------------------------------------------------- 1 | # -*- cmake -*- 2 | # 3 | # Copyright 2022 Dmitry Igrishin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # ------------------------------------------------------------------------------ 18 | # Info 19 | # ------------------------------------------------------------------------------ 20 | 21 | dmitigr_cpplipa_set_library_info(rnd 0 0 0 "Random stuff generators") 22 | 23 | # ------------------------------------------------------------------------------ 24 | # Sources 25 | # ------------------------------------------------------------------------------ 26 | 27 | set(dmitigr_rnd_headers 28 | exceptions.hpp 29 | number.hpp 30 | string.hpp 31 | uuid.hpp 32 | ) 33 | 34 | # ------------------------------------------------------------------------------ 35 | # Tests 36 | # ------------------------------------------------------------------------------ 37 | 38 | if(DMITIGR_CPPLIPA_TESTS) 39 | set(dmitigr_rnd_tests uuid) 40 | set(dmitigr_rnd_tests_target_link_libraries dmitigr_base) 41 | endif() 42 | -------------------------------------------------------------------------------- /cmake/dmitigr_util.cmake: -------------------------------------------------------------------------------- 1 | # -*- cmake -*- 2 | # 3 | # Copyright 2022 Dmitry Igrishin 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # ------------------------------------------------------------------------------ 18 | # Info 19 | # ------------------------------------------------------------------------------ 20 | 21 | dmitigr_cpplipa_set_library_info(util 0 0 0 "Utilities") 22 | 23 | # ------------------------------------------------------------------------------ 24 | # Sources 25 | # ------------------------------------------------------------------------------ 26 | 27 | set(dmitigr_util_headers 28 | diagnostic.hpp 29 | endianness.hpp 30 | enum_bitmask.hpp 31 | memory.hpp 32 | ) 33 | 34 | # ------------------------------------------------------------------------------ 35 | # Tests 36 | # ------------------------------------------------------------------------------ 37 | 38 | if(DMITIGR_CPPLIPA_TESTS) 39 | set(dmitigr_util_tests diag) 40 | endif() 41 | -------------------------------------------------------------------------------- /doc/base/README.md: -------------------------------------------------------------------------------- 1 | # Base stuff 2 | 3 | This library is a core part used by every library in the package. Thus, the 4 | stuff which is not used by *every* library should not be added here. 5 | -------------------------------------------------------------------------------- /doc/fcgi/README.md: -------------------------------------------------------------------------------- 1 | # FastCGI implementation in C++ {#mainpage} 2 | 3 | `dmitigr::fcgi` - is a [FastCGI] protocol implementation written in C++. 4 | 5 | ## Hello, World 6 | 7 | ```cpp 8 | #include 9 | #include 10 | 11 | int main() 12 | { 13 | namespace fcgi = dmitigr::fcgi; 14 | try { 15 | const auto port = 9000; 16 | const auto backlog = 64; 17 | fcgi::Listener server{fcgi::Listener_options{"0.0.0.0", port, backlog}}; 18 | server.listen(); 19 | while (true) { 20 | if (const auto conn = server.accept()) { 21 | conn->out() << "Content-Type: text/plain" << fcgi::crlfcrlf; 22 | conn->out() << "Hello from dmitigr::fcgi!"; 23 | } 24 | } 25 | } catch (const std::exception& e) { 26 | std::cerr << "Oops: " << e.what() << std::endl; 27 | return 1; 28 | } 29 | } 30 | ``` 31 | 32 | ## Hello, Multithreaded World 33 | 34 | ```cpp 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | namespace { 41 | 42 | constexpr std::size_t pool_size{64}; 43 | 44 | } // namespace 45 | 46 | int main() 47 | { 48 | namespace fcgi = dmitigr::fcgi; 49 | try { 50 | const auto serve = [](auto* const server) 51 | { 52 | while (true) { 53 | const auto conn = server->accept(); 54 | conn->out() << "Content-Type: text/plain" << fcgi::crlfcrlf; 55 | conn->out() << "Hello from dmitigr::fcgi!"; 56 | conn->close(); // Optional. 57 | } 58 | }; 59 | 60 | const auto port = 9000; 61 | const auto backlog = 64; 62 | std::clog << "Multi-threaded FastCGI server started:\n" 63 | << " port = " << port << "\n" 64 | << " backlog = " << backlog << "\n" 65 | << " thread pool size = " << pool_size << std::endl; 66 | 67 | fcgi::Listener server{fcgi::Listener_options{"0.0.0.0", port, backlog}}; 68 | server.listen(); 69 | std::vector threads(pool_size); 70 | for (auto& t : threads) 71 | t = std::thread{serve, &server}; 72 | 73 | for (auto& t : threads) 74 | t.join(); 75 | 76 | server.close(); // Optional. 77 | } catch (const std::exception& e) { 78 | std::cerr << "error: " << e.what() << std::endl; 79 | return 1; 80 | } 81 | } 82 | ``` 83 | 84 | ## Usage 85 | 86 | ### Quick usage as header-only library 87 | 88 | Copy the contents of the `src` directory to a project directory which is under 89 | an include path of a compiler, for example, `src/3rdparty/dmitigr`. 90 | 91 | Create `hello.cpp`: 92 | 93 | ```C++ 94 | #include "dmitigr/fcgi/fcgi.hpp" 95 | 96 | int main() 97 | { 98 | // Application code here... 99 | } 100 | ``` 101 | 102 | Compile `hello.cpp`: 103 | 104 | ``` 105 | g++ -std=c++17 -ohello hello.cpp 106 | ``` 107 | 108 | ### Quick usage with CMake 109 | 110 | Create build directory, configure, build and install: 111 | 112 | ``` 113 | cd fcgi 114 | mkdir build && cd build 115 | cmake .. 116 | cmake --build . 117 | sudo cmake --install . 118 | ``` 119 | 120 | Create `hello/hello.cpp`: 121 | 122 | ```C++ 123 | #include "dmitigr/fcgi/fcgi.hpp" 124 | 125 | int main() 126 | { 127 | // Application code here... 128 | } 129 | ``` 130 | 131 | Create `hello/CMakeLists.txt`: 132 | 133 | ```cmake 134 | cmake_minimum_required(VERSION 3.16) 135 | project(foo) 136 | find_package(dmitigr_cpplipa REQUIRED COMPONENTS fcgi) 137 | set(CMAKE_CXX_STANDARD 17) 138 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 139 | add_executable(hello hello.cpp) 140 | target_link_libraries(hello dmitigr_fcgi) 141 | ``` 142 | 143 | Compile `hello/hello.cpp`: 144 | 145 | ``` 146 | mkdir hello/build && cd hello/build 147 | cmake .. 148 | cmake --build . 149 | ``` 150 | 151 | ### Advanced usage 152 | 153 | For more details please, see [usage section][dmitigr_cpplipa_usage] for hints 154 | how to link `dmitigr::fcgi`. 155 | 156 | [dmitigr_cpplipa_usage]: https://github.com/dmitigr/cpplipa.git#usage 157 | 158 | [FastCGI]: https://en.wikipedia.org/wiki/FastCGI 159 | -------------------------------------------------------------------------------- /doc/util/README.md: -------------------------------------------------------------------------------- 1 | # Utilities 2 | 3 | This library contains a *general purpose* useful stuff, that *can* be used by 4 | *any* (not every) library. Specialized (not general purpose) stuff should be 5 | placed into a dedicated library. 6 | -------------------------------------------------------------------------------- /src/base/assert.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_BASE_ASSERT_HPP 18 | #define DMITIGR_BASE_ASSERT_HPP 19 | 20 | #include // std::terminate 21 | #ifndef DMITIGR_ASSERT 22 | #include 23 | #endif 24 | 25 | namespace dmitigr { 26 | 27 | /// The debug mode indicator. 28 | #ifndef NDEBUG 29 | constexpr bool is_debug{true}; 30 | #else 31 | constexpr bool is_debug{false}; 32 | #endif 33 | 34 | } // namespace dmitigr 35 | 36 | #ifndef DMITIGR_ASSERT 37 | /** 38 | * @brief Checks the assertion `a`. 39 | * 40 | * @details Always active regardless of `is_debug` (or `NDEBUG`). 41 | * 42 | * @par Effects Terminates the process if `!a`. 43 | */ 44 | #define DMITIGR_ASSERT(a) do { \ 45 | if (!(a)) { \ 46 | std::cerr<<"assertion ("<<#a<<") failed at "<<__FILE__<<":"<<__LINE__<<"\n"; \ 47 | std::terminate(); \ 48 | } \ 49 | } while (false) 50 | #endif 51 | 52 | #endif // DMITIGR_BASE_ASSERT_HPP 53 | -------------------------------------------------------------------------------- /src/base/base.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_BASE_BASE_HPP 18 | #define DMITIGR_BASE_BASE_HPP 19 | 20 | #include "assert.hpp" 21 | #include "errc.hpp" 22 | #include "errctg.hpp" 23 | #include "exceptions.hpp" 24 | 25 | #endif // DMITIGR_BASE_BASE_HPP 26 | -------------------------------------------------------------------------------- /src/base/errc.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_BASE_ERRC_HPP 18 | #define DMITIGR_BASE_ERRC_HPP 19 | 20 | namespace dmitigr { 21 | 22 | /** 23 | * @ingroup errors 24 | * 25 | * @brief Generic error codes (or conditions). 26 | */ 27 | enum class Errc { 28 | /// Generic error. 29 | generic = 1, 30 | }; 31 | 32 | /** 33 | * @ingroup errors 34 | * 35 | * @returns The literal representation of the `errc`, or `nullptr` 36 | * if `errc` does not corresponds to any value defined by Errc. 37 | */ 38 | constexpr const char* to_literal(const Errc errc) noexcept 39 | { 40 | switch (errc) { 41 | case Errc::generic: return "generic"; 42 | } 43 | return nullptr; 44 | } 45 | 46 | /** 47 | * @ingroup errors 48 | * 49 | * @returns The literal returned by `to_literal(errc)`, or literal 50 | * "unknown error" if `to_literal(errc)` returned `nullptr`. 51 | */ 52 | constexpr const char* to_literal_anyway(const Errc errc) noexcept 53 | { 54 | constexpr const char* unknown{"unknown error"}; 55 | const char* const literal{to_literal(errc)}; 56 | return literal ? literal : unknown; 57 | } 58 | 59 | } // namespace dmitigr 60 | 61 | #endif // DMITIGR_BASE_ERRC_HPP 62 | -------------------------------------------------------------------------------- /src/base/errctg.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_BASE_ERRCTG_HPP 18 | #define DMITIGR_BASE_ERRCTG_HPP 19 | 20 | #include "errc.hpp" 21 | 22 | #include // std::strlen 23 | #include 24 | 25 | namespace std { 26 | 27 | /** 28 | * @ingroup errors 29 | * 30 | * @brief The full specialization for integration with ``. 31 | */ 32 | template<> 33 | struct is_error_condition_enum final : true_type {}; 34 | 35 | } // namespace std 36 | 37 | namespace dmitigr { 38 | 39 | /** 40 | * @ingroup errors 41 | * 42 | * @brief A Generic category of errors. 43 | * 44 | * @see Exception. 45 | */ 46 | class Generic_error_category final : public std::error_category { 47 | public: 48 | /// @returns The literal `dmitigr_generic_error`. 49 | const char* name() const noexcept override 50 | { 51 | return "dmitigr_generic_error"; 52 | } 53 | 54 | /** 55 | * @returns The string that describes the error condition denoted by `ev`. 56 | * 57 | * @par Requires 58 | * `ev` must corresponds to the value of Errc. 59 | * 60 | * @remarks The caller should not rely on the return value as it is a 61 | * subject to change. 62 | */ 63 | std::string message(const int ev) const override 64 | { 65 | const char* const desc{to_literal_anyway(static_cast(ev))}; 66 | constexpr const char* const sep{": "}; 67 | std::string result; 68 | result.reserve(std::strlen(name()) + std::strlen(sep) + std::strlen(desc)); 69 | return result.append(name()).append(sep).append(desc); 70 | } 71 | }; 72 | 73 | /** 74 | * @ingroup errors 75 | * 76 | * @returns The reference to the instance of type Generic_error_category. 77 | */ 78 | inline const Generic_error_category& generic_error_category() noexcept 79 | { 80 | static const Generic_error_category result; 81 | return result; 82 | } 83 | 84 | /** 85 | * @ingroup errors 86 | * 87 | * @returns `std::error_condition(int(errc), generic_error_category())`. 88 | */ 89 | inline std::error_condition make_error_condition(const Errc errc) noexcept 90 | { 91 | return {static_cast(errc), generic_error_category()}; 92 | } 93 | 94 | } // namespace dmitigr 95 | 96 | #endif // DMITIGR_BASE_ERRCTG_HPP 97 | -------------------------------------------------------------------------------- /src/base/exceptions.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_BASE_EXCEPTIONS_HPP 18 | #define DMITIGR_BASE_EXCEPTIONS_HPP 19 | 20 | #include "errctg.hpp" 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | namespace dmitigr { 27 | 28 | /** 29 | * @ingroup errors 30 | * 31 | * @brief The generic exception class. 32 | */ 33 | class Exception : public std::exception { 34 | public: 35 | /** 36 | * @brief Constructs an instance associaterd with `errc`. 37 | * 38 | * @param errc The error condition. 39 | * @param what The what-string. 40 | */ 41 | Exception(const std::error_condition& errc, const std::string& what) 42 | : what_{what} 43 | , condition_{errc} 44 | {} 45 | 46 | /** 47 | * @brief Constructs an instance associated with Errc::generic. 48 | * 49 | * @param what The what-string. 50 | */ 51 | explicit Exception(const std::string& what) 52 | : Exception{Errc::generic, what} 53 | {} 54 | 55 | /// @returns The what-string. 56 | const char* what() const noexcept override 57 | { 58 | return what_.what(); 59 | } 60 | 61 | /// @returns The error condition. 62 | std::error_condition condition() const noexcept 63 | { 64 | return condition_; 65 | } 66 | 67 | private: 68 | std::runtime_error what_; 69 | std::error_condition condition_; 70 | }; 71 | 72 | } // namespace dmitigr 73 | 74 | #endif // DMITIGR_BASE_EXCEPTIONS_HPP 75 | -------------------------------------------------------------------------------- /src/dll.hpp.in: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 18 | // This file is generated automatically. Edit dll.hpp.in instead!!!!!!!!!!!!!!!! 19 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 | 21 | #ifndef DMITIGR_@dmitigr_lib_NAME@_DLL_HPP 22 | #define DMITIGR_@dmitigr_lib_NAME@_DLL_HPP 23 | 24 | #ifdef _WIN32 25 | #ifdef DMITIGR_@dmitigr_lib_NAME@_DLL_BUILDING 26 | #define DMITIGR_@dmitigr_lib_NAME@_API __declspec(dllexport) 27 | #else 28 | #if DMITIGR_@dmitigr_lib_NAME@_DLL 29 | #define DMITIGR_@dmitigr_lib_NAME@_API __declspec(dllimport) 30 | #else /* static or header-only library on Windows */ 31 | #define DMITIGR_@dmitigr_lib_NAME@_API 32 | #endif 33 | #endif 34 | #else /* Unix */ 35 | #define DMITIGR_@dmitigr_lib_NAME@_API 36 | #endif 37 | 38 | #ifndef DMITIGR_@dmitigr_lib_NAME@_INLINE 39 | #if !defined(DMITIGR_@dmitigr_lib_NAME@_NOT_HEADER_ONLY) && !defined(DMITIGR_@dmitigr_lib_NAME@_BUILDING) 40 | #define DMITIGR_@dmitigr_lib_NAME@_INLINE inline 41 | #else 42 | #define DMITIGR_@dmitigr_lib_NAME@_INLINE 43 | #endif 44 | #endif // DMITIGR_@dmitigr_lib_NAME@_INLINE 45 | 46 | #endif // DMITIGR_@dmitigr_lib_NAME@_DLL_HPP 47 | -------------------------------------------------------------------------------- /src/fcgi/basics.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_FCGI_BASICS_HPP 18 | #define DMITIGR_FCGI_BASICS_HPP 19 | 20 | namespace dmitigr::fcgi { 21 | 22 | /// FastCGI role. 23 | enum class Role { 24 | /// The Responder role. 25 | responder = 1, 26 | 27 | /// The Authorizer role. 28 | authorizer = 2, 29 | 30 | /// The Filter role. 31 | filter = 3 32 | }; 33 | 34 | /// Represents a type of stream. 35 | enum class Stream_type { 36 | /** 37 | * @brief A name-value pair stream used in sending name-value 38 | * pairs from a FastCGI client to a FastCGI server. 39 | */ 40 | params = 4, 41 | 42 | /** 43 | * @brief A stream used in sending arbitrary data 44 | * from a FastCGI client to a FastCGI server. 45 | */ 46 | in = 5, 47 | 48 | /** 49 | * @brief A stream used in sending arbitrary data 50 | * from a FastCGI server to a FastCGI client. 51 | */ 52 | out = 6, 53 | 54 | /** 55 | * @brief A stream used in sending error data 56 | * from a FastCGI server to a FastCGI client. 57 | */ 58 | err = 7, 59 | 60 | /** 61 | * @brief A stream used in sending additional data 62 | * from a FastCGI client to a FastCGI server. 63 | */ 64 | data = 8 65 | }; 66 | 67 | } // namespace dmitigr::fcgi 68 | 69 | #ifndef DMITIGR_FCGI_NOT_HEADER_ONLY 70 | #include "basics.cpp" 71 | #endif 72 | 73 | #endif // DMITIGR_FCGI_BASICS_HPP 74 | -------------------------------------------------------------------------------- /src/fcgi/connection.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_FCGI_CONNECTION_HPP 18 | #define DMITIGR_FCGI_CONNECTION_HPP 19 | 20 | #include "types_fwd.hpp" 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | namespace dmitigr::fcgi { 27 | 28 | /// A FastCGI connection. 29 | class Connection { 30 | public: 31 | /// The destructor. 32 | virtual ~Connection() = default; 33 | 34 | /// @returns The request identifier. (Always a non-zero value.) 35 | virtual int request_id() const noexcept = 0; 36 | 37 | /// @returns The role of a FastCGI application that serves this connection. 38 | virtual Role role() const noexcept = 0; 39 | 40 | /// @returns The number of parameters. 41 | virtual std::size_t parameter_count() const noexcept = 0; 42 | 43 | /// @returns The parameter index if presents. 44 | virtual std::optional 45 | parameter_index(std::string_view name) const noexcept = 0; 46 | 47 | /** 48 | * @returns The parameter. 49 | * 50 | * @par Requires 51 | * `index < parameter_count()`. 52 | */ 53 | virtual std::string_view parameter(std::size_t index) const = 0; 54 | 55 | /** 56 | * @overload 57 | * 58 | * @par Requires 59 | * `parameter_index(name)`. 60 | */ 61 | virtual std::string_view parameter(std::string_view name) const = 0; 62 | 63 | /** 64 | * @brief Closes the connection. 65 | * 66 | * @remarks Using this method is optional since it is implicitly called upon 67 | * the object destruction. The main reason of using it explicitly is to catch 68 | * possibly-thrown exceptions (which are always catched by the destructor). 69 | * 70 | * @par Effects 71 | * `is_closed()`. 72 | */ 73 | virtual void close() = 0; 74 | 75 | /// @returns `true` if the connection is closed. 76 | virtual bool is_closed() const noexcept = 0; 77 | 78 | private: 79 | friend Server_connection; 80 | 81 | Connection() = default; 82 | }; 83 | 84 | } // namespace dmitigr::fcgi 85 | 86 | #endif // DMITIGR_FCGI_CONNECTION_HPP 87 | -------------------------------------------------------------------------------- /src/fcgi/dll.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 18 | // This file is generated automatically. Edit dll.hpp.in instead!!!!!!!!!!!!!!!! 19 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 | 21 | #ifndef DMITIGR_FCGI_DLL_HPP 22 | #define DMITIGR_FCGI_DLL_HPP 23 | 24 | #ifdef _WIN32 25 | #ifdef DMITIGR_FCGI_DLL_BUILDING 26 | #define DMITIGR_FCGI_API __declspec(dllexport) 27 | #else 28 | #if DMITIGR_FCGI_DLL 29 | #define DMITIGR_FCGI_API __declspec(dllimport) 30 | #else /* static or header-only library on Windows */ 31 | #define DMITIGR_FCGI_API 32 | #endif 33 | #endif 34 | #else /* Unix */ 35 | #define DMITIGR_FCGI_API 36 | #endif 37 | 38 | #ifndef DMITIGR_FCGI_INLINE 39 | #if !defined(DMITIGR_FCGI_NOT_HEADER_ONLY) && !defined(DMITIGR_FCGI_BUILDING) 40 | #define DMITIGR_FCGI_INLINE inline 41 | #else 42 | #define DMITIGR_FCGI_INLINE 43 | #endif 44 | #endif // DMITIGR_FCGI_INLINE 45 | 46 | #endif // DMITIGR_FCGI_DLL_HPP 47 | -------------------------------------------------------------------------------- /src/fcgi/exceptions.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_FCGI_EXCEPTIONS_HPP 18 | #define DMITIGR_FCGI_EXCEPTIONS_HPP 19 | 20 | #include "../base/exceptions.hpp" 21 | 22 | namespace dmitigr::fcgi { 23 | 24 | /// The generic exception class. 25 | class Exception final : public dmitigr::Exception { 26 | using dmitigr::Exception::Exception; 27 | }; 28 | 29 | } // namespace dmitigr::fcgi 30 | 31 | #endif // DMITIGR_FCGI_EXCEPTIONS_HPP 32 | -------------------------------------------------------------------------------- /src/fcgi/fcgi.cpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 18 | // This file is generated automatically. Edit lib.cpp.in instead!!!!!!!!!!!!!!!! 19 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 | 21 | #ifdef DMITIGR_FCGI_NOT_HEADER_ONLY 22 | #undef DMITIGR_FCGI_NOT_HEADER_ONLY 23 | #endif 24 | #ifndef DMITIGR_FCGI_BUILDING 25 | #define DMITIGR_FCGI_BUILDING 26 | #endif 27 | #include "fcgi.hpp" 28 | -------------------------------------------------------------------------------- /src/fcgi/fcgi.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_FCGI_FCGI_HPP 18 | #define DMITIGR_FCGI_FCGI_HPP 19 | 20 | #include "basics.hpp" 21 | #include "connection.hpp" 22 | #include "listener.hpp" 23 | #include "listener_options.hpp" 24 | #include "server_connection.hpp" 25 | #include "streambuf.hpp" 26 | #include "streams.hpp" 27 | #include "version.hpp" 28 | 29 | #endif // DMITIGR_FCGI_FCGI_HPP 30 | -------------------------------------------------------------------------------- /src/fcgi/lib_version.cpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 18 | // This file is generated automatically. Edit lib_version.cpp.in instead!!!!!!!!!!!! 19 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 | 21 | #include "lib_version.hpp" 22 | #include "version.hpp" 23 | 24 | namespace dmitigr::fcgi { 25 | 26 | DMITIGR_FCGI_INLINE std::int_fast32_t lib_version() noexcept 27 | { 28 | return version(); 29 | } 30 | 31 | } // namespace dmitigr::fcgi 32 | -------------------------------------------------------------------------------- /src/fcgi/lib_version.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 18 | // This file is generated automatically. Edit lib_version.hpp.in instead!!!!!!!!!!!! 19 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 | 21 | #ifndef DMITIGR_FCGI_LIB_VERSION_HPP 22 | #define DMITIGR_FCGI_LIB_VERSION_HPP 23 | 24 | #include "dll.hpp" 25 | 26 | #include 27 | 28 | namespace dmitigr::fcgi { 29 | 30 | /** 31 | * @returns The library version. 32 | * 33 | * @see version(). 34 | */ 35 | DMITIGR_FCGI_API std::int_fast32_t lib_version() noexcept; 36 | 37 | } // namespace dmitigr::fcgi 38 | 39 | #ifndef DMITIGR_FCGI_NOT_HEADER_ONLY 40 | #include "lib_version.cpp" 41 | #endif 42 | 43 | #endif // DMITIGR_FCGI_LIB_VERSION_HPP 44 | -------------------------------------------------------------------------------- /src/fcgi/listener.cpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #include "../base/assert.hpp" 18 | #include "../net/listener.hpp" 19 | #include "basics.hpp" 20 | #include "exceptions.hpp" 21 | #include "listener.hpp" 22 | #include "server_connection_stacked.cpp" 23 | 24 | namespace dmitigr::fcgi { 25 | 26 | DMITIGR_FCGI_INLINE Listener::Listener(Listener_options options) 27 | : listener_{net::Listener::make(options.options_)} 28 | , listener_options_{std::move(options)} 29 | {} 30 | 31 | DMITIGR_FCGI_INLINE const Listener_options& Listener::options() const noexcept 32 | { 33 | return listener_options_; 34 | } 35 | 36 | DMITIGR_FCGI_INLINE bool Listener::is_listening() const noexcept 37 | { 38 | return listener_->is_listening(); 39 | } 40 | 41 | DMITIGR_FCGI_INLINE void Listener::listen() 42 | { 43 | listener_->listen(); 44 | } 45 | 46 | DMITIGR_FCGI_INLINE bool Listener::wait(const std::chrono::milliseconds timeout) 47 | { 48 | return listener_->wait(timeout); 49 | } 50 | 51 | DMITIGR_FCGI_INLINE std::unique_ptr Listener::accept() 52 | { 53 | auto io = listener_->accept(); 54 | detail::Header header{io.get()}; 55 | 56 | const auto end_request = [&](const detail::Protocol_status protocol_status) 57 | { 58 | const detail::End_request_record record{header.request_id(), 59 | 0, protocol_status}; 60 | const auto count = io->write(reinterpret_cast(&record), 61 | sizeof(record)); 62 | DMITIGR_ASSERT(count == sizeof(record)); 63 | }; 64 | 65 | if (header.record_type() == detail::Record_type::begin_request && 66 | !header.is_management_record() && 67 | header.content_length() == sizeof(detail::Begin_request_body)) { 68 | const detail::Begin_request_body body{io.get()}; 69 | const auto role = body.role(); 70 | if (role == Role::responder || 71 | role == Role::authorizer || role == Role::filter) { 72 | return std::make_unique( 73 | std::move(io), role, header.request_id(), body.is_keep_conn()); 74 | } else { 75 | // This is a protocol violation. 76 | end_request(detail::Protocol_status::unknown_role); 77 | throw Exception{"unknown FastCGI role"}; 78 | } 79 | } else { 80 | /* 81 | * Actualy, this is a protocol violation. But the FastCGI protocol has no 82 | * such a protocol status. Thus, detail::Protocol_status::cant_mpx_conn - 83 | * is the best suited protocol status code here. 84 | */ 85 | end_request(detail::Protocol_status::cant_mpx_conn); 86 | throw Exception{"FastCGI protocol violation"}; 87 | } 88 | } 89 | 90 | DMITIGR_FCGI_INLINE void Listener::close() 91 | { 92 | listener_->close(); 93 | } 94 | 95 | } // namespace dmitigr::fcgi 96 | -------------------------------------------------------------------------------- /src/fcgi/listener.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_FCGI_LISTENER_HPP 18 | #define DMITIGR_FCGI_LISTENER_HPP 19 | 20 | #include "dll.hpp" 21 | #include "listener_options.hpp" 22 | #include "types_fwd.hpp" 23 | 24 | #include 25 | 26 | namespace dmitigr::fcgi { 27 | 28 | /// A FastCGI listener. 29 | class Listener final { 30 | public: 31 | /// Constructs the listener. 32 | DMITIGR_FCGI_API explicit Listener(Listener_options options); 33 | 34 | /// @returns Options of the listener. 35 | DMITIGR_FCGI_API const Listener_options& options() const noexcept; 36 | 37 | /// @returns `true` if the listener is listening for new client connections. 38 | DMITIGR_FCGI_API bool is_listening() const noexcept; 39 | 40 | /** 41 | * @brief Starts listening. 42 | * 43 | * @par Requires 44 | * `!is_listening()`. 45 | */ 46 | DMITIGR_FCGI_API void listen(); 47 | 48 | /** 49 | * @brief Waits for a next connection to accept. 50 | * 51 | * @param timeout Maximum amount of time to wait before return. A special 52 | * value of `-1` denotes "eternity". 53 | * 54 | * @returns `true` if the connection is ready to be accepted before 55 | * the `timeout` elapses. 56 | * 57 | * @par Requires 58 | * `is_listening()`. 59 | * 60 | * @see accept(). 61 | */ 62 | DMITIGR_FCGI_API bool 63 | wait(std::chrono::milliseconds timeout = std::chrono::milliseconds{-1}); 64 | 65 | /** 66 | * @brief Accepts a FastCGI connection, or rejects it in case of a 67 | * protocol violation. 68 | * 69 | * @returns An instance of the accepted FastCGI connection. 70 | * 71 | * @par Requires 72 | * `is_listening()`. 73 | * 74 | * @throws Exception in case of protocol violation. 75 | * 76 | * @see wait(). 77 | */ 78 | DMITIGR_FCGI_API std::unique_ptr accept(); 79 | 80 | /// Stops listening. 81 | DMITIGR_FCGI_API void close(); 82 | 83 | private: 84 | std::unique_ptr listener_; 85 | Listener_options listener_options_; 86 | }; 87 | 88 | } // namespace dmitigr::fcgi 89 | 90 | #ifndef DMITIGR_FCGI_NOT_HEADER_ONLY 91 | #include "listener.cpp" 92 | #endif 93 | 94 | #endif // DMITIGR_FCGI_LISTENER_HPP 95 | -------------------------------------------------------------------------------- /src/fcgi/listener_options.cpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #include "listener_options.hpp" 18 | 19 | namespace dmitigr::fcgi { 20 | 21 | #ifdef _WIN32 22 | DMITIGR_FCGI_INLINE Listener_options::Listener_options(std::string pipe_name) 23 | : options_{std::move(pipe_name)} 24 | {} 25 | #endif 26 | 27 | DMITIGR_FCGI_INLINE Listener_options::Listener_options(std::filesystem::path path, 28 | const int backlog) 29 | : options_{std::move(path), backlog} 30 | {} 31 | 32 | DMITIGR_FCGI_INLINE Listener_options::Listener_options(std::string address, 33 | const int port, const int backlog) 34 | : options_{std::move(address), port, backlog} 35 | {} 36 | 37 | DMITIGR_FCGI_INLINE const net::Endpoint& Listener_options::endpoint() const noexcept 38 | { 39 | return options_.endpoint(); 40 | } 41 | 42 | DMITIGR_FCGI_INLINE std::optional Listener_options::backlog() const noexcept 43 | { 44 | return options_.backlog(); 45 | } 46 | 47 | } // namespace dmitigr::fcgi 48 | -------------------------------------------------------------------------------- /src/fcgi/listener_options.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_FCGI_LISTENER_OPTIONS_HPP 18 | #define DMITIGR_FCGI_LISTENER_OPTIONS_HPP 19 | 20 | #include "../fs/filesystem.hpp" 21 | #include "../net/listener.hpp" 22 | #include "dll.hpp" 23 | #include "types_fwd.hpp" 24 | 25 | #include 26 | #include 27 | 28 | namespace dmitigr::fcgi { 29 | 30 | /// FastCGI Listener options. 31 | class Listener_options final { 32 | public: 33 | #ifdef _WIN32 34 | /** 35 | * @returns A new instance of the options for listeners of 36 | * Windows Named Pipes (WNP). 37 | * 38 | * @param pipe_name The pipe name. 39 | * 40 | * @par Effects 41 | * `endpoint().communication_mode() == Communication_mode::wnp`. 42 | */ 43 | DMITIGR_FCGI_API explicit Listener_options(std::string pipe_name); 44 | #endif 45 | 46 | /** 47 | * @returns A new instance of the options for listeners of 48 | * Unix Domain Sockets (UDS). 49 | * 50 | * @param path The path to the socket. 51 | * @param backlog The maximum size of the queue of pending connections. 52 | * 53 | * @par Effects 54 | * `endpoint().communication_mode() == Communication_mode::uds`. 55 | */ 56 | DMITIGR_FCGI_API explicit Listener_options(std::filesystem::path path, 57 | int backlog); 58 | 59 | /** 60 | * @overload 61 | * 62 | * @returns A new instance of the options for listeners of network. 63 | * 64 | * @param address The IPv4 or IPv6 address to use for binding on. 65 | * @param port The port number to use for binding on. 66 | * @param backlog The maximum size of the queue of pending connections. 67 | * 68 | * @par Requires 69 | * `port > 0`. 70 | * 71 | * @par Effects 72 | * `endpoint().communication_mode() == Communication_mode::net`. 73 | */ 74 | DMITIGR_FCGI_API explicit Listener_options(std::string address, 75 | int port, int backlog); 76 | 77 | /// @returns The endpoint identifier. 78 | DMITIGR_FCGI_API const net::Endpoint& endpoint() const noexcept; 79 | 80 | /** 81 | * @returns The value of backlog if the communication mode of the endpoint 82 | * is not `Communication_mode::wnp`, or `std::nullopt` otherwise. 83 | */ 84 | DMITIGR_FCGI_API std::optional backlog() const noexcept; 85 | 86 | private: 87 | friend Listener; 88 | 89 | net::Listener_options options_; 90 | }; 91 | 92 | } // namespace dmitigr::fcgi 93 | 94 | #ifndef DMITIGR_FCGI_NOT_HEADER_ONLY 95 | #include "listener_options.cpp" 96 | #endif 97 | 98 | #endif // DMITIGR_FCGI_LISTENER_OPTIONS_HPP 99 | -------------------------------------------------------------------------------- /src/fcgi/server_connection.cpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #include "../base/assert.hpp" 18 | #include "basics.hpp" 19 | #include "exceptions.hpp" 20 | #include "server_connection.hpp" 21 | 22 | namespace dmitigr::fcgi::detail { 23 | 24 | /// The base implementation of the Server_connection. 25 | class iServer_connection : public Server_connection { 26 | public: 27 | /// The constructor. 28 | explicit iServer_connection(std::unique_ptr io, 29 | const Role role, const int request_id, const bool is_keep_connection) 30 | : is_keep_connection_{is_keep_connection} 31 | , role_{role} 32 | , request_id_{request_id} 33 | { 34 | io_ = std::move(io); 35 | DMITIGR_ASSERT(io_); 36 | } 37 | 38 | // --------------------------------------------------------------------------- 39 | // Connection overridings 40 | // --------------------------------------------------------------------------- 41 | 42 | int request_id() const noexcept override 43 | { 44 | return request_id_; 45 | } 46 | 47 | Role role() const noexcept override 48 | { 49 | return role_; 50 | } 51 | 52 | std::size_t parameter_count() const noexcept override 53 | { 54 | return parameters_.pair_count(); 55 | } 56 | 57 | std::optional 58 | parameter_index(const std::string_view name) const noexcept override 59 | { 60 | return parameters_.pair_index(name); 61 | } 62 | 63 | std::string_view parameter(const std::size_t index) const override 64 | { 65 | if (!(index < parameter_count())) 66 | throw Exception{"cannot get FastCGI parameter by using invalid index"}; 67 | return parameters_.pair(index).value(); 68 | } 69 | 70 | std::string_view parameter(const std::string_view name) const override 71 | { 72 | if (const auto index = parameter_index(name)) 73 | return parameters_.pair(*index).value(); 74 | else 75 | throw Exception{std::string{"cannot get FastCGI parameter "}.append(name)}; 76 | } 77 | 78 | // --------------------------------------------------------------------------- 79 | // Server_connection overridings 80 | // --------------------------------------------------------------------------- 81 | 82 | int application_status() const noexcept override 83 | { 84 | return application_status_; 85 | } 86 | 87 | void set_application_status(const int status) override 88 | { 89 | application_status_ = status; 90 | } 91 | 92 | bool is_keep_connection() const 93 | { 94 | return is_keep_connection_; 95 | } 96 | 97 | private: 98 | friend server_Istream; 99 | friend server_Streambuf; 100 | 101 | bool is_keep_connection_{}; 102 | Role role_{}; 103 | int request_id_{}; 104 | int application_status_{}; 105 | std::unique_ptr io_; 106 | detail::Names_values parameters_; 107 | }; 108 | 109 | } // namespace dmitigr::fcgi::detail 110 | -------------------------------------------------------------------------------- /src/fcgi/server_connection.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_FCGI_SERVER_CONNECTION_HPP 18 | #define DMITIGR_FCGI_SERVER_CONNECTION_HPP 19 | 20 | #include "connection.hpp" 21 | 22 | namespace dmitigr::fcgi { 23 | 24 | /// A FastCGI server connection. 25 | class Server_connection : public Connection { 26 | public: 27 | /// @returns The input stream, associated with the input data stream. 28 | virtual Istream& in() noexcept = 0; 29 | 30 | /// @returns The output stream, associated with the output data stream. 31 | virtual Ostream& out() noexcept = 0; 32 | 33 | /// @returns The output stream, associated with the error data stream. 34 | virtual Ostream& err() noexcept = 0; 35 | 36 | /** 37 | * @returns The application status code for transmitting to the client 38 | * upon closing the connection. By default the returned value is `0`. 39 | * 40 | * @see set_application_status(). 41 | */ 42 | virtual int application_status() const noexcept = 0; 43 | 44 | /** 45 | * @brief Sets the application status code for transmitting to the client 46 | * upon closing the connection. 47 | * 48 | * @see application_status(). 49 | */ 50 | virtual void set_application_status(int status) = 0; 51 | 52 | private: 53 | friend detail::iServer_connection; 54 | 55 | Server_connection() = default; 56 | }; 57 | 58 | } // namespace dmitigr::fcgi 59 | 60 | #ifndef DMITIGR_FCGI_NOT_HEADER_ONLY 61 | #include "server_connection.cpp" 62 | #endif 63 | 64 | #endif // DMITIGR_FCGI_SERVER_CONNECTION_HPP 65 | -------------------------------------------------------------------------------- /src/fcgi/server_connection_stacked.cpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #include "../base/assert.hpp" 18 | #include "basics.hpp" 19 | #include "exceptions.hpp" 20 | #include "server_connection.hpp" 21 | #include "streams.hpp" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | namespace dmitigr::fcgi::detail { 29 | 30 | /// The Server_connection implementation based on stack-allocated buffers. 31 | class stack_buffers_Server_connection final : public iServer_connection { 32 | public: 33 | /// The size of the buffer of Stream_type::in. 34 | static constexpr std::size_t in_buffer_size = 16384; 35 | 36 | /// The size of the buffer of Stream_type::out. 37 | static constexpr std::size_t out_buffer_size = 65528; 38 | 39 | /// The size of the buffer of Stream_type::err. 40 | static constexpr std::size_t err_buffer_size = 65528; 41 | 42 | ~stack_buffers_Server_connection() override 43 | { 44 | try { 45 | close(); 46 | 47 | // ----------------------------------------------------------------------- 48 | // TODO: support for Begin_request_body::Flags::keep_conn flag. 49 | // To make it possible the io_ object should be passed back to the 50 | // Listener which can reuse it for a new Server_connection. 51 | // 52 | // Begin_request_body::Flags::keep_conn flag has no effect if any stream 53 | // is with failbit set. 54 | // const bool keep_conn = keep_connection() && !err().fail() && 55 | // !out().fail() && !in().fail(); 56 | // ----------------------------------------------------------------------- 57 | 58 | } catch (const std::exception& e) { 59 | std::clog << "error upon closing FastCGI connection: %s\n" << e.what(); 60 | } catch (...) { 61 | std::clog << "unknown error upon closing FastCGI connection\n"; 62 | } 63 | } 64 | 65 | explicit stack_buffers_Server_connection(std::unique_ptr io, 66 | const Role role, 67 | const int request_id, 68 | const bool is_keep_connection) 69 | : iServer_connection{std::move(io), role, request_id, is_keep_connection} 70 | , in_{this, in_buffer_.data(), 71 | static_cast(in_buffer_.size())} 72 | , out_{this, out_buffer_.data(), 73 | static_cast(out_buffer_.size()), Stream_type::out} 74 | , err_{this, err_buffer_.data(), 75 | static_cast(err_buffer_.size()), Stream_type::err} 76 | { 77 | static_assert(in_buffer_size <= std::numeric_limits::max()); 78 | static_assert(out_buffer_size <= std::numeric_limits::max()); 79 | static_assert(err_buffer_size <= std::numeric_limits::max()); 80 | } 81 | 82 | // --------------------------------------------------------------------------- 83 | // Connection overridings 84 | // --------------------------------------------------------------------------- 85 | 86 | void close() override 87 | { 88 | // Attention: the order is important! 89 | err().streambuf().close(); 90 | out().streambuf().close(); 91 | in().streambuf().close(); 92 | } 93 | 94 | bool is_closed() const noexcept override 95 | { 96 | return (err().is_closed() && out().is_closed() && in().is_closed()); 97 | } 98 | 99 | // --------------------------------------------------------------------------- 100 | // Server_connection overridings 101 | // --------------------------------------------------------------------------- 102 | 103 | const server_Istream& in() const noexcept 104 | { 105 | return in_; 106 | } 107 | 108 | server_Istream& in() noexcept override 109 | { 110 | return in_; 111 | } 112 | 113 | const server_Ostream& out() const noexcept 114 | { 115 | return out_; 116 | } 117 | 118 | server_Ostream& out() noexcept override 119 | { 120 | return out_; 121 | } 122 | 123 | const server_Ostream& err() const noexcept 124 | { 125 | return err_; 126 | } 127 | 128 | server_Ostream& err() noexcept override 129 | { 130 | return err_; 131 | } 132 | 133 | private: 134 | std::array in_buffer_; 135 | std::array out_buffer_; 136 | std::array err_buffer_; 137 | 138 | server_Istream in_; 139 | server_Ostream out_; 140 | server_Ostream err_; 141 | }; 142 | 143 | } // namespace dmitigr::fcgi::detail 144 | -------------------------------------------------------------------------------- /src/fcgi/streambuf.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_FCGI_STREAMBUF_HPP 18 | #define DMITIGR_FCGI_STREAMBUF_HPP 19 | 20 | #include "types_fwd.hpp" 21 | 22 | #include 23 | 24 | namespace dmitigr::fcgi { 25 | 26 | /// A FastCGI stream buffer. 27 | class Streambuf : public std::streambuf { 28 | protected: 29 | 30 | /// @name Buffer management and positioning 31 | /// @{ 32 | 33 | /** 34 | * @returns `this`. 35 | * 36 | * @par Requires 37 | * The valid memory area in range of [buffer, buffer + size) and 38 | * `buffer && (2048 <= size && size <= 65528)`. 39 | * 40 | * @throws Exception. 41 | * 42 | * @par Exception safety guarantee 43 | * Basic. 44 | */ 45 | virtual Streambuf* setbuf(char_type* buffer, std::streamsize size) override = 0; 46 | 47 | /** 48 | * @brief Sends the put area to a FastCGI client if 49 | * `pbase() && pbase() != pptr()`. 50 | * 51 | * @returns `0` on success. 52 | * 53 | * @throws Exception. 54 | * 55 | * @par Exception safety guarantee 56 | * Basic. 57 | */ 58 | virtual int sync() override = 0; 59 | 60 | /// @} 61 | 62 | /// @name Get area 63 | /// @{ 64 | 65 | /** 66 | * @brief Fills the get area if `(eback() != nullptr)`. 67 | * 68 | * @returns `traits_type::to_int_type(c)`, where `c` is the first character of 69 | * the pending sequence, without moving the input sequence position past it, 70 | * or `traits_type::eof()` to indicate failure if the pending sequence is null. 71 | * 72 | * @throws Exception. 73 | * 74 | * @par Exception safety guarantee 75 | * Basic. 76 | */ 77 | virtual int_type underflow() override = 0; 78 | 79 | /// @} 80 | 81 | 82 | /// @name Put area 83 | /// @{ 84 | 85 | /** 86 | * @brief Consumes the put area. Also consumes `c` if 87 | * `traits_type::eq_int_type(c, traits_type::eof()) == false`. 88 | * 89 | * @returns Some value other than `traits_type::eof()` to indicate success, 90 | * or `traits_type::eof()` to indicate failure. 91 | * 92 | * @throws Exception. 93 | * 94 | * @par Exception safety guarantee 95 | * Basic. 96 | */ 97 | virtual int_type overflow(int_type c = traits_type::eof()) override = 0; 98 | 99 | /// @} 100 | 101 | private: 102 | friend detail::iStreambuf; 103 | 104 | Streambuf() = default; 105 | }; 106 | 107 | } // namespace dmitigr::fcgi 108 | 109 | #ifndef DMITIGR_FCGI_NOT_HEADER_ONLY 110 | #include "streambuf.cpp" 111 | #endif 112 | 113 | #endif // DMITIGR_FCGI_STREAMBUF_HPP 114 | -------------------------------------------------------------------------------- /src/fcgi/streams.cpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #include "../base/assert.hpp" 18 | #include "basics.hpp" 19 | #include "exceptions.hpp" 20 | #include "streambuf.hpp" 21 | #include "streams.hpp" 22 | 23 | namespace dmitigr::fcgi::detail { 24 | 25 | /// The base implementation of Istream. 26 | class iIstream : public Istream { 27 | private: 28 | friend server_Istream; 29 | 30 | using Istream::Istream; 31 | }; 32 | 33 | /// The Istream implementation for a FastCGI server. 34 | class server_Istream final : public iIstream { 35 | public: 36 | server_Istream(iServer_connection* const connection, 37 | char_type* const buffer, const std::streamsize buffer_size) 38 | : iIstream{&streambuf_} 39 | , streambuf_{connection, buffer, buffer_size, Stream_type::params} 40 | { 41 | // Reading the parameters. 42 | DMITIGR_ASSERT(stream_type() == Stream_type::params); 43 | connection->parameters_ = detail::Names_values{*this, 32}; 44 | if (!eof() || bad()) 45 | throw Exception{"unexpected FastCGI input stream state after parameters " 46 | "read attempt"}; 47 | 48 | // Resetting the stream. 49 | const auto role = connection->role(); 50 | if (role == Role::responder || role == Role::filter) { 51 | clear(); 52 | streambuf().reset_reader(Stream_type::in); 53 | } 54 | } 55 | 56 | const server_Streambuf& streambuf() const noexcept override 57 | { 58 | return streambuf_; 59 | } 60 | 61 | server_Streambuf& streambuf() noexcept override 62 | { 63 | return streambuf_; 64 | } 65 | 66 | bool is_closed() const noexcept override 67 | { 68 | return streambuf_.is_closed(); 69 | } 70 | 71 | Stream_type stream_type() const noexcept override 72 | { 73 | return streambuf_.stream_type(); 74 | } 75 | 76 | private: 77 | server_Streambuf streambuf_; 78 | }; 79 | 80 | // ============================================================================= 81 | 82 | /// The base implementation of Ostream. 83 | class iOstream : public Ostream { 84 | private: 85 | friend server_Ostream; 86 | 87 | using Ostream::Ostream; 88 | }; 89 | 90 | /// The Ostream implementation for a FastCGI server. 91 | class server_Ostream final : public iOstream { 92 | public: 93 | server_Ostream(iServer_connection* const connection, char_type* const buffer, 94 | const std::streamsize buffer_size, const Stream_type type) 95 | : iOstream{&streambuf_} 96 | , streambuf_{connection, buffer, buffer_size, type} 97 | { 98 | DMITIGR_ASSERT(stream_type() == Stream_type::out || 99 | stream_type() == Stream_type::err); 100 | } 101 | 102 | const server_Streambuf& streambuf() const noexcept override 103 | { 104 | return streambuf_; 105 | } 106 | 107 | server_Streambuf& streambuf() noexcept override 108 | { 109 | return streambuf_; 110 | } 111 | 112 | bool is_closed() const noexcept override 113 | { 114 | return streambuf_.is_closed(); 115 | } 116 | 117 | Stream_type stream_type() const noexcept override 118 | { 119 | return streambuf_.stream_type(); 120 | } 121 | 122 | private: 123 | server_Streambuf streambuf_; 124 | }; 125 | 126 | } // namespace dmitigr::fcgi::detail 127 | 128 | namespace dmitigr::fcgi { 129 | 130 | DMITIGR_FCGI_INLINE std::ostream& crlf(std::ostream& ostr) 131 | { 132 | return ostr.write("\r\n", 2); 133 | } 134 | 135 | DMITIGR_FCGI_INLINE std::ostream& crlfcrlf(std::ostream& ostr) 136 | { 137 | return ostr.write("\r\n\r\n", 4); 138 | } 139 | 140 | } // namespace dmitigr::fcgi 141 | -------------------------------------------------------------------------------- /src/fcgi/streams.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_FCGI_STREAMS_HPP 18 | #define DMITIGR_FCGI_STREAMS_HPP 19 | 20 | #include "dll.hpp" 21 | #include "types_fwd.hpp" 22 | 23 | #include 24 | #include 25 | 26 | namespace dmitigr::fcgi { 27 | 28 | /// A data stream. 29 | class Stream { 30 | public: 31 | /// The destructor. 32 | virtual ~Stream() = default; 33 | 34 | /// @returns The controlled Streambuf instance. 35 | virtual const Streambuf& streambuf() const noexcept = 0; 36 | 37 | /// @overload 38 | virtual Streambuf& streambuf() noexcept = 0; 39 | 40 | /// @returns `true` if the stream is closed (i.e. unusable anymore). 41 | virtual bool is_closed() const noexcept = 0; 42 | 43 | /** 44 | * @returns The type of stream. The value of Stream_type::data is returned 45 | * when the stream is switched to transmit the data file input to filter it 46 | * out (as prescribed for Role::filter). 47 | * 48 | * @remarks Since the data file input follows the content and `eof() == true` 49 | * right after all of content of Stream_type::in is read, the stream error 50 | * state flags must be cleared before reading the data file input. 51 | * 52 | * See also clear(). 53 | */ 54 | virtual Stream_type stream_type() const noexcept = 0; 55 | 56 | private: 57 | friend Istream; 58 | friend Ostream; 59 | 60 | Stream() = default; 61 | }; 62 | 63 | /// An input data stream. 64 | class Istream : public Stream, public std::istream { 65 | private: 66 | friend detail::iIstream; 67 | 68 | using std::istream::istream; 69 | }; 70 | 71 | /// An output data stream. 72 | class Ostream : public Stream, public std::ostream { 73 | private: 74 | friend detail::iOstream; 75 | 76 | using std::ostream::ostream; 77 | }; 78 | 79 | /// Inserts `CRLF` sequence into the `ostr`. 80 | DMITIGR_FCGI_API std::ostream& crlf(std::ostream& ostr); 81 | 82 | /// Inserts `CRLFCRLF` sequence into the `ostr`. 83 | DMITIGR_FCGI_API std::ostream& crlfcrlf(std::ostream& ostr); 84 | 85 | } // namespace dmitigr::fcgi 86 | 87 | #ifndef DMITIGR_FCGI_NOT_HEADER_ONLY 88 | #include "streams.cpp" 89 | #endif 90 | 91 | #endif // DMITIGR_FCGI_STREAMS_HPP 92 | -------------------------------------------------------------------------------- /src/fcgi/types_fwd.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_FCGI_TYPES_FWD_HPP 18 | #define DMITIGR_FCGI_TYPES_FWD_HPP 19 | 20 | /// The API. 21 | namespace dmitigr::fcgi { 22 | 23 | enum class Role; 24 | enum class Stream_type; 25 | 26 | class Exception; 27 | 28 | class Listener; 29 | class Listener_options; 30 | 31 | class Connection_parameter; 32 | class Connection; 33 | class Server_connection; 34 | 35 | class Streambuf; 36 | 37 | class Stream; 38 | class Istream; 39 | class Ostream; 40 | 41 | /// The implementation details. 42 | namespace detail { 43 | enum class Record_type : unsigned char; 44 | enum class Protocol_status : unsigned char; 45 | struct Header; 46 | struct Begin_request_body; 47 | struct End_request_body; 48 | struct End_request_record; 49 | struct Unknown_type_body; 50 | struct Unknown_type_record; 51 | class Name_value; 52 | class Names_values; 53 | 54 | class iListener; 55 | class iListener_options; 56 | class iServer_connection; 57 | class iStreambuf; 58 | class server_Streambuf; 59 | class iIstream; 60 | class server_Istream; 61 | class iOstream; 62 | class server_Ostream; 63 | 64 | class Name_value; 65 | class Names_values; 66 | } // namespace detail 67 | 68 | } // namespace dmitigr::fcgi 69 | 70 | #endif // DMITIGR_FCGI_TYPES_FWD_HPP 71 | -------------------------------------------------------------------------------- /src/fcgi/version.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 18 | // This file is generated automatically. Edit version.hpp.in instead!!!!!!!!!!!! 19 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 | 21 | #ifndef DMITIGR_FCGI_VERSION_HPP 22 | #define DMITIGR_FCGI_VERSION_HPP 23 | 24 | #include 25 | 26 | namespace dmitigr::fcgi { 27 | 28 | /// @returns The library version. 29 | constexpr std::int_fast32_t version() noexcept 30 | { 31 | // Actual values are set in CMakeLists.txt. 32 | constexpr std::int_least32_t major = 1; 33 | constexpr std::int_least32_t minor = 0; 34 | constexpr std::int_least32_t patch = 0; 35 | 36 | // 111.222.333 -> 111222333 37 | return major*1000000 + minor*1000 + patch; 38 | } 39 | 40 | } // namespace dmitigr::fcgi 41 | 42 | #endif // DMITIGR_FCGI_VERSION_HPP 43 | -------------------------------------------------------------------------------- /src/fcgi/version.rc: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 18 | // This file is generated automatically. Edit version.rc.in instead!!!!!!!!!!!!! 19 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 | 21 | #include 22 | 23 | #ifdef NDEBUG 24 | #define DMITIGR_FCGI_VERSION_DEBUG 0 25 | #define DMITIGR_FCGI_VERSION_ORIGINAL_FILENAME "dmitigr_fcgi.dll\0" 26 | #else 27 | #define DMITIGR_FCGI_VERSION_DEBUG VS_FF_DEBUG 28 | #define DMITIGR_FCGI_VERSION_ORIGINAL_FILENAME "dmitigr_fcgid.dll\0" 29 | #endif 30 | 31 | VS_VERSION_INFO VERSIONINFO 32 | 33 | FILEVERSION 0,1,0,0 34 | PRODUCTVERSION 0,1,0,0 35 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 36 | FILEFLAGS (DMITIGR_FCGI_VERSION_DEBUG) 37 | FILEOS VOS__WINDOWS32 38 | FILETYPE VFT_DLL 39 | FILESUBTYPE 0x0L 40 | BEGIN 41 | BLOCK "StringFileInfo" 42 | BEGIN 43 | BLOCK "040904E4" 44 | BEGIN 45 | VALUE "CompanyName", "Dmitry Igrishin\0" 46 | VALUE "FileDescription", "FastCGI implementation\0" 47 | VALUE "FileVersion", "1.0.0\0" 48 | VALUE "InternalName", "dmitigr_fcgi\0" 49 | VALUE "LegalCopyright", "Copyright (C) Dmitry Igrishin\0" 50 | VALUE "LegalTrademarks", "\0" 51 | VALUE "OriginalFilename", DMITIGR_FCGI_VERSION_ORIGINAL_FILENAME 52 | VALUE "ProductName", "Dmitigr Fcgi\0" 53 | VALUE "ProductVersion", "1.0.0\0" 54 | END 55 | END 56 | BLOCK "VarFileInfo" 57 | BEGIN 58 | VALUE "Translation", 0x409, 1200 59 | END 60 | END 61 | -------------------------------------------------------------------------------- /src/fs/filesystem.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_FS_FILESYSTEM_HPP 18 | #define DMITIGR_FS_FILESYSTEM_HPP 19 | 20 | #if (defined(__clang__) && (__clang_major__ < 7)) || \ 21 | (defined(__GNUG__) && (__GNUC__ < 8) && !defined (__clang__)) 22 | #include 23 | namespace std { 24 | namespace filesystem = experimental::filesystem; 25 | } // namespace std 26 | #else 27 | #include 28 | #endif 29 | 30 | #endif // DMITIGR_FS_FILESYSTEM_HPP 31 | -------------------------------------------------------------------------------- /src/fs/fs.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_FS_FS_HPP 18 | #define DMITIGR_FS_FS_HPP 19 | 20 | #include "filesystem.hpp" 21 | #include "misc.hpp" 22 | 23 | #endif // DMITIGR_FS_FS_HPP 24 | -------------------------------------------------------------------------------- /src/fs/misc.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_FS_MISC_HPP 18 | #define DMITIGR_FS_MISC_HPP 19 | 20 | #include "filesystem.hpp" 21 | 22 | #include 23 | #include 24 | 25 | namespace dmitigr::fs { 26 | 27 | /** 28 | * @returns The vector of the paths. 29 | * 30 | * @param root - the search root; 31 | * @param extension - the extension of files to be included into the result; 32 | * @param recursive - if `true` then do the recursive search; 33 | * @param include_heading - if `true` then include the "heading file" (see 34 | * remarks) into the result. 35 | * 36 | * @remarks The "heading file" - is a regular file with the given `extension` 37 | * which has the same parent directory as the `root`. 38 | */ 39 | inline std::vector 40 | file_paths_by_extension(const std::filesystem::path& root, 41 | const std::filesystem::path& extension, 42 | const bool recursive, const bool include_heading = false) 43 | { 44 | std::vector result; 45 | 46 | if (is_regular_file(root) && root.extension() == extension) 47 | return {root}; 48 | 49 | if (include_heading) { 50 | auto heading_file = root; 51 | heading_file.replace_extension(extension); 52 | if (is_regular_file(heading_file)) 53 | result.push_back(heading_file); 54 | } 55 | 56 | if (is_directory(root)) { 57 | const auto traverse = [&](auto iterator) 58 | { 59 | for (const auto& dirent : iterator) { 60 | const auto& path = dirent.path(); 61 | if (is_regular_file(path) && path.extension() == extension) 62 | result.push_back(dirent); 63 | } 64 | }; 65 | 66 | if (recursive) 67 | traverse(std::filesystem::recursive_directory_iterator{root}); 68 | else 69 | traverse(std::filesystem::directory_iterator{root}); 70 | } 71 | return result; 72 | } 73 | 74 | /** 75 | * @brief Searches for the `dir` directory starting from the current working 76 | * directory and up to the root directory. 77 | * 78 | * @returns The first path found to the `dir` directory, or 79 | * `std::nullopt` if no specified directory found. 80 | */ 81 | inline std::optional 82 | parent_directory_path(const std::filesystem::path& dir) 83 | { 84 | auto path = std::filesystem::current_path(); 85 | while (true) { 86 | if (is_directory(path / dir)) 87 | return path; 88 | else if (path.has_relative_path()) 89 | path = path.parent_path(); 90 | else 91 | return std::nullopt; 92 | } 93 | } 94 | 95 | } // namespace dmitigr::fs 96 | 97 | #endif // DMITIGR_FS_MISC_HPP 98 | -------------------------------------------------------------------------------- /src/lib.cpp.in: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 18 | // This file is generated automatically. Edit lib.cpp.in instead!!!!!!!!!!!!!!!! 19 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 | 21 | #ifdef DMITIGR_@dmitigr_lib_NAME@_NOT_HEADER_ONLY 22 | #undef DMITIGR_@dmitigr_lib_NAME@_NOT_HEADER_ONLY 23 | #endif 24 | #ifndef DMITIGR_@dmitigr_lib_NAME@_BUILDING 25 | #define DMITIGR_@dmitigr_lib_NAME@_BUILDING 26 | #endif 27 | #include "@dmitigr_lib_name@.hpp" 28 | -------------------------------------------------------------------------------- /src/lib_version.cpp.in: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 18 | // This file is generated automatically. Edit lib_version.cpp.in instead!!!!!!!!!!!! 19 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 | 21 | #include "lib_version.hpp" 22 | #include "version.hpp" 23 | 24 | namespace dmitigr::@dmitigr_lib_name@ { 25 | 26 | DMITIGR_@dmitigr_lib_NAME@_INLINE std::int_fast32_t lib_version() noexcept 27 | { 28 | return version(); 29 | } 30 | 31 | } // namespace dmitigr::@dmitigr_lib_name@ 32 | -------------------------------------------------------------------------------- /src/lib_version.hpp.in: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 18 | // This file is generated automatically. Edit lib_version.hpp.in instead!!!!!!!!!!!! 19 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 | 21 | #ifndef DMITIGR_@dmitigr_lib_NAME@_LIB_VERSION_HPP 22 | #define DMITIGR_@dmitigr_lib_NAME@_LIB_VERSION_HPP 23 | 24 | #include "dll.hpp" 25 | 26 | #include 27 | 28 | namespace dmitigr::@dmitigr_lib_name@ { 29 | 30 | /** 31 | * @returns The library version. 32 | * 33 | * @see version(). 34 | */ 35 | DMITIGR_@dmitigr_lib_NAME@_API std::int_fast32_t lib_version() noexcept; 36 | 37 | } // namespace dmitigr::@dmitigr_lib_name@ 38 | 39 | #ifndef DMITIGR_@dmitigr_lib_NAME@_NOT_HEADER_ONLY 40 | #include "lib_version.cpp" 41 | #endif 42 | 43 | #endif // DMITIGR_@dmitigr_lib_NAME@_LIB_VERSION_HPP 44 | -------------------------------------------------------------------------------- /src/math/alignment.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_MATH_ALIGNMENT_HPP 18 | #define DMITIGR_MATH_ALIGNMENT_HPP 19 | 20 | #include "exceptions.hpp" 21 | 22 | namespace dmitigr::math { 23 | 24 | /// @returns `true` if `number` is a power of 2. 25 | template 26 | constexpr bool is_power_of_two(const T number) noexcept 27 | { 28 | return (number & (number - 1)) == 0; 29 | } 30 | 31 | /** 32 | * @returns The size of padding. 33 | * 34 | * @param value A value for which a padding need to be calculated. 35 | * @param alignment An aligment to calculated the padding. 36 | * 37 | * @par Requires 38 | * `(size >= 0 && is_power_of_two(alignment))`. 39 | */ 40 | template 41 | constexpr auto padding(const T value, const T alignment) 42 | { 43 | if (!(value >= 0)) 44 | throw Exception{"cannot calculate padding for a negative value"}; 45 | else if (!is_power_of_two(alignment)) 46 | throw Exception{"cannot calculate padding with alignment that is not " 47 | "power of 2"}; 48 | return (static_cast(0) - value) & static_cast(alignment - 1); 49 | } 50 | 51 | /** 52 | * @returns The value aligned by using `alignment`. 53 | * 54 | * @par Requires 55 | * `(value >= 0 && is_power_of_two(alignment))`. 56 | */ 57 | template 58 | constexpr T aligned(const T value, const T alignment) 59 | { 60 | if (!(value >= 0)) 61 | throw Exception{"cannot align a negative value"}; 62 | else if (!is_power_of_two(alignment)) 63 | throw Exception{"cannot align a value with alignment that is not " 64 | "power of 2"}; 65 | return (value + (alignment - 1)) & -alignment; 66 | } 67 | 68 | } // namespace dmitigr::math 69 | 70 | #endif // DMITIGR_MATH_ALIGNMENT_HPP 71 | -------------------------------------------------------------------------------- /src/math/exceptions.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_MATH_EXCEPTIONS_HPP 18 | #define DMITIGR_MATH_EXCEPTIONS_HPP 19 | 20 | #include "../base/exceptions.hpp" 21 | 22 | namespace dmitigr::math { 23 | 24 | /** 25 | * @ingroup errors 26 | * 27 | * @brief The generic exception class. 28 | */ 29 | class Exception final : public dmitigr::Exception { 30 | using dmitigr::Exception::Exception; 31 | }; 32 | 33 | } // namespace dmitigr::math 34 | 35 | #endif // DMITIGR_MATH_EXCEPTIONS_HPP 36 | -------------------------------------------------------------------------------- /src/math/interval.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_MATH_INTERVAL_HPP 18 | #define DMITIGR_MATH_INTERVAL_HPP 19 | 20 | #include "exceptions.hpp" 21 | #include "../base/assert.hpp" 22 | 23 | #include 24 | 25 | namespace dmitigr::math { 26 | 27 | /// Represents a type of interval. 28 | enum class Interval_type { 29 | /// Denotes [min, max] interval. 30 | closed, 31 | /// Denotes (min, max) interval. 32 | open, 33 | /// Denotes (min, max] interval. 34 | lopen, 35 | /// Denotes [min, max) interval. 36 | ropen 37 | }; 38 | 39 | /// Represents an interval. 40 | template 41 | class Interval final { 42 | public: 43 | /// An alias of T. 44 | using Value_type = T; 45 | 46 | /// An alias of Interval_type. 47 | using Type = Interval_type; 48 | 49 | /// Constructs closed [{},{}] interval. 50 | Interval() = default; 51 | 52 | /** 53 | * @brief Constructs closed [min, max] interval. 54 | * 55 | * @par Requires 56 | * `min <= max`. 57 | */ 58 | explicit Interval(T min, T max) 59 | : type_{Type::closed} 60 | , min_{std::move(min)} 61 | , max_{std::move(max)} 62 | { 63 | if (!(min_ <= max_)) 64 | throw Exception{"interval is invalid (min > max)"}; 65 | } 66 | 67 | /** 68 | * @brief Constructs the interval of the specified type. 69 | * 70 | * @par Requires 71 | * `(type == Type::closed && min <= max) || (type != Type::closed && min < max)`. 72 | */ 73 | explicit Interval(const Type type, T min, T max) 74 | : type_{type} 75 | , min_{std::move(min)} 76 | , max_{std::move(max)} 77 | { 78 | const bool requirement = (type_ == Type::closed && min_ <= max_) || 79 | (type_ != Type::closed && min_ < max_); 80 | if (!requirement) 81 | throw Exception{"interval is invalid (min > max or min >= max)"}; 82 | } 83 | 84 | /// @returns [min, max] interval. 85 | static Interval make_closed(T min, T max) 86 | { 87 | return {Type::closed, std::move(min), std::move(max)}; 88 | } 89 | 90 | /// @returns (min, max) interval. 91 | static Interval make_open(T min, T max) 92 | { 93 | return {Type::open, std::move(min), std::move(max)}; 94 | } 95 | 96 | /// @returns (min, max] interval. 97 | static Interval make_lopen(T min, T max) 98 | { 99 | return {Type::lopen, std::move(min), std::move(max)}; 100 | } 101 | 102 | /// @returns [min, max) interval. 103 | static Interval make_ropen(T min, T max) 104 | { 105 | return {Type::ropen, std::move(min), std::move(max)}; 106 | } 107 | 108 | /// @returns The type of interval. 109 | Type type() const noexcept 110 | { 111 | return type_; 112 | } 113 | 114 | /// @returns The minimum of interval. 115 | const T& min() const noexcept 116 | { 117 | return min_; 118 | } 119 | 120 | /// @returns The maximum of interval. 121 | const T& max() const noexcept 122 | { 123 | return max_; 124 | } 125 | 126 | /// @returns `true` if value belongs to interval, or `false` otherwise. 127 | bool has(const T& value) const noexcept 128 | { 129 | switch (type_) { 130 | case Type::closed: return (min_ <= value) && (value <= max_); // [] 131 | case Type::open: return (min_ < value) && (value < max_); // () 132 | case Type::lopen: return (min_ < value) && (value <= max_); // (] 133 | case Type::ropen: return (min_ <= value) && (value < max_); // [) 134 | } 135 | DMITIGR_ASSERT(false); 136 | } 137 | 138 | /** 139 | * @returns A pair of {min, max}. 140 | * 141 | * @par Effects 142 | * The state of this instance as if it default constructed. 143 | */ 144 | std::pair release() noexcept 145 | { 146 | std::pair result{std::move(min_), std::move(max_)}; 147 | *this = {}; 148 | return result; 149 | } 150 | 151 | private: 152 | Type type_{Type::closed}; 153 | T min_{}; 154 | T max_{}; 155 | }; 156 | 157 | } // namespace dmitigr::math 158 | 159 | #endif // DMITIGR_MATH_INTERVAL_HPP 160 | -------------------------------------------------------------------------------- /src/math/math.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_MATH_MATH_HPP 18 | #define DMITIGR_MATH_MATH_HPP 19 | 20 | #include "alignment.hpp" 21 | #include "exceptions.hpp" 22 | #include "interval.hpp" 23 | #include "statistic.hpp" 24 | #include "version.hpp" 25 | 26 | #endif // DMITIGR_MATH_MATH_HPP 27 | -------------------------------------------------------------------------------- /src/math/statistic.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_MATH_STATISTIC_HPP 18 | #define DMITIGR_MATH_STATISTIC_HPP 19 | 20 | #include "../base/assert.hpp" 21 | 22 | namespace dmitigr::math { 23 | 24 | /** 25 | * @returns An average of values. 26 | * 27 | * @param data Input data 28 | */ 29 | template 30 | constexpr double avg(const Container& data) noexcept 31 | { 32 | double result{}; 33 | const auto data_size = data.size(); 34 | for (const double num : data) 35 | result += (num / static_cast(data_size)); 36 | return result; 37 | } 38 | 39 | /** 40 | * @returns A variance of values. 41 | * 42 | * @param data Input data. 43 | * @param avg An average of `data`. 44 | * @param general Is the `data` represents general population? 45 | */ 46 | template 47 | constexpr double variance(const Container& data, const double avg, 48 | const bool general = true) noexcept 49 | { 50 | const auto den = static_cast(data.size() - !general); 51 | double result{}; 52 | for (const double num : data) { 53 | const double d = num - avg; 54 | result += (d / den) * d; // (d * d) / den 55 | } 56 | DMITIGR_ASSERT(result >= 0); 57 | return result; 58 | } 59 | 60 | /// @overload 61 | template 62 | constexpr double variance(const Container& data, 63 | const bool general = true) noexcept 64 | { 65 | return variance(data, avg(data), general); 66 | } 67 | 68 | } // namespace dmitigr::math 69 | 70 | #endif // DMITIGR_MATH_STATISTIC_HPP 71 | -------------------------------------------------------------------------------- /src/math/version.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 18 | // This file is generated automatically. Edit version.hpp.in instead!!!!!!!!!!!! 19 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 | 21 | #ifndef DMITIGR_MATH_VERSION_HPP 22 | #define DMITIGR_MATH_VERSION_HPP 23 | 24 | #include 25 | 26 | namespace dmitigr::math { 27 | 28 | /// @returns The library version. 29 | constexpr std::int_fast32_t version() noexcept 30 | { 31 | // Actual values are set in CMakeLists.txt. 32 | constexpr std::int_least32_t major = 0; 33 | constexpr std::int_least32_t minor = 1; 34 | 35 | // 11.234 -> 11 * 1000 + 234 = 11234 36 | return major*1000 + minor; 37 | } 38 | 39 | } // namespace dmitigr::math 40 | 41 | #endif // DMITIGR_MATH_VERSION_HPP 42 | -------------------------------------------------------------------------------- /src/net/basics.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_NET_BASICS_HPP 18 | #define DMITIGR_NET_BASICS_HPP 19 | 20 | namespace dmitigr::net { 21 | 22 | /// A communication mode. 23 | enum class Communication_mode { 24 | /// A Unix Domain Socket. 25 | uds = 0, 26 | #ifdef _WIN32 27 | /// A Windows Named Pipe. 28 | wnp = 10, 29 | #endif 30 | /// A network. 31 | net = 100 32 | }; 33 | 34 | } // namespace dmitigr::net 35 | 36 | #endif // DMITIGR_NET_BASICS_HPP 37 | -------------------------------------------------------------------------------- /src/net/client.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_NET_CLIENT_HPP 18 | #define DMITIGR_NET_CLIENT_HPP 19 | 20 | #include "../base/assert.hpp" 21 | #include "descriptor.hpp" 22 | #include "endpoint.hpp" 23 | #include "exceptions.hpp" 24 | #include "socket.hpp" 25 | 26 | #include 27 | #include 28 | 29 | namespace dmitigr::net { 30 | 31 | /// Client options. 32 | class Client_options final { 33 | public: 34 | #ifdef _WIN32 35 | /// wnp. 36 | explicit Client_options(std::string pipe_name) 37 | : endpoint_{std::move(pipe_name)} 38 | {} 39 | #endif 40 | /// uds. 41 | Client_options(std::filesystem::path path) 42 | : endpoint_{std::move(path)} 43 | {} 44 | 45 | /// net. 46 | Client_options(std::string address, int port) 47 | : endpoint_{std::move(address), port} 48 | {} 49 | 50 | /// @return The endpoint. 51 | const net::Endpoint& endpoint() const 52 | { 53 | return endpoint_; 54 | } 55 | 56 | private: 57 | Endpoint endpoint_; 58 | }; 59 | 60 | /** 61 | * @returns A newly created descriptor connected over TCP (or Named Pipe) 62 | * to `remote` endpoint. 63 | */ 64 | inline std::unique_ptr make_tcp_connection(const Client_options& opts) 65 | { 66 | using Sockdesc = detail::socket_Descriptor; 67 | 68 | static const auto make_tcp_connection = [](const Socket_address& addr) 69 | { 70 | auto result = make_tcp_socket(addr.family()); 71 | connect_socket(result, addr); 72 | return result; 73 | }; 74 | 75 | const auto& remote = opts.endpoint(); 76 | switch (remote.communication_mode()) { 77 | #ifdef _WIN32 78 | case Communication_mode::wnp: 79 | throw Exception{"TCP connections over named pipes are not implemented"}; 80 | #endif 81 | case Communication_mode::uds: 82 | return std::make_unique( 83 | make_tcp_connection({remote.uds_path().value()})); 84 | case Communication_mode::net: 85 | return std::make_unique( 86 | make_tcp_connection({net::Ip_address::from_text( 87 | remote.net_address().value()), remote.net_port().value()})); 88 | } 89 | DMITIGR_ASSERT(false); 90 | } 91 | 92 | } // namespace dmitigr::net 93 | 94 | #endif // DMITIGR_NET_CLIENT_HPP 95 | -------------------------------------------------------------------------------- /src/net/conversions.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_NET_CONVERSIONS_HPP 18 | #define DMITIGR_NET_CONVERSIONS_HPP 19 | 20 | #include "../util/endianness.hpp" 21 | #include "exceptions.hpp" 22 | 23 | #include 24 | #include 25 | 26 | namespace dmitigr::net { 27 | 28 | /** 29 | * @brief Copyies `src` to `dest` in big-endian order. 30 | * 31 | * @details If the host architecture is big endian, then the `src` is copyied 32 | * to `dest` as is. Otherwise, the bytes of `src` is copied to `dest` in reverse 33 | * order. 34 | * 35 | * @par Requires 36 | * `dest && src && src_size <= dest_size`. 37 | */ 38 | inline void copy(void* const dest, const std::size_t dest_size, 39 | const void* const src, const std::size_t src_size) 40 | { 41 | if (!dest) 42 | throw Exception{"net::copy destination is nullptr"}; 43 | else if (!src) 44 | throw Exception{"net::copy source is nullptr"}; 45 | else if (!(src_size <= dest_size)) 46 | throw Exception{"net::copy destination would not fit the source"}; 47 | 48 | const auto src_ubytes = static_cast(src); 49 | const auto dest_ubytes = static_cast(dest); 50 | switch (util::endianness()) { 51 | case util::Endianness::big: 52 | for (std::size_t i = 0; i < src_size; ++i) 53 | dest_ubytes[dest_size - src_size + i] = src_ubytes[i]; 54 | break; 55 | case util::Endianness::little: 56 | for (std::size_t i = 0; i < src_size; ++i) 57 | dest_ubytes[dest_size - 1 - i] = src_ubytes[i]; 58 | break; 59 | } 60 | } 61 | 62 | /// @overload 63 | template 64 | inline void copy(void* const dest, const std::size_t dest_size, const Src& value) 65 | { 66 | copy(dest, dest_size, &value, sizeof(value)); 67 | } 68 | 69 | /// @overload 70 | template 71 | inline void copy(void* const dest, const Src& value) 72 | { 73 | copy(dest, sizeof(value), value); 74 | } 75 | 76 | /** 77 | * @brief Converts the `data` to the value of type `Dest` taking into account 78 | * the host's endianness. 79 | * 80 | * @returns The copy of `data` represented as a value of type `Dest`. 81 | * 82 | * @see conv() 83 | */ 84 | template 85 | inline Dest conv(const void* const data, const std::size_t data_size) 86 | { 87 | Dest result{}; 88 | copy(&result, sizeof(result), data, data_size); 89 | return result; 90 | } 91 | 92 | /// @overload 93 | template 94 | inline Dest conv(const Src& value) 95 | { 96 | static_assert(sizeof(Dest) >= sizeof(Src)); 97 | return conv(&value, sizeof(Src)); 98 | } 99 | 100 | /// @overload 101 | template 102 | inline T conv(const T& value) 103 | { 104 | return conv(value); 105 | } 106 | 107 | } // namespace dmitigr::net 108 | 109 | #endif // DMITIGR_NET_CONVERSIONS_HPP 110 | -------------------------------------------------------------------------------- /src/net/descriptor.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_NET_DESCRIPTOR_HPP 18 | #define DMITIGR_NET_DESCRIPTOR_HPP 19 | 20 | #include "../base/assert.hpp" 21 | #include "../os/exceptions.hpp" 22 | #include "socket.hpp" 23 | 24 | #include 25 | #include 26 | #include 27 | #include // std::streamsize 28 | #include // std::move() 29 | 30 | #ifdef _WIN32 31 | #include "../os/windows.hpp" 32 | #endif 33 | 34 | namespace dmitigr::net { 35 | 36 | /// A descriptor to perform low-level I/O operations. 37 | class Descriptor { 38 | public: 39 | /// The destructor. 40 | virtual ~Descriptor() = default; 41 | 42 | /// @returns The maximun number of bytes that can be read. 43 | virtual std::streamsize max_read_size() const = 0; 44 | 45 | /// @returns The maximun number of bytes that can be written. 46 | virtual std::streamsize max_write_size() const = 0; 47 | 48 | /** 49 | * @brief Reads from this descriptor synchronously. 50 | * 51 | * @returns Number of bytes read. 52 | */ 53 | virtual std::streamsize read(char* buf, std::streamsize len) = 0; 54 | 55 | /** 56 | * @brief Writes to this descriptor synchronously. 57 | * 58 | * @returns Number of bytes written. 59 | */ 60 | virtual std::streamsize write(const char* buf, std::streamsize len) = 0; 61 | 62 | /// Closes the descriptor. 63 | virtual void close() = 0; 64 | 65 | /// @returns Native handle (i.e. socket or named pipe). 66 | virtual std::intptr_t native_handle() = 0; 67 | }; 68 | 69 | namespace detail { 70 | 71 | /// The base implementation of Descriptor. 72 | class iDescriptor : public Descriptor { 73 | public: 74 | std::streamsize max_read_size() const override 75 | { 76 | return 2147479552; // as on Linux 77 | } 78 | 79 | std::streamsize max_write_size() const override 80 | { 81 | return 2147479552; // as on Linux 82 | } 83 | }; 84 | 85 | /// The implementation of Descriptor based on sockets. 86 | class socket_Descriptor final : public iDescriptor { 87 | public: 88 | ~socket_Descriptor() override 89 | { 90 | if (net::is_socket_valid(socket_)) { 91 | try { 92 | close(); 93 | } catch (const std::exception& e) { 94 | std::fprintf(stderr, "%s\n", e.what()); 95 | } catch (...) { 96 | std::fprintf(stderr, "bug\n"); 97 | } 98 | } 99 | } 100 | 101 | explicit socket_Descriptor(net::Socket_guard socket) 102 | : socket_{std::move(socket)} 103 | { 104 | DMITIGR_ASSERT(net::is_socket_valid(socket_)); 105 | } 106 | 107 | std::streamsize read(char* const buf, std::streamsize len) override 108 | { 109 | if (!buf) 110 | throw Exception{"cannot read from socket to null buffer"}; 111 | 112 | len = std::min(len, max_read_size()); 113 | constexpr int flags{}; 114 | #ifdef _WIN32 115 | const auto buf_len = static_cast(len); 116 | #else 117 | const auto buf_len = static_cast(len); 118 | #endif 119 | const auto result = ::recv(socket_, buf, buf_len, flags); 120 | if (net::is_socket_error(result)) 121 | throw DMITIGR_NET_EXCEPTION{"cannot read from socket"}; 122 | 123 | return static_cast(result); 124 | } 125 | 126 | std::streamsize write(const char* const buf, std::streamsize len) override 127 | { 128 | if (!buf) 129 | throw Exception{"cannot write to socket from null buffer"}; 130 | 131 | len = std::min(len, max_write_size()); 132 | #if defined(_WIN32) || defined(__APPLE__) 133 | constexpr int flags{}; 134 | #else 135 | constexpr int flags{MSG_NOSIGNAL}; 136 | #endif 137 | #ifdef _WIN32 138 | const auto buf_len = static_cast(len); 139 | #else 140 | const auto buf_len = static_cast(len); 141 | #endif 142 | const auto result = ::send(socket_, buf, buf_len, flags); 143 | if (net::is_socket_error(result)) 144 | throw DMITIGR_NET_EXCEPTION{"cannot write to socket"}; 145 | 146 | return static_cast(result); 147 | } 148 | 149 | void close() override 150 | { 151 | if (!is_shutted_down_) { 152 | graceful_shutdown(); 153 | is_shutted_down_ = true; 154 | } 155 | 156 | if (socket_.close() != 0) 157 | throw os::Sys_exception{"cannot close socket"}; 158 | } 159 | 160 | std::intptr_t native_handle() noexcept override 161 | { 162 | return socket_; 163 | } 164 | 165 | private: 166 | bool is_shutted_down_{}; 167 | net::Socket_guard socket_; 168 | 169 | /** 170 | * @brief Gracefully shutting down the socket. 171 | * 172 | * @details Shutting down the send side and receiving the data from the client 173 | * till the timeout or end to prevent sending a TCP RST to the client. 174 | */ 175 | void graceful_shutdown() 176 | { 177 | constexpr const char* const errmsg{"cannot shutdown socket gracefully"}; 178 | if (const auto r = ::shutdown(socket_, net::sd_send)) { 179 | if (errno == ENOTCONN) 180 | return; 181 | else 182 | throw DMITIGR_NET_EXCEPTION{errmsg}; 183 | } 184 | while (true) { 185 | using Sr = net::Socket_readiness; 186 | const auto mask = net::poll(socket_, Sr::read_ready, std::chrono::seconds{1}); 187 | if (!bool(mask & Sr::read_ready)) 188 | break; // timeout (ok) 189 | 190 | std::array trashcan; 191 | constexpr int flags{}; 192 | #ifdef _WIN32 193 | const auto trashcan_size = static_cast(trashcan.size()); 194 | #else 195 | const auto trashcan_size = static_cast(trashcan.size()); 196 | #endif 197 | const auto result = ::recv(socket_, trashcan.data(), trashcan_size, flags); 198 | if (net::is_socket_error(result)) 199 | throw DMITIGR_NET_EXCEPTION{errmsg}; 200 | else if (result == 0) 201 | break; // the end (ok) 202 | } 203 | } 204 | }; 205 | 206 | #ifdef _WIN32 207 | 208 | /// The implementation of Descriptor based on Windows Named Pipes. 209 | class pipe_Descriptor final : public iDescriptor { 210 | public: 211 | ~pipe_Descriptor() override 212 | { 213 | if (pipe_ != INVALID_HANDLE_VALUE) { 214 | if (!::FlushFileBuffers(pipe_)) 215 | std::fprintf(stderr, "%s\n", "FlushFileBuffers() failed"); 216 | 217 | if (!::DisconnectNamedPipe(pipe_)) 218 | std::fprintf(stderr, "%s\n", "DisconnectNamedPipe() failed"); 219 | } 220 | } 221 | 222 | explicit pipe_Descriptor(os::windows::Handle_guard pipe) 223 | : pipe_{std::move(pipe)} 224 | { 225 | DMITIGR_ASSERT(pipe_ != INVALID_HANDLE_VALUE); 226 | } 227 | 228 | std::streamsize read(char* const buf, std::streamsize len) override 229 | { 230 | if (!buf) 231 | throw Exception{"cannot read from named pipe to null buffer"}; 232 | 233 | len = std::min(len, max_read_size()); 234 | DWORD result{}; 235 | if (!::ReadFile(pipe_, buf, static_cast(len), &result, nullptr)) 236 | throw os::Sys_exception{"cannot read from named pipe"}; 237 | 238 | return static_cast(result); 239 | } 240 | 241 | std::streamsize write(const char* const buf, std::streamsize len) override 242 | { 243 | if (!buf) 244 | throw Exception{"cannot write to named pipe from null buffer"}; 245 | 246 | len = std::min(len, max_write_size()); 247 | DWORD result{}; 248 | if (!::WriteFile(pipe_, buf, static_cast(len), &result, nullptr)) 249 | throw os::Sys_exception{"cannot write to named pipe"}; 250 | 251 | return static_cast(result); 252 | } 253 | 254 | void close() override 255 | { 256 | if (pipe_ != INVALID_HANDLE_VALUE) { 257 | if (!::FlushFileBuffers(pipe_)) 258 | throw os::Sys_exception{"cannot flush file buffers"}; 259 | 260 | if (!::DisconnectNamedPipe(pipe_)) 261 | throw os::Sys_exception{"cannot disconnect named pipe"}; 262 | 263 | if (!pipe_.close()) 264 | throw os::Sys_exception{"cannot close named pipe"}; 265 | } 266 | } 267 | 268 | std::intptr_t native_handle() noexcept override 269 | { 270 | return reinterpret_cast(pipe_.handle()); 271 | } 272 | 273 | private: 274 | os::windows::Handle_guard pipe_; 275 | }; 276 | 277 | #endif // _WIN32 278 | 279 | } // namespace detail 280 | } // namespace dmitigr::net 281 | 282 | #endif // DMITIGR_NET_DESCRIPTOR_HPP 283 | -------------------------------------------------------------------------------- /src/net/endpoint.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_NET_ENDPOINT_HPP 18 | #define DMITIGR_NET_ENDPOINT_HPP 19 | 20 | #include "../base/assert.hpp" 21 | #include "../fs/filesystem.hpp" 22 | #include "basics.hpp" 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | namespace dmitigr::net { 29 | 30 | /** 31 | * @brief A communication endpoint identifier. 32 | * 33 | * @details The objects of this class can identify: 34 | * - Windows Named Pipes (WNP); 35 | * - Unix Domain Sockets (UDS); 36 | * - network services with the address and the port. 37 | */ 38 | class Endpoint final { 39 | public: 40 | #ifdef _WIN32 41 | /// Constructs WNP endpoint. 42 | explicit Endpoint(std::string pipe_name) 43 | : Endpoint{".", std::move(pipe_name)} 44 | {} 45 | 46 | /// @overload 47 | Endpoint(std::string server_name, std::string pipe_name) 48 | : wnp_pipe_name_{std::move(pipe_name)} 49 | , wnp_server_name_{std::move(server_name)} 50 | { 51 | DMITIGR_ASSERT(is_invariant_ok()); 52 | } 53 | #endif 54 | /// Constructs UDS endpoint. 55 | explicit Endpoint(std::filesystem::path path) 56 | : uds_path_{std::move(path)} 57 | { 58 | DMITIGR_ASSERT(is_invariant_ok()); 59 | } 60 | 61 | /// Constructs network endpoint. 62 | Endpoint(std::string address, const int port) 63 | : net_address_{std::move(address)} 64 | , net_port_{port} 65 | { 66 | DMITIGR_ASSERT(is_invariant_ok()); 67 | } 68 | 69 | /// @returns The communication mode of this endpoint. 70 | Communication_mode communication_mode() const 71 | { 72 | #ifdef _WIN32 73 | if (wnp_pipe_name()) 74 | return Communication_mode::wnp; 75 | #endif 76 | return uds_path() ? Communication_mode::uds : Communication_mode::net; 77 | } 78 | 79 | #ifdef _WIN32 80 | /** 81 | * @returns The pipe name of the WNP if the communication mode 82 | * is `Communication_mode::wnp`, or `std::nullopt` otherwise. 83 | */ 84 | const std::optional& wnp_pipe_name() const noexcept 85 | { 86 | return wnp_pipe_name_; 87 | } 88 | 89 | /** 90 | * @returns The server name of the WNP if the communication mode 91 | * is `Communication_mode::wnp`, or `std::nullopt` otherwise. 92 | */ 93 | const std::optional& wnp_server_name() const noexcept 94 | { 95 | return wnp_server_name_; 96 | } 97 | #endif 98 | 99 | /** 100 | * @returns The path to the UDS if the communication mode 101 | * is `Communication_mode::uds`, or `std::nullopt` otherwise. 102 | */ 103 | const std::optional& uds_path() const noexcept 104 | { 105 | return uds_path_; 106 | } 107 | 108 | /** 109 | * @returns The network address of the host if the communication mode 110 | * is `Communication_mode::net`, or `std::nullopt` otherwise. 111 | */ 112 | const std::optional& net_address() const noexcept 113 | { 114 | return net_address_; 115 | } 116 | 117 | /** 118 | * @returns The port number of the host if the communication mode 119 | * is `Communication_mode::net`, or `std::nullopt` otherwise. 120 | */ 121 | std::optional net_port() const noexcept 122 | { 123 | return net_port_; 124 | } 125 | 126 | private: 127 | #ifdef _WIN32 128 | std::optional wnp_pipe_name_; 129 | std::optional wnp_server_name_; 130 | #endif 131 | std::optional uds_path_; 132 | std::optional net_address_; 133 | std::optional net_port_; 134 | 135 | bool is_invariant_ok() const 136 | { 137 | using Cm = Communication_mode; 138 | #ifdef _WIN32 139 | const bool wnp_ok = (!wnp_pipe_name_ && !wnp_server_name_) || 140 | (wnp_pipe_name_ && wnp_server_name_ && !wnp_pipe_name_->empty() && 141 | !wnp_server_name_->empty()); 142 | const bool is_wnp = communication_mode() == Cm::wnp; 143 | #endif 144 | const bool uds_ok = !uds_path_ || !uds_path_->empty(); 145 | const bool is_uds = communication_mode() == Cm::uds; 146 | const bool net_ok = (!net_address_ && !net_port_) || 147 | (net_address_ && net_port_ && !net_address_->empty()); 148 | const bool is_net = communication_mode() == Cm::net; 149 | #ifdef _WIN32 150 | const bool is_ipc = is_wnp || is_uds; 151 | const bool ipc_ok = wnp_ok || uds_ok; 152 | #else 153 | const bool is_ipc = is_uds; 154 | const bool ipc_ok = uds_ok; 155 | #endif 156 | const bool communication_mode_ok = (!is_ipc && is_net) || (is_ipc && !is_net); 157 | 158 | return ipc_ok && net_ok && communication_mode_ok; 159 | } 160 | }; 161 | 162 | } // namespace dmitigr::net 163 | 164 | #endif // DMITIGR_NET_ENDPOINT_HPP 165 | -------------------------------------------------------------------------------- /src/net/errctg.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_NET_ERRCTG_HPP 18 | #define DMITIGR_NET_ERRCTG_HPP 19 | 20 | #include // std::strlen 21 | #include 22 | 23 | namespace dmitigr::net { 24 | 25 | #ifdef _WIN32 26 | // ----------------------------------------------------------------------------- 27 | // Wsa_error_category 28 | // ----------------------------------------------------------------------------- 29 | 30 | /// A category of Windows Socket Application (WSA) errors. 31 | class Wsa_error_category final : public std::error_category { 32 | public: 33 | /// @returns The literal `dmitigr_net_wsa_error`. 34 | const char* name() const noexcept override 35 | { 36 | return "dmitigr_net_wsa_error"; 37 | } 38 | 39 | /** 40 | * @returns The string that describes the error condition denoted by `ev`. 41 | * 42 | * @remarks The caller should not rely on the 43 | * return value since it is a subject to change. 44 | */ 45 | std::string message(const int ev) const override 46 | { 47 | std::string result(name()); 48 | result += ' '; 49 | result += std::to_string(ev); 50 | return result; 51 | } 52 | }; 53 | 54 | /// @returns The reference to instance of type Wsa_error_category. 55 | inline const Wsa_error_category& wsa_error_category() noexcept 56 | { 57 | static const Wsa_error_category result; 58 | return result; 59 | } 60 | #endif // _WIN32 61 | 62 | } // namespace dmitigr::net 63 | 64 | #endif // DMITIGR_NET_ERRCTG_HPP 65 | -------------------------------------------------------------------------------- /src/net/exceptions.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_NET_EXCEPTIONS_HPP 18 | #define DMITIGR_NET_EXCEPTIONS_HPP 19 | 20 | #include "../os/exceptions.hpp" 21 | #include "errctg.hpp" 22 | #ifdef _WIN32 23 | #include "last_error.hpp" 24 | #endif 25 | 26 | #include 27 | #include 28 | 29 | namespace dmitigr::net { 30 | 31 | /** 32 | * @ingroup errors 33 | * 34 | * @brief The generic exception class. 35 | */ 36 | class Exception : public dmitigr::Exception { 37 | using dmitigr::Exception::Exception; 38 | }; 39 | 40 | #ifdef _WIN32 41 | /** 42 | * @ingroup errors 43 | * 44 | * @brief An exception thrown on Windows Socket Application (WSA) error. 45 | */ 46 | class Wsa_exception final : public Exception { 47 | public: 48 | /// The constructor. 49 | explicit Wsa_exception(const std::string& what) 50 | : Wsa_exception{::WSAGetLastError(), what} 51 | {} 52 | 53 | /// @overload 54 | Wsa_exception(const int ev, const std::string& what) 55 | : Exception{std::error_condition{ev, wsa_error_category()}, what} 56 | {} 57 | }; 58 | #endif 59 | 60 | } // namespace dmitigr::net 61 | 62 | /** 63 | * Convenient macro for the cross-platform code. 64 | * 65 | * This macro should be used whenever the error originates from WSA on Windows. 66 | */ 67 | #ifdef _WIN32 68 | #define DMITIGR_NET_EXCEPTION dmitigr::net::Wsa_exception 69 | #else 70 | #define DMITIGR_NET_EXCEPTION dmitigr::os::Sys_exception 71 | #endif 72 | 73 | #endif // DMITIGR_NET_EXCEPTIONS_HPP 74 | -------------------------------------------------------------------------------- /src/net/last_error.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_NET_LAST_ERROR_HPP 18 | #define DMITIGR_NET_LAST_ERROR_HPP 19 | 20 | #include "../base/assert.hpp" 21 | 22 | #ifdef _WIN32 23 | #include 24 | #else 25 | #include "../os/last_error.hpp" 26 | #endif 27 | 28 | namespace dmitigr::net { 29 | /// @returns The last network subsystem's error code. 30 | inline int last_error() noexcept 31 | { 32 | #ifdef _WIN32 33 | return ::WSAGetLastError(); 34 | #else 35 | return os::last_error(); 36 | #endif 37 | } 38 | 39 | /// Prints the last network subsystem's error to the standard error. 40 | inline void print_last_error(const char* const context) noexcept 41 | { 42 | DMITIGR_ASSERT(context); 43 | std::fprintf(stderr, "%s(): error %d\n", context, last_error()); 44 | } 45 | } // namespace dmitigr::net 46 | 47 | #endif // DMITIGR_NET_LAST_ERROR_HPP 48 | -------------------------------------------------------------------------------- /src/net/net.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_NET_NET_HPP 18 | #define DMITIGR_NET_NET_HPP 19 | 20 | #include "address.hpp" 21 | #include "basics.hpp" 22 | #include "client.hpp" 23 | #include "conversions.hpp" 24 | #include "descriptor.hpp" 25 | #include "endpoint.hpp" 26 | #include "listener.hpp" 27 | #include "socket.hpp" 28 | #include "util.hpp" 29 | 30 | #endif // DMITIGR_NET_NET_HPP 31 | -------------------------------------------------------------------------------- /src/net/types_fwd.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_NET_TYPES_FWD_HPP 18 | #define DMITIGR_NET_TYPES_FWD_HPP 19 | 20 | /// The API. 21 | namespace dmitigr::net { 22 | 23 | class Socket_guard; 24 | 25 | enum class Communication_mode; 26 | enum class Socket_readiness; 27 | enum class Protocol_family; 28 | 29 | class Descriptor; 30 | class Ip_address; 31 | class Endpoint; 32 | class Listener_options; 33 | class Listener; 34 | 35 | class Wsa_exception; 36 | class Wsa_error_category; 37 | 38 | /// The implementation details. 39 | namespace detail { 40 | 41 | class iDescriptor; 42 | class socket_Descriptor; 43 | class pipe_Descriptor; 44 | 45 | class iListener; 46 | class socket_Listener; 47 | class pipe_Listener; 48 | 49 | } // namespace detail 50 | } // namespace dmitigr::net 51 | 52 | #endif // DMITIGR_NET_TYPES_FWD_HPP 53 | -------------------------------------------------------------------------------- /src/net/util.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_NET_UTIL_HPP 18 | #define DMITIGR_NET_UTIL_HPP 19 | 20 | #include 21 | #include 22 | 23 | namespace dmitigr::net { 24 | 25 | /// @returns `true` if the `hostname` denotes a valid hostname. 26 | inline bool is_hostname_valid(const std::string& hostname) 27 | { 28 | // Returns `true` if `ch` is a valid hostname character. 29 | static const auto is_hostname_char = [](const char ch) 30 | { 31 | static const std::locale l; 32 | return std::isalnum(ch, l) || (ch == '_') || (ch == '-'); 33 | }; 34 | 35 | constexpr std::string::size_type max_length{253}; 36 | if (hostname.empty() || hostname.size() > max_length) 37 | return false; 38 | 39 | constexpr std::string::size_type label_max_length{63}; 40 | const auto limit = hostname.size(); 41 | for (std::string::size_type i{}, label_length{}; i < limit; ++i) { 42 | const auto c = hostname[i]; 43 | if (c == '.') { 44 | if (label_length == 0) 45 | return false; // empty label 46 | label_length = 0; 47 | } else if (is_hostname_char(c)) { 48 | ++label_length; 49 | if (label_length > label_max_length) 50 | return false; // label too long 51 | } else 52 | return false; // invalid character 53 | } 54 | return true; 55 | } 56 | 57 | } // namespace dmitigr::net 58 | 59 | #endif // DMITIGR_NET_UTIL_HPP 60 | -------------------------------------------------------------------------------- /src/net/version.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 18 | // This file is generated automatically. Edit version.hpp.in instead!!!!!!!!!!!! 19 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 | 21 | #ifndef DMITIGR_NET_VERSION_HPP 22 | #define DMITIGR_NET_VERSION_HPP 23 | 24 | #include 25 | 26 | namespace dmitigr::net { 27 | 28 | /// @returns The library version. 29 | constexpr std::int_fast32_t version() noexcept 30 | { 31 | // Actual values are set in CMakeLists.txt. 32 | constexpr std::int_least32_t major = 0; 33 | constexpr std::int_least32_t minor = 1; 34 | 35 | // 11.234 -> 11 * 1000 + 234 = 11234 36 | return major*1000 + minor; 37 | } 38 | 39 | } // namespace dmitigr::net 40 | 41 | #endif // DMITIGR_NET_VERSION_HPP 42 | -------------------------------------------------------------------------------- /src/os/environment.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_OS_ENVIRONMENT_HPP 18 | #define DMITIGR_OS_ENVIRONMENT_HPP 19 | 20 | #include "exceptions.hpp" 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef _WIN32 29 | 30 | #include "windows.hpp" 31 | 32 | #include 33 | #include 34 | 35 | // IO headers 36 | #include 37 | #include 38 | 39 | #else // Unix 40 | 41 | #include 42 | #include 43 | #include 44 | 45 | #endif 46 | 47 | namespace dmitigr::os { 48 | 49 | /// @returns The current username of the running process. 50 | inline std::string current_username() 51 | { 52 | std::string result; 53 | #ifdef _WIN32 54 | constexpr DWORD max_size = UNLEN + 1; 55 | result.resize(max_size); 56 | DWORD sz{max_size}; 57 | if (::GetUserName(result.data(), &sz) != 0) 58 | result.resize(sz - 1); 59 | else 60 | throw Sys_exception{"cannot get current username of the running process"}; 61 | #else 62 | struct passwd pwd; 63 | struct passwd *pwd_ptr{}; 64 | const uid_t uid = geteuid(); 65 | const std::size_t bufsz = []() 66 | { 67 | auto result = sysconf(_SC_GETPW_R_SIZE_MAX); 68 | if (result == -1) 69 | result = 16384; 70 | return result; 71 | }(); 72 | const std::unique_ptr buf{new char[bufsz]}; 73 | const int s = getpwuid_r(uid, &pwd, buf.get(), bufsz, &pwd_ptr); 74 | if (!pwd_ptr) { 75 | if (s) 76 | throw Sys_exception{s, "cannot get current username of the running process"}; 77 | else 78 | result = std::to_string(uid); 79 | } else 80 | result = pwd.pw_name; 81 | #endif 82 | return result; 83 | } 84 | 85 | /** 86 | * @returns The value of the environment variable `name` that is accessible 87 | * from the running process, or `std::nullopt` if there is no such a variable. 88 | * 89 | * @remarks Cannot be used in applications that execute in the Windows Runtime, 90 | * because environment variables are not available to UWP applications. 91 | */ 92 | inline std::optional environment_variable(const std::string& name) 93 | { 94 | #if defined(_WIN32) && defined(_MSC_VER) 95 | const std::unique_ptr buffer{nullptr, &std::free}; 96 | char* result = buffer.get(); 97 | if (const auto err = _dupenv_s(&result, nullptr, name.c_str())) 98 | throw Sys_exception{err, "cannot get the environment variable \""+name+"\""}; 99 | #else 100 | const char* const result = std::getenv(name.c_str()); 101 | #endif 102 | return result ? std::make_optional(std::string{result}) : std::nullopt; 103 | } 104 | 105 | } // namespace dmitigr::os 106 | 107 | #endif // DMITIGR_OS_ENVIRONMENT_HPP 108 | -------------------------------------------------------------------------------- /src/os/error.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_OS_ERROR_HPP 18 | #define DMITIGR_OS_ERROR_HPP 19 | 20 | #include "exceptions.hpp" 21 | 22 | #include 23 | #include 24 | 25 | namespace dmitigr::os { 26 | 27 | /// @returns String describing OS error code. 28 | inline std::string error_message(const int code) 29 | { 30 | #ifdef _WIN32 31 | char buf[128]; 32 | if (const int e = ::strerror_s(buf, code)) 33 | throw Sys_exception{e, "cannot get an OS error message"}; 34 | else 35 | return buf; 36 | #else 37 | char buf[1024]; 38 | #if ((_POSIX_C_SOURCE >= 200112L) && !_GNU_SOURCE) || __APPLE__ 39 | const int e = ::strerror_r(code, buf, sizeof(buf)); 40 | return !e ? buf : "unknown error"; 41 | #elif _GNU_SOURCE 42 | const char* const msg = ::strerror_r(code, buf, sizeof(buf)); 43 | return msg ? msg : "unknown error"; 44 | #else 45 | #error Supported version of strerror_r() is not available. 46 | #endif 47 | #endif 48 | } 49 | 50 | } // namespace dmitigr::os 51 | 52 | #endif // DMITIGR_OS_ERROR_HPP 53 | -------------------------------------------------------------------------------- /src/os/exceptions.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_OS_EXCEPTIONS_HPP 18 | #define DMITIGR_OS_EXCEPTIONS_HPP 19 | 20 | #include "../base/exceptions.hpp" 21 | #include "last_error.hpp" 22 | 23 | #include 24 | #include 25 | 26 | namespace dmitigr::os { 27 | 28 | // ----------------------------------------------------------------------------- 29 | // Exception 30 | // ----------------------------------------------------------------------------- 31 | 32 | /** 33 | * @ingroup errors 34 | * 35 | * @brief The generic exception class. 36 | */ 37 | class Exception : public dmitigr::Exception { 38 | using dmitigr::Exception::Exception; 39 | }; 40 | 41 | // ----------------------------------------------------------------------------- 42 | // Sys_exception 43 | // ----------------------------------------------------------------------------- 44 | 45 | /** 46 | * @ingroup errors 47 | * 48 | * @brief An exception thrown on system error. 49 | */ 50 | class Sys_exception final : public Exception { 51 | public: 52 | /// The constructor. 53 | explicit Sys_exception(const std::string& what) 54 | : Sys_exception{last_error(), what} 55 | {} 56 | 57 | /// @overload 58 | Sys_exception(const int ev, const std::string& what) 59 | : Exception{std::system_category().default_error_condition(ev), what} 60 | {} 61 | }; 62 | 63 | } // namespace dmitigr::os 64 | 65 | #endif // DMITIGR_OS_EXCEPTIONS_HPP 66 | -------------------------------------------------------------------------------- /src/os/last_error.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_OS_LAST_ERROR_HPP 18 | #define DMITIGR_OS_LAST_ERROR_HPP 19 | 20 | #include "../base/assert.hpp" 21 | 22 | #ifdef _WIN32 23 | #include "windows.hpp" 24 | #else 25 | #include 26 | #endif 27 | 28 | #include 29 | 30 | namespace dmitigr::os { 31 | /** 32 | * @returns The last system error code. 33 | * 34 | * @par Thread safety 35 | * Thread-safe. 36 | */ 37 | inline int last_error() noexcept 38 | { 39 | #ifdef _WIN32 40 | // Note: the last-error code is maintained on a per-thread basis. 41 | return static_cast(::GetLastError()); 42 | #else 43 | /* 44 | * Note: errno is thread-local on Linux. 45 | * See also http://www.unix.org/whitepapers/reentrant.html 46 | */ 47 | return errno; 48 | #endif 49 | } 50 | 51 | /// Prints the last system error to the standard error. 52 | inline void print_last_error(const char* const context) noexcept 53 | { 54 | DMITIGR_ASSERT(context); 55 | std::fprintf(stderr, "%s: error %d\n", context, last_error()); 56 | } 57 | } // namespace dmitigr::os 58 | 59 | #endif // DMITIGR_OS_LAST_ERROR_HPP 60 | -------------------------------------------------------------------------------- /src/os/os.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_OS_OS_HPP 18 | #define DMITIGR_OS_OS_HPP 19 | 20 | #include "environment.hpp" 21 | #include "error.hpp" 22 | #include "exceptions.hpp" 23 | #include "last_error.hpp" 24 | #include "pid.hpp" 25 | #include "types_fwd.hpp" 26 | #include "version.hpp" 27 | #ifdef _WIN32 28 | #include "windows.hpp" 29 | #endif 30 | 31 | #endif // DMITIGR_OS_OS_HPP 32 | -------------------------------------------------------------------------------- /src/os/pid.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_OS_PID_HPP 18 | #define DMITIGR_OS_PID_HPP 19 | 20 | #ifdef _WIN32 21 | #include "windows.hpp" 22 | #else 23 | #include 24 | #include 25 | #endif 26 | 27 | namespace dmitigr::os { 28 | 29 | #ifdef _WIN32 30 | /// The alias of the process identifier type. 31 | using Pid = DWORD; 32 | #else 33 | /// The alias of the process identifier type. 34 | using Pid = ::pid_t; 35 | #endif 36 | 37 | /// @returns The current process identifier of the calling process. 38 | inline Pid pid() noexcept 39 | { 40 | #ifdef _WIN32 41 | return ::GetCurrentProcessId(); 42 | #else 43 | return ::getpid(); 44 | #endif 45 | } 46 | 47 | } // namespace dmitigr::os 48 | 49 | #endif // DMITIGR_OS_PID_HPP 50 | -------------------------------------------------------------------------------- /src/os/types_fwd.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_OS_TYPES_FWD_HPP 18 | #define DMITIGR_OS_TYPES_FWD_HPP 19 | 20 | namespace dmitigr { 21 | 22 | /// The API. 23 | namespace os { 24 | 25 | #ifdef _WIN32 26 | namespace windows { 27 | struct Handle_guard; 28 | } // namespace windows 29 | #endif // _WIN32 30 | 31 | /// The implementation detail. 32 | namespace detail { 33 | } // namespace detail 34 | } // namespace os 35 | } // namespace dmitigr 36 | 37 | #endif // DMITIGR_OS_TYPES_FWD_HPP 38 | -------------------------------------------------------------------------------- /src/os/version.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 18 | // This file is generated automatically. Edit version.hpp.in instead!!!!!!!!!!!! 19 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 | 21 | #ifndef DMITIGR_OS_VERSION_HPP 22 | #define DMITIGR_OS_VERSION_HPP 23 | 24 | #include 25 | 26 | namespace dmitigr::os { 27 | 28 | /// @returns The library version. 29 | constexpr std::int_fast32_t version() noexcept 30 | { 31 | // Actual values are set in CMakeLists.txt. 32 | constexpr std::int_least32_t major = 0; 33 | constexpr std::int_least32_t minor = 1; 34 | 35 | // 11.234 -> 11 * 1000 + 234 = 11234 36 | return major*1000 + minor; 37 | } 38 | 39 | } // namespace dmitigr::os 40 | 41 | #endif // DMITIGR_OS_VERSION_HPP 42 | -------------------------------------------------------------------------------- /src/os/windows.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // Include this header instead of Windows.h whenever Windows.h is needed. 18 | 19 | #ifndef _WIN32 20 | #error windows.hpp is usable only on Microsoft Windows! 21 | #endif 22 | 23 | #ifndef DMITIGR_OS_WINDOWS_HPP 24 | #define DMITIGR_OS_WINDOWS_HPP 25 | 26 | #include 27 | #include 28 | 29 | /* 30 | * For historical reasons, the Windows.h header defaults to including the 31 | * Winsock.h header file for Windows Sockets 1.1. The declarations in the 32 | * Winsock.h header file will conflict with the declarations in the Winsock2.h 33 | * header file required by Windows Sockets 2.0. The WIN32_LEAN_AND_MEAN macro 34 | * prevents the Winsock.h from being included by the Windows.h header. 35 | * 36 | * https://docs.microsoft.com/en-us/windows/desktop/winsock/include-files-2 37 | * https://social.msdn.microsoft.com/Forums/vstudio/en-US/671124df-c42b-48b8-a4ac-3413230bc43b/dll-compilationredefinition-error 38 | */ 39 | #ifndef WIN32_LEAN_AND_MEAN 40 | #define WIN32_LEAN_AND_MEAN 41 | #endif 42 | #ifndef NOMINMAX 43 | #define NOMINMAX 44 | #endif 45 | #include 46 | 47 | namespace dmitigr::os::windows { 48 | 49 | /// A very thin wrapper around the HANDLE data type. 50 | struct Handle_guard final { 51 | /// The destructor. 52 | ~Handle_guard() 53 | { 54 | if (!close()) 55 | std::fprintf(stderr, "%s: error %d\n", "CloseHandle", GetLastError()); 56 | } 57 | 58 | /// The constructor. 59 | explicit Handle_guard(const HANDLE handle = INVALID_HANDLE_VALUE) noexcept 60 | : handle_{handle} 61 | {} 62 | 63 | /// Non-copyable. 64 | Handle_guard(const Handle_guard&) = delete; 65 | 66 | /// Non-copyable. 67 | Handle_guard& operator=(const Handle_guard&) = delete; 68 | 69 | /// The move constructor. 70 | Handle_guard(Handle_guard&& rhs) noexcept 71 | : handle_{rhs.handle_} 72 | { 73 | rhs.handle_ = INVALID_HANDLE_VALUE; 74 | } 75 | 76 | /// The move assignment operator. 77 | Handle_guard& operator=(Handle_guard&& rhs) noexcept 78 | { 79 | if (this != &rhs) { 80 | Handle_guard tmp{std::move(rhs)}; 81 | swap(tmp); 82 | } 83 | return *this; 84 | } 85 | 86 | /// The swap operation. 87 | void swap(Handle_guard& other) noexcept 88 | { 89 | std::swap(handle_, other.handle_); 90 | } 91 | 92 | /// @returns The guarded HANDLE. 93 | HANDLE handle() const noexcept 94 | { 95 | return handle_; 96 | } 97 | 98 | /// @returns The guarded HANDLE. 99 | operator HANDLE() const noexcept 100 | { 101 | return handle(); 102 | } 103 | 104 | /// @returns `true` on success, or `false` otherwise. 105 | bool close() noexcept 106 | { 107 | bool result{true}; 108 | if (handle_ != INVALID_HANDLE_VALUE) { 109 | result = CloseHandle(handle_); 110 | if (result) 111 | handle_ = INVALID_HANDLE_VALUE; 112 | } 113 | return result; 114 | } 115 | 116 | private: 117 | HANDLE handle_{INVALID_HANDLE_VALUE}; 118 | }; 119 | 120 | } // namespace dmitigr::os::windows 121 | 122 | #endif // DMITIGR_OS_WINDOWS_HPP 123 | -------------------------------------------------------------------------------- /src/rnd/exceptions.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_RND_EXCEPTIONS_HPP 18 | #define DMITIGR_RND_EXCEPTIONS_HPP 19 | 20 | #include "../base/exceptions.hpp" 21 | 22 | namespace dmitigr::rnd { 23 | 24 | /** 25 | * @ingroup errors 26 | * 27 | * @brief The generic exception class. 28 | */ 29 | class Exception final : public dmitigr::Exception { 30 | using dmitigr::Exception::Exception; 31 | }; 32 | 33 | } // namespace dmitigr::rnd 34 | 35 | #endif // DMITIGR_RND_EXCEPTIONS_HPP 36 | -------------------------------------------------------------------------------- /src/rnd/number.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_RND_NUMBER_HPP 18 | #define DMITIGR_RND_NUMBER_HPP 19 | 20 | #include "exceptions.hpp" 21 | 22 | #include 23 | #include 24 | 25 | namespace dmitigr::rnd { 26 | 27 | // ----------------------------------------------------------------------------- 28 | // Number generators 29 | // ----------------------------------------------------------------------------- 30 | 31 | /// Seeds the pseudo-random number generator. 32 | inline void seed_by_now() noexcept 33 | { 34 | const auto seed = std::chrono::duration_cast( 35 | std::chrono::system_clock::now().time_since_epoch()).count(); 36 | std::srand(static_cast(seed)); 37 | } 38 | 39 | /** 40 | * @returns The random number. 41 | * 42 | * @remarks From TC++PL 3rd, 22.7. 43 | */ 44 | template 45 | constexpr T cpp_pl_3rd(const T maximum) noexcept 46 | { 47 | const auto rand_num = static_cast(std::rand()); 48 | return static_cast(maximum * (rand_num / RAND_MAX)); 49 | } 50 | 51 | /** 52 | * @overload 53 | * 54 | * @par Requires 55 | * `(minimum < maximum)`. 56 | */ 57 | template 58 | constexpr T cpp_pl_3rd(const T minimum, const T maximum) 59 | { 60 | if (!(minimum < maximum)) 61 | throw Exception{"invalid interval for random number generation"}; 62 | 63 | const auto range_length = maximum - minimum; 64 | return (cpp_pl_3rd(maximum) % range_length) + minimum; 65 | } 66 | 67 | } // namespace dmitigr::rnd 68 | 69 | #endif // DMITIGR_RND_NUMBER_HPP 70 | -------------------------------------------------------------------------------- /src/rnd/rnd.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_RND_RND_HPP 18 | #define DMITIGR_RND_RND_HPP 19 | 20 | #include "exceptions.hpp" 21 | #include "number.hpp" 22 | #include "string.hpp" 23 | #include "uuid.hpp" 24 | #include "version.hpp" 25 | 26 | #endif // DMITIGR_RND_RND_HPP 27 | -------------------------------------------------------------------------------- /src/rnd/string.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_RND_STRING_HPP 18 | #define DMITIGR_RND_STRING_HPP 19 | 20 | #include "number.hpp" 21 | 22 | #include 23 | 24 | namespace dmitigr::rnd { 25 | 26 | // ----------------------------------------------------------------------------- 27 | // Strings generators 28 | // ----------------------------------------------------------------------------- 29 | 30 | /** 31 | * @returns The random string. 32 | * 33 | * @param size The result size. 34 | * @param palette The palette of characters the result will consist of. 35 | */ 36 | inline std::string random_string(const std::string& palette, 37 | const std::string::size_type size) 38 | { 39 | std::string result; 40 | result.resize(size); 41 | if (const auto pallete_size = palette.size()) { 42 | for (std::string::size_type i{}; i < size; ++i) 43 | result[i] = palette[cpp_pl_3rd(pallete_size - 1)]; 44 | } 45 | return result; 46 | } 47 | 48 | /** 49 | * @returns The random string. 50 | * 51 | * @param beg The start of source range. 52 | * @param end The past of end of source range. 53 | * @param size The result size. 54 | * 55 | * @par Requires 56 | * `(beg <= end)`. 57 | */ 58 | inline std::string random_string(const char beg, const char end, 59 | const std::string::size_type size) 60 | { 61 | if (!(beg <= end)) 62 | throw Exception{"invalid character range for random string generation"}; 63 | 64 | std::string result; 65 | if (beg < end) { 66 | result.resize(size); 67 | const auto len = end - beg; 68 | for (std::string::size_type i{}; i < size; ++i) 69 | result[i] = static_cast((cpp_pl_3rd(end) % len) + beg); 70 | } 71 | return result; 72 | } 73 | 74 | } // namespace dmitigr::rnd 75 | 76 | #endif // DMITIGR_RND_STRING_HPP 77 | -------------------------------------------------------------------------------- /src/rnd/uuid.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_RND_UUID_HPP 18 | #define DMITIGR_RND_UUID_HPP 19 | 20 | #include "../base/assert.hpp" 21 | #include "number.hpp" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | namespace dmitigr::rnd { 30 | 31 | /// An UUID. 32 | class Uuid final { 33 | public: 34 | /// Constructs Nil UUID. 35 | Uuid() = default; 36 | 37 | /** 38 | * @returns The random UUID (version 4). 39 | * 40 | * @remarks Please be sure to seed the pseudo-random number generator with 41 | * `std::srand()` (or use convenient `dmitigr::rnd::seed_by_now()`) before 42 | * calling this maker function. 43 | */ 44 | static Uuid make_v4() 45 | { 46 | Uuid result; 47 | 48 | // Filling the data with random bytes. 49 | { 50 | constexpr auto minimum = static_cast(1); 51 | constexpr auto maximum = std::numeric_limits::max(); 52 | for (std::size_t i{}; i < sizeof(result.data_.raw_); ++i) 53 | result.data_.raw_[i] = cpp_pl_3rd(minimum, maximum); 54 | } 55 | 56 | /* 57 | * Setting magic numbers for the "version 4" (pseudorandom) UUID. 58 | * See http://tools.ietf.org/html/rfc4122#section-4.4 59 | */ 60 | result.data_.rep_.time_hi_and_version_ = 61 | (result.data_.rep_.time_hi_and_version_ & 0x0fff) | 0x4000; 62 | result.data_.rep_.clock_seq_hi_and_reserved_ = 63 | (result.data_.rep_.clock_seq_hi_and_reserved_ & 0x3f) | 0x80; 64 | 65 | DMITIGR_ASSERT(result.is_invariant_ok()); 66 | return result; 67 | } 68 | 69 | /// @returns The string representation of the UUID. 70 | std::string to_string() const 71 | { 72 | constexpr std::size_t buf_size{36}; 73 | char buf[buf_size + 1]; 74 | const int count = std::snprintf(buf, sizeof(buf), 75 | "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 76 | data_.rep_.time_low_, 77 | data_.rep_.time_mid_, 78 | data_.rep_.time_hi_and_version_, 79 | data_.rep_.clock_seq_hi_and_reserved_, 80 | data_.rep_.clock_seq_low_, 81 | data_.rep_.node_[0], 82 | data_.rep_.node_[1], 83 | data_.rep_.node_[2], 84 | data_.rep_.node_[3], 85 | data_.rep_.node_[4], 86 | data_.rep_.node_[5]); 87 | DMITIGR_ASSERT(count == buf_size); 88 | return std::string{buf, buf_size}; 89 | } 90 | 91 | private: 92 | union { 93 | struct { 94 | std::uint32_t time_low_; 95 | std::uint16_t time_mid_; 96 | std::uint16_t time_hi_and_version_; 97 | std::uint8_t clock_seq_hi_and_reserved_; 98 | std::uint8_t clock_seq_low_; 99 | std::uint8_t node_[6]; 100 | } rep_; 101 | unsigned char raw_[16]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 102 | } data_; 103 | 104 | bool is_invariant_ok() const noexcept 105 | { 106 | return std::any_of(std::cbegin(data_.raw_), std::cend(data_.raw_), 107 | [](const auto b) { return b != 0; }); 108 | } 109 | }; 110 | 111 | } // namespace dmitigr::rnd 112 | 113 | #endif // DMITIGR_RND_UUID_HPP 114 | -------------------------------------------------------------------------------- /src/rnd/version.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 18 | // This file is generated automatically. Edit version.hpp.in instead!!!!!!!!!!!! 19 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 | 21 | #ifndef DMITIGR_RND_VERSION_HPP 22 | #define DMITIGR_RND_VERSION_HPP 23 | 24 | #include 25 | 26 | namespace dmitigr::rnd { 27 | 28 | /// @returns The library version. 29 | constexpr std::int_fast32_t version() noexcept 30 | { 31 | // Actual values are set in CMakeLists.txt. 32 | constexpr std::int_least32_t major = 0; 33 | constexpr std::int_least32_t minor = 1; 34 | 35 | // 11.234 -> 11 * 1000 + 234 = 11234 36 | return major*1000 + minor; 37 | } 38 | 39 | } // namespace dmitigr::rnd 40 | 41 | #endif // DMITIGR_RND_VERSION_HPP 42 | -------------------------------------------------------------------------------- /src/util/contract.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_UTIL_CONTRACT_HPP 18 | #define DMITIGR_UTIL_CONTRACT_HPP 19 | 20 | #include 21 | 22 | namespace dmitigr::util { 23 | 24 | template 25 | T&& not_false(T&& value) 26 | { 27 | if (value) 28 | return std::forward(value); 29 | else 30 | throw E{"unexpected false value"}; 31 | } 32 | 33 | } // namespace dmitigr::util 34 | 35 | #endif // DMITIGR_UTIL_CONTRACT_HPP 36 | -------------------------------------------------------------------------------- /src/util/diagnostic.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_UTIL_DIAGNOSTIC_HPP 18 | #define DMITIGR_UTIL_DIAGNOSTIC_HPP 19 | 20 | #include 21 | 22 | namespace dmitigr::util { 23 | 24 | /// @returns `true` if instance of type `E` is thrown upon calling of `f`. 25 | template 26 | bool with_catch(const F& f) noexcept 27 | { 28 | try { 29 | f(); 30 | } catch (const E&) { 31 | return true; 32 | } catch (...) {} 33 | return false; 34 | } 35 | 36 | /// @returns The duration of call of `f`. 37 | template 38 | auto with_measure(const F& f) 39 | { 40 | namespace chrono = std::chrono; 41 | const auto start = chrono::high_resolution_clock::now(); 42 | f(); 43 | const auto end = chrono::high_resolution_clock::now(); 44 | return chrono::duration_cast(end - start); 45 | } 46 | 47 | } // namespace dmitigr::util 48 | 49 | #endif // DMITIGR_UTIL_DIAGNOSTIC_HPP 50 | -------------------------------------------------------------------------------- /src/util/endianness.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_UTIL_ENDIANNESS_HPP 18 | #define DMITIGR_UTIL_ENDIANNESS_HPP 19 | 20 | namespace dmitigr::util { 21 | 22 | /// An endianness. 23 | enum class Endianness { 24 | /// Big-endian. 25 | big, 26 | /// Little-endian. 27 | little 28 | }; 29 | 30 | /// @returns Endianness of the system. 31 | inline Endianness endianness() noexcept 32 | { 33 | static_assert(sizeof(unsigned char) < sizeof(unsigned long), 34 | "unknown endianness"); 35 | static const unsigned long number{0x01}; 36 | static const auto result = 37 | (reinterpret_cast(&number)[0] == 1) 38 | ? Endianness::little : Endianness::big; 39 | return result; 40 | } 41 | 42 | } // namespace dmitigr::util 43 | 44 | #endif // DMITIGR_UTIL_ENDIANNESS_HPP 45 | -------------------------------------------------------------------------------- /src/util/enum_bitmask.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_UTIL_ENUM_BITMASK_HPP 18 | #define DMITIGR_UTIL_ENUM_BITMASK_HPP 19 | 20 | #include 21 | 22 | namespace dmitigr::util { 23 | 24 | /// Structure inspired by the exposition from 14822:2014 17.5.2.1.3. 25 | template struct Is_bitmask_enum : std::false_type {}; 26 | 27 | /// Bitwise AND for `T`. 28 | template 29 | constexpr std::enable_if_t::value, T> 30 | operator&(const T lhs, const T rhs) noexcept 31 | { 32 | using U = std::underlying_type_t; 33 | return static_cast(U(lhs) & U(rhs)); 34 | } 35 | 36 | /// Bitwise OR for `T`. 37 | template 38 | constexpr std::enable_if_t::value, T> 39 | operator|(const T lhs, const T rhs) noexcept 40 | { 41 | using U = std::underlying_type_t; 42 | return static_cast(U(lhs) | U(rhs)); 43 | } 44 | 45 | /// Bitwise XOR for `T`. 46 | template 47 | constexpr std::enable_if_t::value, T> 48 | operator^(const T lhs, const T rhs) noexcept 49 | { 50 | using U = std::underlying_type_t; 51 | return static_cast(U(lhs) ^ U(rhs)); 52 | } 53 | 54 | /// Bitwise NOT for `T`. 55 | template 56 | constexpr std::enable_if_t::value, T> 57 | operator~(const T rhs) noexcept 58 | { 59 | using U = std::underlying_type_t; 60 | return static_cast(~U(rhs)); 61 | } 62 | 63 | /// Bitwise AND for `T` with assignment to lvalue. 64 | template 65 | constexpr std::enable_if_t::value, T&> 66 | operator&=(T& lhs, const T rhs) noexcept 67 | { 68 | return lhs = (lhs & rhs); 69 | } 70 | 71 | /// Bitwise OR for `T` with assignment to lvalue. 72 | template 73 | constexpr std::enable_if_t::value, T&> 74 | operator|=(T& lhs, const T rhs) noexcept 75 | { 76 | return lhs = (lhs | rhs); 77 | } 78 | 79 | /// Bitwise XOR for `T` with assignment to lvalue. 80 | template 81 | constexpr std::enable_if_t::value, T&> 82 | operator^=(T& lhs, const T rhs) noexcept 83 | { 84 | return lhs = (lhs ^ rhs); 85 | } 86 | 87 | } // namespace dmitigr::util 88 | 89 | /** 90 | * @brief The helper macro for defining enum bitmask operators above in any 91 | * namespace. 92 | * 93 | * @param T The type name. 94 | */ 95 | #define DMITIGR_DEFINE_ENUM_BITMASK_OPERATORS(T) \ 96 | /** Bitwise AND for `T`. */ \ 97 | constexpr T operator&(const T lhs, const T rhs) noexcept \ 98 | { \ 99 | return dmitigr::util::operator&(lhs, rhs); \ 100 | } \ 101 | \ 102 | /** Bitwise OR for `T`. */ \ 103 | constexpr T operator|(const T lhs, const T rhs) noexcept \ 104 | { \ 105 | return dmitigr::util::operator|(lhs, rhs); \ 106 | } \ 107 | \ 108 | /** Bitwise XOR for `T`. */ \ 109 | constexpr T operator^(const T lhs, const T rhs) noexcept \ 110 | { \ 111 | return dmitigr::util::operator^(lhs, rhs); \ 112 | } \ 113 | \ 114 | /** Bitwise NOT for `T`. */ \ 115 | constexpr T operator~(const T rhs) noexcept \ 116 | { \ 117 | return dmitigr::util::operator~(rhs); \ 118 | } \ 119 | \ 120 | /** Bitwise AND for `T` with assignment to lvalue. */ \ 121 | constexpr T& operator&=(T& lhs, T rhs) noexcept \ 122 | { \ 123 | return dmitigr::util::operator&=(lhs, rhs); \ 124 | } \ 125 | \ 126 | /** Bitwise OR for `T` with assignment to lvalue. */ \ 127 | constexpr T& operator|=(T& lhs, T rhs) noexcept \ 128 | { \ 129 | return dmitigr::util::operator|=(lhs, rhs); \ 130 | } \ 131 | \ 132 | /** Bitwise XOR for `T` with assignment to lvalue. */ \ 133 | constexpr T& operator^=(T& lhs, T rhs) noexcept \ 134 | { \ 135 | return dmitigr::util::operator^=(lhs, rhs); \ 136 | } 137 | 138 | #endif // DMITIGR_UTIL_ENUM_BITMASK_HPP 139 | -------------------------------------------------------------------------------- /src/util/memory.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_UTIL_MEMORY_HPP 18 | #define DMITIGR_UTIL_MEMORY_HPP 19 | 20 | #include 21 | 22 | namespace dmitigr::util { 23 | 24 | /// A custom deleter for smart pointers. 25 | template 26 | class Conditional_delete final { 27 | public: 28 | /** 29 | * @brief The constructor. 30 | * 31 | * @par Effects 32 | * `condition() == condition`. 33 | */ 34 | explicit constexpr Conditional_delete(const bool condition = true) noexcept 35 | : condition_(condition) 36 | {} 37 | 38 | /// @returns The value of condition. 39 | constexpr bool condition() const noexcept 40 | { 41 | return condition_; 42 | } 43 | 44 | /** 45 | * @brief Applies `std::default_delete::operator()` to the 46 | * pointer `o` if and only if `(condition() == true)`. 47 | */ 48 | void operator()(T* const o) const noexcept 49 | { 50 | if (condition()) 51 | std::default_delete{}(o); 52 | } 53 | 54 | private: 55 | bool condition_{true}; 56 | }; 57 | 58 | } // namespace dmitigr::util 59 | 60 | #endif // DMITIGR_UTIL_MEMORY_HPP 61 | -------------------------------------------------------------------------------- /src/util/util.hpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #ifndef DMITIGR_UTIL_UTIL_HPP 18 | #define DMITIGR_UTIL_UTIL_HPP 19 | 20 | #include "diagnostic.hpp" 21 | #include "endianness.hpp" 22 | #include "enum_bitmask.hpp" 23 | #include "memory.hpp" 24 | 25 | #endif // DMITIGR_UTIL_UTIL_HPP 26 | -------------------------------------------------------------------------------- /src/version.hpp.in: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 18 | // This file is generated automatically. Edit version.hpp.in instead!!!!!!!!!!!! 19 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 | 21 | #ifndef DMITIGR_@dmitigr_lib_NAME@_VERSION_HPP 22 | #define DMITIGR_@dmitigr_lib_NAME@_VERSION_HPP 23 | 24 | #include 25 | 26 | namespace dmitigr::@dmitigr_lib_name@ { 27 | 28 | /// @returns The library version. 29 | constexpr std::int_fast32_t version() noexcept 30 | { 31 | // Actual values are set in CMakeLists.txt. 32 | constexpr std::int_least32_t major = @dmitigr_lib_version_major@; 33 | constexpr std::int_least32_t minor = @dmitigr_lib_version_minor@; 34 | constexpr std::int_least32_t patch = @dmitigr_lib_version_patch@; 35 | 36 | // 111.222.333 -> 111222333 37 | return major*1000000 + minor*1000 + patch; 38 | } 39 | 40 | } // namespace dmitigr::@dmitigr_lib_name@ 41 | 42 | #endif // DMITIGR_@dmitigr_lib_NAME@_VERSION_HPP 43 | -------------------------------------------------------------------------------- /src/version.rc.in: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 18 | // This file is generated automatically. Edit version.rc.in instead!!!!!!!!!!!!! 19 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 20 | 21 | #include 22 | 23 | #ifdef NDEBUG 24 | #define DMITIGR_@dmitigr_lib_NAME@_VERSION_DEBUG 0 25 | #define DMITIGR_@dmitigr_lib_NAME@_VERSION_ORIGINAL_FILENAME "@dmitigr_lib_internal_name@.dll\0" 26 | #else 27 | #define DMITIGR_@dmitigr_lib_NAME@_VERSION_DEBUG VS_FF_DEBUG 28 | #define DMITIGR_@dmitigr_lib_NAME@_VERSION_ORIGINAL_FILENAME "@dmitigr_lib_internal_name@d.dll\0" 29 | #endif 30 | 31 | VS_VERSION_INFO VERSIONINFO 32 | 33 | FILEVERSION @dmitigr_lib_version_major_hi@,@dmitigr_lib_version_major_lo@,@dmitigr_lib_version_minor_hi@,@dmitigr_lib_version_minor_lo@ 34 | PRODUCTVERSION @dmitigr_lib_version_major_hi@,@dmitigr_lib_version_major_lo@,@dmitigr_lib_version_minor_hi@,@dmitigr_lib_version_minor_lo@ 35 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 36 | FILEFLAGS (DMITIGR_@dmitigr_lib_NAME@_VERSION_DEBUG) 37 | FILEOS VOS__WINDOWS32 38 | FILETYPE VFT_DLL 39 | FILESUBTYPE 0x0L 40 | BEGIN 41 | BLOCK "StringFileInfo" 42 | BEGIN 43 | BLOCK "040904E4" 44 | BEGIN 45 | VALUE "CompanyName", "Dmitry Igrishin\0" 46 | VALUE "FileDescription", "@dmitigr_lib_description@\0" 47 | VALUE "FileVersion", "@dmitigr_lib_version_major@.@dmitigr_lib_version_minor@.@dmitigr_lib_version_patch@\0" 48 | VALUE "InternalName", "@dmitigr_lib_internal_name@\0" 49 | VALUE "LegalCopyright", "Copyright (C) Dmitry Igrishin\0" 50 | VALUE "LegalTrademarks", "\0" 51 | VALUE "OriginalFilename", DMITIGR_@dmitigr_lib_NAME@_VERSION_ORIGINAL_FILENAME 52 | VALUE "ProductName", "@dmitigr_lib_product_name@\0" 53 | VALUE "ProductVersion", "@dmitigr_lib_version_major@.@dmitigr_lib_version_minor@.@dmitigr_lib_version_patch@\0" 54 | END 55 | END 56 | BLOCK "VarFileInfo" 57 | BEGIN 58 | VALUE "Translation", 0x409, 1200 59 | END 60 | END 61 | -------------------------------------------------------------------------------- /test/fcgi/fcgi-hello.cpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #include "../../src/fcgi/fcgi.hpp" 18 | 19 | #include 20 | 21 | int main() 22 | { 23 | namespace fcgi = dmitigr::fcgi; 24 | try { 25 | const auto port = 9000; 26 | const auto backlog = 64; 27 | fcgi::Listener server{fcgi::Listener_options{"0.0.0.0", port, backlog}}; 28 | server.listen(); 29 | while (true) { 30 | if (const auto conn = server.accept()) { 31 | conn->out() << "Content-Type: text/plain" << fcgi::crlfcrlf; 32 | conn->out() << "Hello from dmitigr::fcgi!"; 33 | } 34 | } 35 | } catch (const std::exception& e) { 36 | std::cerr << "Oops: " << e.what() << std::endl; 37 | return 1; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/fcgi/fcgi-hellomt.cpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #include "../../src/fcgi/fcgi.hpp" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | namespace { 24 | 25 | constexpr std::size_t pool_size{64}; 26 | 27 | } // namespace 28 | 29 | int main() 30 | { 31 | namespace fcgi = dmitigr::fcgi; 32 | try { 33 | const auto serve = [](auto* const server) 34 | { 35 | while (true) { 36 | const auto conn = server->accept(); 37 | conn->out() << "Content-Type: text/plain" << fcgi::crlfcrlf; 38 | conn->out() << "Hello from dmitigr::fcgi!"; 39 | conn->close(); // Optional. 40 | } 41 | }; 42 | 43 | const auto port = 9000; 44 | const auto backlog = 64; 45 | std::clog << "Multi-threaded FastCGI server started:\n" 46 | << " port = " << port << "\n" 47 | << " backlog = " << backlog << "\n" 48 | << " thread pool size = " << pool_size << std::endl; 49 | 50 | fcgi::Listener server{fcgi::Listener_options{"0.0.0.0", port, backlog}}; 51 | server.listen(); 52 | std::vector threads(pool_size); 53 | for (auto& t : threads) 54 | t = std::thread{serve, &server}; 55 | 56 | for (auto& t : threads) 57 | t.join(); 58 | 59 | server.close(); // Optional. 60 | } catch (const std::exception& e) { 61 | std::cerr << "error: " << e.what() << std::endl; 62 | return 1; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /test/fcgi/fcgi-largesend.cpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #include "../../src/fcgi/fcgi.hpp" 18 | #include "../../src/rnd/string.hpp" 19 | 20 | #include 21 | 22 | int main() 23 | { 24 | namespace fcgi = dmitigr::fcgi; 25 | namespace rnd = dmitigr::rnd; 26 | 27 | rnd::seed_by_now(); 28 | std::streamsize str_size{100500}; 29 | try { 30 | const auto port = 9000; 31 | const auto backlog = 64; 32 | fcgi::Listener server{fcgi::Listener_options{"0.0.0.0", port, backlog}}; 33 | server.listen(); 34 | while (true) { 35 | if (const auto conn = server.accept()) { 36 | conn->out() << "Content-Type: text/plain" << fcgi::crlfcrlf; 37 | const std::string str = rnd::random_string("abc", str_size); 38 | conn->out() << str << "\n" << str_size; 39 | str_size += rnd::cpp_pl_3rd(str_size); 40 | } 41 | } 42 | } catch (const std::exception& e) { 43 | std::cerr << "Oops: " << e.what() << std::endl; 44 | return 1; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/fcgi/fcgi-overload.cpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #include "../../src/base/assert.hpp" 18 | #include "../../src/fcgi/fcgi.hpp" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | namespace { 27 | 28 | constexpr std::size_t pool_size = 64; 29 | 30 | class Busyness_counter { 31 | public: 32 | ~Busyness_counter() 33 | { 34 | assert(value_ >= 1); 35 | value_--; 36 | } 37 | 38 | Busyness_counter() 39 | { 40 | value_++; 41 | } 42 | 43 | static std::size_t value() 44 | { 45 | return value_; 46 | } 47 | 48 | private: 49 | static std::atomic value_; 50 | }; 51 | 52 | std::atomic Busyness_counter::value_{}; 53 | 54 | bool is_ready() 55 | { 56 | return Busyness_counter::value() <= pool_size; 57 | } 58 | 59 | } // namespace 60 | 61 | int main(int, char**) 62 | { 63 | namespace fcgi = dmitigr::fcgi; 64 | try { 65 | const auto serve = [](auto* const server) 66 | { 67 | while (true) { 68 | const auto conn = server->accept(); 69 | if (is_ready()) { 70 | const Busyness_counter counter; 71 | conn->out() << "Content-Type: text/plain" << fcgi::crlfcrlf; 72 | // Simulate being busy. 73 | std::this_thread::sleep_for(std::chrono::milliseconds{50}); 74 | conn->out() << "Hello from dmitigr::fcgi!" << fcgi::crlf; 75 | } else 76 | // Report "Service Unavailable". 77 | conn->out() << "Status: 503" << fcgi::crlfcrlf; 78 | conn->close(); // optional. 79 | } 80 | }; 81 | 82 | const auto port = 9000; 83 | const auto backlog = 64; 84 | const auto overload_pool_size = std::thread::hardware_concurrency(); 85 | std::clog << "Multi-threaded FastCGI server started:\n" 86 | << " port = " << port << "\n" 87 | << " backlog = " << backlog << "\n" 88 | << " working thread pool size = " << pool_size << "\n" 89 | << " overload thread pool size = " << overload_pool_size << std::endl; 90 | 91 | fcgi::Listener server{fcgi::Listener_options{"0.0.0.0", port, backlog}}; 92 | DMITIGR_ASSERT(!server.is_listening()); 93 | server.listen(); 94 | DMITIGR_ASSERT(server.is_listening()); 95 | 96 | std::vector threads(pool_size + overload_pool_size); 97 | for (auto& t : threads) 98 | t = std::thread{serve, &server}; 99 | 100 | for (auto& t : threads) 101 | t.join(); 102 | 103 | server.close(); 104 | DMITIGR_ASSERT(!server.is_listening()); 105 | } catch (const std::exception& e) { 106 | std::cerr << e.what() << std::endl; 107 | return 1; 108 | } catch (...) { 109 | std::cerr << "unknown error" << std::endl; 110 | return 2; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /test/math/math-unit-test.cpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #include "../../src/base/assert.hpp" 18 | #include "../../src/math/math.hpp" 19 | 20 | #include 21 | #include 22 | 23 | int main() 24 | { 25 | try { 26 | namespace math = dmitigr::math; 27 | 28 | // avg 29 | { 30 | constexpr auto a1 = math::avg(std::array{1,2,3,4,5}); 31 | static_assert(static_cast(a1) == static_cast(3)); 32 | const auto a2 = math::avg(std::vector{1,2,3,4,5}); 33 | DMITIGR_ASSERT(a2 == static_cast(3)); 34 | } 35 | 36 | // variance 1 37 | { 38 | constexpr auto d1 = math::variance(std::array{1,2,3,4,5}); 39 | static_assert(static_cast(d1) == static_cast(2)); 40 | const auto d2 = math::variance(std::vector{1,2,3,4,5}); 41 | DMITIGR_ASSERT(d2 == static_cast(2)); 42 | constexpr auto d3 = math::variance(std::array{600,470,170,430,300}); 43 | static_assert(static_cast(d3) == static_cast(21704)); 44 | } 45 | 46 | // variance 2 47 | { 48 | constexpr auto d1 = math::variance(std::array{1,2,3,4,5}, false); 49 | static_assert(static_cast(d1) == static_cast(2)); 50 | const auto d2 = math::variance(std::vector{1,2,3,4,5}); 51 | DMITIGR_ASSERT(d2 == static_cast(2)); 52 | constexpr auto d3 = math::variance(std::array{600,470,170,430,300}); 53 | static_assert(static_cast(d3) == static_cast(21704)); 54 | } 55 | 56 | // ------------------------------------------------------------------------- 57 | // Interval 58 | // ------------------------------------------------------------------------- 59 | 60 | using math::Interval; 61 | using math::Interval_type; 62 | 63 | { 64 | Interval i; 65 | DMITIGR_ASSERT(i.type() == Interval_type::closed); 66 | DMITIGR_ASSERT(i.min() == 0); 67 | DMITIGR_ASSERT(i.max() == 0); 68 | } 69 | { 70 | Interval i{Interval_type::ropen, 0, 3}; 71 | DMITIGR_ASSERT(i.type() == Interval_type::ropen); 72 | DMITIGR_ASSERT(i.min() == 0); 73 | DMITIGR_ASSERT(i.max() == 3); 74 | DMITIGR_ASSERT(!i.has(-1)); 75 | DMITIGR_ASSERT(i.has(0)); 76 | DMITIGR_ASSERT(i.has(1)); 77 | DMITIGR_ASSERT(i.has(2)); 78 | DMITIGR_ASSERT(!i.has(3)); 79 | } 80 | { 81 | Interval i{Interval_type::lopen, 0, 3}; 82 | DMITIGR_ASSERT(i.type() == Interval_type::lopen); 83 | DMITIGR_ASSERT(i.min() == 0); 84 | DMITIGR_ASSERT(i.max() == 3); 85 | DMITIGR_ASSERT(!i.has(-1)); 86 | DMITIGR_ASSERT(!i.has(0)); 87 | DMITIGR_ASSERT(i.has(1)); 88 | DMITIGR_ASSERT(i.has(2)); 89 | DMITIGR_ASSERT(i.has(3)); 90 | DMITIGR_ASSERT(!i.has(4)); 91 | const auto [min, max] = i.release(); 92 | DMITIGR_ASSERT(min == 0); 93 | DMITIGR_ASSERT(max == 3); 94 | DMITIGR_ASSERT(i.type() == Interval_type::closed); 95 | DMITIGR_ASSERT(i.min() == 0); 96 | DMITIGR_ASSERT(i.max() == 0); 97 | } 98 | { 99 | Interval i{Interval_type::open, .0f, 1.0f}; 100 | DMITIGR_ASSERT(i.type() == Interval_type::open); 101 | DMITIGR_ASSERT(!i.has(-.3f)); 102 | DMITIGR_ASSERT(i.has(.3f)); 103 | DMITIGR_ASSERT(!i.has(1.3f)); 104 | } 105 | } catch (const std::exception& e) { 106 | std::cerr << e.what() << std::endl; 107 | return 1; 108 | } catch (...) { 109 | std::cerr << "unknown error" << std::endl; 110 | return 2; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /test/net/net-unit-net.cpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #include "../../src/base/assert.hpp" 18 | #include "../../src/net/net.hpp" 19 | 20 | int main() 21 | { 22 | try { 23 | namespace net = dmitigr::net; 24 | 25 | const std::string v4_addr_str{"192.168.1.2"}; 26 | DMITIGR_ASSERT(net::Ip_address::is_valid(v4_addr_str)); 27 | 28 | auto ip = net::Ip_address::from_text(v4_addr_str); 29 | DMITIGR_ASSERT(ip); 30 | DMITIGR_ASSERT(ip.is_valid()); 31 | DMITIGR_ASSERT(ip.family() == net::Protocol_family::ipv4); 32 | DMITIGR_ASSERT(ip.binary()); 33 | DMITIGR_ASSERT(ip.to_string() == v4_addr_str); 34 | 35 | const std::string invalid_v4_addr_str{"256.168.1.2"}; 36 | DMITIGR_ASSERT(!net::Ip_address::is_valid(invalid_v4_addr_str)); 37 | 38 | const std::string v6_addr_str{"fe80::1:2:3:4"}; 39 | ip = net::Ip_address::from_text(v6_addr_str); 40 | DMITIGR_ASSERT(ip.family() == net::Protocol_family::ipv6); 41 | DMITIGR_ASSERT(ip.binary()); 42 | DMITIGR_ASSERT(ip.to_string() == v6_addr_str); 43 | 44 | const int n = 10; 45 | auto n1 = net::conv(n); 46 | DMITIGR_ASSERT(n != n1); 47 | n1 = net::conv(n1); 48 | DMITIGR_ASSERT(n == n1); 49 | 50 | const float f = 123.456; 51 | auto f1 = net::conv(f); 52 | DMITIGR_ASSERT(f != f1); 53 | f1 = net::conv(f1); 54 | DMITIGR_ASSERT(f == f1); 55 | } catch (const std::exception& e) { 56 | std::cerr << e.what() << std::endl; 57 | return 1; 58 | } catch (...) { 59 | std::cerr << "unknown error" << std::endl; 60 | return 2; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /test/rnd/rnd-uuid.cpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #include "../../src/base/assert.hpp" 18 | #include "../../src/rnd/uuid.hpp" 19 | 20 | int main() 21 | { 22 | try { 23 | namespace rnd = dmitigr::rnd; 24 | rnd::seed_by_now(); 25 | const auto u = rnd::Uuid::make_v4(); 26 | const auto s = u.to_string(); 27 | DMITIGR_ASSERT(s.size() == 36); 28 | std::cout << s << std::endl; 29 | } catch (const std::exception& e) { 30 | std::cerr << e.what() << std::endl; 31 | return 1; 32 | } catch (...) { 33 | std::cerr << "unknown error" << std::endl; 34 | return 2; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test/util/util-diag.cpp: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | // 3 | // Copyright 2022 Dmitry Igrishin 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | #include "../../src/util/diagnostic.hpp" 18 | 19 | #include 20 | #include 21 | 22 | int main() 23 | { 24 | const auto t = dmitigr::util::with_measure([] 25 | { 26 | std::this_thread::sleep_for(std::chrono::milliseconds{10}); 27 | }); 28 | std::cout << t.count() << std::endl; 29 | } 30 | --------------------------------------------------------------------------------