├── .clang-format ├── .clang-tidy ├── .conan ├── build.py └── test_package │ ├── CMakeLists.txt │ ├── conanfile.py │ └── test_package.cpp ├── .github ├── FUNDING.yml └── workflows │ ├── build-macos.yml │ ├── build-meson.yml │ ├── build-ubuntu.yml │ ├── build-win.yml │ ├── coverage.yml │ ├── deploy.yml │ ├── sanitizer.yml │ └── tools.yml ├── .gitignore ├── AUTHORS ├── CMakeLists.txt ├── CMakePresets.json ├── LICENSE ├── README.md ├── TODO ├── build └── .gitignore ├── conanfile.py ├── docs ├── CMakeLists.txt ├── doxy.in └── extra.dox ├── meson.build ├── src ├── CMakeLists.txt ├── uvw.hpp └── uvw │ ├── async.cpp │ ├── async.h │ ├── async.ipp │ ├── check.cpp │ ├── check.h │ ├── check.ipp │ ├── config.h │ ├── dns.cpp │ ├── dns.h │ ├── dns.ipp │ ├── emitter.cpp │ ├── emitter.h │ ├── emitter.ipp │ ├── enum.hpp │ ├── fs.cpp │ ├── fs.h │ ├── fs.ipp │ ├── fs_event.cpp │ ├── fs_event.h │ ├── fs_event.ipp │ ├── fs_poll.cpp │ ├── fs_poll.h │ ├── fs_poll.ipp │ ├── handle.hpp │ ├── idle.cpp │ ├── idle.h │ ├── idle.ipp │ ├── lib.cpp │ ├── lib.h │ ├── lib.ipp │ ├── loop.cpp │ ├── loop.h │ ├── loop.ipp │ ├── pipe.cpp │ ├── pipe.h │ ├── pipe.ipp │ ├── poll.cpp │ ├── poll.h │ ├── poll.ipp │ ├── prepare.cpp │ ├── prepare.h │ ├── prepare.ipp │ ├── process.cpp │ ├── process.h │ ├── process.ipp │ ├── request.hpp │ ├── resource.hpp │ ├── signal.cpp │ ├── signal.h │ ├── signal.ipp │ ├── stream.cpp │ ├── stream.h │ ├── stream.ipp │ ├── tcp.cpp │ ├── tcp.h │ ├── tcp.ipp │ ├── thread.cpp │ ├── thread.h │ ├── thread.ipp │ ├── timer.cpp │ ├── timer.h │ ├── timer.ipp │ ├── tty.cpp │ ├── tty.h │ ├── tty.ipp │ ├── type_info.hpp │ ├── udp.cpp │ ├── udp.h │ ├── udp.ipp │ ├── util.cpp │ ├── util.h │ ├── util.ipp │ ├── uv_type.hpp │ ├── work.cpp │ ├── work.h │ └── work.ipp ├── subprojects ├── .gitignore └── libuv.wrap ├── test ├── CMakeLists.txt ├── fake.cpp ├── main.cpp ├── odr.cpp └── uvw │ ├── async.cpp │ ├── check.cpp │ ├── dns.cpp │ ├── emitter.cpp │ ├── file_req.cpp │ ├── file_req_sendfile.cpp │ ├── fs_event.cpp │ ├── fs_req.cpp │ ├── handle.cpp │ ├── idle.cpp │ ├── lib.cpp │ ├── loop.cpp │ ├── pipe.cpp │ ├── prepare.cpp │ ├── process.cpp │ ├── request.cpp │ ├── resource.cpp │ ├── signal.cpp │ ├── stream.cpp │ ├── tcp.cpp │ ├── thread.cpp │ ├── timer.cpp │ ├── tty.cpp │ ├── udp.cpp │ ├── util.cpp │ ├── uv_type.cpp │ └── work.cpp └── uvw.imp /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: llvm 2 | --- 3 | AccessModifierOffset: -4 4 | AlignEscapedNewlines: DontAlign 5 | AllowShortBlocksOnASingleLine: Empty 6 | AllowShortEnumsOnASingleLine: true 7 | AllowShortFunctionsOnASingleLine: Empty 8 | AllowShortIfStatementsOnASingleLine: WithoutElse 9 | AllowShortLoopsOnASingleLine: true 10 | AlwaysBreakTemplateDeclarations: Yes 11 | BreakBeforeBinaryOperators: NonAssignment 12 | BreakBeforeTernaryOperators: true 13 | ColumnLimit: 0 14 | DerivePointerAlignment: false 15 | IncludeCategories: 16 | - Regex: '<[[:alnum:]_]+>' 17 | Priority: 1 18 | - Regex: '<(gtest|gmock)/' 19 | Priority: 2 20 | - Regex: '<[[:alnum:]_./]+>' 21 | Priority: 3 22 | - Regex: ' 2 | bugprone-*, 3 | -bugprone-easily-swappable-parameters, 4 | concurrency-*, 5 | modernize-*, 6 | -modernize-avoid-c-arrays, 7 | -modernize-use-trailing-return-type, 8 | performance-*, 9 | portability-*, 10 | CheckOptions: 11 | - key: bugprone-suspicious-include.HeaderFileExtensions 12 | value: ";h;hpp;ipp" 13 | -------------------------------------------------------------------------------- /.conan/build.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import re 6 | import platform 7 | from cpt.packager import ConanMultiPackager 8 | 9 | 10 | def get_version(): 11 | with open("CMakeLists.txt") as cmake: 12 | content = cmake.read() 13 | match = re.search(r'project\(uvw VERSION (.*)\)', content) 14 | if match: 15 | return match.group(1) 16 | tag_version = os.getenv("GITHUB_REF") 17 | package_version = tag_version.replace("refs/tags/v", "") 18 | return package_version 19 | 20 | def get_username(): 21 | return os.getenv("CONAN_USERNAME", "skypjack") 22 | 23 | 24 | def get_reference(): 25 | version = get_version() 26 | username = get_username() 27 | return "uvw/{}@{}/stable".format(version, username) 28 | 29 | 30 | def get_upload(): 31 | username = get_username() 32 | url = "https://api.bintray.com/conan/{}/conan".format(username) 33 | default_upload = url if os.getenv("GITHUB_REF") else False 34 | return os.getenv("CONAN_UPLOAD", default_upload) 35 | 36 | 37 | def upload_when_stable(): 38 | return os.getenv("CONAN_UPLOAD_ONLY_WHEN_STABLE", "1").lower() not in ["0", "false", "no"] 39 | 40 | 41 | if __name__ == "__main__": 42 | test_folder = os.path.join(".conan", "test_package") 43 | builder = ConanMultiPackager(reference=get_reference(), 44 | username=get_username(), 45 | upload=get_upload(), 46 | test_folder=test_folder, 47 | stable_branch_pattern=r'v?\d+\.\d+\.\d+.*', 48 | upload_only_when_stable=upload_when_stable()) 49 | if platform.system() == "Linux": 50 | builder.add(settings={"compiler": "gcc", "compiler.version": "8", 51 | "arch": "x86_64", "build_type": "Release"}, 52 | options={}, env_vars={}, build_requires={}) 53 | builder.run() 54 | -------------------------------------------------------------------------------- /.conan/test_package/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(test_package) 2 | cmake_minimum_required(VERSION 2.8) 3 | 4 | set(CMAKE_VERBOSE_MAKEFILE TRUE) 5 | 6 | include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) 7 | conan_basic_setup(TARGETS) 8 | 9 | add_executable(${PROJECT_NAME} test_package.cpp) 10 | target_link_libraries(${PROJECT_NAME} CONAN_PKG::uvw) -------------------------------------------------------------------------------- /.conan/test_package/conanfile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | from conans import ConanFile, CMake 6 | 7 | class TestPackageConan(ConanFile): 8 | settings = "os", "compiler", "build_type", "arch" 9 | generators = "cmake" 10 | 11 | def build(self): 12 | cmake = CMake(self) 13 | cmake.configure() 14 | cmake.build() 15 | 16 | def test(self): 17 | test_package = os.path.join("bin", "test_package") 18 | self.run(test_package, run_environment=True) 19 | -------------------------------------------------------------------------------- /.conan/test_package/test_package.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void listen(uvw::loop &loop) { 7 | std::shared_ptr tcp = loop.resource(); 8 | 9 | tcp->on([](const uvw::listen_event &, uvw::tcp_handle &srv) { 10 | std::shared_ptr client = srv.loop().resource(); 11 | 12 | client->on([ptr = srv.shared_from_this()](const uvw::close_event &, uvw::tcp_handle &) { ptr->close(); }); 13 | client->on([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); }); 14 | 15 | srv.accept(*client); 16 | client->read(); 17 | }); 18 | 19 | tcp->bind("127.0.0.1", 4242); 20 | tcp->listen(); 21 | } 22 | 23 | void conn(uvw::loop &loop) { 24 | auto tcp = loop.resource(); 25 | 26 | tcp->on([](const uvw::error_event &, uvw::tcp_handle &) { /* handle errors */ }); 27 | 28 | tcp->on([](const uvw::connect_event &, uvw::tcp_handle &tcp) { 29 | auto dataWrite = std::unique_ptr(new char[2]{ 'b', 'c' }); 30 | tcp.write(std::move(dataWrite), 2); 31 | tcp.close(); 32 | }); 33 | 34 | tcp->connect(std::string{"127.0.0.1"}, 4242); 35 | } 36 | 37 | int main() { 38 | std::cout << "Getting UVW loop ...\n"; 39 | auto loop = uvw::loop::get_default(); 40 | std::cout << "Staring UVW listener ...\n"; 41 | listen(*loop); 42 | std::cout << "Connecting ...\n"; 43 | conn(*loop); 44 | loop->run(); 45 | std::cout << "Done!\n"; 46 | 47 | return EXIT_SUCCESS; 48 | } 49 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: skypjack 4 | patreon: 5 | open_collective: 6 | ko_fi: 7 | tidelift: 8 | community_bridge: 9 | liberapay: 10 | issuehunt: 11 | otechie: 12 | custom: https://www.paypal.me/skypjack 13 | -------------------------------------------------------------------------------- /.github/workflows/build-macos.yml: -------------------------------------------------------------------------------- 1 | name: build-macos 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | 7 | macos: 8 | timeout-minutes: 60 9 | runs-on: macOS-latest 10 | 11 | strategy: 12 | matrix: 13 | mode: [-DUVW_BUILD_SHARED_LIB=ON, -DUVW_BUILD_LIBS=ON, -DUVW_BUILD_LIBS=OFF] 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | - name: Compile tests 18 | working-directory: build 19 | run: | 20 | cmake ${{ matrix.mode }} -DUVW_BUILD_TESTING=ON -Dlibuv_buildtests=OFF .. 21 | make -j2 22 | -------------------------------------------------------------------------------- /.github/workflows/build-meson.yml: -------------------------------------------------------------------------------- 1 | name: build-meson 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | meson: 7 | if: false # This disables the entire workflow 8 | timeout-minutes: 60 9 | runs-on: ubuntu-22.04 10 | steps: 11 | - uses: actions/checkout@v4 12 | - name: Install Meson 13 | env: 14 | DEBIAN_FRONTEND: noninteractive 15 | run: | 16 | sudo apt-get update --fix-missing 17 | sudo apt-get install -y meson 18 | - name: Meson Build (shared) 19 | run: | 20 | meson setup build 21 | meson compile -C build 22 | - name: Meson Build (static) 23 | run: | 24 | rm -rf build/ 25 | meson setup build --default-library=static 26 | meson compile -C build 27 | -------------------------------------------------------------------------------- /.github/workflows/build-ubuntu.yml: -------------------------------------------------------------------------------- 1 | name: build-ubuntu-latest 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | 7 | linux: 8 | timeout-minutes: 60 9 | strategy: 10 | matrix: 11 | compiler: 12 | - { pkg: g++, exe: 'g++', version: 12 } 13 | - { pkg: g++, exe: 'g++', version: 13 } 14 | - { pkg: g++, exe: 'g++', version: 14 } 15 | - { pkg: clang, exe: 'clang++', version: 16 } 16 | - { pkg: clang, exe: 'clang++', version: 17 } 17 | - { pkg: clang, exe: 'clang++', version: 18 } 18 | mode: [-DUVW_BUILD_SHARED_LIB=ON, -DUVW_BUILD_LIBS=ON, -DUVW_BUILD_LIBS=OFF] 19 | 20 | runs-on: ubuntu-latest 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | - name: Install ${{ matrix.compiler.exe }} 25 | run: | 26 | sudo apt-get update --fix-missing 27 | sudo apt install -y ${{ matrix.compiler.pkg }}-${{ matrix.compiler.version }} 28 | - name: Compile tests 29 | env: 30 | CXX: ${{ matrix.compiler.exe }}-${{ matrix.compiler.version }} 31 | run: | 32 | cmake ${{ matrix.mode }} --preset ci-ubuntu 33 | cmake --build build/ --parallel 2 34 | - name: Run tests 35 | working-directory: build 36 | env: 37 | CTEST_OUTPUT_ON_FAILURE: 1 38 | run: ctest --timeout 5 -C Debug -j2 39 | -------------------------------------------------------------------------------- /.github/workflows/build-win.yml: -------------------------------------------------------------------------------- 1 | name: build-win 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | 7 | windows: 8 | timeout-minutes: 60 9 | runs-on: windows-latest 10 | 11 | strategy: 12 | matrix: 13 | generator: [Visual Studio 17 2022] 14 | mode: [-DUVW_BUILD_SHARED_LIB=ON, -DUVW_BUILD_LIBS=ON, -DUVW_BUILD_LIBS=OFF] 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | - name: Compile tests 19 | working-directory: build 20 | run: | 21 | cmake -DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=TRUE ${{ matrix.mode }} -DUVW_BUILD_TESTING=ON -Dlibuv_buildtests=OFF -DCMAKE_CXX_FLAGS=/W1 -G"${{ matrix.generator }}" .. 22 | cmake --build . -j 2 23 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: coverage 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | 7 | codecov: 8 | timeout-minutes: 30 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Compile tests 14 | working-directory: build 15 | env: 16 | CXXFLAGS: "-O0 --coverage -fno-inline -fno-inline-small-functions -fno-default-inline" 17 | CXX: g++ 18 | run: | 19 | cmake -DUVW_BUILD_TESTING=ON -Dlibuv_buildtests=OFF .. 20 | make -j4 21 | - name: Run tests 22 | working-directory: build 23 | env: 24 | CTEST_OUTPUT_ON_FAILURE: 1 25 | run: ctest --timeout 5 -C Debug -j4 26 | - name: Upload coverage to Codecov 27 | working-directory: build 28 | env: 29 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 30 | run: | 31 | wget https://codecov.io/bash -O codecov 32 | chmod +x codecov 33 | ./codecov -t $CODECOV_TOKEN -B $GITHUB_REF -s . 34 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: deploy 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | 8 | jobs: 9 | 10 | conan: 11 | timeout-minutes: 5 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: docker://conanio/gcc8 16 | - uses: actions/checkout@v4 17 | - name: Setup Python 18 | uses: actions/setup-python@master 19 | with: 20 | version: 3.7 21 | - name: Install 22 | run: | 23 | pip install --upgrade wheel 24 | pip install conan_package_tools 25 | - name: Deploy 26 | env: 27 | CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_LOGIN_USERNAME }} 28 | CONAN_PASSWORD: ${{ secrets.CONAN_PASSWORD }} 29 | CONAN_UPLOAD: ${{ secrets.CONAN_UPLOAD }} 30 | CONAN_GCC_VERSIONS: 8 31 | run: | 32 | python .conan/build.py 33 | -------------------------------------------------------------------------------- /.github/workflows/sanitizer.yml: -------------------------------------------------------------------------------- 1 | name: sanitizer 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | 7 | clang: 8 | timeout-minutes: 15 9 | 10 | strategy: 11 | matrix: 12 | compiler: [clang++] 13 | sanitizer: [ASAN, UBSAN] 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: Compile tests 20 | working-directory: build 21 | env: 22 | CXX: ${{ matrix.compiler }} 23 | run: | 24 | cmake ${{ matrix.mode }} -DUVW_BUILD_TESTING=ON -DUVW_USE_${{ matrix.sanitizer }}=ON -Dlibuv_buildtests=OFF .. 25 | make -j2 26 | - name: Run tests 27 | working-directory: build 28 | env: 29 | CTEST_OUTPUT_ON_FAILURE: 1 30 | run: ctest --timeout 5 -C Debug -j2 31 | -------------------------------------------------------------------------------- /.github/workflows/tools.yml: -------------------------------------------------------------------------------- 1 | name: tools 2 | 3 | on: 4 | push: 5 | branches: 6 | - tools 7 | 8 | jobs: 9 | 10 | iwyu: 11 | timeout-minutes: 60 12 | 13 | env: 14 | IWYU: "0.22" 15 | LLVM: "18" 16 | 17 | runs-on: ubuntu-latest 18 | continue-on-error: true 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | - name: Install llvm/clang 23 | # see: https://apt.llvm.org/ 24 | run: | 25 | wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - 26 | sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-$LLVM main" 27 | sudo apt update 28 | sudo apt remove -y "llvm*" 29 | sudo apt remove -y "libclang-dev*" 30 | sudo apt remove -y "clang*" 31 | sudo apt install -y llvm-$LLVM-dev 32 | sudo apt install -y libclang-$LLVM-dev 33 | sudo apt install -y clang-$LLVM 34 | - name: Compile iwyu 35 | # see: https://github.com/include-what-you-use/include-what-you-use 36 | working-directory: build 37 | run: | 38 | git clone https://github.com/include-what-you-use/include-what-you-use.git --branch $IWYU --depth 1 39 | mkdir include-what-you-use/build 40 | cd include-what-you-use/build 41 | cmake -DCMAKE_C_COMPILER=clang-$LLVM \ 42 | -DCMAKE_CXX_COMPILER=clang++-$LLVM \ 43 | -DCMAKE_INSTALL_PREFIX=./ \ 44 | .. 45 | make -j4 46 | bin/include-what-you-use --version 47 | - name: Compile tests 48 | working-directory: build 49 | run: | 50 | export PATH=$PATH:${GITHUB_WORKSPACE}/build/include-what-you-use/build/bin 51 | cmake -DUVW_BUILD_TESTING=ON \ 52 | -Dlibuv_buildtests=OFF \ 53 | -DCMAKE_C_COMPILER=clang-$LLVM \ 54 | -DCMAKE_CXX_COMPILER=clang++-$LLVM \ 55 | -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="include-what-you-use;-Xiwyu;--mapping_file=${GITHUB_WORKSPACE}/uvw.imp;-Xiwyu;--no_fwd_decls;-Xiwyu;--verbose=1" \ 56 | .. 57 | make -j4 58 | 59 | clang-tidy: 60 | timeout-minutes: 60 61 | 62 | runs-on: ubuntu-latest 63 | continue-on-error: true 64 | 65 | steps: 66 | - uses: actions/checkout@v4 67 | - name: Compile tests 68 | working-directory: build 69 | env: 70 | CXX: clang++ 71 | run: | 72 | cmake -DUVW_BUILD_TESTING=ON -DUVW_USE_CLANG_TIDY=ON -Dlibuv_buildtests=OFF .. 73 | make -j4 74 | - name: Run tests 75 | working-directory: build 76 | env: 77 | CTEST_OUTPUT_ON_FAILURE: 1 78 | run: ctest -C Debug -j4 79 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.user 2 | CMakeSettings.json 3 | .conan/test_package/build 4 | cmake-build-debug/ 5 | .idea/ 6 | .vs/ 7 | .vscode/ 8 | .cache/ 9 | out/ 10 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # Author 2 | 3 | skypjack 4 | 5 | # Collaborators 6 | 7 | morbo84 8 | stefanofiorentino 9 | 10 | # Contributors 11 | 12 | lessness 13 | lordlukas 14 | lpmi-13 15 | Zikoel 16 | fradefe 17 | tusharpm 18 | fcelda 19 | raoul 20 | filonik 21 | yisonPylkita 22 | Miigon 23 | slyshykO 24 | bmagistro 25 | richardbmx 26 | wnsgml972 27 | ffontaine 28 | elindsey 29 | erez-o 30 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # uvw 3 | # 4 | 5 | cmake_minimum_required(VERSION 3.13) 6 | 7 | # 8 | # Building in-tree is not allowed (we take care of your craziness). 9 | # 10 | 11 | if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) 12 | message(FATAL_ERROR "Prevented in-tree built. Please create a build directory outside of the source code and call cmake from there. Thank you.") 13 | endif() 14 | 15 | # 16 | # Project configuration 17 | # 18 | set(UVW_VERSION_MAJOR 3) 19 | set(UVW_VERSION_MINOR 5) 20 | set(UVW_VERSION_PATCH 0) 21 | 22 | project( 23 | uvw 24 | VERSION ${UVW_VERSION_MAJOR}.${UVW_VERSION_MINOR}.${UVW_VERSION_PATCH} 25 | DESCRIPTION "Header-only, event based, tiny and easy to use libuv wrapper in modern C++ - now available also as static library!" 26 | HOMEPAGE_URL "https://github.com/skypjack/uvw" 27 | LANGUAGES C CXX 28 | ) 29 | 30 | if(NOT CMAKE_BUILD_TYPE) 31 | set(CMAKE_BUILD_TYPE Debug) 32 | endif() 33 | 34 | option(UVW_USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if available." ON) 35 | option(UVW_USE_ASAN "Use address sanitizer by adding -fsanitize=address -fno-omit-frame-pointer flags" OFF) 36 | option(UVW_USE_UBSAN "Use address sanitizer by adding -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer flags" OFF) 37 | option(UVW_USE_CLANG_TIDY "Enable static analysis with clang-tidy" OFF) 38 | option(UVW_BUILD_LIBS "Prepare targets for static library rather than for a header-only library." OFF) 39 | option(UVW_BUILD_SHARED_LIB "Prepare targets for shared library rather than for a header-only library." OFF) 40 | option(UVW_FIND_LIBUV "Try finding libuv library development files in the system" OFF) 41 | 42 | if(UVW_BUILD_SHARED_LIB) 43 | set(UVW_BUILD_LIBS BOOL:ON) 44 | endif() 45 | 46 | # 47 | # Compiler stuff 48 | # 49 | 50 | if(NOT WIN32 AND UVW_USE_LIBCPP) 51 | include(CheckCXXSourceCompiles) 52 | include(CMakePushCheckState) 53 | 54 | cmake_push_check_state() 55 | 56 | set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -stdlib=libc++") 57 | 58 | check_cxx_source_compiles(" 59 | #include 60 | int main() { return std::is_same_v; } 61 | " UVW_HAS_LIBCPP) 62 | 63 | if(NOT UVW_HAS_LIBCPP) 64 | message(WARNING "The option UVW_USE_LIBCPP is set (by default) but libc++ is not available. The flag will not be added to the target.") 65 | endif() 66 | 67 | cmake_pop_check_state() 68 | endif() 69 | 70 | if(UVW_USE_CLANG_TIDY) 71 | find_program(UVW_CLANG_TIDY_EXECUTABLE "clang-tidy") 72 | 73 | if(NOT UVW_CLANG_TIDY_EXECUTABLE) 74 | message(VERBOSE "The option UVW_USE_CLANG_TIDY is set but clang-tidy executable is not available.") 75 | endif() 76 | endif() 77 | 78 | # Required minimal libuv version 79 | set(UVW_LIBUV_VERSION 1.50.0) 80 | 81 | function(fetch_libuv) 82 | if (UVW_FETCH_LIBUV) 83 | include(FetchContent) 84 | 85 | FetchContent_Declare( 86 | libuv 87 | GIT_REPOSITORY https://github.com/libuv/libuv.git 88 | GIT_TAG "v${UVW_LIBUV_VERSION}" 89 | GIT_SHALLOW 1 90 | ) 91 | 92 | FetchContent_GetProperties(libuv) 93 | 94 | if(NOT libuv_POPULATED) 95 | FetchContent_Populate(libuv) 96 | add_subdirectory(${libuv_SOURCE_DIR} ${libuv_BINARY_DIR} EXCLUDE_FROM_ALL) 97 | endif() 98 | 99 | if(UVW_BUILD_SHARED_LIB) 100 | add_library(uv::uv-shared ALIAS uv) 101 | set_target_properties(uv PROPERTIES POSITION_INDEPENDENT_CODE 1) 102 | else() 103 | add_library(uv::uv-static ALIAS uv_a) 104 | set_target_properties(uv_a PROPERTIES POSITION_INDEPENDENT_CODE 1) 105 | endif() 106 | endif(UVW_FETCH_LIBUV) 107 | endfunction() 108 | 109 | function(use_libuv) 110 | set(UVW_FETCH_LIBUV_DEFAULT ON) 111 | 112 | if (UVW_FIND_LIBUV) 113 | find_package(libuv ${LIBUV_VERSION} QUIET) 114 | if (libuv_FOUND) 115 | add_library(uv::uv-shared ALIAS uv) 116 | set(UVW_FETCH_LIBUV_DEFAULT OFF) 117 | message(STATUS "libuv ${libuv_VERSION} found via cmake") 118 | else(libuv_FOUND) 119 | find_package(PkgConfig QUIET) 120 | if (PkgConfig_FOUND) 121 | pkg_check_modules(libuv IMPORTED_TARGET libuv>=${LIBUV_VERSION}) 122 | if (libuv_FOUND) 123 | add_library(uv::uv-shared ALIAS PkgConfig::libuv) 124 | set(UVW_FETCH_LIBUV_DEFAULT OFF) 125 | message(STATUS "libuv ${libuv_VERSION} found via pkg-config") 126 | endif(libuv_FOUND) 127 | endif(PkgConfig_FOUND) 128 | endif(libuv_FOUND) 129 | endif(UVW_FIND_LIBUV) 130 | 131 | option(UVW_FETCH_LIBUV "Fetch the libuv repo using CMake FetchContent facility" ${UVW_FETCH_LIBUV_DEFAULT}) 132 | 133 | fetch_libuv() 134 | endfunction() 135 | 136 | # 137 | # Add uvw target 138 | # 139 | 140 | include(GNUInstallDirs) 141 | 142 | if(UVW_BUILD_LIBS) 143 | use_libuv() 144 | 145 | add_subdirectory(src) 146 | file(GLOB HEADERS src/uvw/*.h src/uvw/*.hpp) 147 | else() 148 | add_library(uvw INTERFACE) 149 | add_library(uvw::uvw ALIAS uvw) 150 | 151 | target_compile_features(uvw INTERFACE cxx_std_17) 152 | 153 | target_include_directories( 154 | uvw 155 | INTERFACE 156 | $ 157 | $ 158 | ) 159 | 160 | if(UVW_USE_ASAN) 161 | target_compile_options(uvw INTERFACE $<$:-fsanitize=address -fno-omit-frame-pointer>) 162 | target_link_libraries(uvw INTERFACE $<$:-fsanitize=address>) 163 | endif() 164 | 165 | if(UVW_USE_UBSAN) 166 | target_compile_options(uvw INTERFACE $<$:-fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer>) 167 | target_link_libraries(uvw INTERFACE $<$:-fsanitize=undefined>) 168 | endif() 169 | 170 | if(UVW_CLANG_TIDY_EXECUTABLE) 171 | set(CMAKE_CXX_CLANG_TIDY "${UVW_CLANG_TIDY_EXECUTABLE};--config-file=${uvw_SOURCE_DIR}/.clang-tidy;--header-filter=${uvw_SOURCE_DIR}/src/uvw/.*") 172 | endif() 173 | 174 | if(UVW_HAS_LIBCPP) 175 | target_compile_options(uvw BEFORE INTERFACE -stdlib=libc++) 176 | endif() 177 | 178 | file(GLOB HEADERS src/uvw/*.h src/uvw/*.hpp) 179 | endif() 180 | 181 | # 182 | # Install targets 183 | # 184 | 185 | install( 186 | FILES ${HEADERS} 187 | COMPONENT ${PROJECT_NAME} 188 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/uvw 189 | PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ 190 | ) 191 | 192 | install( 193 | FILES src/uvw.hpp 194 | COMPONENT ${PROJECT_NAME} 195 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 196 | PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ 197 | ) 198 | 199 | # 200 | # Install targets 201 | # 202 | 203 | if (UVW_BUILD_LIBS) 204 | set_target_properties( 205 | uvw PROPERTIES 206 | VERSION ${UVW_VERSION_MAJOR}.${UVW_VERSION_MINOR}.${UVW_VERSION_PATCH} 207 | SOVERSION ${UVW_VERSION_MAJOR} 208 | ) 209 | endif() 210 | 211 | install( 212 | EXPORT uvwConfig 213 | NAMESPACE uvw:: 214 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/uvw 215 | ) 216 | 217 | install( 218 | TARGETS uvw 219 | EXPORT uvwConfig 220 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 221 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 222 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 223 | ) 224 | 225 | if(UVW_FETCH_LIBUV AND UVW_BUILD_LIBS) 226 | # libuv is only fetched when both above conditions are true 227 | install(DIRECTORY ${libuv_SOURCE_DIR}/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/uvw/uv/include) 228 | if (UVW_BUILD_SHARED_LIB) 229 | install(TARGETS uv EXPORT uvwConfig LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/uvw) 230 | else() 231 | install(TARGETS uv_a EXPORT uvwConfig ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/uvw) 232 | endif() 233 | endif(UVW_FETCH_LIBUV AND UVW_BUILD_LIBS) 234 | 235 | export(EXPORT uvwConfig) 236 | 237 | ### Testing 238 | 239 | option(UVW_BUILD_TESTING "Enable testing with ctest." OFF) 240 | 241 | if(UVW_BUILD_TESTING) 242 | option(UVW_FIND_GTEST_PACKAGE "Enable finding gtest package." OFF) 243 | 244 | if (NOT UVW_BUILD_LIBS) 245 | use_libuv() 246 | endif() 247 | 248 | enable_testing() 249 | add_subdirectory(test) 250 | endif() 251 | 252 | # 253 | # Documentation 254 | # 255 | 256 | option(UVW_BUILD_DOCS "Enable building with documentation." OFF) 257 | 258 | if(UVW_BUILD_DOCS) 259 | find_package(Doxygen 1.10) 260 | 261 | if(DOXYGEN_FOUND) 262 | add_subdirectory(docs) 263 | endif() 264 | endif() 265 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "cmakeMinimumRequired": { 4 | "major": 3, 5 | "minor": 13, 6 | "patch": 0 7 | }, 8 | "configurePresets": [ 9 | { 10 | "name": "cmake-pedantic", 11 | "description": "Enables all CMake warnings.`", 12 | "hidden": true, 13 | "warnings": { 14 | "dev": true, 15 | "deprecated": true, 16 | "uninitialized": true, 17 | "unusedCli": true, 18 | "systemVars": false 19 | } 20 | }, 21 | { 22 | "name": "dev-mode", 23 | "hidden": true, 24 | "description": "Common (non-OS specific) mode for development", 25 | "inherits": "cmake-pedantic", 26 | "cacheVariables": { 27 | "UVW_BUILD_TESTING": true, 28 | "libuv_buildtests": false 29 | } 30 | }, 31 | { 32 | "name": "flags-linux", 33 | "hidden": true, 34 | "description": "Compiler flags for GNU and Clang compilers. When compiling in DEBUG mode, all warnings will be converted into errors.", 35 | "cacheVariables": { 36 | "CMAKE_CXX_FLAGS": "-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wimplicit-fallthrough -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast", 37 | "CMAKE_CXX_FLAGS_DEBUG": "-Werror" 38 | } 39 | }, 40 | { 41 | "name": "ci-linux", 42 | "generator": "Unix Makefiles", 43 | "hidden": true, 44 | "inherits": ["flags-linux"], 45 | "cacheVariables": { 46 | "CMAKE_BUILD_TYPE": "Debug" 47 | } 48 | }, 49 | { 50 | "name": "ci-build", 51 | "binaryDir": "${sourceDir}/build", 52 | "hidden": true 53 | }, 54 | { 55 | "name": "ci-ubuntu", 56 | "inherits": ["ci-build", "ci-linux", "dev-mode"] 57 | } 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2024 Michele Caini 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copy of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copy or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | * do not send error events when the return value is enough (still wip) 2 | * also cleanup error event mentions in the doc 3 | * Make all tests pass on all platforms 4 | * add iwyu and clean up everything 5 | * Allocator support 6 | -------------------------------------------------------------------------------- /build/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /conanfile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | from conans import ConanFile 4 | 5 | class UVWConan(ConanFile): 6 | name = "uvw" 7 | description = "Header-only, event based, tiny and easy to use libuv wrapper in modern C++" 8 | homepage = "https://github.com/skypjack/uvw" 9 | url = homepage 10 | license = "MIT" 11 | topics = ("conan", "uvw", "libuv", "header-only", "wrapper", "event-loop") 12 | author = "Michele Caini " 13 | exports = "LICENSE" 14 | exports_sources = "src/*" 15 | no_copy_source = True 16 | requires = "libuv/1.50.0@bincrafters/stable" 17 | 18 | def package(self): 19 | self.copy(pattern="LICENSE", dst="licenses") 20 | self.copy(pattern="*.hpp", dst="include", src="src") 21 | 22 | def package_id(self): 23 | self.info.header_only() 24 | -------------------------------------------------------------------------------- /docs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Doxygen configuration (documentation) 3 | # 4 | 5 | set(DOXY_DEPS_DIRECTORY ${uvw_SOURCE_DIR}/deps) 6 | set(DOXY_SOURCE_DIRECTORY ${uvw_SOURCE_DIR}/src) 7 | set(DOXY_DOCS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) 8 | set(DOXY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 9 | 10 | configure_file(doxy.in doxy.cfg @ONLY) 11 | 12 | add_custom_target( 13 | docs ALL 14 | COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.cfg 15 | WORKING_DIRECTORY ${uvw_SOURCE_DIR} 16 | VERBATIM 17 | SOURCES doxy.in 18 | ) 19 | 20 | install( 21 | DIRECTORY ${DOXY_OUTPUT_DIRECTORY}/html 22 | DESTINATION share/${PROJECT_NAME}-${PROJECT_VERSION}/ 23 | ) 24 | -------------------------------------------------------------------------------- /docs/extra.dox: -------------------------------------------------------------------------------- 1 | /** 2 | * @namespace uvw 3 | * 4 | * @brief `uvw` default namespace. 5 | */ 6 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'uvw', 3 | 'cpp', 4 | version: '3.3.0', 5 | license: 'MIT', 6 | default_options: ['cpp_std=c++17'], 7 | ) 8 | 9 | libuv_dep = dependency('libuv', version: '1.48.0', required: true) 10 | 11 | sources = [ 12 | 'src/uvw/async.cpp', 13 | 'src/uvw/check.cpp', 14 | 'src/uvw/dns.cpp', 15 | 'src/uvw/emitter.cpp', 16 | 'src/uvw/fs.cpp', 17 | 'src/uvw/fs_event.cpp', 18 | 'src/uvw/fs_poll.cpp', 19 | 'src/uvw/idle.cpp', 20 | 'src/uvw/lib.cpp', 21 | 'src/uvw/loop.cpp', 22 | 'src/uvw/pipe.cpp', 23 | 'src/uvw/poll.cpp', 24 | 'src/uvw/prepare.cpp', 25 | 'src/uvw/process.cpp', 26 | 'src/uvw/signal.cpp', 27 | 'src/uvw/stream.cpp', 28 | 'src/uvw/tcp.cpp', 29 | 'src/uvw/thread.cpp', 30 | 'src/uvw/timer.cpp', 31 | 'src/uvw/tty.cpp', 32 | 'src/uvw/udp.cpp', 33 | 'src/uvw/util.cpp', 34 | 'src/uvw/work.cpp', 35 | ] 36 | 37 | uvw_lib = library( 38 | 'uvw', 39 | sources, 40 | include_directories: 'src', 41 | dependencies: [libuv_dep], 42 | cpp_args: ['-DUVW_AS_LIB'], 43 | install: true, 44 | ) 45 | 46 | uvw_dep = declare_dependency( 47 | include_directories: ['src'], 48 | dependencies: [libuv_dep], 49 | link_with: [uvw_lib], 50 | ) 51 | 52 | if meson.version().version_compare('>=0.54.0') 53 | meson.override_dependency('uvw', uvw_dep) 54 | endif 55 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Setup libraries 3 | # 4 | 5 | function(add_uvw_library LIB_NAME) 6 | target_sources( 7 | ${LIB_NAME} 8 | PRIVATE 9 | uvw/async.cpp 10 | uvw/check.cpp 11 | uvw/dns.cpp 12 | uvw/emitter.cpp 13 | uvw/fs.cpp 14 | uvw/fs_event.cpp 15 | uvw/fs_poll.cpp 16 | uvw/idle.cpp 17 | uvw/lib.cpp 18 | uvw/loop.cpp 19 | uvw/pipe.cpp 20 | uvw/poll.cpp 21 | uvw/prepare.cpp 22 | uvw/process.cpp 23 | uvw/signal.cpp 24 | uvw/stream.cpp 25 | uvw/tcp.cpp 26 | uvw/thread.cpp 27 | uvw/timer.cpp 28 | uvw/tty.cpp 29 | uvw/udp.cpp 30 | uvw/util.cpp 31 | uvw/work.cpp 32 | ) 33 | 34 | set_target_properties(${LIB_NAME} PROPERTIES POSITION_INDEPENDENT_CODE 1) 35 | target_compile_definitions(${LIB_NAME} PUBLIC UVW_AS_LIB) 36 | target_compile_features(${LIB_NAME} PUBLIC cxx_std_17) 37 | 38 | target_include_directories( 39 | ${LIB_NAME} 40 | PUBLIC 41 | $ 42 | $ 43 | ) 44 | 45 | if(UVW_USE_ASAN) 46 | target_compile_options(${LIB_NAME} PUBLIC $<$:-fsanitize=address -fno-omit-frame-pointer>) 47 | target_link_libraries(${LIB_NAME} PUBLIC $<$:-fsanitize=address>) 48 | endif() 49 | 50 | if(UVW_USE_UBSAN) 51 | target_compile_options(${LIB_NAME} PUBLIC $<$:-fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer>) 52 | target_link_libraries(${LIB_NAME} PUBLIC $<$:-fsanitize=undefined>) 53 | endif() 54 | 55 | if(UVW_HAS_LIBCPP) 56 | target_compile_options(${LIB_NAME} BEFORE PUBLIC -stdlib=libc++) 57 | endif() 58 | endfunction() 59 | 60 | # 61 | # Build and install libraries 62 | # 63 | 64 | if (UVW_BUILD_SHARED_LIB) 65 | add_library(uvw SHARED) 66 | add_library(uvw::uvw-shared ALIAS uvw) 67 | # If libuv is not fetched by ourselves, it's the caller's responsibility to make sure of the linkage. 68 | if(UVW_FETCH_LIBUV OR libuv_FOUND) 69 | target_link_libraries(uvw PUBLIC uv::uv-shared) 70 | endif() 71 | else() 72 | add_library(uvw STATIC) 73 | add_library(uvw::uvw-static ALIAS uvw) 74 | # If libuv is not fetched by ourselves, it's the caller's responsibility to make sure of the linkage. 75 | if(UVW_FETCH_LIBUV OR libuv_FOUND) 76 | target_link_libraries(uvw PUBLIC uv::uv-static) 77 | endif() 78 | endif() 79 | 80 | add_library(uvw::uvw ALIAS uvw) 81 | set_target_properties(uvw PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD 1) 82 | add_uvw_library(uvw) 83 | -------------------------------------------------------------------------------- /src/uvw.hpp: -------------------------------------------------------------------------------- 1 | #include "uvw/async.h" 2 | #include "uvw/check.h" 3 | #include "uvw/config.h" 4 | #include "uvw/dns.h" 5 | #include "uvw/emitter.h" 6 | #include "uvw/enum.hpp" 7 | #include "uvw/fs.h" 8 | #include "uvw/fs_event.h" 9 | #include "uvw/fs_poll.h" 10 | #include "uvw/handle.hpp" 11 | #include "uvw/idle.h" 12 | #include "uvw/lib.h" 13 | #include "uvw/loop.h" 14 | #include "uvw/pipe.h" 15 | #include "uvw/poll.h" 16 | #include "uvw/prepare.h" 17 | #include "uvw/process.h" 18 | #include "uvw/request.hpp" 19 | #include "uvw/resource.hpp" 20 | #include "uvw/signal.h" 21 | #include "uvw/tcp.h" 22 | #include "uvw/thread.h" 23 | #include "uvw/timer.h" 24 | #include "uvw/tty.h" 25 | #include "uvw/udp.h" 26 | #include "uvw/util.h" 27 | #include "uvw/uv_type.hpp" 28 | #include "uvw/work.h" 29 | -------------------------------------------------------------------------------- /src/uvw/async.cpp: -------------------------------------------------------------------------------- 1 | #include "async.h" 2 | #include "async.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/async.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_ASYNC_INCLUDE_H 2 | #define UVW_ASYNC_INCLUDE_H 3 | 4 | #include 5 | #include "handle.hpp" 6 | #include "loop.h" 7 | 8 | namespace uvw { 9 | 10 | /*! @brief Async event. */ 11 | struct async_event {}; 12 | 13 | /** 14 | * @brief The async handle. 15 | * 16 | * Async handles allow the user to _wakeup_ the event loop and get an event 17 | * emitted from another thread. 18 | * 19 | * To create an `async_handle` through a `loop`, no arguments are required. 20 | */ 21 | class async_handle final: public handle { 22 | static void send_callback(uv_async_t *hndl); 23 | 24 | public: 25 | using handle::handle; 26 | 27 | /** 28 | * @brief Initializes the handle. 29 | * 30 | * Unlike other handle initialization functions, it immediately starts the 31 | * handle. 32 | * 33 | * @return Underlying return value. 34 | */ 35 | int init(); 36 | 37 | /** 38 | * @brief Wakeups the event loop and emits the async event. 39 | * 40 | * It’s safe to call this function from any thread.
41 | * An async event is emitted on the loop thread. 42 | * 43 | * See the official 44 | * [documentation](http://docs.libuv.org/en/v1.x/async.html#c.uv_async_send) 45 | * for further details. 46 | * 47 | * @return Underlying return value. 48 | */ 49 | int send(); 50 | }; 51 | 52 | } // namespace uvw 53 | 54 | #ifndef UVW_AS_LIB 55 | # include "async.ipp" 56 | #endif 57 | 58 | #endif // UVW_ASYNC_INCLUDE_H 59 | -------------------------------------------------------------------------------- /src/uvw/async.ipp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | namespace uvw { 4 | 5 | UVW_INLINE void async_handle::send_callback(uv_async_t *hndl) { 6 | async_handle &async = *(static_cast(hndl->data)); 7 | async.publish(async_event{}); 8 | } 9 | 10 | UVW_INLINE int async_handle::init() { 11 | return leak_if(uv_async_init(parent().raw(), raw(), &send_callback)); 12 | } 13 | 14 | UVW_INLINE int async_handle::send() { 15 | return uv_async_send(raw()); 16 | } 17 | 18 | } // namespace uvw 19 | -------------------------------------------------------------------------------- /src/uvw/check.cpp: -------------------------------------------------------------------------------- 1 | #include "check.h" 2 | #include "check.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/check.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_CHECK_INCLUDE_H 2 | #define UVW_CHECK_INCLUDE_H 3 | 4 | #include 5 | #include "handle.hpp" 6 | #include "loop.h" 7 | 8 | namespace uvw { 9 | 10 | /*! @brief Check event. */ 11 | struct check_event {}; 12 | 13 | /** 14 | * @brief The check handle. 15 | * 16 | * Check handles will emit a check event once per loop iteration, right after 17 | * polling for I/O. 18 | * 19 | * To create a `check_handle` through a `loop`, no arguments are required. 20 | */ 21 | class check_handle final: public handle { 22 | static void start_callback(uv_check_t *hndl); 23 | 24 | public: 25 | using handle::handle; 26 | 27 | /** 28 | * @brief Initializes the handle. 29 | * @return Underlying return value. 30 | */ 31 | int init(); 32 | 33 | /** 34 | * @brief Starts the handle. 35 | * 36 | * A check event will be emitted once per loop iteration, right after 37 | * polling for I/O. 38 | * 39 | * @return Underlying return value. 40 | */ 41 | int start(); 42 | 43 | /** 44 | * @brief Stops the handle. 45 | * @return Underlying return value. 46 | */ 47 | int stop(); 48 | }; 49 | 50 | } // namespace uvw 51 | 52 | #ifndef UVW_AS_LIB 53 | # include "check.ipp" 54 | #endif 55 | 56 | #endif // UVW_CHECK_INCLUDE_H 57 | -------------------------------------------------------------------------------- /src/uvw/check.ipp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | namespace uvw { 4 | 5 | UVW_INLINE void check_handle::start_callback(uv_check_t *hndl) { 6 | check_handle &check = *(static_cast(hndl->data)); 7 | check.publish(check_event{}); 8 | } 9 | 10 | UVW_INLINE int check_handle::init() { 11 | return leak_if(uv_check_init(parent().raw(), raw())); 12 | } 13 | 14 | UVW_INLINE int check_handle::start() { 15 | return uv_check_start(raw(), &start_callback); 16 | } 17 | 18 | UVW_INLINE int check_handle::stop() { 19 | return uv_check_stop(raw()); 20 | } 21 | 22 | } // namespace uvw 23 | -------------------------------------------------------------------------------- /src/uvw/config.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_CONFIG_H 2 | #define UVW_CONFIG_H 3 | 4 | #ifndef UVW_AS_LIB 5 | # define UVW_INLINE inline 6 | #else 7 | # define UVW_INLINE 8 | #endif 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/uvw/dns.cpp: -------------------------------------------------------------------------------- 1 | #include "dns.h" 2 | #include "dns.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/dns.ipp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | namespace uvw { 4 | 5 | UVW_INLINE addr_info_event::addr_info_event(std::unique_ptr addr) 6 | : data{std::move(addr)} {} 7 | 8 | UVW_INLINE name_info_event::name_info_event(const char *host, const char *serv) 9 | : hostname{host}, service{serv} {} 10 | 11 | UVW_INLINE void get_addr_info_req::addr_info_callback(uv_getaddrinfo_t *req, int status, addrinfo *res) { 12 | if(auto ptr = reserve(req); status) { 13 | ptr->publish(error_event{status}); 14 | } else { 15 | auto data = std::unique_ptr{res, [](addrinfo *addr) { uv_freeaddrinfo(addr); }}; 16 | ptr->publish(addr_info_event{std::move(data)}); 17 | } 18 | } 19 | 20 | UVW_INLINE int get_addr_info_req::node_addr_info(const char *node, const char *service, addrinfo *hints) { 21 | return this->leak_if(uv_getaddrinfo(parent().raw(), raw(), &addr_info_callback, node, service, hints)); 22 | } 23 | 24 | UVW_INLINE auto get_addr_info_req::node_addr_info_sync(const char *node, const char *service, addrinfo *hints) { 25 | auto req = raw(); 26 | auto err = uv_getaddrinfo(parent().raw(), req, nullptr, node, service, hints); 27 | auto data = std::unique_ptr{req->addrinfo, [](addrinfo *addr) { uv_freeaddrinfo(addr); }}; 28 | return std::make_pair(!err, std::move(data)); 29 | } 30 | 31 | UVW_INLINE int get_addr_info_req::node_addr_info(const std::string &node, addrinfo *hints) { 32 | return node_addr_info(node.data(), nullptr, hints); 33 | } 34 | 35 | UVW_INLINE std::pair> get_addr_info_req::node_addr_info_sync(const std::string &node, addrinfo *hints) { 36 | return node_addr_info_sync(node.data(), nullptr, hints); 37 | } 38 | 39 | UVW_INLINE int get_addr_info_req::service_addr_info(const std::string &service, addrinfo *hints) { 40 | return node_addr_info(nullptr, service.data(), hints); 41 | } 42 | 43 | UVW_INLINE std::pair> get_addr_info_req::service_addr_info_sync(const std::string &service, addrinfo *hints) { 44 | return node_addr_info_sync(nullptr, service.data(), hints); 45 | } 46 | 47 | UVW_INLINE int get_addr_info_req::addr_info(const std::string &node, const std::string &service, addrinfo *hints) { 48 | return node_addr_info(node.data(), service.data(), hints); 49 | } 50 | 51 | UVW_INLINE std::pair> get_addr_info_req::addr_info_sync(const std::string &node, const std::string &service, addrinfo *hints) { 52 | return node_addr_info_sync(node.data(), service.data(), hints); 53 | } 54 | 55 | UVW_INLINE void get_name_info_req::name_info_callback(uv_getnameinfo_t *req, int status, const char *hostname, const char *service) { 56 | if(auto ptr = reserve(req); status) { 57 | ptr->publish(error_event{status}); 58 | } else { 59 | ptr->publish(name_info_event{hostname, service}); 60 | } 61 | } 62 | 63 | UVW_INLINE int get_name_info_req::name_info(const sockaddr &addr, int flags) { 64 | return this->leak_if(uv_getnameinfo(parent().raw(), raw(), &name_info_callback, &addr, flags)); 65 | } 66 | 67 | UVW_INLINE int get_name_info_req::name_info(const std::string &ip, unsigned int port, int flags) { 68 | return name_info(details::ip_addr(ip.data(), port), flags); 69 | } 70 | 71 | UVW_INLINE int get_name_info_req::name_info(const socket_address &addr, int flags) { 72 | return name_info(addr.ip, addr.port, flags); 73 | } 74 | 75 | UVW_INLINE std::pair> get_name_info_req::name_info_sync(const sockaddr &addr, int flags) { 76 | auto req = raw(); 77 | auto err = uv_getnameinfo(parent().raw(), req, nullptr, &addr, flags); 78 | return std::make_pair(!err, std::make_pair(req->host, req->service)); 79 | } 80 | 81 | UVW_INLINE std::pair> get_name_info_req::name_info_sync(const std::string &ip, unsigned int port, int flags) { 82 | return name_info_sync(details::ip_addr(ip.data(), port), flags); 83 | } 84 | 85 | UVW_INLINE std::pair> get_name_info_req::name_info_sync(const socket_address &addr, int flags) { 86 | return name_info_sync(addr.ip, addr.port, flags); 87 | } 88 | 89 | } // namespace uvw 90 | -------------------------------------------------------------------------------- /src/uvw/emitter.cpp: -------------------------------------------------------------------------------- 1 | #include "emitter.h" 2 | #include "emitter.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/emitter.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_EMITTER_INCLUDE_H 2 | #define UVW_EMITTER_INCLUDE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "config.h" 14 | #include "type_info.hpp" 15 | 16 | namespace uvw { 17 | 18 | /** 19 | * @brief Error event. 20 | * 21 | * Custom wrapper around error constants of `libuv`. 22 | */ 23 | struct error_event { 24 | template>> 25 | explicit error_event(Type val) noexcept 26 | : ec{static_cast(val)} {} 27 | 28 | /** 29 | * @brief Returns the `libuv` error code equivalent to the given platform dependent error code. 30 | * 31 | * It returns: 32 | * * POSIX error codes on Unix (the ones stored in errno). 33 | * * Win32 error codes on Windows (those returned by GetLastError() or WSAGetLastError()). 34 | * 35 | * If `sys` is already a `libuv` error code, it is simply returned. 36 | * 37 | * @param sys A platform dependent error code. 38 | * @return The `libuv` error code equivalent to the given platform dependent error code. 39 | */ 40 | [[nodiscard]] static int translate(int sys) noexcept; 41 | 42 | /** 43 | * @brief Returns the error message for the given error code. 44 | * 45 | * Leaks a few bytes of memory when you call it with an unknown error code. 46 | * 47 | * @return The error message for the given error code. 48 | */ 49 | [[nodiscard]] const char *what() const noexcept; 50 | 51 | /** 52 | * @brief Returns the error name for the given error code. 53 | * 54 | * Leaks a few bytes of memory when you call it with an unknown error code. 55 | * 56 | * @return The error name for the given error code. 57 | */ 58 | [[nodiscard]] const char *name() const noexcept; 59 | 60 | /** 61 | * @brief Gets the underlying error code, that is an error constant of `libuv`. 62 | * @return The underlying error code. 63 | */ 64 | [[nodiscard]] int code() const noexcept; 65 | 66 | /** 67 | * @brief Checks if the event contains a valid error code. 68 | * @return True in case of success, false otherwise. 69 | */ 70 | explicit operator bool() const noexcept; 71 | 72 | private: 73 | int ec; 74 | }; 75 | 76 | /** 77 | * @brief Event emitter base class. 78 | * 79 | * Almost everything in `uvw` is an event emitter.
80 | * This is the base class from which resources and loops inherit. 81 | */ 82 | template 83 | class emitter { 84 | public: 85 | template 86 | using listener_t = std::function; 87 | 88 | private: 89 | template 90 | [[nodiscard]] const auto &handler() const noexcept { 91 | return std::get>(handlers); 92 | } 93 | 94 | template 95 | [[nodiscard]] auto &handler() noexcept { 96 | return std::get>(handlers); 97 | } 98 | 99 | protected: 100 | template 101 | void publish(Type event) { 102 | if(auto &listener = handler(); listener) { 103 | listener(event, *static_cast(this)); 104 | } 105 | } 106 | 107 | public: 108 | virtual ~emitter() noexcept { 109 | static_assert(std::is_base_of_v, Elem>); 110 | } 111 | 112 | /** 113 | * @brief Registers a long-lived listener with the event emitter. 114 | * 115 | * This method is used to register a listener with the emitter.
116 | * A listener is usually defined as a callable object assignable to a 117 | * `std::function 123 | void on(listener_t f) { 124 | handler() = std::move(f); 125 | } 126 | 127 | /*! @brief Disconnects the listener for the given event type. */ 128 | template 129 | void reset() noexcept { 130 | handler() = nullptr; 131 | } 132 | 133 | /*! @brief Disconnects all listeners. */ 134 | void reset() noexcept { 135 | reset(); 136 | (reset(), ...); 137 | } 138 | 139 | /** 140 | * @brief Checks if there is a listener registered for the specific event. 141 | * @return True if there is a listener registered for the specific event, 142 | * false otherwise. 143 | */ 144 | template 145 | [[nodiscard]] bool has() const noexcept { 146 | return static_cast(handler()); 147 | } 148 | 149 | private: 150 | std::tuple, listener_t...> handlers{}; 151 | }; 152 | 153 | } // namespace uvw 154 | 155 | #ifndef UVW_AS_LIB 156 | # include "emitter.ipp" 157 | #endif 158 | 159 | #endif // UVW_EMITTER_INCLUDE_H 160 | -------------------------------------------------------------------------------- /src/uvw/emitter.ipp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | namespace uvw { 4 | 5 | UVW_INLINE int error_event::translate(int sys) noexcept { 6 | return uv_translate_sys_error(sys); 7 | } 8 | 9 | UVW_INLINE const char *error_event::what() const noexcept { 10 | return uv_strerror(ec); 11 | } 12 | 13 | UVW_INLINE const char *error_event::name() const noexcept { 14 | return uv_err_name(ec); 15 | } 16 | 17 | UVW_INLINE int error_event::code() const noexcept { 18 | return ec; 19 | } 20 | 21 | UVW_INLINE error_event::operator bool() const noexcept { 22 | return ec < 0; 23 | } 24 | 25 | } // namespace uvw 26 | -------------------------------------------------------------------------------- /src/uvw/enum.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UVW_ENUM_INCLUDE_HPP 2 | #define UVW_ENUM_INCLUDE_HPP 3 | 4 | #include 5 | #include "config.h" 6 | 7 | /** 8 | * @brief Operator available for enums for which bitmask support is enabled. 9 | * @tparam Type Enum class type. 10 | * @param lhs The first value to use. 11 | * @param rhs The second value to use. 12 | * @return The result of invoking the operator on the underlying types of the 13 | * two values provided. 14 | */ 15 | template 16 | [[nodiscard]] constexpr std::enable_if_t, decltype(Type::UVW_ENUM)> 17 | operator|(const Type lhs, const Type rhs) noexcept { 18 | return static_cast(static_cast>(lhs) | static_cast>(rhs)); 19 | } 20 | 21 | /*! @copydoc operator| */ 22 | template 23 | [[nodiscard]] constexpr std::enable_if_t, decltype(Type::UVW_ENUM)> 24 | operator&(const Type lhs, const Type rhs) noexcept { 25 | return static_cast(static_cast>(lhs) & static_cast>(rhs)); 26 | } 27 | 28 | /*! @copydoc operator| */ 29 | template 30 | [[nodiscard]] constexpr std::enable_if_t, decltype(Type::UVW_ENUM)> 31 | operator^(const Type lhs, const Type rhs) noexcept { 32 | return static_cast(static_cast>(lhs) ^ static_cast>(rhs)); 33 | } 34 | 35 | /** 36 | * @brief Operator available for enums for which bitmask support is enabled. 37 | * @tparam Type Enum class type. 38 | * @param value The value to use. 39 | * @return The result of invoking the operator on the underlying types of the 40 | * value provided. 41 | */ 42 | template 43 | [[nodiscard]] constexpr std::enable_if_t, decltype(Type::UVW_ENUM)> 44 | operator~(const Type value) noexcept { 45 | return static_cast(~static_cast>(value)); 46 | } 47 | 48 | /*! @copydoc operator~ */ 49 | template 50 | [[nodiscard]] constexpr std::enable_if_t, decltype(Type::UVW_ENUM, bool{})> 51 | operator!(const Type value) noexcept { 52 | return !static_cast>(value); 53 | } 54 | 55 | /*! @copydoc operator| */ 56 | template 57 | constexpr std::enable_if_t, decltype(Type::UVW_ENUM) &> 58 | operator|=(Type &lhs, const Type rhs) noexcept { 59 | return (lhs = (lhs | rhs)); 60 | } 61 | 62 | /*! @copydoc operator| */ 63 | template 64 | constexpr std::enable_if_t, decltype(Type::UVW_ENUM) &> 65 | operator&=(Type &lhs, const Type rhs) noexcept { 66 | return (lhs = (lhs & rhs)); 67 | } 68 | 69 | /*! @copydoc operator| */ 70 | template 71 | constexpr std::enable_if_t, decltype(Type::UVW_ENUM) &> 72 | operator^=(Type &lhs, const Type rhs) noexcept { 73 | return (lhs = (lhs ^ rhs)); 74 | } 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /src/uvw/fs.cpp: -------------------------------------------------------------------------------- 1 | #include "fs.h" 2 | #include "fs.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/fs_event.cpp: -------------------------------------------------------------------------------- 1 | #include "fs_event.h" 2 | #include "fs_event.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/fs_event.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_FS_EVENT_INCLUDE_H 2 | #define UVW_FS_EVENT_INCLUDE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "config.h" 8 | #include "enum.hpp" 9 | #include "handle.hpp" 10 | #include "loop.h" 11 | #include "util.h" 12 | 13 | namespace uvw { 14 | 15 | namespace details { 16 | 17 | enum class uvw_fs_event_flags : std::underlying_type_t { 18 | WATCH_ENTRY = UV_FS_EVENT_WATCH_ENTRY, 19 | STAT = UV_FS_EVENT_STAT, 20 | RECURSIVE = UV_FS_EVENT_RECURSIVE, 21 | UVW_ENUM = 0 22 | }; 23 | 24 | enum class uvw_fs_event : std::underlying_type_t { 25 | RENAME = UV_RENAME, 26 | CHANGE = UV_CHANGE 27 | }; 28 | 29 | } // namespace details 30 | 31 | /*! @brief Fs event event. */ 32 | struct fs_event_event { 33 | fs_event_event(const char *pathname, details::uvw_fs_event events); 34 | 35 | /** 36 | * @brief The path to the file being monitored. 37 | * 38 | * If the handle was started with a directory, the filename parameter will 39 | * be a relative path to a file contained in the directory. 40 | */ 41 | const char *filename; 42 | 43 | /** 44 | * @brief Detected events all in one. 45 | * 46 | * Available flags are: 47 | * 48 | * * `fs_event_handle::watch::RENAME` 49 | * * `fs_event_handle::watch::CHANGE` 50 | */ 51 | details::uvw_fs_event flags; 52 | }; 53 | 54 | /** 55 | * @brief The fs event handle. 56 | * 57 | * These handles allow the user to monitor a given path for changes, for 58 | * example, if the file was renamed or there was a generic change in it. The 59 | * best backend for the job on each platform is chosen by the handle. 60 | * 61 | * To create a `fs_event_handle` through a `loop`, no arguments are required. 62 | * 63 | * See the official 64 | * [documentation](http://docs.libuv.org/en/v1.x/fs_event.html) 65 | * for further details. 66 | */ 67 | class fs_event_handle final: public handle { 68 | static void start_callback(uv_fs_event_t *hndl, const char *filename, int events, int status); 69 | 70 | public: 71 | using watch = details::uvw_fs_event; 72 | using event_flags = details::uvw_fs_event_flags; 73 | 74 | using handle::handle; 75 | 76 | /** 77 | * @brief Initializes the handle. 78 | * @return Underlying return value. 79 | */ 80 | int init(); 81 | 82 | /** 83 | * @brief Starts watching the specified path. 84 | * 85 | * It will watch the specified path for changes.
86 | * As soon as a change is observed, a fs_event_event is emitted by the 87 | * handle. 88 | * 89 | * Available flags are: 90 | * 91 | * * `fs_event_handle::event_flags::WATCH_ENTRY` 92 | * * `fs_event_handle::event_flags::STAT` 93 | * * `fs_event_handle::event_flags::RECURSIVE` 94 | * 95 | * @param path The file or directory to be monitored. 96 | * @param flags Additional flags to control the behavior. 97 | * @return Underlying return value. 98 | */ 99 | int start(const std::string &path, event_flags flags = event_flags::UVW_ENUM); 100 | 101 | /** 102 | * @brief Stops polling the file descriptor. 103 | * @return Underlying return value. 104 | */ 105 | int stop(); 106 | 107 | /** 108 | * @brief Gets the path being monitored. 109 | * @return The path being monitored, an empty string in case of errors. 110 | */ 111 | std::string path() noexcept; 112 | }; 113 | 114 | } // namespace uvw 115 | 116 | #ifndef UVW_AS_LIB 117 | # include "fs_event.ipp" 118 | #endif 119 | 120 | #endif // UVW_FS_EVENT_INCLUDE_H 121 | -------------------------------------------------------------------------------- /src/uvw/fs_event.ipp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | namespace uvw { 4 | 5 | UVW_INLINE fs_event_event::fs_event_event(const char *pathname, details::uvw_fs_event events) 6 | : filename{pathname}, flags{events} {} 7 | 8 | // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) 9 | UVW_INLINE void fs_event_handle::start_callback(uv_fs_event_t *hndl, const char *filename, int events, int status) { 10 | if(fs_event_handle &fsEvent = *(static_cast(hndl->data)); status) { 11 | fsEvent.publish(error_event{status}); 12 | } else { 13 | fsEvent.publish(fs_event_event{filename, details::uvw_fs_event(events)}); 14 | } 15 | } 16 | 17 | UVW_INLINE int fs_event_handle::init() { 18 | return leak_if(uv_fs_event_init(parent().raw(), raw())); 19 | } 20 | 21 | UVW_INLINE int fs_event_handle::start(const std::string &path, event_flags flags) { 22 | return uv_fs_event_start(raw(), &start_callback, path.data(), static_cast(flags)); 23 | } 24 | 25 | UVW_INLINE int fs_event_handle::stop() { 26 | return uv_fs_event_stop(raw()); 27 | } 28 | 29 | UVW_INLINE std::string fs_event_handle::path() noexcept { 30 | return details::try_read(&uv_fs_event_getpath, raw()); 31 | } 32 | 33 | } // namespace uvw 34 | -------------------------------------------------------------------------------- /src/uvw/fs_poll.cpp: -------------------------------------------------------------------------------- 1 | #include "fs_poll.h" 2 | #include "fs_poll.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/fs_poll.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_FS_POLL_INCLUDE_H 2 | #define UVW_FS_POLL_INCLUDE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "config.h" 8 | #include "handle.hpp" 9 | #include "loop.h" 10 | #include "util.h" 11 | 12 | namespace uvw { 13 | 14 | /*! @brief Fs pos event. */ 15 | struct fs_poll_event { 16 | explicit fs_poll_event(file_info previous, file_info current) noexcept; 17 | 18 | file_info prev; /*!< The old file_info struct. */ 19 | file_info curr; /*!< The new file_info struct. */ 20 | }; 21 | 22 | /** 23 | * @brief The fs poll handle. 24 | * 25 | * It allows users to monitor a given path for changes. Unlike fs_event_handle, 26 | * fs_poll_handle uses stat to detect when a file has changed so it can work on 27 | * file systems where fs_event_handle handles can’t. 28 | * 29 | * To create a `fs_poll_handle` through a `loop`, no arguments are required. 30 | */ 31 | class fs_poll_handle final: public handle { 32 | static void start_callback(uv_fs_poll_t *hndl, int status, const uv_stat_t *prev, const uv_stat_t *curr); 33 | 34 | public: 35 | using time = std::chrono::duration; 36 | 37 | using handle::handle; 38 | 39 | /** 40 | * @brief Initializes the handle. 41 | * @return Underlying return value. 42 | */ 43 | int init(); 44 | 45 | /** 46 | * @brief Starts the handle. 47 | * 48 | * The handle will start emitting fs_poll_event when needed. 49 | * 50 | * @param file The path to the file to be checked. 51 | * @param interval Milliseconds between successive checks. 52 | * @return Underlying return value. 53 | */ 54 | int start(const std::string &file, time interval); 55 | 56 | /** 57 | * @brief Stops the handle. 58 | * @return Underlying return value. 59 | */ 60 | int stop(); 61 | 62 | /** 63 | * @brief Gets the path being monitored by the handle. 64 | * @return The path being monitored by the handle, an empty string in case 65 | * of errors. 66 | */ 67 | std::string path() noexcept; 68 | }; 69 | 70 | } // namespace uvw 71 | 72 | #ifndef UVW_AS_LIB 73 | # include "fs_poll.ipp" 74 | #endif 75 | 76 | #endif // UVW_FS_POLL_INCLUDE_H 77 | -------------------------------------------------------------------------------- /src/uvw/fs_poll.ipp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | namespace uvw { 4 | 5 | UVW_INLINE fs_poll_event::fs_poll_event(file_info previous, file_info current) noexcept 6 | : prev{previous}, curr{current} {} 7 | 8 | UVW_INLINE void fs_poll_handle::start_callback(uv_fs_poll_t *hndl, int status, const uv_stat_t *prev, const uv_stat_t *curr) { 9 | if(fs_poll_handle &fsPoll = *(static_cast(hndl->data)); status) { 10 | fsPoll.publish(error_event{status}); 11 | } else { 12 | fsPoll.publish(fs_poll_event{*prev, *curr}); 13 | } 14 | } 15 | 16 | UVW_INLINE int fs_poll_handle::init() { 17 | return leak_if(uv_fs_poll_init(parent().raw(), raw())); 18 | } 19 | 20 | UVW_INLINE int fs_poll_handle::start(const std::string &file, fs_poll_handle::time interval) { 21 | return uv_fs_poll_start(raw(), &start_callback, file.data(), interval.count()); 22 | } 23 | 24 | UVW_INLINE int fs_poll_handle::stop() { 25 | return uv_fs_poll_stop(raw()); 26 | } 27 | 28 | UVW_INLINE std::string fs_poll_handle::path() noexcept { 29 | return details::try_read(&uv_fs_poll_getpath, raw()); 30 | } 31 | 32 | } // namespace uvw 33 | -------------------------------------------------------------------------------- /src/uvw/idle.cpp: -------------------------------------------------------------------------------- 1 | #include "idle.h" 2 | #include "idle.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/idle.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_IDLE_INCLUDE_H 2 | #define UVW_IDLE_INCLUDE_H 3 | 4 | #include 5 | #include "handle.hpp" 6 | #include "loop.h" 7 | 8 | namespace uvw { 9 | 10 | /*! @brief Idle event. */ 11 | struct idle_event {}; 12 | 13 | /** 14 | * @brief The idle handle. 15 | * 16 | * Idle handles will emit a idle event once per loop iteration, right before the 17 | * prepare handles. 18 | * 19 | * The notable difference with prepare handles is that when there are active 20 | * idle handles, the loop will perform a zero timeout poll instead of blocking 21 | * for I/O. 22 | * 23 | * @note 24 | * Despite the name, idle handles will emit events on every loop iteration, not 25 | * when the loop is actually _idle_. 26 | * 27 | * To create an `idle_handle` through a `loop`, no arguments are required. 28 | */ 29 | class idle_handle final: public handle { 30 | static void start_callback(uv_idle_t *hndl); 31 | 32 | public: 33 | using handle::handle; 34 | 35 | /** 36 | * @brief Initializes the handle. 37 | * @return Underlying return value. 38 | */ 39 | int init(); 40 | 41 | /** 42 | * @brief Starts the handle. 43 | * 44 | * An idle event will be emitted once per loop iteration, right before 45 | * polling the prepare handles. 46 | * 47 | * @return Underlying return value. 48 | */ 49 | int start(); 50 | 51 | /** 52 | * @brief Stops the handle. 53 | * 54 | * @return Underlying return value. 55 | */ 56 | int stop(); 57 | }; 58 | 59 | } // namespace uvw 60 | 61 | #ifndef UVW_AS_LIB 62 | # include "idle.ipp" 63 | #endif 64 | 65 | #endif // UVW_IDLE_INCLUDE_H 66 | -------------------------------------------------------------------------------- /src/uvw/idle.ipp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | namespace uvw { 4 | 5 | UVW_INLINE void idle_handle::start_callback(uv_idle_t *hndl) { 6 | idle_handle &idle = *(static_cast(hndl->data)); 7 | idle.publish(idle_event{}); 8 | } 9 | 10 | UVW_INLINE int idle_handle::init() { 11 | return leak_if(uv_idle_init(parent().raw(), raw())); 12 | } 13 | 14 | UVW_INLINE int idle_handle::start() { 15 | return uv_idle_start(raw(), &start_callback); 16 | } 17 | 18 | UVW_INLINE int idle_handle::stop() { 19 | return uv_idle_stop(raw()); 20 | } 21 | 22 | } // namespace uvw 23 | -------------------------------------------------------------------------------- /src/uvw/lib.cpp: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | #include "lib.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/lib.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_LIB_INCLUDE_H 2 | #define UVW_LIB_INCLUDE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "config.h" 9 | #include "loop.h" 10 | #include "uv_type.hpp" 11 | 12 | namespace uvw { 13 | 14 | /** 15 | * @brief The shared lib class. 16 | * 17 | * `uvw` provides cross platform utilities for loading shared libraries and 18 | * retrieving symbols from them, by means of the API offered by `libuv`. 19 | */ 20 | class shared_lib final: public uv_type { 21 | public: 22 | explicit shared_lib(loop::token token, std::shared_ptr ref, const std::string &filename) noexcept; 23 | 24 | ~shared_lib() noexcept; 25 | 26 | /** 27 | * @brief Checks if the library has been correctly opened. 28 | * @return True if the library is opened, false otherwise. 29 | */ 30 | explicit operator bool() const noexcept; 31 | 32 | /** 33 | * @brief Retrieves a data pointer from a dynamic library. 34 | * 35 | * `F` shall be a valid function type (as an example, `void(int)`).
36 | * It is legal for a symbol to map to `nullptr`. 37 | * 38 | * @param name The symbol to be retrieved. 39 | * @return A valid function pointer in case of success, `nullptr` otherwise. 40 | */ 41 | template 42 | F *sym(const std::string &name) { 43 | static_assert(std::is_function_v); 44 | F *func; 45 | auto err = uv_dlsym(raw(), name.data(), reinterpret_cast(&func)); 46 | if(err) { 47 | func = nullptr; 48 | } 49 | return func; 50 | } 51 | 52 | /** 53 | * @brief Returns the last error message, if any. 54 | * @return The last error message, if any. 55 | */ 56 | [[nodiscard]] const char *error() const noexcept; 57 | 58 | private: 59 | bool opened; 60 | }; 61 | 62 | } // namespace uvw 63 | 64 | #ifndef UVW_AS_LIB 65 | # include "lib.ipp" 66 | #endif 67 | 68 | #endif // UVW_LIB_INCLUDE_H 69 | -------------------------------------------------------------------------------- /src/uvw/lib.ipp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "config.h" 3 | 4 | namespace uvw { 5 | 6 | UVW_INLINE shared_lib::shared_lib(loop::token token, std::shared_ptr ref, const std::string &filename) noexcept 7 | : uv_type{token, std::move(ref)} { 8 | opened = (0 == uv_dlopen(filename.data(), raw())); 9 | } 10 | 11 | UVW_INLINE shared_lib::~shared_lib() noexcept { 12 | uv_dlclose(raw()); 13 | } 14 | 15 | UVW_INLINE shared_lib::operator bool() const noexcept { 16 | return opened; 17 | } 18 | 19 | UVW_INLINE const char *shared_lib::error() const noexcept { 20 | return uv_dlerror(raw()); 21 | } 22 | 23 | } // namespace uvw 24 | -------------------------------------------------------------------------------- /src/uvw/loop.cpp: -------------------------------------------------------------------------------- 1 | #include "loop.h" 2 | #include "loop.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/loop.ipp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | namespace uvw { 4 | 5 | UVW_INLINE loop::loop(std::unique_ptr ptr) noexcept 6 | : uv_loop{std::move(ptr)} {} 7 | 8 | UVW_INLINE std::shared_ptr loop::create() { 9 | auto ptr = std::unique_ptr{new uv_loop_t, [](uv_loop_t *l) { delete l; }}; 10 | auto curr = std::shared_ptr{new loop{std::move(ptr)}}; 11 | 12 | if(uv_loop_init(curr->uv_loop.get())) { 13 | curr = nullptr; 14 | } 15 | 16 | return curr; 17 | } 18 | 19 | UVW_INLINE std::shared_ptr loop::create(uv_loop_t *res) { 20 | auto ptr = std::unique_ptr{res, [](uv_loop_t *) {}}; 21 | return std::shared_ptr{new loop{std::move(ptr)}}; 22 | } 23 | 24 | UVW_INLINE std::shared_ptr loop::get_default() { 25 | static std::weak_ptr ref; 26 | std::shared_ptr curr; 27 | 28 | if(ref.expired()) { 29 | auto def = uv_default_loop(); 30 | 31 | if(def) { 32 | auto ptr = std::unique_ptr(def, [](uv_loop_t *) {}); 33 | curr = std::shared_ptr{new loop{std::move(ptr)}}; 34 | } 35 | 36 | ref = curr; 37 | } else { 38 | curr = ref.lock(); 39 | } 40 | 41 | return curr; 42 | } 43 | 44 | UVW_INLINE loop::~loop() noexcept { 45 | if(uv_loop) { 46 | close(); 47 | } 48 | } 49 | 50 | UVW_INLINE int loop::close() { 51 | int ret = 0; 52 | 53 | if(uv_loop) { 54 | ret = uv_loop_close(uv_loop.get()); 55 | uv_loop.reset(); 56 | } 57 | 58 | return ret; 59 | } 60 | 61 | UVW_INLINE int loop::run(run_mode mode) noexcept { 62 | return uv_run(uv_loop.get(), static_cast(mode)); 63 | } 64 | 65 | UVW_INLINE bool loop::alive() const noexcept { 66 | return !!uv_loop_alive(uv_loop.get()); 67 | } 68 | 69 | UVW_INLINE void loop::stop() noexcept { 70 | uv_stop(uv_loop.get()); 71 | } 72 | 73 | UVW_INLINE int loop::descriptor() const noexcept { 74 | return uv_backend_fd(uv_loop.get()); 75 | } 76 | 77 | UVW_INLINE std::pair loop::timeout() const noexcept { 78 | auto to = uv_backend_timeout(uv_loop.get()); 79 | return std::make_pair(to == -1, time{to}); 80 | } 81 | 82 | UVW_INLINE loop::time loop::idle_time() const noexcept { 83 | return time{uv_metrics_idle_time(uv_loop.get())}; 84 | } 85 | 86 | UVW_INLINE metrics_type loop::metrics() const noexcept { 87 | metrics_type res{}; 88 | uv_metrics_info(uv_loop.get(), &res); 89 | return res; 90 | } 91 | 92 | UVW_INLINE loop::time loop::now() const noexcept { 93 | return time{uv_now(uv_loop.get())}; 94 | } 95 | 96 | UVW_INLINE void loop::update() const noexcept { 97 | return uv_update_time(uv_loop.get()); 98 | } 99 | 100 | UVW_INLINE int loop::fork() noexcept { 101 | return uv_loop_fork(uv_loop.get()); 102 | } 103 | 104 | UVW_INLINE void loop::data(std::shared_ptr ud) { 105 | user_data = std::move(ud); 106 | } 107 | 108 | UVW_INLINE const uv_loop_t *loop::raw() const noexcept { 109 | return uv_loop.get(); 110 | } 111 | 112 | UVW_INLINE uv_loop_t *loop::raw() noexcept { 113 | return const_cast(const_cast(this)->raw()); 114 | } 115 | 116 | } // namespace uvw 117 | -------------------------------------------------------------------------------- /src/uvw/pipe.cpp: -------------------------------------------------------------------------------- 1 | #include "pipe.h" 2 | #include "pipe.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/pipe.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_PIPE_INCLUDE_H 2 | #define UVW_PIPE_INCLUDE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "config.h" 9 | #include "enum.hpp" 10 | #include "loop.h" 11 | #include "request.hpp" 12 | #include "stream.h" 13 | #include "util.h" 14 | 15 | namespace uvw { 16 | 17 | namespace details { 18 | 19 | enum class uvw_chmod_flags : std::underlying_type_t { 20 | READABLE = UV_READABLE, 21 | WRITABLE = UV_WRITABLE, 22 | UVW_ENUM = 0 23 | }; 24 | 25 | } 26 | 27 | /** 28 | * @brief The pipe handle. 29 | * 30 | * Pipe handles provide an abstraction over local domain sockets on Unix and 31 | * named pipes on Windows. 32 | * 33 | * To create a `pipe_handle` through a `loop`, arguments follow: 34 | * 35 | * * An optional boolean value that indicates if this pipe will be used for 36 | * handle passing between processes. 37 | */ 38 | class pipe_handle final: public stream_handle { 39 | public: 40 | using chmod_flags = details::uvw_chmod_flags; 41 | 42 | explicit pipe_handle(loop::token token, std::shared_ptr ref, bool pass = false); 43 | 44 | /** 45 | * @brief Initializes the handle. 46 | * @return Underlying return value. 47 | */ 48 | int init(); 49 | 50 | /** 51 | * @brief Opens an existing file descriptor or HANDLE as a pipe. 52 | * 53 | * The passed file descriptor or HANDLE is not checked for its type, but 54 | * it’s required that it represents a valid pipe. 55 | * 56 | * @param file A valid file handle (either a file descriptor or a HANDLE). 57 | * @return Underlying return value. 58 | */ 59 | int open(file_handle file); 60 | 61 | /** 62 | * @brief bind Binds the pipe to a file path (Unix) or a name (Windows). 63 | * 64 | * Paths on Unix get truncated typically between 92 and 108 bytes. 65 | * 66 | * @param name A valid file path. 67 | * @param no_truncate Force an error rather than allow truncating a path. 68 | * @return Underlying return value. 69 | */ 70 | int bind(const std::string &name, const bool no_truncate = false); 71 | 72 | /** 73 | * @brief Connects to the Unix domain socket or the named pipe. 74 | * 75 | * Paths on Unix get truncated typically between 92 and 108 bytes.
76 | * A connect event is emitted when the connection has been 77 | * established. 78 | * 79 | * @param name A valid domain socket or named pipe. 80 | * @param no_truncate Force an error rather than allow truncating a path. 81 | * @return Underlying return value. 82 | */ 83 | int connect(const std::string &name, const bool no_truncate = false); 84 | 85 | /** 86 | * @brief Gets the name of the Unix domain socket or the named pipe. 87 | * @return The name of the Unix domain socket or the named pipe, an empty 88 | * string in case of errors. 89 | */ 90 | std::string sock() const noexcept; 91 | 92 | /** 93 | * @brief Gets the name of the Unix domain socket or the named pipe to which 94 | * the handle is connected. 95 | * @return The name of the Unix domain socket or the named pipe to which 96 | * the handle is connected, an empty string in case of errors. 97 | */ 98 | std::string peer() const noexcept; 99 | 100 | /** 101 | * @brief Sets the number of pending pipe this instance can handle. 102 | * 103 | * This method can be used to set the number of pending pipe this instance 104 | * handles when the pipe server is waiting for connections.
105 | * Note that this setting applies to Windows only. 106 | * 107 | * @param count The number of accepted pending pipe. 108 | */ 109 | void pending(int count) noexcept; 110 | 111 | /** 112 | * @brief Gets the number of pending pipe this instance can handle. 113 | * @return The number of pending pipe this instance can handle. 114 | */ 115 | int pending() noexcept; 116 | 117 | /** 118 | * @brief Used to receive handles over IPC pipes. 119 | * 120 | * Steps to be done: 121 | * 122 | * * Call `pending()`, if it’s greater than zero then proceed. 123 | * * Initialize a handle of the given type, as returned by `receive()`. 124 | * * Call `accept(pipe, handle)`. 125 | * 126 | * @return The type of the pending handle. Possible values are: 127 | * 128 | * * `handle_type::PIPE` 129 | * * `handle_type::TCP` 130 | * * `handle_type::UDP` 131 | * * `handle_type::UNKNOWN` 132 | */ 133 | handle_type receive() noexcept; 134 | 135 | /** 136 | * @brief Alters pipe permissions. 137 | * 138 | * It allows the pipe to be accessed from processes run by different users. 139 | * 140 | * Available flags are: 141 | * 142 | * * `pipe_handle::chmod_flags::READABLE` 143 | * * `pipe_handle::chmod_flags::WRITABLE` 144 | * 145 | * See the official 146 | * [documentation](http://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_chmod) 147 | * for further details. 148 | * 149 | * @param flags A valid set of flags. 150 | * @return Underlying return value. 151 | */ 152 | int chmod(chmod_flags flags) noexcept; 153 | 154 | private: 155 | bool ipc; 156 | }; 157 | 158 | } // namespace uvw 159 | 160 | #ifndef UVW_AS_LIB 161 | # include "pipe.ipp" 162 | #endif 163 | 164 | #endif // UVW_PIPE_INCLUDE_H 165 | -------------------------------------------------------------------------------- /src/uvw/pipe.ipp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "config.h" 3 | 4 | namespace uvw { 5 | 6 | UVW_INLINE pipe_handle::pipe_handle(loop::token token, std::shared_ptr ref, bool pass) 7 | : stream_handle{token, std::move(ref)}, ipc{pass} {} 8 | 9 | UVW_INLINE int pipe_handle::init() { 10 | return leak_if(uv_pipe_init(parent().raw(), raw(), ipc)); 11 | } 12 | 13 | UVW_INLINE int pipe_handle::open(file_handle file) { 14 | return uv_pipe_open(raw(), file); 15 | } 16 | 17 | UVW_INLINE int pipe_handle::bind(const std::string &name, const bool no_truncate) { 18 | return uv_pipe_bind2(raw(), name.data(), name.size(), no_truncate * UV_PIPE_NO_TRUNCATE); 19 | } 20 | 21 | UVW_INLINE int pipe_handle::connect(const std::string &name, const bool no_truncate) { 22 | auto listener = [ptr = shared_from_this()](const auto &event, const auto &) { 23 | ptr->publish(event); 24 | }; 25 | 26 | auto connect = parent().resource(); 27 | connect->on(listener); 28 | connect->on(listener); 29 | 30 | unsigned int flags = no_truncate * UV_PIPE_NO_TRUNCATE; 31 | return connect->connect(&uv_pipe_connect2, raw(), name.data(), name.size(), flags); 32 | } 33 | 34 | UVW_INLINE std::string pipe_handle::sock() const noexcept { 35 | return details::try_read(&uv_pipe_getsockname, raw()); 36 | } 37 | 38 | UVW_INLINE std::string pipe_handle::peer() const noexcept { 39 | return details::try_read(&uv_pipe_getpeername, raw()); 40 | } 41 | 42 | UVW_INLINE void pipe_handle::pending(int count) noexcept { 43 | uv_pipe_pending_instances(raw(), count); 44 | } 45 | 46 | UVW_INLINE int pipe_handle::pending() noexcept { 47 | return uv_pipe_pending_count(raw()); 48 | } 49 | 50 | UVW_INLINE handle_type pipe_handle::receive() noexcept { 51 | handle_category category = uv_pipe_pending_type(raw()); 52 | return utilities::guess_handle(category); 53 | } 54 | 55 | UVW_INLINE int pipe_handle::chmod(chmod_flags flags) noexcept { 56 | return uv_pipe_chmod(raw(), static_cast(flags)); 57 | } 58 | 59 | } // namespace uvw 60 | -------------------------------------------------------------------------------- /src/uvw/poll.cpp: -------------------------------------------------------------------------------- 1 | #include "poll.h" 2 | #include "poll.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/poll.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_POLL_INCLUDE_H 2 | #define UVW_POLL_INCLUDE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "config.h" 8 | #include "enum.hpp" 9 | #include "handle.hpp" 10 | #include "util.h" 11 | 12 | namespace uvw { 13 | 14 | namespace details { 15 | 16 | enum class uvw_poll_event : std::underlying_type_t { 17 | READABLE = UV_READABLE, 18 | WRITABLE = UV_WRITABLE, 19 | DISCONNECT = UV_DISCONNECT, 20 | PRIORITIZED = UV_PRIORITIZED, 21 | UVW_ENUM = 0 22 | }; 23 | 24 | } 25 | 26 | /*! @brief Poll event. */ 27 | struct poll_event { 28 | explicit poll_event(details::uvw_poll_event events) noexcept; 29 | 30 | /** 31 | * @brief Detected events all in one. 32 | * 33 | * Available flags are: 34 | * 35 | * * `poll_handle::event::READABLE` 36 | * * `poll_handle::event::WRITABLE` 37 | * * `poll_handle::event::DISCONNECT` 38 | * * `poll_handle::event::PRIORITIZED` 39 | */ 40 | details::uvw_poll_event flags; 41 | }; 42 | 43 | /** 44 | * @brief The poll handle. 45 | * 46 | * Poll handles are used to watch file descriptors for readability, writability 47 | * and disconnection. 48 | * 49 | * To create a `poll_handle` through a `loop`, arguments follow: 50 | * 51 | * * A descriptor that can be: 52 | * * either an `int` file descriptor 53 | * * or a `os_socket_handle` socket descriptor 54 | * 55 | * See the official 56 | * [documentation](http://docs.libuv.org/en/v1.x/poll.html) 57 | * for further details. 58 | */ 59 | class poll_handle final: public handle { 60 | static void start_callback(uv_poll_t *hndl, int status, int events); 61 | 62 | public: 63 | using poll_event_flags = details::uvw_poll_event; 64 | 65 | explicit poll_handle(loop::token token, std::shared_ptr ref, int desc); 66 | explicit poll_handle(loop::token token, std::shared_ptr ref, os_socket_handle sock); 67 | 68 | /** 69 | * @brief Initializes the handle. 70 | * @return Underlying return value. 71 | */ 72 | int init(); 73 | 74 | /** 75 | * @brief Starts polling the file descriptor. 76 | * 77 | * Available flags are: 78 | * 79 | * * `poll_handle::event::READABLE` 80 | * * `poll_handle::event::WRITABLE` 81 | * * `poll_handle::event::DISCONNECT` 82 | * * `poll_handle::event::PRIORITIZED` 83 | * 84 | * As soon as an event is detected, a poll event is emitted by the 85 | * handle. 86 | * 87 | * Calling more than once this method will update the flags to which the 88 | * caller is interested. 89 | * 90 | * @param flags The events to which the caller is interested. 91 | * @return Underlying return value. 92 | */ 93 | int start(poll_event_flags flags); 94 | 95 | /** 96 | * @brief Stops polling the file descriptor. 97 | * @return Underlying return value. 98 | */ 99 | int stop(); 100 | 101 | private: 102 | enum { 103 | FD, 104 | SOCKET 105 | } tag; 106 | 107 | union { 108 | int file_desc; 109 | os_socket_handle socket; 110 | }; 111 | }; 112 | 113 | } // namespace uvw 114 | 115 | #ifndef UVW_AS_LIB 116 | # include "poll.ipp" 117 | #endif 118 | 119 | #endif // UVW_POLL_INCLUDE_H 120 | -------------------------------------------------------------------------------- /src/uvw/poll.ipp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "config.h" 3 | 4 | namespace uvw { 5 | 6 | UVW_INLINE poll_event::poll_event(details::uvw_poll_event events) noexcept 7 | : flags{events} {} 8 | 9 | UVW_INLINE poll_handle::poll_handle(loop::token token, std::shared_ptr ref, int desc) 10 | : handle{token, std::move(ref)}, tag{FD}, file_desc{desc} {} 11 | 12 | UVW_INLINE poll_handle::poll_handle(loop::token token, std::shared_ptr ref, os_socket_handle sock) 13 | : handle{token, std::move(ref)}, tag{SOCKET}, socket{sock} {} 14 | 15 | // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) 16 | UVW_INLINE void poll_handle::start_callback(uv_poll_t *hndl, int status, int events) { 17 | if(poll_handle &poll = *(static_cast(hndl->data)); status) { 18 | poll.publish(error_event{status}); 19 | } else { 20 | poll.publish(poll_event{poll_event_flags(events)}); 21 | } 22 | } 23 | 24 | UVW_INLINE int poll_handle::init() { 25 | if(tag == SOCKET) { 26 | return leak_if(uv_poll_init_socket(parent().raw(), raw(), socket)); 27 | } else { 28 | return leak_if(uv_poll_init(parent().raw(), raw(), file_desc)); 29 | } 30 | } 31 | 32 | UVW_INLINE int poll_handle::start(poll_event_flags flags) { 33 | return uv_poll_start(raw(), static_cast(flags), &start_callback); 34 | } 35 | 36 | UVW_INLINE int poll_handle::stop() { 37 | return uv_poll_stop(raw()); 38 | } 39 | 40 | } // namespace uvw 41 | -------------------------------------------------------------------------------- /src/uvw/prepare.cpp: -------------------------------------------------------------------------------- 1 | #include "prepare.h" 2 | #include "prepare.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/prepare.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_PREPARE_INCLUDE_H 2 | #define UVW_PREPARE_INCLUDE_H 3 | 4 | #include 5 | #include "handle.hpp" 6 | #include "loop.h" 7 | 8 | namespace uvw { 9 | 10 | /*! @brief Prepare event. */ 11 | struct prepare_event {}; 12 | 13 | /** 14 | * @brief The prepare handle. 15 | * 16 | * Prepare handles will emit a prepare event once per loop iteration, right 17 | * before polling for I/O. 18 | * 19 | * To create a `prepare_handle` through a `loop`, no arguments are required. 20 | */ 21 | class prepare_handle final: public handle { 22 | static void start_callback(uv_prepare_t *hndl); 23 | 24 | public: 25 | using handle::handle; 26 | 27 | /** 28 | * @brief Initializes the handle. 29 | * @return Underlying return value. 30 | */ 31 | int init(); 32 | 33 | /** 34 | * @brief Starts the handle. 35 | * 36 | * A prepare event will be emitted once per loop iteration, right before 37 | * polling for I/O. 38 | * 39 | * The handle will start emitting prepare events when needed. 40 | * 41 | * @return Underlying return value. 42 | */ 43 | int start(); 44 | 45 | /** 46 | * @brief Stops the handle. 47 | * @return Underlying return value. 48 | */ 49 | int stop(); 50 | }; 51 | 52 | } // namespace uvw 53 | 54 | #ifndef UVW_AS_LIB 55 | # include "prepare.ipp" 56 | #endif 57 | 58 | #endif // UVW_PREPARE_INCLUDE_H 59 | -------------------------------------------------------------------------------- /src/uvw/prepare.ipp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | namespace uvw { 4 | 5 | UVW_INLINE void prepare_handle::start_callback(uv_prepare_t *hndl) { 6 | prepare_handle &prepare = *(static_cast(hndl->data)); 7 | prepare.publish(prepare_event{}); 8 | } 9 | 10 | UVW_INLINE int prepare_handle::init() { 11 | return leak_if(uv_prepare_init(parent().raw(), raw())); 12 | } 13 | 14 | UVW_INLINE int prepare_handle::start() { 15 | return uv_prepare_start(raw(), &start_callback); 16 | } 17 | 18 | UVW_INLINE int prepare_handle::stop() { 19 | return uv_prepare_stop(raw()); 20 | } 21 | 22 | } // namespace uvw 23 | -------------------------------------------------------------------------------- /src/uvw/process.cpp: -------------------------------------------------------------------------------- 1 | #include "process.h" 2 | #include "process.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/process.ipp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "config.h" 3 | 4 | namespace uvw { 5 | 6 | UVW_INLINE exit_event::exit_event(int64_t code, int sig) noexcept 7 | : status{code}, signal{sig} {} 8 | 9 | UVW_INLINE void process_handle::exit_callback(uv_process_t *hndl, int64_t exit_status, int term_signal) { 10 | process_handle &process = *(static_cast(hndl->data)); 11 | process.publish(exit_event{exit_status, term_signal}); 12 | } 13 | 14 | UVW_INLINE process_handle::process_handle(loop::token token, std::shared_ptr ref) 15 | : handle{token, std::move(ref)} {} 16 | 17 | UVW_INLINE void process_handle::disable_stdio_inheritance() noexcept { 18 | uv_disable_stdio_inheritance(); 19 | } 20 | 21 | UVW_INLINE bool process_handle::kill(int pid, int signum) noexcept { 22 | return (0 == uv_kill(pid, signum)); 23 | } 24 | 25 | UVW_INLINE int process_handle::init() { 26 | // deferred initialization: libuv initializes process handles only when 27 | // uv_spawn is invoked and uvw stays true to the underlying library 28 | return 0; 29 | } 30 | 31 | UVW_INLINE int process_handle::spawn(const char *file, char **args, char **env) { 32 | uv_process_options_t po; 33 | 34 | po.exit_cb = &exit_callback; 35 | po.file = file; 36 | po.args = args; 37 | po.env = env; 38 | po.cwd = po_cwd.empty() ? nullptr : po_cwd.data(); 39 | po.flags = static_cast(po_flags); 40 | po.uid = po_uid; 41 | po.gid = po_gid; 42 | 43 | std::vector poStdio; 44 | poStdio.reserve(po_fd_stdio.size() + po_stream_stdio.size()); 45 | poStdio.insert(poStdio.begin(), po_fd_stdio.cbegin(), po_fd_stdio.cend()); 46 | poStdio.insert(poStdio.end(), po_stream_stdio.cbegin(), po_stream_stdio.cend()); 47 | 48 | po.stdio_count = static_cast(poStdio.size()); 49 | po.stdio = poStdio.data(); 50 | 51 | // see init member function for more details 52 | static_cast(leak_if(0)); 53 | 54 | return uv_spawn(parent().raw(), raw(), &po); 55 | } 56 | 57 | UVW_INLINE int process_handle::kill(int signum) { 58 | return uv_process_kill(raw(), signum); 59 | } 60 | 61 | UVW_INLINE int process_handle::pid() noexcept { 62 | return raw()->pid; 63 | } 64 | 65 | UVW_INLINE process_handle &process_handle::cwd(const std::string &path) noexcept { 66 | po_cwd = path; 67 | return *this; 68 | } 69 | 70 | UVW_INLINE process_handle &process_handle::flags(process_flags flags) noexcept { 71 | po_flags = flags; 72 | return *this; 73 | } 74 | 75 | UVW_INLINE process_handle &process_handle::stdio(file_handle fd, stdio_flags flags) { 76 | auto fgs = static_cast(flags); 77 | 78 | auto actual = uvw::file_handle{fd}; 79 | 80 | auto it = std::find_if(po_fd_stdio.begin(), po_fd_stdio.end(), [actual](auto &&container) { 81 | return static_cast>(container.data.fd) == static_cast>(actual); 82 | }); 83 | 84 | if(it == po_fd_stdio.cend()) { 85 | uv_stdio_container_t container; 86 | container.flags = fgs; 87 | container.data.fd = actual; 88 | po_fd_stdio.push_back(container); 89 | } else { 90 | it->flags = fgs; 91 | it->data.fd = actual; 92 | } 93 | 94 | return *this; 95 | } 96 | 97 | UVW_INLINE process_handle &process_handle::uid(uid_type id) { 98 | po_uid = id; 99 | return *this; 100 | } 101 | 102 | UVW_INLINE process_handle &process_handle::gid(gid_type id) { 103 | po_gid = id; 104 | return *this; 105 | } 106 | 107 | } // namespace uvw 108 | -------------------------------------------------------------------------------- /src/uvw/request.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UVW_REQUEST_INCLUDE_H 2 | #define UVW_REQUEST_INCLUDE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "config.h" 9 | #include "resource.hpp" 10 | 11 | namespace uvw { 12 | 13 | /** 14 | * @brief Request base class. 15 | * 16 | * Base type for all `uvw` request types. 17 | */ 18 | template 19 | class request: public resource { 20 | protected: 21 | [[nodiscard]] static auto reserve(U *req) { 22 | auto ptr = static_cast(req->data)->shared_from_this(); 23 | ptr->self_reset(); 24 | return ptr; 25 | } 26 | 27 | public: 28 | using resource::resource; 29 | 30 | /** 31 | * @brief Cancels a pending request. 32 | * 33 | * This method fails if the request is executing or has finished 34 | * executing. 35 | * 36 | * See the official 37 | * [documentation](http://docs.libuv.org/en/v1.x/request.html#c.uv_cancel) 38 | * for further details. 39 | * 40 | * @return Underlying return value. 41 | */ 42 | int cancel() { 43 | return uv_cancel(reinterpret_cast(this->raw())); 44 | } 45 | 46 | /** 47 | * @brief Returns the size of the underlying request type. 48 | * @return The size of the underlying request type. 49 | */ 50 | [[nodiscard]] std::size_t size() const noexcept { 51 | return uv_req_size(reinterpret_cast(this->raw())->type); 52 | } 53 | }; 54 | 55 | } // namespace uvw 56 | 57 | #endif // UVW_REQUEST_INCLUDE_H 58 | -------------------------------------------------------------------------------- /src/uvw/resource.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UVW_RESOURCE_INCLUDE_H 2 | #define UVW_RESOURCE_INCLUDE_H 3 | 4 | #include 5 | #include 6 | #include "config.h" 7 | #include "emitter.h" 8 | #include "uv_type.hpp" 9 | 10 | namespace uvw { 11 | 12 | /** 13 | * @brief Common class for almost all the resources available in `uvw`. 14 | * 15 | * This is the base class for handles and requests. 16 | */ 17 | template 18 | class resource: public uv_type, public emitter, public std::enable_shared_from_this { 19 | protected: 20 | [[nodiscard]] int leak_if(int err) noexcept { 21 | if(err == 0) { 22 | self_ptr = this->shared_from_this(); 23 | } 24 | 25 | return err; 26 | } 27 | 28 | void self_reset() noexcept { 29 | self_ptr.reset(); 30 | } 31 | 32 | [[nodiscard]] bool has_self() const noexcept { 33 | return static_cast(self_ptr); 34 | } 35 | 36 | public: 37 | explicit resource(loop::token token, std::shared_ptr ref) 38 | : uv_type{token, std::move(ref)} { 39 | this->raw()->data = this; 40 | } 41 | 42 | /** 43 | * @brief Gets user-defined data. `uvw` won't use this field in any case. 44 | * @return User-defined data if any, an invalid pointer otherwise. 45 | */ 46 | template 47 | [[nodiscard]] std::shared_ptr data() const { 48 | return std::static_pointer_cast(user_data); 49 | } 50 | 51 | /** 52 | * @brief Sets arbitrary data. `uvw` won't use this field in any case. 53 | * @param udata User-defined arbitrary data. 54 | */ 55 | void data(std::shared_ptr udata) { 56 | user_data = std::move(udata); 57 | } 58 | 59 | private: 60 | std::shared_ptr user_data{nullptr}; 61 | std::shared_ptr self_ptr{nullptr}; 62 | }; 63 | 64 | } // namespace uvw 65 | 66 | #endif // UVW_RESOURCE_INCLUDE_H 67 | -------------------------------------------------------------------------------- /src/uvw/signal.cpp: -------------------------------------------------------------------------------- 1 | #include "signal.h" 2 | #include "signal.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/signal.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_SIGNAL_INCLUDE_H 2 | #define UVW_SIGNAL_INCLUDE_H 3 | 4 | #include 5 | #include "config.h" 6 | #include "handle.hpp" 7 | #include "loop.h" 8 | 9 | namespace uvw { 10 | 11 | /*! @brief Signal event. */ 12 | struct signal_event { 13 | explicit signal_event(int sig) noexcept; 14 | 15 | int signum; /*!< The signal being monitored by this handle. */ 16 | }; 17 | 18 | /** 19 | * @brief The signal handle. 20 | * 21 | * Signal handles implement Unix style signal handling on a per-event loop 22 | * bases.
23 | * Reception of some signals is emulated on Windows. 24 | * 25 | * To create a `signal_handle` through a `loop`, no arguments are required. 26 | * 27 | * See the official 28 | * [documentation](http://docs.libuv.org/en/v1.x/signal.html) 29 | * for further details. 30 | */ 31 | class signal_handle final: public handle { 32 | static void start_callback(uv_signal_t *hndl, int signum); 33 | 34 | public: 35 | using handle::handle; 36 | 37 | /** 38 | * @brief Initializes the handle. 39 | * @return Underlying return value. 40 | */ 41 | int init(); 42 | 43 | /** 44 | * @brief Starts the handle. 45 | * 46 | * The handle will start emitting signal events when needed. 47 | * 48 | * @param signum The signal to be monitored. 49 | * @return Underlying return value. 50 | */ 51 | int start(int signum); 52 | 53 | /** 54 | * @brief Starts the handle. 55 | * 56 | * Same functionality as signal_handle::start but the signal handler is 57 | * reset the moment the signal is received. 58 | * 59 | * @param signum The signal to be monitored. 60 | * @return Underlying return value. 61 | */ 62 | int one_shot(int signum); 63 | 64 | /** 65 | * @brief Stops the handle. 66 | * @return Underlying return value. 67 | */ 68 | int stop(); 69 | 70 | /** 71 | * @brief Gets the signal being monitored. 72 | * @return The signal being monitored. 73 | */ 74 | int signal() const noexcept; 75 | }; 76 | 77 | } // namespace uvw 78 | 79 | #ifndef UVW_AS_LIB 80 | # include "signal.ipp" 81 | #endif 82 | 83 | #endif // UVW_SIGNAL_INCLUDE_H 84 | -------------------------------------------------------------------------------- /src/uvw/signal.ipp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | namespace uvw { 4 | 5 | UVW_INLINE signal_event::signal_event(int sig) noexcept 6 | : signum{sig} {} 7 | 8 | UVW_INLINE void signal_handle::start_callback(uv_signal_t *hndl, int signum) { 9 | signal_handle &signal = *(static_cast(hndl->data)); 10 | signal.publish(signal_event{signum}); 11 | } 12 | 13 | UVW_INLINE int signal_handle::init() { 14 | return leak_if(uv_signal_init(parent().raw(), raw())); 15 | } 16 | 17 | UVW_INLINE int signal_handle::start(int signum) { 18 | return uv_signal_start(raw(), &start_callback, signum); 19 | } 20 | 21 | UVW_INLINE int signal_handle::one_shot(int signum) { 22 | return uv_signal_start_oneshot(raw(), &start_callback, signum); 23 | } 24 | 25 | UVW_INLINE int signal_handle::stop() { 26 | return uv_signal_stop(raw()); 27 | } 28 | 29 | UVW_INLINE int signal_handle::signal() const noexcept { 30 | return raw()->signum; 31 | } 32 | 33 | } // namespace uvw 34 | -------------------------------------------------------------------------------- /src/uvw/stream.cpp: -------------------------------------------------------------------------------- 1 | #include "stream.h" 2 | #include "stream.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/stream.ipp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | namespace uvw { 4 | 5 | UVW_INLINE data_event::data_event(std::unique_ptr buf, std::size_t len) noexcept 6 | : data{std::move(buf)}, 7 | length{len} {} 8 | 9 | UVW_INLINE void details::connect_req::connect_callback(uv_connect_t *req, int status) { 10 | if(auto ptr = reserve(req); status) { 11 | ptr->publish(error_event{status}); 12 | } else { 13 | ptr->publish(connect_event{}); 14 | } 15 | } 16 | 17 | UVW_INLINE void details::shutdown_req::shoutdown_callback(uv_shutdown_t *req, int status) { 18 | if(auto ptr = reserve(req); status) { 19 | ptr->publish(error_event{status}); 20 | } else { 21 | ptr->publish(shutdown_event{}); 22 | } 23 | } 24 | 25 | UVW_INLINE int details::shutdown_req::shutdown(uv_stream_t *hndl) { 26 | return this->leak_if(uv_shutdown(raw(), hndl, &shoutdown_callback)); 27 | } 28 | 29 | } // namespace uvw 30 | -------------------------------------------------------------------------------- /src/uvw/tcp.cpp: -------------------------------------------------------------------------------- 1 | #include "tcp.h" 2 | #include "tcp.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/tcp.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_TCP_INCLUDE_H 2 | #define UVW_TCP_INCLUDE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "config.h" 11 | #include "enum.hpp" 12 | #include "request.hpp" 13 | #include "stream.h" 14 | #include "util.h" 15 | 16 | namespace uvw { 17 | 18 | namespace details { 19 | 20 | enum class uvw_tcp_flags : std::underlying_type_t { 21 | IPV6ONLY = UV_TCP_IPV6ONLY, 22 | UVW_ENUM = 0 23 | }; 24 | 25 | } 26 | 27 | /** 28 | * @brief The TCP handle. 29 | * 30 | * TCP handles are used to represent both TCP streams and servers.
31 | * By default, _ipv4_ is used as a template parameter. The handle already 32 | * supports _IPv6_ out-of-the-box by using `uvw::ipv6`. 33 | * 34 | * To create a `tcp_handle` through a `loop`, arguments follow: 35 | * 36 | * * An optional integer value that indicates the flags used to initialize 37 | * the socket. 38 | * 39 | * See the official 40 | * [documentation](http://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_init_ex) 41 | * for further details. 42 | */ 43 | class tcp_handle final: public stream_handle { 44 | public: 45 | using time = std::chrono::duration; 46 | using tcp_flags = details::uvw_tcp_flags; 47 | using ipv4 = uvw::ipv4; 48 | using ipv6 = uvw::ipv6; 49 | 50 | explicit tcp_handle(loop::token token, std::shared_ptr ref, unsigned int f = {}); 51 | 52 | /** 53 | * @brief Initializes the handle. No socket is created as of yet. 54 | * @return Underlying return value. 55 | */ 56 | int init(); 57 | 58 | /** 59 | * @brief Opens an existing file descriptor or SOCKET as a TCP handle. 60 | * 61 | * The passed file descriptor or SOCKET is not checked for its type, but 62 | * it’s required that it represents a valid stream socket. 63 | * 64 | * @param socket A valid socket handle (either a file descriptor or a 65 | * SOCKET). 66 | * 67 | * @return Underlying return value. 68 | */ 69 | int open(os_socket_handle socket); 70 | 71 | /** 72 | * @brief Enables/Disables Nagle’s algorithm. 73 | * @param value True to enable it, false otherwise. 74 | * @return True in case of success, false otherwise. 75 | */ 76 | bool no_delay(bool value = false); 77 | 78 | /** 79 | * @brief Enables/Disables TCP keep-alive. 80 | * @param enable True to enable it, false otherwise. 81 | * @param val Initial delay in seconds (use 82 | * `std::chrono::duration`). 83 | * @return True in case of success, false otherwise. 84 | */ 85 | bool keep_alive(bool enable = false, time val = time{0}); 86 | 87 | /** 88 | * @brief Enables/Disables simultaneous asynchronous accept requests. 89 | * 90 | * Enables/Disables simultaneous asynchronous accept requests that are 91 | * queued by the operating system when listening for new TCP 92 | * connections.
93 | * This setting is used to tune a TCP server for the desired performance. 94 | * Having simultaneous accepts can significantly improve the rate of 95 | * accepting connections (which is why it is enabled by default) but may 96 | * lead to uneven load distribution in multi-process setups. 97 | * 98 | * @param enable True to enable it, false otherwise. 99 | * @return True in case of success, false otherwise. 100 | */ 101 | bool simultaneous_accepts(bool enable = true); 102 | 103 | /** 104 | * @brief Binds the handle to an address and port. 105 | * 106 | * A successful call to this function does not guarantee that the call to 107 | * `listen()` or `connect()` will work properly. 108 | * 109 | * Available flags are: 110 | * 111 | * * `tcp_handle::tcp_flags::IPV6ONLY`: it disables dual-stack support and 112 | * only IPv6 is used. 113 | * 114 | * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure. 115 | * @param opts Optional additional flags. 116 | * @return Underlying return value. 117 | */ 118 | int bind(const sockaddr &addr, tcp_flags opts = tcp_flags::UVW_ENUM); 119 | 120 | /** 121 | * @brief Binds the handle to an address and port. 122 | * 123 | * A successful call to this function does not guarantee that the call to 124 | * `listen()` or `connect()` will work properly. 125 | * 126 | * Available flags are: 127 | * 128 | * * `tcp_handle::tcp_flags::IPV6ONLY`: it disables dual-stack support and 129 | * only IPv6 is used. 130 | * 131 | * @param ip The address to which to bind. 132 | * @param port The port to which to bind. 133 | * @param opts Optional additional flags. 134 | * @return Underlying return value. 135 | */ 136 | int bind(const std::string &ip, unsigned int port, tcp_flags opts = tcp_flags::UVW_ENUM); 137 | 138 | /** 139 | * @brief Binds the handle to an address and port. 140 | * 141 | * A successful call to this function does not guarantee that the call to 142 | * `listen()` or `connect()` will work properly. 143 | * 144 | * Available flags are: 145 | * 146 | * * `tcp_handle::tcp_flags::IPV6ONLY`: it disables dual-stack support and 147 | * only IPv6 is used. 148 | * 149 | * @param addr A valid instance of socket_address. 150 | * @param opts Optional additional flags. 151 | * @return Underlying return value. 152 | */ 153 | int bind(const socket_address &addr, tcp_flags opts = tcp_flags::UVW_ENUM); 154 | 155 | /** 156 | * @brief Gets the current address to which the handle is bound. 157 | * @return A valid instance of socket_address, an empty one in case of 158 | * errors. 159 | */ 160 | socket_address sock() const noexcept; 161 | 162 | /** 163 | * @brief Gets the address of the peer connected to the handle. 164 | * @return A valid instance of socket_address, an empty one in case of 165 | * errors. 166 | */ 167 | socket_address peer() const noexcept; 168 | 169 | /** 170 | * @brief Establishes an IPv4 or IPv6 TCP connection. 171 | * 172 | * On Windows if the addr is initialized to point to an unspecified address 173 | * (`0.0.0.0` or `::`) it will be changed to point to localhost. This is 174 | * done to match the behavior of Linux systems. 175 | * 176 | * A connect event is emitted when the connection has been established. 177 | * 178 | * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure. 179 | * @return Underlying return value. 180 | */ 181 | int connect(const sockaddr &addr); 182 | 183 | /** 184 | * @brief Establishes an IPv4 or IPv6 TCP connection. 185 | * 186 | * A connect event is emitted when the connection has been established. 187 | * 188 | * @param ip The address to which to bind. 189 | * @param port The port to which to bind. 190 | * @return Underlying return value. 191 | */ 192 | int connect(const std::string &ip, unsigned int port); 193 | 194 | /** 195 | * @brief Establishes an IPv4 or IPv6 TCP connection. 196 | * 197 | * A connect event is emitted when the connection has been established. 198 | * 199 | * @param addr A valid instance of socket_address. 200 | * @return Underlying return value. 201 | */ 202 | int connect(const socket_address &addr); 203 | 204 | /** 205 | * @brief Resets a TCP connection by sending a RST packet. 206 | * 207 | * This is accomplished by setting the `SO_LINGER` socket option with a 208 | * linger interval of zero and then calling `close`.
209 | * Due to some platform inconsistencies, mixing of `shutdown` and 210 | * `close_reset` calls is not allowed. 211 | * 212 | * A close event is emitted when the connection has been reset. 213 | * 214 | * @return Underlying return value. 215 | */ 216 | int close_reset(); 217 | 218 | private: 219 | enum { 220 | DEFAULT, 221 | FLAGS 222 | } tag; 223 | 224 | unsigned int flags; 225 | }; 226 | 227 | } // namespace uvw 228 | 229 | #ifndef UVW_AS_LIB 230 | # include "tcp.ipp" 231 | #endif 232 | 233 | #endif // UVW_TCP_INCLUDE_H 234 | -------------------------------------------------------------------------------- /src/uvw/tcp.ipp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | namespace uvw { 4 | 5 | UVW_INLINE tcp_handle::tcp_handle(loop::token token, std::shared_ptr ref, unsigned int f) 6 | : stream_handle{token, std::move(ref)}, tag{f ? FLAGS : DEFAULT}, flags{f} {} 7 | 8 | UVW_INLINE int tcp_handle::init() { 9 | if(tag == FLAGS) { 10 | return leak_if(uv_tcp_init_ex(parent().raw(), raw(), flags)); 11 | } else { 12 | return leak_if(uv_tcp_init(parent().raw(), raw())); 13 | } 14 | } 15 | 16 | UVW_INLINE int tcp_handle::open(os_socket_handle socket) { 17 | return uv_tcp_open(raw(), socket); 18 | } 19 | 20 | UVW_INLINE bool tcp_handle::no_delay(bool value) { 21 | return (0 == uv_tcp_nodelay(raw(), value)); 22 | } 23 | 24 | UVW_INLINE bool tcp_handle::keep_alive(bool enable, tcp_handle::time val) { 25 | return (0 == uv_tcp_keepalive(raw(), enable, val.count())); 26 | } 27 | 28 | UVW_INLINE bool tcp_handle::simultaneous_accepts(bool enable) { 29 | return (0 == uv_tcp_simultaneous_accepts(raw(), enable)); 30 | } 31 | 32 | UVW_INLINE int tcp_handle::bind(const sockaddr &addr, tcp_flags opts) { 33 | return uv_tcp_bind(raw(), &addr, static_cast(opts)); 34 | } 35 | 36 | UVW_INLINE int tcp_handle::bind(const std::string &ip, unsigned int port, tcp_flags opts) { 37 | return bind(details::ip_addr(ip.data(), port), opts); 38 | } 39 | 40 | UVW_INLINE int tcp_handle::bind(const socket_address &addr, tcp_flags opts) { 41 | return bind(addr.ip, addr.port, opts); 42 | } 43 | 44 | UVW_INLINE socket_address tcp_handle::sock() const noexcept { 45 | sockaddr_storage storage; 46 | int len = sizeof(sockaddr_storage); 47 | uv_tcp_getsockname(raw(), reinterpret_cast(&storage), &len); 48 | return details::sock_addr(storage); 49 | } 50 | 51 | UVW_INLINE socket_address tcp_handle::peer() const noexcept { 52 | sockaddr_storage storage; 53 | int len = sizeof(sockaddr_storage); 54 | uv_tcp_getpeername(raw(), reinterpret_cast(&storage), &len); 55 | return details::sock_addr(storage); 56 | } 57 | 58 | UVW_INLINE int tcp_handle::connect(const std::string &ip, unsigned int port) { 59 | return connect(details::ip_addr(ip.data(), port)); 60 | } 61 | 62 | UVW_INLINE int tcp_handle::connect(const socket_address &addr) { 63 | return connect(addr.ip, addr.port); 64 | } 65 | 66 | UVW_INLINE int tcp_handle::connect(const sockaddr &addr) { 67 | auto listener = [ptr = shared_from_this()](const auto &event, const auto &) { 68 | ptr->publish(event); 69 | }; 70 | 71 | auto req = parent().resource(); 72 | req->on(listener); 73 | req->on(listener); 74 | 75 | return req->connect(&uv_tcp_connect, raw(), &addr); 76 | } 77 | 78 | UVW_INLINE int tcp_handle::close_reset() { 79 | return uv_tcp_close_reset(raw(), &this->close_callback); 80 | } 81 | 82 | } // namespace uvw 83 | -------------------------------------------------------------------------------- /src/uvw/thread.cpp: -------------------------------------------------------------------------------- 1 | #include "thread.h" 2 | #include "thread.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/thread.ipp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | namespace uvw { 4 | 5 | UVW_INLINE thread::thread(loop::token token, std::shared_ptr ref, task t, std::shared_ptr d) noexcept 6 | : uv_type{token, std::move(ref)}, 7 | data{std::move(d)}, 8 | func{std::move(t)} {} 9 | 10 | UVW_INLINE void thread::create_callback(void *arg) { 11 | thread &curr = *(static_cast(arg)); 12 | curr.func(curr.data); 13 | } 14 | 15 | UVW_INLINE thread::type thread::self() noexcept { 16 | return uv_thread_self(); 17 | } 18 | 19 | UVW_INLINE int thread::getcpu() noexcept { 20 | return uv_thread_getcpu(); 21 | } 22 | 23 | UVW_INLINE bool thread::equal(const thread &tl, const thread &tr) noexcept { 24 | return !(0 == uv_thread_equal(tl.raw(), tr.raw())); 25 | } 26 | 27 | UVW_INLINE bool thread::name(const std::string &value) noexcept { 28 | return (uv_thread_setname(value.data()) == 0); 29 | } 30 | 31 | UVW_INLINE std::string thread::name(thread &tl) noexcept { 32 | char buf[details::DEFAULT_SIZE]; 33 | uv_thread_getname(tl.raw(), buf, details::DEFAULT_SIZE); 34 | return std::string{buf}; 35 | } 36 | 37 | UVW_INLINE bool thread::priority(const thread &tl, thread_priority val) noexcept { 38 | return (uv_thread_setpriority(*tl.raw(), static_cast>(val)) == 0); 39 | } 40 | 41 | UVW_INLINE std::pair thread::priority(const thread &tl) noexcept { 42 | int prio{}; 43 | const bool res = (uv_thread_getpriority(*tl.raw(), &prio) == 0); 44 | return {res, thread_priority{static_cast>(prio)}}; 45 | } 46 | 47 | UVW_INLINE thread::~thread() noexcept { 48 | join(); 49 | } 50 | 51 | UVW_INLINE bool thread::run() noexcept { 52 | return (0 == uv_thread_create(raw(), &create_callback, this)); 53 | } 54 | 55 | UVW_INLINE bool thread::run(create_flags opts, std::size_t stack) noexcept { 56 | uv_thread_options_t params{static_cast(opts), stack}; 57 | return (0 == uv_thread_create_ex(raw(), ¶ms, &create_callback, this)); 58 | } 59 | 60 | UVW_INLINE bool thread::join() noexcept { 61 | return (0 == uv_thread_join(raw())); 62 | } 63 | 64 | UVW_INLINE thread_local_storage::thread_local_storage(loop::token token, std::shared_ptr ref) noexcept 65 | : uv_type{token, std::move(ref)} { 66 | uv_key_create(uv_type::raw()); 67 | } 68 | 69 | UVW_INLINE thread_local_storage::~thread_local_storage() noexcept { 70 | uv_key_delete(uv_type::raw()); 71 | } 72 | 73 | UVW_INLINE uv_once_t *once::guard() noexcept { 74 | static uv_once_t once = UV_ONCE_INIT; 75 | return &once; 76 | } 77 | 78 | UVW_INLINE mutex::mutex(loop::token token, std::shared_ptr ref, bool recursive) noexcept 79 | : uv_type{token, std::move(ref)} { 80 | if(recursive) { 81 | uv_mutex_init_recursive(raw()); 82 | } else { 83 | uv_mutex_init(raw()); 84 | } 85 | } 86 | 87 | UVW_INLINE mutex::~mutex() noexcept { 88 | uv_mutex_destroy(raw()); 89 | } 90 | 91 | UVW_INLINE void mutex::lock() noexcept { 92 | uv_mutex_lock(raw()); 93 | } 94 | 95 | UVW_INLINE bool mutex::try_lock() noexcept { 96 | return (0 == uv_mutex_trylock(raw())); 97 | } 98 | 99 | UVW_INLINE void mutex::unlock() noexcept { 100 | uv_mutex_unlock(raw()); 101 | } 102 | 103 | UVW_INLINE rwlock::rwlock(loop::token token, std::shared_ptr ref) noexcept 104 | : uv_type{token, std::move(ref)} { 105 | uv_rwlock_init(raw()); 106 | } 107 | 108 | UVW_INLINE rwlock::~rwlock() noexcept { 109 | uv_rwlock_destroy(raw()); 110 | } 111 | 112 | UVW_INLINE void rwlock::rdlock() noexcept { 113 | uv_rwlock_rdlock(raw()); 114 | } 115 | 116 | UVW_INLINE bool rwlock::try_rdlock() noexcept { 117 | return (0 == uv_rwlock_tryrdlock(raw())); 118 | } 119 | 120 | UVW_INLINE void rwlock::rdunlock() noexcept { 121 | uv_rwlock_rdunlock(raw()); 122 | } 123 | 124 | UVW_INLINE void rwlock::wrlock() noexcept { 125 | uv_rwlock_wrlock(raw()); 126 | } 127 | 128 | UVW_INLINE bool rwlock::try_wrlock() noexcept { 129 | return (0 == uv_rwlock_trywrlock(raw())); 130 | } 131 | 132 | UVW_INLINE void rwlock::wrunlock() noexcept { 133 | uv_rwlock_wrunlock(raw()); 134 | } 135 | 136 | UVW_INLINE semaphore::semaphore(loop::token token, std::shared_ptr ref, unsigned int value) noexcept 137 | : uv_type{token, std::move(ref)} { 138 | uv_sem_init(raw(), value); 139 | } 140 | 141 | UVW_INLINE semaphore::~semaphore() noexcept { 142 | uv_sem_destroy(raw()); 143 | } 144 | 145 | UVW_INLINE void semaphore::post() noexcept { 146 | uv_sem_post(raw()); 147 | } 148 | 149 | UVW_INLINE void semaphore::wait() noexcept { 150 | uv_sem_wait(raw()); 151 | } 152 | 153 | UVW_INLINE bool semaphore::try_wait() noexcept { 154 | return (0 == uv_sem_trywait(raw())); 155 | } 156 | 157 | UVW_INLINE condition::condition(loop::token token, std::shared_ptr ref) noexcept 158 | : uv_type{token, std::move(ref)} { 159 | uv_cond_init(raw()); 160 | } 161 | 162 | UVW_INLINE condition::~condition() noexcept { 163 | uv_cond_destroy(raw()); 164 | } 165 | 166 | UVW_INLINE void condition::signal() noexcept { 167 | uv_cond_signal(raw()); 168 | } 169 | 170 | UVW_INLINE void condition::broadcast() noexcept { 171 | uv_cond_broadcast(raw()); 172 | } 173 | 174 | UVW_INLINE void condition::wait(mutex &mtx) noexcept { 175 | uv_cond_wait(raw(), mtx.raw()); 176 | } 177 | 178 | UVW_INLINE bool condition::timed_wait(mutex &mtx, uint64_t timeout) noexcept { 179 | return (0 == uv_cond_timedwait(raw(), mtx.raw(), timeout)); 180 | } 181 | 182 | UVW_INLINE barrier::barrier(loop::token token, std::shared_ptr ref, unsigned int count) noexcept 183 | : uv_type{token, std::move(ref)} { 184 | uv_barrier_init(raw(), count); 185 | } 186 | 187 | UVW_INLINE barrier::~barrier() noexcept { 188 | uv_barrier_destroy(raw()); 189 | } 190 | 191 | UVW_INLINE bool barrier::wait() noexcept { 192 | return (0 == uv_barrier_wait(raw())); 193 | } 194 | 195 | } // namespace uvw 196 | -------------------------------------------------------------------------------- /src/uvw/timer.cpp: -------------------------------------------------------------------------------- 1 | #include "timer.h" 2 | #include "timer.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_TIMER_INCLUDE_H 2 | #define UVW_TIMER_INCLUDE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "handle.hpp" 8 | #include "loop.h" 9 | 10 | namespace uvw { 11 | 12 | /*! @brief Timer event. */ 13 | struct timer_event {}; 14 | 15 | /** 16 | * @brief The timer handle. 17 | * 18 | * Timer handles are used to schedule events to be emitted in the future. 19 | * 20 | * To create a `timer_handle` through a `loop`, no arguments are required. 21 | */ 22 | class timer_handle final: public handle { 23 | static void start_callback(uv_timer_t *hndl); 24 | 25 | public: 26 | using time = std::chrono::duration; 27 | 28 | using handle::handle; 29 | 30 | /** 31 | * @brief Initializes the handle. 32 | * @return Underlying return value. 33 | */ 34 | int init(); 35 | 36 | /** 37 | * @brief Starts the timer. 38 | * 39 | * If timeout is zero, a timer event is emitted on the next event loop 40 | * iteration. If repeat is non-zero, a timer event is emitted first after 41 | * timeout milliseconds and then repeatedly after repeat milliseconds. 42 | * 43 | * @param timeout Milliseconds before to emit an event (use 44 | * `std::chrono::duration`). 45 | * @param repeat Milliseconds between successive events (use 46 | * `std::chrono::duration`). 47 | * 48 | * @return Underlying return value. 49 | */ 50 | int start(time timeout, time repeat); 51 | 52 | /** 53 | * @brief Stops the handle. 54 | * @return Underlying return value. 55 | */ 56 | int stop(); 57 | 58 | /** 59 | * @brief Stops the timer and restarts it if it was repeating. 60 | * 61 | * Stop the timer, and if it is repeating restart it using the repeat value 62 | * as the timeout. 63 | * 64 | * @return Underlying return value. 65 | */ 66 | int again(); 67 | 68 | /** 69 | * @brief Sets the repeat interval value. 70 | * 71 | * The timer will be scheduled to run on the given interval and will follow 72 | * normal timer semantics in the case of a time-slice overrun.
73 | * For example, if a 50ms repeating timer first runs for 17ms, it will be 74 | * scheduled to run again 33ms later. If other tasks consume more than the 75 | * 33ms following the first timer event, then another event will be emitted 76 | * as soon as possible. 77 | * 78 | * If the repeat value is set from a listener bound to an event, it does 79 | * not immediately take effect. If the timer was non-repeating before, it 80 | * will have been stopped. If it was repeating, then the old repeat value 81 | * will have been used to schedule the next timeout. 82 | * 83 | * @param repeat Repeat interval in milliseconds (use 84 | * `std::chrono::duration`). 85 | */ 86 | void repeat(time repeat); 87 | 88 | /** 89 | * @brief Gets the timer repeat value. 90 | * @return Timer repeat value in milliseconds (as a 91 | * `std::chrono::duration`). 92 | */ 93 | time repeat(); 94 | 95 | /** 96 | * @brief Gets the timer due value. 97 | * 98 | * The time is relative to `loop::now()`. 99 | * 100 | * @return The timer due value or 0 if it has expired. 101 | */ 102 | time due_in(); 103 | }; 104 | 105 | } // namespace uvw 106 | 107 | #ifndef UVW_AS_LIB 108 | # include "timer.ipp" 109 | #endif 110 | 111 | #endif // UVW_TIMER_INCLUDE_H 112 | -------------------------------------------------------------------------------- /src/uvw/timer.ipp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | namespace uvw { 4 | 5 | UVW_INLINE void timer_handle::start_callback(uv_timer_t *hndl) { 6 | timer_handle &timer = *(static_cast(hndl->data)); 7 | timer.publish(timer_event{}); 8 | } 9 | 10 | UVW_INLINE int timer_handle::init() { 11 | return leak_if(uv_timer_init(parent().raw(), raw())); 12 | } 13 | 14 | UVW_INLINE int timer_handle::start(timer_handle::time timeout, timer_handle::time repeat) { 15 | return uv_timer_start(raw(), &start_callback, timeout.count(), repeat.count()); 16 | } 17 | 18 | UVW_INLINE int timer_handle::stop() { 19 | return uv_timer_stop(raw()); 20 | } 21 | 22 | UVW_INLINE int timer_handle::again() { 23 | return uv_timer_again(raw()); 24 | } 25 | 26 | UVW_INLINE void timer_handle::repeat(timer_handle::time repeat) { 27 | uv_timer_set_repeat(raw(), repeat.count()); 28 | } 29 | 30 | UVW_INLINE timer_handle::time timer_handle::repeat() { 31 | return time{uv_timer_get_repeat(raw())}; 32 | } 33 | 34 | UVW_INLINE timer_handle::time timer_handle::due_in() { 35 | return time{uv_timer_get_due_in(raw())}; 36 | } 37 | 38 | } // namespace uvw 39 | -------------------------------------------------------------------------------- /src/uvw/tty.cpp: -------------------------------------------------------------------------------- 1 | #include "tty.h" 2 | #include "tty.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/tty.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_TTY_INCLUDE_H 2 | #define UVW_TTY_INCLUDE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "config.h" 8 | #include "stream.h" 9 | #include "util.h" 10 | 11 | namespace uvw { 12 | 13 | namespace details { 14 | 15 | struct reset_mode_memo { 16 | ~reset_mode_memo(); 17 | }; 18 | 19 | enum class uvw_tty_mode_t : std::underlying_type_t { 20 | NORMAL = UV_TTY_MODE_NORMAL, 21 | RAW = UV_TTY_MODE_RAW, 22 | IO = UV_TTY_MODE_IO 23 | }; 24 | 25 | enum class uvw_tty_vtermstate_t : std::underlying_type_t { 26 | SUPPORTED = UV_TTY_SUPPORTED, 27 | UNSUPPORTED = UV_TTY_UNSUPPORTED 28 | }; 29 | 30 | } // namespace details 31 | 32 | /** 33 | * @brief The tty handle. 34 | * 35 | * TTY handles represent a stream for the console. 36 | * 37 | * To create a `tty_handle` through a `loop`, arguments follow: 38 | * 39 | * * A valid file_handle. Usually the file descriptor will be: 40 | * * `uvw::std_in` or `0` for `stdin` 41 | * * `uvw::std_out` or `1` for `stdout` 42 | * * `uvw::std_err` or `2` for `stderr` 43 | * * A boolean value that specifies the plan on calling `read()` with this 44 | * stream. Remember that `stdin` is readable, `stdout` is not. 45 | * 46 | * See the official 47 | * [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_init) 48 | * for further details. 49 | */ 50 | class tty_handle final: public stream_handle { 51 | static std::shared_ptr mode_memo_handler(); 52 | 53 | public: 54 | using tty_mode = details::uvw_tty_mode_t; 55 | using tty_vtermstate = details::uvw_tty_vtermstate_t; 56 | 57 | explicit tty_handle(loop::token token, std::shared_ptr ref, file_handle desc, bool readable); 58 | 59 | /** 60 | * @brief Initializes the handle. 61 | * @return Underlying return value. 62 | */ 63 | int init(); 64 | 65 | /** 66 | * @brief Sets the TTY using the specified terminal mode. 67 | * 68 | * Available modes are: 69 | * 70 | * * `TTY::tty_mode::NORMAL` 71 | * * `TTY::tty_mode::RAW` 72 | * * `TTY::tty_mode::IO` 73 | * 74 | * See the official 75 | * [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_mode_t) 76 | * for further details. 77 | * 78 | * @param m The mode to be set. 79 | * @return True in case of success, false otherwise. 80 | */ 81 | bool mode(tty_mode m); 82 | 83 | /** 84 | * @brief Resets TTY settings to default values. 85 | * @return True in case of success, false otherwise. 86 | */ 87 | bool reset_mode() noexcept; 88 | 89 | /** 90 | * @brief Gets the current Window size. 91 | * @return The current Window size or `{-1, -1}` in case of errors. 92 | */ 93 | win_size get_win_size(); 94 | 95 | /** 96 | * @brief Controls whether console virtual terminal sequences are processed 97 | * by the library or console. 98 | * 99 | * This function is only meaningful on Windows systems. On Unix it is 100 | * silently ignored. 101 | * 102 | * Available states are: 103 | * 104 | * * `TTY::tty_vtermstate::SUPPORTED` 105 | * * `TTY::tty_vtermstate::UNSUPPORTED` 106 | * 107 | * See the official 108 | * [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_vtermstate_t) 109 | * for further details. 110 | * 111 | * @param s The state to be set. 112 | */ 113 | void vterm_state(tty_vtermstate s) const noexcept; 114 | 115 | /** 116 | * @brief Gets the current state of whether console virtual terminal 117 | * sequences are handled by the library or the console. 118 | * 119 | * This function is not implemented on Unix. 120 | * 121 | * Available states are: 122 | * 123 | * * `TTY::tty_vtermstate::SUPPORTED` 124 | * * `TTY::tty_vtermstate::UNSUPPORTED` 125 | * 126 | * See the official 127 | * [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_vtermstate_t) 128 | * for further details. 129 | * 130 | * @return The current state. 131 | */ 132 | tty_vtermstate vterm_state() const noexcept; 133 | 134 | private: 135 | std::shared_ptr memo; 136 | file_handle fd; 137 | int rw; 138 | }; 139 | 140 | } // namespace uvw 141 | 142 | #ifndef UVW_AS_LIB 143 | # include "tty.ipp" 144 | #endif 145 | 146 | #endif // UVW_TTY_INCLUDE_H 147 | -------------------------------------------------------------------------------- /src/uvw/tty.ipp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "config.h" 3 | 4 | namespace uvw { 5 | 6 | UVW_INLINE details::reset_mode_memo::~reset_mode_memo() { 7 | uv_tty_reset_mode(); 8 | } 9 | 10 | UVW_INLINE tty_handle::tty_handle(loop::token token, std::shared_ptr ref, file_handle desc, bool readable) 11 | : stream_handle{token, std::move(ref)}, 12 | memo{mode_memo_handler()}, 13 | fd{desc}, 14 | rw{readable} {} 15 | 16 | UVW_INLINE std::shared_ptr tty_handle::mode_memo_handler() { 17 | static std::weak_ptr weak; 18 | auto shared = weak.lock(); 19 | if(!shared) { 20 | weak = shared = std::make_shared(); 21 | } 22 | return shared; 23 | } 24 | 25 | UVW_INLINE int tty_handle::init() { 26 | return leak_if(uv_tty_init(parent().raw(), raw(), fd, rw)); 27 | } 28 | 29 | UVW_INLINE bool tty_handle::mode(tty_handle::tty_mode m) { 30 | return (0 == uv_tty_set_mode(raw(), static_cast(m))); 31 | } 32 | 33 | UVW_INLINE bool tty_handle::reset_mode() noexcept { 34 | return (0 == uv_tty_reset_mode()); 35 | } 36 | 37 | UVW_INLINE win_size tty_handle::get_win_size() { 38 | win_size size; 39 | 40 | if(0 != uv_tty_get_winsize(raw(), &size.width, &size.height)) { 41 | size.width = -1; 42 | size.height = -1; 43 | } 44 | 45 | return size; 46 | } 47 | 48 | UVW_INLINE void tty_handle::vterm_state(tty_handle::tty_vtermstate s) const noexcept { 49 | switch(s) { 50 | case tty_vtermstate::SUPPORTED: 51 | uv_tty_set_vterm_state(uv_tty_vtermstate_t::UV_TTY_SUPPORTED); 52 | break; 53 | case tty_vtermstate::UNSUPPORTED: 54 | uv_tty_set_vterm_state(uv_tty_vtermstate_t::UV_TTY_UNSUPPORTED); 55 | break; 56 | } 57 | } 58 | 59 | UVW_INLINE tty_handle::tty_vtermstate tty_handle::vterm_state() const noexcept { 60 | uv_tty_vtermstate_t state; 61 | uv_tty_get_vterm_state(&state); 62 | return tty_vtermstate{state}; 63 | } 64 | 65 | } // namespace uvw 66 | -------------------------------------------------------------------------------- /src/uvw/type_info.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UVW_TYPE_INFO_INCLUDE_HPP 2 | #define UVW_TYPE_INFO_INCLUDE_HPP 3 | 4 | #include 5 | #include 6 | #include "config.h" 7 | 8 | namespace uvw { 9 | 10 | /** 11 | * @cond TURN_OFF_DOXYGEN 12 | * Internal details not to be documented. 13 | */ 14 | 15 | namespace internal { 16 | 17 | // Fowler-Noll-Vo hash function v. 1a - the good 18 | [[nodiscard]] static constexpr std::uint32_t fnv1a(const std::string_view view) noexcept { 19 | constexpr std::uint32_t offset = 2166136261; 20 | constexpr std::uint32_t prime = 16777619; 21 | auto value = offset; 22 | 23 | for(auto &&curr: view) { 24 | value = (value ^ static_cast(static_cast(curr))) * prime; 25 | } 26 | 27 | return value; 28 | } 29 | 30 | [[nodiscard]] static inline std::uint32_t counter() noexcept { 31 | static std::uint32_t cnt{}; 32 | return cnt++; 33 | } 34 | 35 | template 36 | [[nodiscard]] static std::uint32_t fake() noexcept { 37 | static std::uint32_t local = counter(); 38 | return local; 39 | } 40 | 41 | } // namespace internal 42 | 43 | /** 44 | * Internal details not to be documented. 45 | * @endcond 46 | */ 47 | 48 | /** 49 | * @brief Returns a numerical identifier for a given type. 50 | * @tparam Type The type for which to return the numerical identifier. 51 | * @return The numerical identifier of the give type. 52 | */ 53 | template 54 | [[nodiscard]] static constexpr std::uint32_t type() noexcept { 55 | #if defined __clang__ || defined __GNUC__ 56 | return internal::fnv1a(__PRETTY_FUNCTION__); 57 | #elif defined _MSC_VER 58 | return internal::fnv1a(__FUNCSIG__); 59 | #else 60 | return internal::fake(); 61 | #endif 62 | } 63 | 64 | } // namespace uvw 65 | 66 | #endif // UVW_TYPE_INFO_INCLUDE_HPP 67 | -------------------------------------------------------------------------------- /src/uvw/udp.cpp: -------------------------------------------------------------------------------- 1 | #include "udp.h" 2 | #include "udp.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/udp.ipp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "config.h" 3 | 4 | namespace uvw { 5 | 6 | UVW_INLINE udp_data_event::udp_data_event(socket_address sndr, std::unique_ptr buf, std::size_t len, bool part) noexcept 7 | : data{std::move(buf)}, 8 | length{len}, 9 | sender{std::move(sndr)}, 10 | partial{part} {} 11 | 12 | UVW_INLINE void details::send_req::udp_send_callback(uv_udp_send_t *req, int status) { 13 | if(auto ptr = reserve(req); status) { 14 | ptr->publish(error_event{status}); 15 | } else { 16 | ptr->publish(send_event{}); 17 | } 18 | } 19 | 20 | UVW_INLINE details::send_req::send_req(loop::token token, std::shared_ptr parent, std::unique_ptr dt, unsigned int len) 21 | : request{token, std::move(parent)}, 22 | data{std::move(dt)}, 23 | buf{uv_buf_init(data.get(), len)} {} 24 | 25 | UVW_INLINE int details::send_req::send(uv_udp_t *hndl, const struct sockaddr *addr) { 26 | return this->leak_if(uv_udp_send(raw(), hndl, &buf, 1, addr, &udp_send_callback)); 27 | } 28 | 29 | UVW_INLINE void udp_handle::recv_callback(uv_udp_t *hndl, ssize_t nread, const uv_buf_t *buf, const sockaddr *addr, unsigned flags) { 30 | udp_handle &udp = *(static_cast(hndl->data)); 31 | // data will be destroyed no matter of what the value of nread is 32 | std::unique_ptr data{buf->base}; 33 | 34 | if(nread > 0) { 35 | // data available (can be truncated) 36 | udp.publish(udp_data_event{details::sock_addr(*addr), std::move(data), static_cast(nread), !(0 == (flags & UV_UDP_PARTIAL))}); 37 | } else if(nread == 0 && addr == nullptr) { 38 | // no more data to be read, doing nothing is fine 39 | } else if(nread == 0 && addr != nullptr) { 40 | // empty udp packet 41 | udp.publish(udp_data_event{details::sock_addr(*addr), std::move(data), static_cast(nread), false}); 42 | } else { 43 | // transmission error 44 | udp.publish(error_event(nread)); 45 | } 46 | } 47 | 48 | UVW_INLINE udp_handle::udp_handle(loop::token token, std::shared_ptr ref, unsigned int f) 49 | : handle{token, std::move(ref)}, tag{FLAGS}, flags{f} {} 50 | 51 | UVW_INLINE int udp_handle::init() { 52 | if(tag == FLAGS) { 53 | return leak_if(uv_udp_init_ex(parent().raw(), raw(), flags)); 54 | } else { 55 | return leak_if(uv_udp_init(parent().raw(), raw())); 56 | } 57 | } 58 | 59 | UVW_INLINE int udp_handle::open(os_socket_handle socket) { 60 | return uv_udp_open(raw(), socket); 61 | } 62 | 63 | UVW_INLINE int udp_handle::connect(const sockaddr &addr) { 64 | return uv_udp_connect(raw(), &addr); 65 | } 66 | 67 | UVW_INLINE int udp_handle::connect(const std::string &ip, unsigned int port) { 68 | return connect(details::ip_addr(ip.data(), port)); 69 | } 70 | 71 | UVW_INLINE int udp_handle::connect(const socket_address &addr) { 72 | return connect(addr.ip, addr.port); 73 | } 74 | 75 | UVW_INLINE int udp_handle::disconnect() { 76 | return uv_udp_connect(raw(), nullptr); 77 | } 78 | 79 | UVW_INLINE socket_address udp_handle::peer() const noexcept { 80 | sockaddr_storage storage; 81 | int len = sizeof(sockaddr_storage); 82 | uv_udp_getpeername(raw(), reinterpret_cast(&storage), &len); 83 | return details::sock_addr(storage); 84 | } 85 | 86 | UVW_INLINE int udp_handle::bind(const sockaddr &addr, udp_handle::udp_flags opts) { 87 | return uv_udp_bind(raw(), &addr, static_cast(opts)); 88 | } 89 | 90 | UVW_INLINE int udp_handle::bind(const std::string &ip, unsigned int port, udp_flags opts) { 91 | return bind(details::ip_addr(ip.data(), port), opts); 92 | } 93 | 94 | UVW_INLINE int udp_handle::bind(const socket_address &addr, udp_flags opts) { 95 | return bind(addr.ip, addr.port, opts); 96 | } 97 | 98 | UVW_INLINE socket_address udp_handle::sock() const noexcept { 99 | sockaddr_storage storage; 100 | int len = sizeof(sockaddr_storage); 101 | uv_udp_getsockname(raw(), reinterpret_cast(&storage), &len); 102 | return details::sock_addr(storage); 103 | } 104 | 105 | UVW_INLINE bool udp_handle::multicast_membership(const std::string &multicast, const std::string &iface, membership ms) { 106 | return (0 == uv_udp_set_membership(raw(), multicast.data(), iface.data(), static_cast(ms))); 107 | } 108 | 109 | UVW_INLINE bool udp_handle::multicast_loop(bool enable) { 110 | return (0 == uv_udp_set_multicast_loop(raw(), enable)); 111 | } 112 | 113 | UVW_INLINE bool udp_handle::multicast_ttl(int val) { 114 | return (0 == uv_udp_set_multicast_ttl(raw(), val > 255 ? 255 : val)); 115 | } 116 | 117 | UVW_INLINE bool udp_handle::multicast_interface(const std::string &iface) { 118 | return (0 == uv_udp_set_multicast_interface(raw(), iface.data())); 119 | } 120 | 121 | UVW_INLINE bool udp_handle::broadcast(bool enable) { 122 | return (0 == uv_udp_set_broadcast(raw(), enable)); 123 | } 124 | 125 | UVW_INLINE bool udp_handle::ttl(int val) { 126 | return (0 == uv_udp_set_ttl(raw(), val > 255 ? 255 : val)); 127 | } 128 | 129 | UVW_INLINE int udp_handle::send(const sockaddr &addr, std::unique_ptr data, unsigned int len) { 130 | auto req = parent().resource(std::unique_ptr{data.release(), [](char *ptr) { delete[] ptr; }}, len); 131 | 132 | auto listener = [ptr = shared_from_this()](const auto &event, const auto &) { 133 | ptr->publish(event); 134 | }; 135 | 136 | req->on(listener); 137 | req->on(listener); 138 | 139 | return req->send(raw(), &addr); 140 | } 141 | 142 | UVW_INLINE int udp_handle::send(const std::string &ip, unsigned int port, std::unique_ptr data, unsigned int len) { 143 | return send(details::ip_addr(ip.data(), port), std::move(data), len); 144 | } 145 | 146 | UVW_INLINE int udp_handle::send(const socket_address &addr, std::unique_ptr data, unsigned int len) { 147 | return send(addr.ip, addr.port, std::move(data), len); 148 | } 149 | 150 | UVW_INLINE int udp_handle::send(const sockaddr &addr, char *data, unsigned int len) { 151 | auto req = parent().resource(std::unique_ptr{data, [](char *) {}}, len); 152 | 153 | auto listener = [ptr = shared_from_this()](const auto &event, const auto &) { 154 | ptr->publish(event); 155 | }; 156 | 157 | req->on(listener); 158 | req->on(listener); 159 | 160 | return req->send(raw(), &addr); 161 | } 162 | 163 | UVW_INLINE int udp_handle::send(const std::string &ip, unsigned int port, char *data, unsigned int len) { 164 | return send(details::ip_addr(ip.data(), port), data, len); 165 | } 166 | 167 | UVW_INLINE int udp_handle::send(const socket_address &addr, char *data, unsigned int len) { 168 | return send(addr.ip, addr.port, data, len); 169 | } 170 | 171 | UVW_INLINE int udp_handle::try_send(const sockaddr &addr, std::unique_ptr data, unsigned int len) { 172 | std::array bufs{uv_buf_init(data.get(), len)}; 173 | return uv_udp_try_send(raw(), bufs.data(), 1, &addr); 174 | } 175 | 176 | UVW_INLINE int udp_handle::try_send(const std::string &ip, unsigned int port, std::unique_ptr data, unsigned int len) { 177 | return try_send(details::ip_addr(ip.data(), port), std::move(data), len); 178 | } 179 | 180 | UVW_INLINE int udp_handle::try_send(const socket_address &addr, std::unique_ptr data, unsigned int len) { 181 | return try_send(addr.ip, addr.port, std::move(data), len); 182 | } 183 | 184 | UVW_INLINE int udp_handle::try_send(const sockaddr &addr, char *data, unsigned int len) { 185 | std::array bufs{uv_buf_init(data, len)}; 186 | return uv_udp_try_send(raw(), bufs.data(), 1, &addr); 187 | } 188 | 189 | UVW_INLINE int udp_handle::try_send(const std::string &ip, unsigned int port, char *data, unsigned int len) { 190 | return try_send(details::ip_addr(ip.data(), port), data, len); 191 | } 192 | 193 | UVW_INLINE int udp_handle::try_send(const socket_address &addr, char *data, unsigned int len) { 194 | return try_send(addr.ip, addr.port, data, len); 195 | } 196 | 197 | UVW_INLINE int udp_handle::recv() { 198 | return uv_udp_recv_start(raw(), &details::common_alloc_callback, &recv_callback); 199 | } 200 | 201 | UVW_INLINE int udp_handle::stop() { 202 | return uv_udp_recv_stop(raw()); 203 | } 204 | 205 | UVW_INLINE size_t udp_handle::send_queue_size() const noexcept { 206 | return uv_udp_get_send_queue_size(raw()); 207 | } 208 | 209 | UVW_INLINE size_t udp_handle::send_queue_count() const noexcept { 210 | return uv_udp_get_send_queue_count(raw()); 211 | } 212 | 213 | } // namespace uvw 214 | -------------------------------------------------------------------------------- /src/uvw/util.cpp: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | #include "util.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/uv_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UVW_UV_TYPE_INCLUDE_H 2 | #define UVW_UV_TYPE_INCLUDE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "config.h" 8 | #include "loop.h" 9 | 10 | namespace uvw { 11 | 12 | /** 13 | * @brief Wrapper class for underlying types. 14 | * 15 | * It acts mainly as a wrapper around data structures of the underlying library. 16 | */ 17 | template 18 | struct uv_type { 19 | explicit uv_type(loop::token, std::shared_ptr ref) noexcept 20 | : owner{std::move(ref)} {} 21 | 22 | uv_type(const uv_type &) = delete; 23 | uv_type(uv_type &&) = delete; 24 | 25 | uv_type &operator=(const uv_type &) = delete; 26 | uv_type &operator=(uv_type &&) = delete; 27 | 28 | /** 29 | * @brief Gets the loop from which the resource was originated. 30 | * @return A reference to a loop instance. 31 | */ 32 | [[nodiscard]] loop &parent() const noexcept { 33 | return *owner; 34 | } 35 | 36 | /** 37 | * @brief Gets the underlying raw data structure. 38 | * 39 | * This function should not be used, unless you know exactly what you are 40 | * doing and what are the risks.
41 | * Going raw is dangerous, mainly because the lifetime management of a loop, 42 | * a handle or a request is in charge to the library itself and users should 43 | * not work around it. 44 | * 45 | * @warning 46 | * Use this function at your own risk, but do not expect any support in case 47 | * of bugs. 48 | * 49 | * @return The underlying raw data structure. 50 | */ 51 | [[nodiscard]] const U *raw() const noexcept { 52 | return &resource; 53 | } 54 | 55 | /** 56 | * @brief Gets the underlying raw data structure. 57 | * 58 | * This function should not be used, unless you know exactly what you are 59 | * doing and what are the risks.
60 | * Going raw is dangerous, mainly because the lifetime management of a loop, 61 | * a handle or a request is in charge to the library itself and users should 62 | * not work around it. 63 | * 64 | * @warning 65 | * Use this function at your own risk, but do not expect any support in case 66 | * of bugs. 67 | * 68 | * @return The underlying raw data structure. 69 | */ 70 | [[nodiscard]] U *raw() noexcept { 71 | return &resource; 72 | } 73 | 74 | protected: 75 | ~uv_type() = default; 76 | 77 | private: 78 | std::shared_ptr owner; 79 | U resource{}; 80 | }; 81 | 82 | } // namespace uvw 83 | 84 | #endif // UVW_UV_TYPE_INCLUDE_H 85 | -------------------------------------------------------------------------------- /src/uvw/work.cpp: -------------------------------------------------------------------------------- 1 | #include "work.h" 2 | #include "work.ipp" 3 | -------------------------------------------------------------------------------- /src/uvw/work.h: -------------------------------------------------------------------------------- 1 | #ifndef UVW_WORK_INCLUDE_H 2 | #define UVW_WORK_INCLUDE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "loop.h" 8 | #include "request.hpp" 9 | 10 | namespace uvw { 11 | 12 | /*! @brief Work event. */ 13 | struct work_event {}; 14 | 15 | /** 16 | * @brief The work request. 17 | * 18 | * It runs user code using a thread from the threadpool and gets notified in the 19 | * loop thread by means of an event. 20 | * 21 | * To create a `work_req` through a `loop`, arguments follow: 22 | * 23 | * * A valid instance of a `Task`, that is of type `std::function`. 24 | * 25 | * See the official 26 | * [documentation](http://docs.libuv.org/en/v1.x/threadpool.html) 27 | * for further details. 28 | */ 29 | class work_req final: public request { 30 | static void work_callback(uv_work_t *req); 31 | static void after_work_callback(uv_work_t *req, int status); 32 | 33 | public: 34 | using task = std::function; 35 | 36 | explicit work_req(loop::token token, std::shared_ptr ref, task t); 37 | 38 | /** 39 | * @brief Runs the given task in a separate thread. 40 | * 41 | * A work event will be emitted on the loop thread when the task is 42 | * finished.
43 | * This request can be cancelled with `cancel()`. 44 | * 45 | * @return Underlying return value. 46 | */ 47 | int queue(); 48 | 49 | private: 50 | task func{}; 51 | }; 52 | 53 | } // namespace uvw 54 | 55 | #ifndef UVW_AS_LIB 56 | # include "work.ipp" 57 | #endif 58 | 59 | #endif // UVW_WORK_INCLUDE_H 60 | -------------------------------------------------------------------------------- /src/uvw/work.ipp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "config.h" 3 | 4 | namespace uvw { 5 | 6 | UVW_INLINE work_req::work_req(loop::token token, std::shared_ptr ref, task t) 7 | : request{token, std::move(ref)}, func{std::move(t)} {} 8 | 9 | UVW_INLINE void work_req::work_callback(uv_work_t *req) { 10 | static_cast(req->data)->func(); 11 | } 12 | 13 | UVW_INLINE void work_req::after_work_callback(uv_work_t *req, int status) { 14 | if(auto ptr = reserve(req); status) { 15 | ptr->publish(error_event{status}); 16 | } else { 17 | ptr->publish(work_event{}); 18 | } 19 | } 20 | 21 | UVW_INLINE int work_req::queue() { 22 | return this->leak_if(uv_queue_work(parent().raw(), raw(), &work_callback, &after_work_callback)); 23 | } 24 | 25 | } // namespace uvw 26 | -------------------------------------------------------------------------------- /subprojects/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !*.wrap 4 | -------------------------------------------------------------------------------- /subprojects/libuv.wrap: -------------------------------------------------------------------------------- 1 | [wrap-file] 2 | directory = libuv-v1.48.0 3 | source_url = https://dist.libuv.org/dist/v1.48.0/libuv-v1.48.0.tar.gz 4 | source_filename = libuv-v1.48.0.tar.gz 5 | source_hash = 7f1db8ac368d89d1baf163bac1ea5fe5120697a73910c8ae6b2fffb3551d59fb 6 | patch_filename = libuv_1.48.0-1_patch.zip 7 | patch_url = https://wrapdb.mesonbuild.com/v2/libuv_1.48.0-1/get_patch 8 | patch_hash = 27b18917c914a5d6dfb459073710e9bfb6b2962d69d4e0bad5bc7b1173482be7 9 | source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/libuv_1.48.0-1/libuv-v1.48.0.tar.gz 10 | wrapdb_version = 1.48.0-1 11 | 12 | [provide] 13 | libuv = libuv_dep 14 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Tests configuration 3 | # 4 | 5 | include(FetchContent) 6 | 7 | set(THREADS_PREFER_PTHREAD_FLAG ON) 8 | find_package(Threads REQUIRED) 9 | 10 | if(UVW_FIND_GTEST_PACKAGE) 11 | find_package(GTest REQUIRED) 12 | else() 13 | FetchContent_Declare( 14 | googletest 15 | GIT_REPOSITORY https://github.com/google/googletest.git 16 | GIT_TAG main 17 | GIT_SHALLOW 1 18 | ) 19 | 20 | FetchContent_GetProperties(googletest) 21 | 22 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 23 | FetchContent_MakeAvailable(googletest) 24 | 25 | add_library(GTest::Main ALIAS gtest_main) 26 | 27 | target_compile_features(gtest PUBLIC cxx_std_17) 28 | set_target_properties(gtest PROPERTIES CXX_CLANG_TIDY "") 29 | 30 | target_compile_features(gtest_main PUBLIC cxx_std_17) 31 | set_target_properties(gtest_main PROPERTIES CXX_CLANG_TIDY "") 32 | 33 | target_compile_features(gmock PUBLIC cxx_std_17) 34 | set_target_properties(gmock PROPERTIES CXX_CLANG_TIDY "") 35 | 36 | target_compile_features(gmock_main PUBLIC cxx_std_17) 37 | set_target_properties(gmock_main PROPERTIES CXX_CLANG_TIDY "") 38 | 39 | if(CMAKE_SYSTEM_NAME MATCHES OpenBSD) 40 | target_compile_options(gtest PRIVATE -Wno-error) 41 | endif() 42 | endif() 43 | 44 | if(WIN32) 45 | set(WINSOCK2 ws2_32) 46 | endif() 47 | 48 | function(UVW_ADD_TEST TEST_NAME TEST_SOURCE) 49 | add_executable(${TEST_NAME} ${TEST_SOURCE}) 50 | 51 | target_link_libraries( 52 | ${TEST_NAME} 53 | PRIVATE 54 | $<$:uvw::uvw> 55 | $<$:uv::uv-static> 56 | $<$:uvw::uvw-static> 57 | $<$:uv::uv-shared> 58 | $<$:uvw::uvw-shared> 59 | GTest::Main 60 | Threads::Threads 61 | ${LIBRT} 62 | ${WINSOCK2} 63 | ) 64 | 65 | target_compile_options( 66 | ${TEST_NAME} 67 | PRIVATE 68 | $<$>:-Wall> 69 | $<$:/EHsc> 70 | ) 71 | 72 | target_compile_definitions(${TEST_NAME} PRIVATE $<$>:UVW_AS_LIB>) 73 | add_test(NAME uvw_${TEST_NAME} COMMAND $) 74 | endfunction() 75 | 76 | function(UVW_ADD_DIR_TEST TEST_NAME TEST_SOURCE) 77 | UVW_ADD_TEST(${TEST_NAME} ${TEST_SOURCE}) 78 | string(TOUPPER "${TEST_NAME}" TEST_NAME_UPPER) 79 | set(TEST_DIR_VAR "TARGET_${TEST_NAME_UPPER}_DIR") 80 | file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME}_data) 81 | target_compile_definitions(${TEST_NAME} PRIVATE ${TEST_DIR_VAR}="${TEST_NAME}_data") 82 | endfunction() 83 | 84 | function(UVW_ADD_LIB_TEST TEST_NAME TEST_SOURCE) 85 | UVW_ADD_TEST(${TEST_NAME} ${TEST_SOURCE}) 86 | target_link_libraries(${TEST_NAME} PRIVATE ${CMAKE_DL_LIBS}) 87 | target_compile_definitions(${TEST_NAME} PRIVATE TARGET_LIB_SO="$") 88 | endfunction() 89 | 90 | add_library(fake SHARED fake.cpp) 91 | 92 | # List of available targets 93 | 94 | option(UVW_BUILD_DNS_TEST "Build DNS test." OFF) 95 | 96 | UVW_ADD_TEST(main main.cpp) 97 | UVW_ADD_TEST(async uvw/async.cpp) 98 | UVW_ADD_TEST(check uvw/check.cpp) 99 | UVW_ADD_TEST(emitter uvw/emitter.cpp) 100 | UVW_ADD_DIR_TEST(file_req uvw/file_req.cpp) 101 | UVW_ADD_DIR_TEST(fs_event uvw/fs_event.cpp) 102 | UVW_ADD_DIR_TEST(fs_req uvw/fs_req.cpp) 103 | UVW_ADD_TEST(handle uvw/handle.cpp) 104 | UVW_ADD_TEST(idle uvw/idle.cpp) 105 | UVW_ADD_LIB_TEST(lib uvw/lib.cpp) 106 | UVW_ADD_TEST(loop uvw/loop.cpp) 107 | UVW_ADD_DIR_TEST(pipe uvw/pipe.cpp) 108 | UVW_ADD_TEST(prepare uvw/prepare.cpp) 109 | UVW_ADD_TEST(process uvw/process.cpp) 110 | UVW_ADD_TEST(request uvw/request.cpp) 111 | UVW_ADD_TEST(resource uvw/resource.cpp) 112 | UVW_ADD_TEST(signal uvw/signal.cpp) 113 | UVW_ADD_TEST(stream uvw/stream.cpp) 114 | UVW_ADD_TEST(tcp uvw/tcp.cpp) 115 | UVW_ADD_TEST(thread uvw/thread.cpp) 116 | UVW_ADD_TEST(timer uvw/timer.cpp) 117 | UVW_ADD_TEST(tty uvw/tty.cpp) 118 | UVW_ADD_TEST(udp uvw/udp.cpp) 119 | UVW_ADD_TEST(uv_type uvw/uv_type.cpp) 120 | UVW_ADD_TEST(util uvw/util.cpp) 121 | UVW_ADD_TEST(work uvw/work.cpp) 122 | 123 | if(NOT CMAKE_SYSTEM_NAME MATCHES OpenBSD) 124 | UVW_ADD_DIR_TEST(file_req_sendfile uvw/file_req_sendfile.cpp) 125 | endif() 126 | 127 | if(UVW_BUILD_DNS_TEST) 128 | UVW_ADD_TEST(dns uvw/dns.cpp) 129 | endif() 130 | -------------------------------------------------------------------------------- /test/fake.cpp: -------------------------------------------------------------------------------- 1 | extern "C" int fake_func(double *); 2 | 3 | int fake_func(double *d) { 4 | if(d) { *d = -*d; } 5 | return -42; 6 | } 7 | -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void listen(uvw::loop &loop) { 8 | std::shared_ptr tcp = loop.resource(); 9 | tcp->on([](const uvw::error_event &, uvw::tcp_handle &) { assert(false); }); 10 | 11 | tcp->on([](const uvw::listen_event &, uvw::tcp_handle &srv) { 12 | std::cout << "listen" << std::endl; 13 | 14 | std::shared_ptr client = srv.parent().resource(); 15 | client->on([](const uvw::error_event &, uvw::tcp_handle &) { assert(false); }); 16 | 17 | client->on([ptr = srv.shared_from_this()](const uvw::close_event &, uvw::tcp_handle &) { 18 | std::cout << "close" << std::endl; 19 | ptr->close(); 20 | }); 21 | 22 | srv.accept(*client); 23 | 24 | uvw::socket_address local = srv.sock(); 25 | std::cout << "local: " << local.ip << " " << local.port << std::endl; 26 | 27 | uvw::socket_address remote = client->peer(); 28 | std::cout << "remote: " << remote.ip << " " << remote.port << std::endl; 29 | 30 | client->on([](const uvw::data_event &event, uvw::tcp_handle &) { 31 | std::cout.write(event.data.get(), static_cast(event.length)) << std::endl; 32 | std::cout << "data length: " << event.length << std::endl; 33 | }); 34 | 35 | client->on([](const uvw::end_event &, uvw::tcp_handle &handle) { 36 | std::cout << "end" << std::endl; 37 | int count = 0; 38 | handle.parent().walk([&count](auto &) { ++count; }); 39 | std::cout << "still alive: " << count << " handles" << std::endl; 40 | handle.close(); 41 | }); 42 | 43 | client->read(); 44 | }); 45 | 46 | tcp->on([](const uvw::close_event &, uvw::tcp_handle &) { 47 | std::cout << "close" << std::endl; 48 | }); 49 | 50 | tcp->bind("127.0.0.1", 4242); 51 | tcp->listen(); 52 | } 53 | 54 | void conn(uvw::loop &loop) { 55 | auto tcp = loop.resource(); 56 | tcp->on([](const uvw::error_event &, uvw::tcp_handle &) { assert(false); }); 57 | 58 | tcp->on([](const uvw::write_event &, uvw::tcp_handle &handle) { 59 | std::cout << "write" << std::endl; 60 | handle.close(); 61 | }); 62 | 63 | tcp->on([](const uvw::connect_event &, uvw::tcp_handle &handle) { 64 | std::cout << "connect" << std::endl; 65 | 66 | auto dataTryWrite = std::unique_ptr(new char[1]{'a'}); 67 | int bw = handle.try_write(std::move(dataTryWrite), 1); 68 | std::cout << "written: " << static_cast(bw) << std::endl; 69 | 70 | auto dataWrite = std::unique_ptr(new char[2]{'b', 'c'}); 71 | handle.write(std::move(dataWrite), 2); 72 | }); 73 | 74 | tcp->on([](const uvw::close_event &, uvw::tcp_handle &) { 75 | std::cout << "close" << std::endl; 76 | }); 77 | 78 | tcp->connect("127.0.0.1", 4242); 79 | } 80 | 81 | void g() { 82 | auto loop = uvw::loop::get_default(); 83 | listen(*loop); 84 | conn(*loop); 85 | loop->run(); 86 | loop = nullptr; 87 | } 88 | 89 | int main() { 90 | g(); 91 | } 92 | -------------------------------------------------------------------------------- /test/odr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /test/uvw/async.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(Async, Send) { 5 | auto loop = uvw::loop::get_default(); 6 | auto handle = loop->resource(); 7 | 8 | bool checkAsyncEvent = false; 9 | 10 | handle->on([](auto &&...) { FAIL(); }); 11 | 12 | handle->on([&checkAsyncEvent](const auto &, auto &hndl) { 13 | ASSERT_FALSE(checkAsyncEvent); 14 | checkAsyncEvent = true; 15 | hndl.close(); 16 | ASSERT_TRUE(hndl.closing()); 17 | }); 18 | 19 | ASSERT_EQ(0, handle->send()); 20 | ASSERT_TRUE(handle->active()); 21 | ASSERT_FALSE(handle->closing()); 22 | 23 | loop->run(); 24 | 25 | ASSERT_TRUE(checkAsyncEvent); 26 | } 27 | 28 | TEST(Async, Fake) { 29 | auto loop = uvw::loop::get_default(); 30 | auto handle = loop->resource(); 31 | 32 | handle->on([](auto &&...) { FAIL(); }); 33 | handle->on([](auto &&...) { FAIL(); }); 34 | 35 | handle->send(); 36 | handle->close(); 37 | 38 | ASSERT_FALSE(handle->active()); 39 | ASSERT_TRUE(handle->closing()); 40 | 41 | loop->run(); 42 | } 43 | -------------------------------------------------------------------------------- /test/uvw/check.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(Check, StartAndStop) { 5 | auto loop = uvw::loop::get_default(); 6 | auto handle = loop->resource(); 7 | 8 | bool checkCheckEvent = false; 9 | 10 | handle->on([](auto &&...) { FAIL(); }); 11 | 12 | handle->on([&checkCheckEvent](const auto &, auto &hndl) { 13 | ASSERT_FALSE(checkCheckEvent); 14 | 15 | checkCheckEvent = true; 16 | 17 | ASSERT_EQ(0, hndl.stop()); 18 | 19 | hndl.close(); 20 | 21 | ASSERT_TRUE(hndl.closing()); 22 | }); 23 | 24 | ASSERT_EQ(0, handle->start()); 25 | ASSERT_TRUE(handle->active()); 26 | ASSERT_FALSE(handle->closing()); 27 | 28 | loop->run(uvw::loop::run_mode::NOWAIT); 29 | 30 | ASSERT_TRUE(checkCheckEvent); 31 | } 32 | 33 | TEST(Check, Fake) { 34 | auto loop = uvw::loop::get_default(); 35 | auto handle = loop->resource(); 36 | 37 | handle->on([](auto &&...) { FAIL(); }); 38 | handle->on([](auto &&...) { FAIL(); }); 39 | 40 | handle->start(); 41 | handle->close(); 42 | 43 | ASSERT_FALSE(handle->active()); 44 | ASSERT_TRUE(handle->closing()); 45 | 46 | loop->run(); 47 | } 48 | -------------------------------------------------------------------------------- /test/uvw/dns.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(GetAddrInfo, GetNodeAddrInfo) { 5 | auto loop = uvw::loop::get_default(); 6 | auto request = loop->resource(); 7 | 8 | bool checkAddrInfoEvent = false; 9 | 10 | request->on([](const auto &, auto &) { FAIL(); }); 11 | 12 | request->on([&checkAddrInfoEvent](const auto &, auto &) { 13 | ASSERT_FALSE(checkAddrInfoEvent); 14 | checkAddrInfoEvent = true; 15 | }); 16 | 17 | request->node_addr_info("irc.freenode.net"); 18 | 19 | loop->run(); 20 | 21 | ASSERT_TRUE(checkAddrInfoEvent); 22 | } 23 | 24 | TEST(GetAddrInfo, GetNodeAddrInfoSync) { 25 | auto loop = uvw::loop::get_default(); 26 | auto request = loop->resource(); 27 | 28 | ASSERT_TRUE(request->node_addr_info_sync("irc.freenode.net").first); 29 | ASSERT_FALSE(request->node_addr_info_sync("").first); 30 | 31 | loop->run(); 32 | } 33 | 34 | TEST(GetAddrInfo, GetServiceAddrInfo) { 35 | auto loop = uvw::loop::get_default(); 36 | auto request = loop->resource(); 37 | 38 | bool checkErrorEvent = false; 39 | 40 | request->on([&checkErrorEvent](const auto &, auto &) { 41 | ASSERT_FALSE(checkErrorEvent); 42 | checkErrorEvent = true; 43 | }); 44 | 45 | request->service_addr_info("foobar"); 46 | 47 | loop->run(); 48 | 49 | ASSERT_TRUE(checkErrorEvent); 50 | } 51 | 52 | TEST(GetAddrInfo, GetServiceAddrInfoSync) { 53 | auto loop = uvw::loop::get_default(); 54 | auto request = loop->resource(); 55 | 56 | ASSERT_FALSE(request->service_addr_info_sync("foobar").first); 57 | 58 | loop->run(); 59 | } 60 | 61 | TEST(GetAddrInfo, GetAddrInfo) { 62 | auto loop = uvw::loop::get_default(); 63 | auto request = loop->resource(); 64 | 65 | bool checkAddrInfoEvent = false; 66 | 67 | request->on([](const auto &, auto &) { FAIL(); }); 68 | 69 | request->on([&checkAddrInfoEvent](const auto &, auto &) { 70 | ASSERT_FALSE(checkAddrInfoEvent); 71 | checkAddrInfoEvent = true; 72 | }); 73 | 74 | request->addr_info("irc.freenode.net", "6667"); 75 | 76 | loop->run(); 77 | 78 | ASSERT_TRUE(checkAddrInfoEvent); 79 | } 80 | 81 | TEST(GetAddrInfo, GetAddrInfoSync) { 82 | auto loop = uvw::loop::get_default(); 83 | auto request = loop->resource(); 84 | 85 | ASSERT_TRUE(request->addr_info_sync("irc.freenode.net", "6667").first); 86 | ASSERT_FALSE(request->addr_info_sync("", "").first); 87 | 88 | loop->run(); 89 | } 90 | 91 | TEST(GetNameInfo, GetNameInfo) { 92 | auto loop = uvw::loop::get_default(); 93 | auto koRequest = loop->resource(); 94 | auto okRequest = loop->resource(); 95 | 96 | bool checkErrorEvent = false; 97 | bool checkNameInfoEvent = false; 98 | 99 | koRequest->on([&checkErrorEvent](const auto &, auto &) { 100 | ASSERT_FALSE(checkErrorEvent); 101 | checkErrorEvent = true; 102 | }); 103 | 104 | okRequest->on([&checkNameInfoEvent](const auto &, auto &) { 105 | ASSERT_FALSE(checkNameInfoEvent); 106 | checkNameInfoEvent = true; 107 | }); 108 | 109 | koRequest->name_info(uvw::socket_address{"", 0}, -1); 110 | okRequest->name_info("irc.freenode.net", 6667); 111 | 112 | loop->run(); 113 | 114 | ASSERT_TRUE(checkErrorEvent); 115 | ASSERT_TRUE(checkNameInfoEvent); 116 | } 117 | 118 | TEST(GetNameInfo, GetNameInfoSync) { 119 | auto loop = uvw::loop::get_default(); 120 | auto request = loop->resource(); 121 | 122 | ASSERT_FALSE(request->name_info_sync(uvw::socket_address{"", 0}, -1).first); 123 | ASSERT_TRUE(request->name_info_sync("irc.freenode.net", 6667).first); 124 | 125 | loop->run(); 126 | } 127 | -------------------------------------------------------------------------------- /test/uvw/emitter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct FakeEvent {}; 6 | 7 | struct TestEmitter: uvw::emitter { 8 | void emit() { 9 | publish(FakeEvent{}); 10 | } 11 | }; 12 | 13 | TEST(ErrorEvent, Functionalities) { 14 | auto ecode = static_cast>(UV_EADDRINUSE); 15 | 16 | uvw::error_event event{ecode}; 17 | 18 | ASSERT_EQ(ecode, uvw::error_event::translate(ecode)); 19 | ASSERT_NE(event.what(), nullptr); 20 | ASSERT_NE(event.name(), nullptr); 21 | ASSERT_EQ(event.code(), ecode); 22 | 23 | ASSERT_FALSE(static_cast(uvw::error_event{0})); 24 | ASSERT_TRUE(static_cast(uvw::error_event{ecode})); 25 | } 26 | 27 | TEST(Emitter, Functionalities) { 28 | TestEmitter emitter{}; 29 | 30 | emitter.on([](const auto &, auto &) {}); 31 | 32 | ASSERT_TRUE(emitter.has()); 33 | ASSERT_FALSE(emitter.has()); 34 | 35 | emitter.reset(); 36 | 37 | ASSERT_TRUE(emitter.has()); 38 | ASSERT_FALSE(emitter.has()); 39 | 40 | emitter.reset(); 41 | 42 | ASSERT_FALSE(emitter.has()); 43 | ASSERT_FALSE(emitter.has()); 44 | 45 | bool sentinel = false; 46 | emitter.on([](const auto &, auto &) {}); 47 | emitter.on([&](const auto &, auto &) { sentinel = true; }); 48 | 49 | ASSERT_FALSE(sentinel); 50 | ASSERT_TRUE(emitter.has()); 51 | ASSERT_TRUE(emitter.has()); 52 | 53 | emitter.emit(); 54 | 55 | ASSERT_TRUE(sentinel); 56 | ASSERT_TRUE(emitter.has()); 57 | ASSERT_TRUE(emitter.has()); 58 | 59 | emitter.reset(); 60 | 61 | ASSERT_FALSE(emitter.has()); 62 | ASSERT_FALSE(emitter.has()); 63 | } 64 | -------------------------------------------------------------------------------- /test/uvw/file_req_sendfile.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifdef _WIN32 5 | # define _CRT_DECLARE_NONSTDC_NAMES 1 6 | # include 7 | #endif 8 | 9 | TEST(FileReq, SendFile) { 10 | const std::string srcFilename = std::string{TARGET_FILE_REQ_SENDFILE_DIR} + std::string{"/src.file"}; 11 | const std::string dstFilename = std::string{TARGET_FILE_REQ_SENDFILE_DIR} + std::string{"/dst.file"}; 12 | 13 | auto loop = uvw::loop::get_default(); 14 | auto srcReq = loop->resource(); 15 | auto dstReq = loop->resource(); 16 | 17 | bool checkFileSendFileEvent = false; 18 | 19 | dstReq->on([](const auto &, auto &) { FAIL(); }); 20 | srcReq->on([](const auto &, auto &) { FAIL(); }); 21 | 22 | dstReq->on([&](const auto &event, auto &req) { 23 | if(event.type == uvw::fs_req::fs_type::OPEN) { 24 | srcReq->sendfile(static_cast(req), 0, 0); 25 | } 26 | }); 27 | 28 | srcReq->on([&](const auto &event, auto &req) { 29 | if(event.type == uvw::fs_req::fs_type::SENDFILE) { 30 | ASSERT_FALSE(checkFileSendFileEvent); 31 | checkFileSendFileEvent = true; 32 | dstReq->close(); 33 | req.close(); 34 | } else if(event.type == uvw::fs_req::fs_type::OPEN) { 35 | dstReq->open(dstFilename, uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::WRONLY | uvw::file_req::file_open_flags::TRUNC, 0644); 36 | } 37 | }); 38 | 39 | auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDONLY | uvw::file_req::file_open_flags::TRUNC; 40 | srcReq->open(srcFilename, flags, 0644); 41 | 42 | loop->run(); 43 | 44 | ASSERT_TRUE(checkFileSendFileEvent); 45 | } 46 | 47 | TEST(FileReq, SendFileSync) { 48 | const std::string srcFilename = std::string{TARGET_FILE_REQ_SENDFILE_DIR} + std::string{"/src.file"}; 49 | const std::string dstFilename = std::string{TARGET_FILE_REQ_SENDFILE_DIR} + std::string{"/dst.file"}; 50 | 51 | auto loop = uvw::loop::get_default(); 52 | auto srcReq = loop->resource(); 53 | auto dstReq = loop->resource(); 54 | 55 | ASSERT_TRUE(srcReq->open_sync(srcFilename, uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDONLY | uvw::file_req::file_open_flags::TRUNC, 0644)); 56 | ASSERT_TRUE(dstReq->open_sync(dstFilename, uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::WRONLY | uvw::file_req::file_open_flags::TRUNC, 0644)); 57 | 58 | auto sendfileR = srcReq->sendfile_sync(static_cast(*dstReq), 0, 0); 59 | 60 | ASSERT_TRUE(sendfileR.first); 61 | ASSERT_TRUE(srcReq->close_sync()); 62 | ASSERT_TRUE(dstReq->close_sync()); 63 | 64 | loop->run(); 65 | } 66 | -------------------------------------------------------------------------------- /test/uvw/fs_event.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | TEST(FsEvent, Functionalities) { 6 | const std::string filename = std::string{TARGET_FS_EVENT_DIR} + std::string{"/test.file"}; 7 | 8 | auto loop = uvw::loop::get_default(); 9 | auto handle = loop->resource(); 10 | auto request = loop->resource(); 11 | 12 | bool checkFsEventEvent = false; 13 | 14 | handle->on([&](const auto &, auto &) { FAIL(); }); 15 | request->on([](const auto &, auto &) { FAIL(); }); 16 | 17 | handle->on([&checkFsEventEvent](const auto &event, auto &hndl) { 18 | ASSERT_FALSE(checkFsEventEvent); 19 | ASSERT_EQ(std::string{event.filename}, std::string{"test.file"}); 20 | 21 | checkFsEventEvent = true; 22 | 23 | ASSERT_EQ(0, hndl.stop()); 24 | 25 | hndl.close(); 26 | 27 | ASSERT_TRUE(hndl.closing()); 28 | }); 29 | 30 | request->on([&](const auto &event, auto &req) { 31 | if(event.type == uvw::fs_req::fs_type::WRITE) { 32 | req.close(); 33 | } else if(event.type == uvw::fs_req::fs_type::OPEN) { 34 | req.write(std::unique_ptr{new char[1]{42}}, 1, 0); 35 | } 36 | }); 37 | 38 | ASSERT_EQ(0, handle->start(std::string{TARGET_FS_EVENT_DIR}, uvw::fs_event_handle::event_flags::RECURSIVE)); 39 | 40 | auto flags = uvw::file_req::file_open_flags::CREAT | uvw::file_req::file_open_flags::RDWR | uvw::file_req::file_open_flags::TRUNC; 41 | request->open(filename, flags, 0644); 42 | 43 | ASSERT_EQ(handle->path(), std::string{TARGET_FS_EVENT_DIR}); 44 | ASSERT_TRUE(handle->active()); 45 | ASSERT_FALSE(handle->closing()); 46 | 47 | ASSERT_NE(0, handle->start(std::string{TARGET_FS_EVENT_DIR}, uvw::fs_event_handle::event_flags::RECURSIVE)); 48 | 49 | ASSERT_FALSE(checkFsEventEvent); 50 | 51 | loop->run(); 52 | 53 | ASSERT_TRUE(checkFsEventEvent); 54 | } 55 | -------------------------------------------------------------------------------- /test/uvw/handle.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct fake_handle_t { 6 | void *data; 7 | }; 8 | 9 | struct fake_handle: uvw::handle { 10 | using handle::handle; 11 | 12 | int init() { 13 | return 1; 14 | } 15 | }; 16 | 17 | TEST(Handle, Functionalities) { 18 | auto loop = uvw::loop::get_default(); 19 | auto handle = loop->resource(); 20 | 21 | ASSERT_EQ(uvw::utilities::guess_handle(handle->category()), uvw::handle_type::ASYNC); 22 | ASSERT_EQ(handle->type(), uvw::handle_type::ASYNC); 23 | 24 | ASSERT_TRUE(handle->active()); 25 | ASSERT_FALSE(handle->closing()); 26 | ASSERT_NO_THROW(handle->close()); 27 | ASSERT_FALSE(handle->active()); 28 | 29 | // this forces an internal call to the close callback 30 | // (possible leak detected by valgrind otherwise) 31 | loop->run(); 32 | 33 | ASSERT_NO_THROW(handle->reference()); 34 | ASSERT_TRUE(handle->referenced()); 35 | ASSERT_NO_THROW(handle->unreference()); 36 | ASSERT_FALSE(handle->referenced()); 37 | 38 | ASSERT_NE(handle->size(), static_castsize())>(0)); 39 | 40 | ASSERT_LT(handle->send_buffer_size(), 0); 41 | ASSERT_NE(0, handle->send_buffer_size(0)); 42 | 43 | ASSERT_LT(handle->recv_buffer_size(), 0); 44 | ASSERT_NE(0, handle->recv_buffer_size(0)); 45 | 46 | ASSERT_NO_THROW([[maybe_unused]] const auto fd = handle->fd()); 47 | } 48 | 49 | TEST(Handle, InitializationFailure) { 50 | auto loop = uvw::loop::get_default(); 51 | auto resource = loop->resource(); 52 | 53 | ASSERT_FALSE(static_cast(resource)); 54 | } 55 | -------------------------------------------------------------------------------- /test/uvw/idle.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(Idle, StartAndStop) { 5 | auto loop = uvw::loop::get_default(); 6 | auto handle = loop->resource(); 7 | 8 | bool checkIdleEvent = false; 9 | 10 | handle->on([](auto &&...) { FAIL(); }); 11 | 12 | handle->on([&checkIdleEvent](const auto &, auto &hndl) { 13 | ASSERT_FALSE(checkIdleEvent); 14 | 15 | checkIdleEvent = true; 16 | 17 | ASSERT_EQ(0, hndl.stop()); 18 | 19 | hndl.close(); 20 | 21 | ASSERT_TRUE(hndl.closing()); 22 | }); 23 | 24 | ASSERT_EQ(0, handle->start()); 25 | ASSERT_TRUE(handle->active()); 26 | ASSERT_FALSE(handle->closing()); 27 | 28 | loop->run(); 29 | 30 | ASSERT_TRUE(checkIdleEvent); 31 | } 32 | 33 | TEST(Idle, Fake) { 34 | auto loop = uvw::loop::get_default(); 35 | auto handle = loop->resource(); 36 | 37 | handle->on([](auto &&...) { FAIL(); }); 38 | handle->on([](auto &&...) { FAIL(); }); 39 | 40 | handle->start(); 41 | handle->close(); 42 | 43 | ASSERT_FALSE(handle->active()); 44 | ASSERT_TRUE(handle->closing()); 45 | 46 | loop->run(); 47 | } 48 | -------------------------------------------------------------------------------- /test/uvw/lib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(SharedLib, Failure) { 5 | auto loop = uvw::loop::get_default(); 6 | auto lib = loop->resource("foobar.so"); 7 | 8 | ASSERT_FALSE(static_cast(*lib)); 9 | ASSERT_NE(lib->error(), nullptr); 10 | ASSERT_EQ(&lib->parent(), loop.get()); 11 | 12 | // this forces a call to the destructor to invoke uv_dlclose 13 | lib.reset(); 14 | } 15 | 16 | TEST(SharedLib, Success) { 17 | auto loop = uvw::loop::get_default(); 18 | auto lib = loop->resource(TARGET_LIB_SO); 19 | 20 | ASSERT_TRUE(static_cast(*lib)); 21 | ASSERT_EQ(&lib->parent(), loop.get()); 22 | ASSERT_EQ(lib->sym("foobar"), nullptr); 23 | ASSERT_NE(lib->sym("fake_func"), nullptr); 24 | double d{1.}; 25 | ASSERT_EQ(-42, lib->sym("fake_func")(&d)); 26 | ASSERT_DOUBLE_EQ(-1., d); 27 | 28 | // this forces a call to the destructor to invoke uv_dlclose 29 | lib.reset(); 30 | } 31 | -------------------------------------------------------------------------------- /test/uvw/loop.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(Loop, DefaultLoop) { 5 | auto def = uvw::loop::get_default(); 6 | 7 | ASSERT_TRUE(static_cast(def)); 8 | ASSERT_FALSE(def->alive()); 9 | ASSERT_NO_THROW(def->stop()); 10 | 11 | def->walk([](auto &) { FAIL(); }); 12 | auto def2 = uvw::loop::get_default(); 13 | 14 | ASSERT_EQ(def, def2); 15 | ASSERT_EQ(0, def->close()); 16 | } 17 | 18 | TEST(Loop, Functionalities) { 19 | auto loop = uvw::loop::create(); 20 | auto handle = loop->resource(); 21 | auto req = loop->resource([] {}); 22 | 23 | loop->on([](auto &&...) { FAIL(); }); 24 | req->on([](auto &&...) { FAIL(); }); 25 | handle->on([](auto &&...) { FAIL(); }); 26 | 27 | ASSERT_TRUE(static_cast(handle)); 28 | ASSERT_TRUE(static_cast(req)); 29 | 30 | ASSERT_TRUE(loop->descriptor()); 31 | ASSERT_NO_THROW(loop->now()); 32 | ASSERT_NO_THROW(loop->update()); 33 | 34 | #ifndef _MSC_VER 35 | // fork isn't implemented on Windows in libuv and it returns an error by default 36 | ASSERT_EQ(0, loop->fork()); 37 | #endif 38 | 39 | ASSERT_FALSE(loop->alive()); 40 | ASSERT_FALSE(loop->timeout().first); 41 | 42 | handle->start(); 43 | handle->on([](const auto &, auto &hndl) { 44 | hndl.parent().walk([](auto &) { 45 | static bool trigger = true; 46 | ASSERT_TRUE(trigger); 47 | trigger = false; 48 | }); 49 | 50 | hndl.close(); 51 | }); 52 | 53 | ASSERT_TRUE(loop->alive()); 54 | ASSERT_EQ(0, loop->run()); 55 | 56 | loop->walk([](auto &) { FAIL(); }); 57 | 58 | ASSERT_EQ(0, loop->run(uvw::loop::run_mode::ONCE)); 59 | ASSERT_EQ(0, loop->run(uvw::loop::run_mode::NOWAIT)); 60 | 61 | ASSERT_FALSE(loop->alive()); 62 | ASSERT_EQ(0, loop->close()); 63 | } 64 | 65 | TEST(Loop, Walk) { 66 | auto loop = uvw::loop::create(); 67 | 68 | loop->resource(); 69 | loop->resource(); 70 | loop->resource(); 71 | loop->resource(); 72 | loop->resource(); 73 | loop->resource(); 74 | loop->resource(); 75 | loop->resource(); 76 | loop->resource(); 77 | loop->resource(); 78 | loop->resource(0, true); 79 | loop->resource(); 80 | 81 | std::size_t count{}; 82 | 83 | loop->walk([&count](auto &handle) { 84 | ++count; 85 | handle.close(); 86 | }); 87 | 88 | ASSERT_EQ(count, 12u); 89 | 90 | loop->run(); 91 | loop->walk([&count](auto &) { --count; }); 92 | 93 | ASSERT_EQ(count, 12u); 94 | 95 | ASSERT_EQ(0, loop->close()); 96 | } 97 | 98 | TEST(Loop, UserData) { 99 | auto loop = uvw::loop::create(); 100 | loop->data(std::make_shared(42)); 101 | 102 | ASSERT_EQ(*std::static_pointer_cast(loop->data()), 42); 103 | ASSERT_EQ(*loop->data(), 42); 104 | 105 | loop->run(); 106 | 107 | ASSERT_EQ(*std::static_pointer_cast(loop->data()), 42); 108 | ASSERT_EQ(*loop->data(), 42); 109 | 110 | ASSERT_EQ(0, loop->close()); 111 | } 112 | 113 | TEST(Loop, Configure) { 114 | auto loop = uvw::loop::create(); 115 | ASSERT_EQ(0, loop->configure(uvw::loop::option::IDLE_TIME)); 116 | ASSERT_EQ(0, loop->run()); 117 | ASSERT_EQ(0, loop->close()); 118 | } 119 | 120 | TEST(Loop, IdleTime) { 121 | auto loop = uvw::loop::create(); 122 | loop->configure(uvw::loop::option::IDLE_TIME); 123 | ASSERT_EQ(loop->idle_time().count(), 0u); 124 | ASSERT_EQ(0, loop->close()); 125 | } 126 | 127 | TEST(Loop, Metrics) { 128 | auto loop = uvw::loop::create(); 129 | uvw::metrics_type metrics = loop->metrics(); 130 | ASSERT_EQ(0, metrics.loop_count); 131 | ASSERT_EQ(0, metrics.events); 132 | ASSERT_EQ(0, metrics.events_waiting); 133 | } 134 | 135 | TEST(Loop, Raw) { 136 | auto loop = uvw::loop::get_default(); 137 | const auto &cloop = uvw::loop::get_default(); 138 | 139 | auto *raw = loop->raw(); 140 | auto *craw = cloop->raw(); 141 | 142 | ASSERT_EQ(raw, craw); 143 | 144 | ASSERT_EQ(0, loop->close()); 145 | } 146 | -------------------------------------------------------------------------------- /test/uvw/pipe.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(Pipe, ReadWrite) { 5 | #ifdef _MSC_VER 6 | const std::string sockname{"\\\\.\\pipe\\test.sock"}; 7 | #else 8 | const std::string sockname = std::string{TARGET_PIPE_DIR} + std::string{"/test.sock"}; 9 | #endif 10 | 11 | auto loop = uvw::loop::get_default(); 12 | auto server = loop->resource(); 13 | auto client = loop->resource(); 14 | 15 | server->on([](const auto &, auto &) { FAIL(); }); 16 | client->on([](const auto &, auto &) { FAIL(); }); 17 | 18 | server->on([](const uvw::listen_event &, uvw::pipe_handle &handle) { 19 | std::shared_ptr socket = handle.parent().resource(); 20 | 21 | socket->on([](const uvw::error_event &, uvw::pipe_handle &) { FAIL(); }); 22 | socket->on([&handle](const uvw::close_event &, uvw::pipe_handle &) { handle.close(); }); 23 | socket->on([](const uvw::end_event &, uvw::pipe_handle &sock) { sock.close(); }); 24 | 25 | ASSERT_EQ(0, handle.accept(*socket)); 26 | ASSERT_EQ(0, socket->read()); 27 | }); 28 | 29 | client->on([](const uvw::write_event &, uvw::pipe_handle &handle) { 30 | handle.close(); 31 | }); 32 | 33 | client->on([](const uvw::connect_event &, uvw::pipe_handle &handle) { 34 | ASSERT_TRUE(handle.writable()); 35 | ASSERT_TRUE(handle.readable()); 36 | 37 | auto dataWrite = std::unique_ptr(new char[2]{'x', 'y'}); 38 | handle.write(std::move(dataWrite), 2); 39 | }); 40 | 41 | server->bind(sockname); 42 | 43 | ASSERT_EQ(0, server->listen()); 44 | ASSERT_EQ(0, client->connect(sockname)); 45 | 46 | loop->run(); 47 | } 48 | 49 | TEST(Pipe, SockPeer) { 50 | #ifdef _MSC_VER 51 | const std::string sockname{"\\\\.\\pipe\\test.sock"}; 52 | const std::string peername{"\\\\?\\pipe\\test.sock"}; 53 | #else 54 | const std::string sockname = std::string{TARGET_PIPE_DIR} + std::string{"/test.sock"}; 55 | const auto peername = sockname; 56 | #endif 57 | 58 | auto loop = uvw::loop::get_default(); 59 | auto server = loop->resource(); 60 | auto client = loop->resource(); 61 | 62 | server->on([](const auto &, auto &) { FAIL(); }); 63 | client->on([](const auto &, auto &) { FAIL(); }); 64 | 65 | server->on([&peername](const uvw::listen_event &, uvw::pipe_handle &handle) { 66 | std::shared_ptr socket = handle.parent().resource(); 67 | 68 | socket->on([](const uvw::error_event &, uvw::pipe_handle &) { FAIL(); }); 69 | socket->on([&handle](const uvw::close_event &, uvw::pipe_handle &) { handle.close(); }); 70 | socket->on([](const uvw::end_event &, uvw::pipe_handle &sock) { sock.close(); }); 71 | 72 | ASSERT_EQ(0, handle.accept(*socket)); 73 | ASSERT_EQ(0, socket->read()); 74 | ASSERT_EQ(handle.sock(), peername); 75 | }); 76 | 77 | client->on([&peername](const uvw::connect_event &, uvw::pipe_handle &handle) { 78 | ASSERT_EQ(handle.peer(), peername); 79 | 80 | handle.close(); 81 | }); 82 | 83 | server->bind(sockname); 84 | 85 | ASSERT_EQ(0, server->listen()); 86 | ASSERT_EQ(0, client->connect(sockname)); 87 | 88 | loop->run(); 89 | } 90 | 91 | TEST(Pipe, Shutdown) { 92 | #ifdef _MSC_VER 93 | const std::string sockname{"\\\\.\\pipe\\test.sock"}; 94 | #else 95 | const std::string sockname = std::string{TARGET_PIPE_DIR} + std::string{"/test.sock"}; 96 | #endif 97 | 98 | auto data = std::unique_ptr(new char[3]{'a', 'b', 'c'}); 99 | 100 | auto loop = uvw::loop::get_default(); 101 | auto server = loop->resource(); 102 | auto client = loop->resource(); 103 | 104 | server->on([](const auto &, auto &) { FAIL(); }); 105 | client->on([](const auto &, auto &) { FAIL(); }); 106 | 107 | server->on([](const uvw::listen_event &, uvw::pipe_handle &handle) { 108 | std::shared_ptr socket = handle.parent().resource(); 109 | 110 | socket->on([](const uvw::error_event &, uvw::pipe_handle &) { FAIL(); }); 111 | socket->on([&handle](const uvw::close_event &, uvw::pipe_handle &) { handle.close(); }); 112 | socket->on([](const uvw::end_event &, uvw::pipe_handle &sock) { sock.close(); }); 113 | 114 | ASSERT_EQ(0, handle.accept(*socket)); 115 | ASSERT_EQ(0, socket->read()); 116 | }); 117 | 118 | client->on([](const uvw::shutdown_event &, uvw::pipe_handle &handle) { 119 | handle.close(); 120 | }); 121 | 122 | client->on([&data](const uvw::connect_event &, uvw::pipe_handle &handle) { 123 | handle.write(data.get(), 3); 124 | 125 | ASSERT_EQ(0, handle.shutdown()); 126 | }); 127 | 128 | server->bind(sockname); 129 | 130 | ASSERT_EQ(0, server->listen()); 131 | ASSERT_EQ(0, client->connect(sockname)); 132 | 133 | loop->run(); 134 | } 135 | -------------------------------------------------------------------------------- /test/uvw/prepare.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(Prepare, StartAndStop) { 5 | auto loop = uvw::loop::get_default(); 6 | auto handle = loop->resource(); 7 | 8 | bool checkPrepareEvent = false; 9 | 10 | handle->on([](auto &&...) { FAIL(); }); 11 | 12 | handle->on([&checkPrepareEvent](const auto &, auto &hndl) { 13 | ASSERT_FALSE(checkPrepareEvent); 14 | 15 | checkPrepareEvent = true; 16 | 17 | ASSERT_EQ(0, hndl.stop()); 18 | 19 | hndl.close(); 20 | 21 | ASSERT_TRUE(hndl.closing()); 22 | }); 23 | 24 | ASSERT_EQ(0, handle->start()); 25 | ASSERT_TRUE(handle->active()); 26 | ASSERT_FALSE(handle->closing()); 27 | 28 | loop->run(); 29 | 30 | ASSERT_TRUE(checkPrepareEvent); 31 | } 32 | 33 | TEST(Prepare, Fake) { 34 | auto loop = uvw::loop::get_default(); 35 | auto handle = loop->resource(); 36 | 37 | handle->on([](auto &&...) { FAIL(); }); 38 | handle->on([](auto &&...) { FAIL(); }); 39 | 40 | handle->start(); 41 | handle->close(); 42 | 43 | ASSERT_FALSE(handle->active()); 44 | ASSERT_TRUE(handle->closing()); 45 | 46 | loop->run(); 47 | } 48 | -------------------------------------------------------------------------------- /test/uvw/process.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | TEST(Process, Pid) { 6 | auto loop = uvw::loop::get_default(); 7 | auto handle = loop->resource(); 8 | 9 | ASSERT_EQ(handle->pid(), 0); 10 | 11 | loop->run(); 12 | } 13 | 14 | TEST(Process, Cwd) { 15 | auto loop = uvw::loop::get_default(); 16 | auto handle = loop->resource(); 17 | 18 | handle->cwd("."); 19 | 20 | loop->run(); 21 | } 22 | 23 | TEST(Process, StdIO) { 24 | auto loop = uvw::loop::get_default(); 25 | auto handle = loop->resource(); 26 | auto pipe = loop->resource(); 27 | 28 | uvw::process_handle::disable_stdio_inheritance(); 29 | handle->stdio(*pipe, uvw::process_handle::stdio_flags::CREATE_PIPE | uvw::process_handle::stdio_flags::READABLE_PIPE); 30 | handle->stdio(uvw::std_in, uvw::process_handle::stdio_flags::IGNORE_STREAM); 31 | handle->stdio(uvw::std_out, uvw::process_handle::stdio_flags::IGNORE_STREAM); 32 | handle->stdio(uvw::std_out, uvw::process_handle::stdio_flags::INHERIT_FD); 33 | 34 | pipe->close(); 35 | loop->run(); 36 | } 37 | -------------------------------------------------------------------------------- /test/uvw/request.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | TEST(Request, Functionalities) { 6 | auto loop = uvw::loop::get_default(); 7 | auto req = loop->resource([]() {}); 8 | 9 | ASSERT_NE(req->size(), decltype(req->size()){0}); 10 | ASSERT_LT(req->cancel(), 0); 11 | 12 | loop->run(); 13 | } 14 | -------------------------------------------------------------------------------- /test/uvw/resource.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | TEST(Resource, Functionalities) { 8 | ASSERT_FALSE(std::is_copy_constructible::value); 9 | ASSERT_FALSE(std::is_copy_assignable::value); 10 | 11 | ASSERT_FALSE(std::is_move_constructible::value); 12 | ASSERT_FALSE(std::is_move_assignable::value); 13 | 14 | auto loop = uvw::loop::get_default(); 15 | auto resource = loop->resource(); 16 | 17 | ASSERT_EQ(&resource->parent(), loop.get()); 18 | 19 | resource->data(std::make_shared(42)); 20 | 21 | ASSERT_EQ(*std::static_pointer_cast(resource->data()), 42); 22 | ASSERT_EQ(*resource->data(), 42); 23 | 24 | resource->close(); 25 | loop->run(); 26 | } 27 | -------------------------------------------------------------------------------- /test/uvw/signal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(Signal, Start) { 5 | auto loop = uvw::loop::get_default(); 6 | auto handle = loop->resource(); 7 | 8 | handle->on([](auto &&...) { FAIL(); }); 9 | 10 | ASSERT_EQ(0, handle->start(2)); 11 | ASSERT_EQ(2, handle->signal()); 12 | ASSERT_EQ(0, handle->stop()); 13 | 14 | handle->close(); 15 | 16 | ASSERT_FALSE(handle->active()); 17 | ASSERT_TRUE(handle->closing()); 18 | 19 | loop->run(); 20 | } 21 | 22 | TEST(Signal, OneShot) { 23 | auto loop = uvw::loop::get_default(); 24 | auto handle = loop->resource(); 25 | 26 | handle->on([](auto &&...) { FAIL(); }); 27 | 28 | ASSERT_EQ(0, handle->one_shot(2)); 29 | ASSERT_EQ(2, handle->signal()); 30 | ASSERT_EQ(0, handle->stop()); 31 | 32 | handle->close(); 33 | 34 | ASSERT_FALSE(handle->active()); 35 | ASSERT_TRUE(handle->closing()); 36 | 37 | loop->run(); 38 | } 39 | -------------------------------------------------------------------------------- /test/uvw/stream.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct fake_stream_t { 5 | void *data; 6 | }; 7 | 8 | struct fake_stream_handle: uvw::stream_handle { 9 | using stream_handle::stream_handle; 10 | 11 | template 12 | int init(Args &&...) { 13 | return 0; 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /test/uvw/tcp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static auto custom_alloc_callback(const uvw::tcp_handle &, std::size_t suggested) { 5 | return std::make_pair(new char[suggested], suggested); 6 | } 7 | 8 | TEST(TCP, Functionalities) { 9 | auto loop = uvw::loop::get_default(); 10 | auto handle = loop->resource(); 11 | 12 | ASSERT_TRUE(handle->no_delay(true)); 13 | ASSERT_TRUE(handle->keep_alive(true, uvw::tcp_handle::time{128})); 14 | ASSERT_TRUE(handle->simultaneous_accepts()); 15 | 16 | handle->close(); 17 | loop->run(); 18 | } 19 | 20 | TEST(TCP, ReadWrite) { 21 | const std::string address = std::string{"127.0.0.1"}; 22 | const unsigned int port = 4242; 23 | 24 | auto loop = uvw::loop::get_default(); 25 | auto server = loop->resource(); 26 | auto client = loop->resource(); 27 | 28 | server->on([](const auto &, auto &) { FAIL(); }); 29 | client->on([](const auto &, auto &) { FAIL(); }); 30 | 31 | server->on([](const uvw::listen_event &, uvw::tcp_handle &handle) { 32 | std::shared_ptr socket = handle.parent().resource(); 33 | 34 | socket->on([](const uvw::error_event &, uvw::tcp_handle &) { FAIL(); }); 35 | socket->on([&handle](const uvw::close_event &, uvw::tcp_handle &) { handle.close(); }); 36 | socket->on([](const uvw::end_event &, uvw::tcp_handle &sock) { sock.close(); }); 37 | 38 | ASSERT_EQ(0, handle.accept(*socket)); 39 | ASSERT_EQ(0, socket->read()); 40 | }); 41 | 42 | client->on([](const uvw::write_event &, uvw::tcp_handle &handle) { 43 | handle.close(); 44 | }); 45 | 46 | client->on([](const uvw::connect_event &, uvw::tcp_handle &handle) { 47 | ASSERT_TRUE(handle.writable()); 48 | ASSERT_TRUE(handle.readable()); 49 | 50 | auto dataTryWrite = std::unique_ptr(new char[1]{'a'}); 51 | 52 | ASSERT_EQ(1, handle.try_write(std::move(dataTryWrite), 1)); 53 | 54 | auto dataWrite = std::unique_ptr(new char[2]{'b', 'c'}); 55 | handle.write(std::move(dataWrite), 2); 56 | }); 57 | 58 | ASSERT_EQ(0, (server->bind(address, port))); 59 | ASSERT_EQ(0, server->listen()); 60 | ASSERT_EQ(0, (client->connect(address, port))); 61 | 62 | loop->run(); 63 | } 64 | 65 | TEST(TCP, ReadWriteCustomAlloc) { 66 | const std::string address = std::string{"127.0.0.1"}; 67 | const unsigned int port = 4242; 68 | 69 | auto loop = uvw::loop::get_default(); 70 | auto server = loop->resource(); 71 | auto client = loop->resource(); 72 | 73 | server->on([](const auto &, auto &) { FAIL(); }); 74 | client->on([](const auto &, auto &) { FAIL(); }); 75 | 76 | server->on([](const uvw::listen_event &, uvw::tcp_handle &handle) { 77 | std::shared_ptr socket = handle.parent().resource(); 78 | 79 | socket->on([](const uvw::error_event &, uvw::tcp_handle &) { FAIL(); }); 80 | socket->on([&handle](const uvw::close_event &, uvw::tcp_handle &) { handle.close(); }); 81 | socket->on([](const uvw::end_event &, uvw::tcp_handle &sock) { sock.close(); }); 82 | 83 | ASSERT_EQ(0, handle.accept(*socket)); 84 | ASSERT_EQ(0, socket->read<&custom_alloc_callback>()); 85 | }); 86 | 87 | client->on([](const uvw::write_event &, uvw::tcp_handle &handle) { 88 | handle.close(); 89 | }); 90 | 91 | client->on([](const uvw::connect_event &, uvw::tcp_handle &handle) { 92 | ASSERT_TRUE(handle.writable()); 93 | ASSERT_TRUE(handle.readable()); 94 | 95 | auto dataTryWrite = std::unique_ptr(new char[1]{'a'}); 96 | 97 | ASSERT_EQ(1, handle.try_write(std::move(dataTryWrite), 1)); 98 | 99 | auto dataWrite = std::unique_ptr(new char[2]{'b', 'c'}); 100 | handle.write(std::move(dataWrite), 2); 101 | }); 102 | 103 | ASSERT_EQ(0, (server->bind(address, port))); 104 | ASSERT_EQ(0, server->listen()); 105 | ASSERT_EQ(0, (client->connect(address, port))); 106 | 107 | loop->run(); 108 | } 109 | 110 | TEST(TCP, SockPeer) { 111 | const std::string address = std::string{"127.0.0.1"}; 112 | const unsigned int port = 4242; 113 | 114 | auto loop = uvw::loop::get_default(); 115 | auto server = loop->resource(); 116 | auto client = loop->resource(); 117 | 118 | server->on([](const auto &, auto &) { FAIL(); }); 119 | client->on([](const auto &, auto &) { FAIL(); }); 120 | 121 | server->on([&address](const uvw::listen_event &, uvw::tcp_handle &handle) { 122 | std::shared_ptr socket = handle.parent().resource(); 123 | 124 | socket->on([](const uvw::error_event &, uvw::tcp_handle &) { FAIL(); }); 125 | socket->on([&handle](const uvw::close_event &, uvw::tcp_handle &) { handle.close(); }); 126 | socket->on([](const uvw::end_event &, uvw::tcp_handle &sock) { sock.close(); }); 127 | 128 | ASSERT_EQ(0, handle.accept(*socket)); 129 | ASSERT_EQ(0, socket->read()); 130 | 131 | uvw::socket_address addr = handle.sock(); 132 | 133 | ASSERT_EQ(addr.ip, address); 134 | }); 135 | 136 | client->on([&address](const uvw::connect_event &, uvw::tcp_handle &handle) { 137 | uvw::socket_address addr = handle.peer(); 138 | 139 | ASSERT_EQ(addr.ip, address); 140 | 141 | handle.close(); 142 | }); 143 | 144 | ASSERT_EQ(0, (server->bind(uvw::socket_address{address, port}))); 145 | ASSERT_EQ(0, server->listen()); 146 | ASSERT_EQ(0, (client->connect(uvw::socket_address{address, port}))); 147 | 148 | loop->run(); 149 | } 150 | 151 | TEST(TCP, Shutdown) { 152 | const std::string address = std::string{"127.0.0.1"}; 153 | const unsigned int port = 4242; 154 | 155 | auto loop = uvw::loop::get_default(); 156 | auto server = loop->resource(); 157 | auto client = loop->resource(); 158 | 159 | server->on([](const auto &, auto &) { FAIL(); }); 160 | client->on([](const auto &, auto &) { FAIL(); }); 161 | 162 | server->on([](const uvw::listen_event &, uvw::tcp_handle &handle) { 163 | std::shared_ptr socket = handle.parent().resource(); 164 | 165 | socket->on([](const uvw::error_event &, uvw::tcp_handle &) { FAIL(); }); 166 | socket->on([&handle](const uvw::close_event &, uvw::tcp_handle &) { handle.close(); }); 167 | socket->on([](const uvw::end_event &, uvw::tcp_handle &sock) { sock.close(); }); 168 | 169 | ASSERT_EQ(0, handle.accept(*socket)); 170 | ASSERT_EQ(0, socket->read()); 171 | }); 172 | 173 | client->on([](const uvw::shutdown_event &, uvw::tcp_handle &handle) { 174 | handle.close(); 175 | }); 176 | 177 | client->on([](const uvw::connect_event &, uvw::tcp_handle &handle) { 178 | ASSERT_EQ(0, handle.shutdown()); 179 | }); 180 | 181 | ASSERT_EQ(0, (server->bind(address, port))); 182 | ASSERT_EQ(0, server->listen()); 183 | ASSERT_EQ(0, (client->connect(address, port))); 184 | 185 | loop->run(); 186 | } 187 | 188 | TEST(TCP, WriteError) { 189 | auto loop = uvw::loop::get_default(); 190 | auto handle = loop->resource(); 191 | 192 | handle->close(); 193 | 194 | ASSERT_NE(0, (handle->write(std::unique_ptr{}, 0))); 195 | ASSERT_NE(0, (handle->write(nullptr, 0))); 196 | 197 | ASSERT_LT(handle->try_write(std::unique_ptr{}, 0), 0); 198 | ASSERT_LT(handle->try_write(nullptr, 0), 0); 199 | } 200 | -------------------------------------------------------------------------------- /test/uvw/thread.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(Thread, Run) { 5 | auto loop = uvw::loop::get_default(); 6 | auto has_run = std::make_shared(); 7 | auto cb = [](const std::shared_ptr &data) { 8 | if(auto has_run_ptr = std::static_pointer_cast(data); has_run_ptr) { 9 | *has_run_ptr = true; 10 | } 11 | }; 12 | 13 | auto handle = loop->resource(cb, has_run); 14 | 15 | ASSERT_TRUE(handle->run()); 16 | ASSERT_TRUE(handle->join()); 17 | ASSERT_TRUE(*has_run); 18 | 19 | loop->run(); 20 | } 21 | 22 | TEST(ThreadLocalStorage, SetGet) { 23 | auto loop = uvw::loop::get_default(); 24 | auto localStorage = loop->resource(); 25 | auto flag{true}; 26 | 27 | localStorage->set(&flag); 28 | ASSERT_TRUE(localStorage->get()); 29 | 30 | loop->run(); 31 | } 32 | 33 | TEST(Mutex, LockUnlock) { 34 | auto loop = uvw::loop::get_default(); 35 | auto mtx = loop->resource(); 36 | 37 | mtx->lock(); 38 | 39 | #ifdef _MSC_VER 40 | // this is allowed by libuv on Windows 41 | ASSERT_TRUE(mtx->try_lock()); 42 | #else 43 | ASSERT_FALSE(mtx->try_lock()); 44 | #endif 45 | 46 | mtx->unlock(); 47 | ASSERT_TRUE(mtx->try_lock()); 48 | 49 | #ifdef _MSC_VER 50 | // this is allowed by libuv on Windows 51 | ASSERT_TRUE(mtx->try_lock()); 52 | #else 53 | ASSERT_FALSE(mtx->try_lock()); 54 | #endif 55 | 56 | mtx->unlock(); 57 | 58 | loop->run(); 59 | } 60 | 61 | TEST(Mutex, RecursiveLockUnlock) { 62 | auto loop = uvw::loop::get_default(); 63 | auto recursive_mtx = loop->resource(true); 64 | 65 | recursive_mtx->lock(); 66 | recursive_mtx->unlock(); 67 | 68 | recursive_mtx->lock(); 69 | ASSERT_TRUE(recursive_mtx->try_lock()); 70 | recursive_mtx->unlock(); 71 | recursive_mtx->unlock(); 72 | 73 | loop->run(); 74 | } 75 | -------------------------------------------------------------------------------- /test/uvw/timer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(Timer, StartAndStop) { 5 | auto loop = uvw::loop::get_default(); 6 | auto handleNoRepeat = loop->resource(); 7 | auto handleRepeat = loop->resource(); 8 | 9 | bool checkTimerNoRepeatEvent = false; 10 | bool checkTimerRepeatEvent = false; 11 | 12 | handleNoRepeat->on([](auto &&...) { FAIL(); }); 13 | handleRepeat->on([](auto &&...) { FAIL(); }); 14 | 15 | handleNoRepeat->on([&checkTimerNoRepeatEvent](const auto &, auto &handle) { 16 | ASSERT_FALSE(checkTimerNoRepeatEvent); 17 | 18 | checkTimerNoRepeatEvent = true; 19 | 20 | ASSERT_EQ(0, handle.stop()); 21 | 22 | handle.close(); 23 | 24 | ASSERT_TRUE(handle.closing()); 25 | }); 26 | 27 | handleRepeat->on([&checkTimerRepeatEvent](const auto &, auto &handle) { 28 | if(checkTimerRepeatEvent) { 29 | ASSERT_EQ(0, handle.stop()); 30 | 31 | handle.close(); 32 | 33 | ASSERT_TRUE(handle.closing()); 34 | } else { 35 | checkTimerRepeatEvent = true; 36 | ASSERT_FALSE(handle.closing()); 37 | } 38 | }); 39 | 40 | ASSERT_EQ(0, handleNoRepeat->start(uvw::timer_handle::time{0}, uvw::timer_handle::time{0})); 41 | ASSERT_EQ(0, handleRepeat->start(uvw::timer_handle::time{0}, uvw::timer_handle::time{1})); 42 | 43 | ASSERT_TRUE(handleNoRepeat->active()); 44 | ASSERT_FALSE(handleNoRepeat->closing()); 45 | 46 | ASSERT_TRUE(handleRepeat->active()); 47 | ASSERT_FALSE(handleRepeat->closing()); 48 | 49 | loop->run(); 50 | 51 | ASSERT_TRUE(checkTimerNoRepeatEvent); 52 | ASSERT_TRUE(checkTimerRepeatEvent); 53 | } 54 | 55 | TEST(Timer, Again) { 56 | auto loop = uvw::loop::get_default(); 57 | auto handle = loop->resource(); 58 | 59 | bool checkTimerEvent = false; 60 | 61 | handle->on([](const auto &, auto &) { FAIL(); }); 62 | 63 | handle->on([&checkTimerEvent](const auto &, auto &hndl) { 64 | static bool guard = false; 65 | 66 | if(guard) { 67 | hndl.stop(); 68 | hndl.close(); 69 | checkTimerEvent = true; 70 | ASSERT_TRUE(hndl.closing()); 71 | } else { 72 | guard = true; 73 | ASSERT_EQ(0, hndl.again()); 74 | ASSERT_EQ(hndl.repeat(), uvw::timer_handle::time{1}); 75 | ASSERT_FALSE(hndl.closing()); 76 | } 77 | }); 78 | 79 | ASSERT_NE(0, handle->again()); 80 | ASSERT_FALSE(handle->active()); 81 | 82 | handle->start(uvw::timer_handle::time{0}, uvw::timer_handle::time{1}); 83 | 84 | ASSERT_TRUE(handle->active()); 85 | ASSERT_FALSE(handle->closing()); 86 | 87 | loop->run(); 88 | 89 | ASSERT_TRUE(checkTimerEvent); 90 | 91 | handle->close(); 92 | 93 | ASSERT_FALSE(handle->active()); 94 | ASSERT_TRUE(handle->closing()); 95 | 96 | ASSERT_NE(0, handle->start(uvw::timer_handle::time{0}, uvw::timer_handle::time{1})); 97 | } 98 | 99 | TEST(Timer, Repeat) { 100 | auto loop = uvw::loop::get_default(); 101 | auto handle = loop->resource(); 102 | 103 | ASSERT_NO_THROW(handle->repeat(uvw::timer_handle::time{42})); 104 | ASSERT_EQ(handle->repeat(), uvw::timer_handle::time{42}); 105 | ASSERT_NO_THROW(handle->close()); 106 | 107 | // this forces an internal call to the close callback 108 | // (possible leak detected by valgrind otherwise) 109 | loop->run(); 110 | } 111 | 112 | TEST(Timer, Fake) { 113 | auto loop = uvw::loop::get_default(); 114 | auto handle = loop->resource(); 115 | 116 | handle->on([](auto &&...) { FAIL(); }); 117 | handle->on([](auto &&...) { FAIL(); }); 118 | 119 | handle->start(uvw::timer_handle::time{0}, uvw::timer_handle::time{0}); 120 | handle->close(); 121 | 122 | ASSERT_FALSE(handle->active()); 123 | ASSERT_TRUE(handle->closing()); 124 | 125 | loop->run(); 126 | } 127 | 128 | TEST(Timer, BaseHandleWalk) { 129 | auto loop = uvw::loop::get_default(); 130 | auto timer = loop->resource(); 131 | 132 | timer->on([](const auto &, uvw::timer_handle &handle) { 133 | handle.parent().walk(uvw::overloaded{[](uvw::timer_handle &h) { h.close(); }, [](auto &&) {}}); 134 | }); 135 | 136 | timer->start(uvw::timer_handle::time{100}, uvw::timer_handle::time{100}); 137 | loop->run(); 138 | } 139 | -------------------------------------------------------------------------------- /test/uvw/tty.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | TEST(TTY, Functionalities) { 6 | auto loop = uvw::loop::get_default(); 7 | auto handle = loop->resource(uvw::std_out, false); 8 | auto timer = loop->resource(); 9 | 10 | bool checkWriteEvent = false; 11 | 12 | handle->on([&checkWriteEvent](const auto &, auto &hndl) { 13 | ASSERT_FALSE(checkWriteEvent); 14 | checkWriteEvent = true; 15 | hndl.close(); 16 | }); 17 | 18 | timer->on([handle](const auto &, auto &hndl) { 19 | auto data = std::make_unique('*'); 20 | 21 | ASSERT_EQ(0, (handle->write(std::move(data), 1))); 22 | 23 | hndl.close(); 24 | }); 25 | 26 | ASSERT_TRUE(handle->reset_mode()); 27 | ASSERT_TRUE(!handle->readable() || handle->mode(uvw::tty_handle::tty_mode::NORMAL)); 28 | ASSERT_NO_THROW(handle->get_win_size()); 29 | 30 | timer->start(uvw::timer_handle::time{0}, uvw::timer_handle::time{0}); 31 | loop->run(); 32 | 33 | ASSERT_TRUE(checkWriteEvent); 34 | } 35 | -------------------------------------------------------------------------------- /test/uvw/udp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static auto custom_alloc_callback(const uvw::udp_handle &, std::size_t suggested) { 5 | return std::make_pair(new char[suggested], suggested); 6 | } 7 | 8 | TEST(UDP, Functionalities) { 9 | auto loop = uvw::loop::get_default(); 10 | auto handle = loop->resource(); 11 | 12 | ASSERT_FALSE(handle->multicast_membership("0.0.0.0", "127.0.0.1", uvw::udp_handle::membership::JOIN_GROUP)); 13 | ASSERT_TRUE(handle->multicast_membership("224.0.0.1", "127.0.0.1", uvw::udp_handle::membership::JOIN_GROUP)); 14 | ASSERT_TRUE(handle->multicast_membership("224.0.0.1", "127.0.0.1", uvw::udp_handle::membership::LEAVE_GROUP)); 15 | ASSERT_TRUE(handle->multicast_loop(true)); 16 | ASSERT_TRUE(handle->multicast_ttl(42)); 17 | ASSERT_TRUE(handle->multicast_interface("127.0.0.1")); 18 | ASSERT_TRUE(handle->broadcast(true)); 19 | ASSERT_TRUE(handle->ttl(42)); 20 | ASSERT_FALSE(handle->ttl(0)); 21 | 22 | handle->close(); 23 | loop->run(); 24 | } 25 | 26 | TEST(UDP, BindRecvStop) { 27 | const std::string address = std::string{"127.0.0.1"}; 28 | const unsigned int port = 4242; 29 | 30 | auto loop = uvw::loop::get_default(); 31 | auto handle = loop->resource(); 32 | 33 | handle->on([](const auto &, auto &) { FAIL(); }); 34 | 35 | ASSERT_EQ(0, (handle->bind(address, port))); 36 | ASSERT_EQ(0, handle->recv()); 37 | ASSERT_EQ(0, handle->stop()); 38 | 39 | handle->close(); 40 | 41 | loop->run(); 42 | } 43 | 44 | TEST(UDP, ReadTrySend) { 45 | const std::string address = std::string{"127.0.0.1"}; 46 | const unsigned int port = 4242; 47 | 48 | auto loop = uvw::loop::get_default(); 49 | auto server = loop->resource(); 50 | auto client = loop->resource(); 51 | 52 | server->on([](const auto &, auto &) { FAIL(); }); 53 | client->on([](const auto &, auto &) { FAIL(); }); 54 | 55 | server->on([&client](const uvw::udp_data_event &, uvw::udp_handle &handle) { 56 | client->close(); 57 | handle.close(); 58 | }); 59 | 60 | ASSERT_EQ(0, (server->bind(uvw::socket_address{address, port}))); 61 | ASSERT_EQ(0, server->recv()); 62 | 63 | auto dataTrySend = std::unique_ptr(new char[1]{'a'}); 64 | 65 | ASSERT_EQ(1, client->try_send(uvw::socket_address{address, port}, dataTrySend.get(), 1)); 66 | ASSERT_EQ(0, client->try_send(address, port, nullptr, 0)); 67 | 68 | ASSERT_EQ(1, client->try_send(uvw::socket_address{address, port}, std::move(dataTrySend), 1)); 69 | ASSERT_EQ(0, client->try_send(address, port, std::unique_ptr{}, 0)); 70 | 71 | loop->run(); 72 | } 73 | 74 | TEST(UDP, ReadSend) { 75 | const std::string address = std::string{"127.0.0.1"}; 76 | const unsigned int port = 4242; 77 | 78 | auto loop = uvw::loop::get_default(); 79 | auto server = loop->resource(); 80 | auto client = loop->resource(); 81 | 82 | server->on([](const auto &, auto &) { FAIL(); }); 83 | client->on([](const auto &, auto &) { FAIL(); }); 84 | 85 | server->on([](const uvw::udp_data_event &, uvw::udp_handle &handle) { 86 | handle.close(); 87 | }); 88 | 89 | client->on([](const uvw::send_event &, uvw::udp_handle &handle) { 90 | handle.close(); 91 | }); 92 | 93 | ASSERT_EQ(0, (server->bind(address, port))); 94 | ASSERT_EQ(0, server->recv()); 95 | 96 | auto dataSend = std::unique_ptr(new char[2]{'b', 'c'}); 97 | 98 | client->send(uvw::socket_address{address, port}, dataSend.get(), 2); 99 | client->send(address, port, nullptr, 0); 100 | 101 | client->send(uvw::socket_address{address, port}, std::move(dataSend), 2); 102 | client->send(address, port, std::unique_ptr{}, 0); 103 | 104 | loop->run(); 105 | } 106 | 107 | TEST(UDP, ReadSendCustomAlloc) { 108 | const std::string address = std::string{"127.0.0.1"}; 109 | const unsigned int port = 4242; 110 | 111 | auto loop = uvw::loop::get_default(); 112 | auto server = loop->resource(); 113 | auto client = loop->resource(); 114 | 115 | server->on([](const auto &, auto &) { FAIL(); }); 116 | client->on([](const auto &, auto &) { FAIL(); }); 117 | 118 | server->on([](const uvw::udp_data_event &, uvw::udp_handle &handle) { 119 | handle.close(); 120 | }); 121 | 122 | client->on([](const uvw::send_event &, uvw::udp_handle &handle) { 123 | handle.close(); 124 | }); 125 | 126 | ASSERT_EQ(0, (server->bind(address, port))); 127 | ASSERT_EQ(0, server->recv<&custom_alloc_callback>()); 128 | 129 | auto dataSend = std::unique_ptr(new char[5]{'b', 'c'}); 130 | 131 | client->send(uvw::socket_address{address, port}, dataSend.get(), 2); 132 | client->send(address, port, nullptr, 0); 133 | 134 | client->send(uvw::socket_address{address, port}, std::move(dataSend), 2); 135 | client->send(address, port, std::unique_ptr{}, 0); 136 | 137 | loop->run(); 138 | } 139 | 140 | TEST(UDP, Sock) { 141 | const std::string address = std::string{"127.0.0.1"}; 142 | const unsigned int port = 4242; 143 | 144 | auto loop = uvw::loop::get_default(); 145 | auto handle = loop->resource(); 146 | 147 | handle->on([](const auto &, auto &) { FAIL(); }); 148 | 149 | handle->bind(address, port); 150 | handle->recv(); 151 | 152 | uvw::socket_address sock = handle->sock(); 153 | 154 | ASSERT_EQ(sock.ip, address); 155 | ASSERT_EQ(sock.port, decltype(sock.port){port}); 156 | 157 | handle->close(); 158 | loop->run(); 159 | } 160 | -------------------------------------------------------------------------------- /test/uvw/util.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct tag { 8 | using type = T; 9 | }; 10 | 11 | TEST(Util, Utilities) { 12 | ASSERT_EQ(uvw::pid_type{}, uvw::pid_type{}); 13 | 14 | ASSERT_NE(uvw::utilities::os::pid(), uvw::pid_type{}); 15 | ASSERT_NE(uvw::utilities::os::ppid(), uvw::pid_type{}); 16 | ASSERT_FALSE(uvw::utilities::os::homedir().empty()); 17 | ASSERT_FALSE(uvw::utilities::os::tmpdir().empty()); 18 | ASSERT_NE(uvw::utilities::os::hostname(), ""); 19 | 20 | ASSERT_TRUE(uvw::utilities::os::env("UVW_TEST_UTIL_UTILITIES", "TRUE")); 21 | ASSERT_TRUE(uvw::utilities::os::env("UVW_TEST_UTIL_UTILITIES") == "TRUE"); 22 | ASSERT_TRUE(uvw::utilities::os::env("UVW_TEST_UTIL_UTILITIES", "")); 23 | ASSERT_FALSE(uvw::utilities::os::env("UVW_TEST_UTIL_UTILITIES") == "TRUE"); 24 | 25 | auto passwd = uvw::utilities::os::passwd(); 26 | 27 | ASSERT_TRUE(static_cast(passwd)); 28 | ASSERT_FALSE(passwd.username().empty()); 29 | ASSERT_FALSE(passwd.homedir().empty()); 30 | ASSERT_NO_THROW([[maybe_unused]] const auto uid = passwd.uid()); 31 | ASSERT_NO_THROW([[maybe_unused]] const auto gid = passwd.gid()); 32 | 33 | #ifndef _MSC_VER 34 | // libuv returns a null string for the shell on Windows 35 | ASSERT_FALSE(passwd.shell().empty()); 36 | #endif 37 | 38 | ASSERT_EQ(uvw::utilities::guess_handle(uvw::file_handle{-1}), uvw::handle_type::UNKNOWN); 39 | ASSERT_NE(uvw::utilities::guess_handle(uvw::std_in), uvw::handle_type::UNKNOWN); 40 | 41 | auto guessHandle = [](auto tag, auto type) { 42 | auto loop = uvw::loop::get_default(); 43 | auto handle = loop->resource(); 44 | ASSERT_EQ(uvw::utilities::guess_handle(handle->category()), type); 45 | handle->close(); 46 | loop->run(); 47 | }; 48 | 49 | guessHandle(tag{}, uvw::handle_type::ASYNC); 50 | guessHandle(tag{}, uvw::handle_type::CHECK); 51 | guessHandle(tag{}, uvw::handle_type::FS_EVENT); 52 | guessHandle(tag{}, uvw::handle_type::FS_POLL); 53 | guessHandle(tag{}, uvw::handle_type::IDLE); 54 | guessHandle(tag{}, uvw::handle_type::PIPE); 55 | guessHandle(tag{}, uvw::handle_type::PREPARE); 56 | guessHandle(tag{}, uvw::handle_type::TCP); 57 | guessHandle(tag{}, uvw::handle_type::TIMER); 58 | guessHandle(tag{}, uvw::handle_type::UDP); 59 | guessHandle(tag{}, uvw::handle_type::SIGNAL); 60 | 61 | auto cpuInfo = uvw::utilities::cpu(); 62 | 63 | ASSERT_NE(cpuInfo.size(), decltype(cpuInfo.size()){0}); 64 | ASSERT_FALSE(cpuInfo[0].model.empty()); 65 | /* returns 0 on unsupported architectures */ 66 | ASSERT_GE(cpuInfo[0].speed, decltype(cpuInfo[0].speed){0}); 67 | 68 | auto interfaceAddresses = uvw::utilities::interface_addresses(); 69 | 70 | ASSERT_NE(interfaceAddresses.size(), decltype(interfaceAddresses.size()){0}); 71 | ASSERT_FALSE(interfaceAddresses[0].name.empty()); 72 | ASSERT_FALSE(interfaceAddresses[0].address.ip.empty()); 73 | ASSERT_FALSE(interfaceAddresses[0].netmask.ip.empty()); 74 | 75 | ASSERT_NO_THROW([[maybe_unused]] const auto name = uvw::utilities::index_to_name(0)); 76 | ASSERT_NO_THROW([[maybe_unused]] const auto iid = uvw::utilities::index_to_iid(0)); 77 | 78 | ASSERT_TRUE(uvw::utilities::replace_allocator( 79 | [](size_t size) { return malloc(size); }, 80 | [](void *ptr, size_t size) { return realloc(ptr, size); }, 81 | // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) 82 | [](size_t num, size_t size) { return calloc(num, size); }, 83 | [](void *ptr) { return free(ptr); })); 84 | 85 | ASSERT_NO_THROW([[maybe_unused]] const auto load_average = uvw::utilities::load_average()); 86 | ASSERT_NE(uvw::utilities::total_memory(), decltype(uvw::utilities::total_memory()){0}); 87 | ASSERT_NE(uvw::utilities::available_memory(), decltype(uvw::utilities::available_memory()){0}); 88 | ASSERT_NE(uvw::utilities::uptime(), decltype(uvw::utilities::uptime()){0}); 89 | ASSERT_NO_THROW([[maybe_unused]] const auto rusage = uvw::utilities::rusage()); 90 | ASSERT_NO_THROW([[maybe_unused]] const auto time = uvw::utilities::gettime(uvw::clock_id::MONOTONIC)); 91 | ASSERT_NE(uvw::utilities::hrtime(), decltype(uvw::utilities::hrtime()){0}); 92 | ASSERT_FALSE(uvw::utilities::path().empty()); 93 | ASSERT_FALSE(uvw::utilities::cwd().empty()); 94 | ASSERT_TRUE(uvw::utilities::chdir(uvw::utilities::cwd())); 95 | 96 | std::unique_ptr fake{new char[1], [](void *ptr) { delete[] static_cast(ptr); }}; 97 | char *argv = fake.get(); 98 | argv[0] = '\0'; 99 | 100 | ASSERT_NE(uvw::utilities::setup_args(1, &argv), nullptr); 101 | ASSERT_NE(uvw::utilities::process_title(), std::string{}); 102 | ASSERT_TRUE(uvw::utilities::process_title(uvw::utilities::process_title())); 103 | 104 | ASSERT_NE(uvw::utilities::available_parallelism(), 0u); 105 | } 106 | -------------------------------------------------------------------------------- /test/uvw/uv_type.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | TEST(UvType, Functionalities) { 6 | auto loop = uvw::loop::get_default(); 7 | auto handle = loop->resource(); 8 | 9 | ASSERT_TRUE(handle); 10 | ASSERT_EQ(&handle->parent(), loop.get()); 11 | } 12 | 13 | TEST(UvType, Raw) { 14 | auto loop = uvw::loop::get_default(); 15 | auto handle = loop->resource(); 16 | const auto &chandle = handle; 17 | 18 | auto *raw = handle->raw(); 19 | auto *craw = chandle->raw(); 20 | 21 | ASSERT_EQ(raw, craw); 22 | } 23 | -------------------------------------------------------------------------------- /test/uvw/work.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | TEST(Work, RunTask) { 7 | auto loop = uvw::loop::get_default(); 8 | auto handle = loop->resource(); 9 | 10 | bool checkTask = false; 11 | 12 | auto req = loop->resource([&checkTask]() { 13 | ASSERT_FALSE(checkTask); 14 | checkTask = true; 15 | }); 16 | 17 | req->on([](const auto &, auto &) { FAIL(); }); 18 | 19 | req->on([&handle](const auto &, auto &) { 20 | handle->close(); 21 | }); 22 | 23 | handle->start(); 24 | 25 | ASSERT_EQ(0, req->queue()); 26 | 27 | loop->run(); 28 | 29 | ASSERT_TRUE(checkTask); 30 | } 31 | 32 | TEST(Work, Cancellation) { 33 | auto loop = uvw::loop::get_default(); 34 | auto handle = loop->resource(); 35 | 36 | bool checkErrorEvent = false; 37 | 38 | handle->on([](const auto &, auto &hndl) { 39 | hndl.stop(); 40 | hndl.close(); 41 | }); 42 | 43 | for(auto i = 0; i < 5 /* default uv thread pool size + 1 */; ++i) { 44 | auto req = loop->resource([]() {}); 45 | 46 | req->on([](const auto &, auto &) {}); 47 | req->on([&checkErrorEvent](const auto &, auto &) { checkErrorEvent = true; }); 48 | 49 | req->queue(); 50 | req->cancel(); 51 | } 52 | 53 | handle->start(uvw::timer_handle::time{500}, uvw::timer_handle::time{500}); 54 | loop->run(); 55 | 56 | ASSERT_TRUE(checkErrorEvent); 57 | } 58 | -------------------------------------------------------------------------------- /uvw.imp: -------------------------------------------------------------------------------- 1 | [ 2 | # gtest only 3 | { "include": [ "@", "private", "", "public" ] }, 4 | { "include": [ "@", "private", "", "public" ] }, 5 | ] 6 | --------------------------------------------------------------------------------