├── .clang-format ├── .cmake-format ├── .github └── workflows │ ├── lint.yml │ ├── macos-clang.yml │ ├── rockylinux-gcc.yml │ ├── ubuntu-gcc.yml │ └── windows-msvc.yml ├── .gitignore ├── CMakeLists.txt ├── ChangeLog.md ├── License ├── README.md ├── build.sh ├── cmake └── templates │ └── TrantorConfig.cmake.in ├── cmake_modules ├── FindBotan.cmake └── Findc-ares.cmake ├── conanfile.txt ├── format.sh ├── third_party └── wepoll │ ├── LICENSE │ ├── README.md │ ├── Wepoll.c │ └── Wepoll.h └── trantor ├── net ├── AsyncStream.h ├── Certificate.h ├── Channel.cc ├── Channel.h ├── EventLoop.cc ├── EventLoop.h ├── EventLoopThread.cc ├── EventLoopThread.h ├── EventLoopThreadPool.cc ├── EventLoopThreadPool.h ├── InetAddress.cc ├── InetAddress.h ├── Resolver.h ├── TLSPolicy.h ├── TcpClient.cc ├── TcpClient.h ├── TcpConnection.h ├── TcpServer.cc ├── TcpServer.h ├── callbacks.h └── inner │ ├── Acceptor.cc │ ├── Acceptor.h │ ├── AresResolver.cc │ ├── AresResolver.h │ ├── AsyncStreamBufferNode.cc │ ├── BufferNode.h │ ├── Connector.cc │ ├── Connector.h │ ├── FileBufferNodeUnix.cc │ ├── FileBufferNodeWin.cc │ ├── MemBufferNode.cc │ ├── NormalResolver.cc │ ├── NormalResolver.h │ ├── Poller.cc │ ├── Poller.h │ ├── Socket.cc │ ├── Socket.h │ ├── StreamBufferNode.cc │ ├── TLSProvider.h │ ├── TcpConnectionImpl.cc │ ├── TcpConnectionImpl.h │ ├── Timer.cc │ ├── Timer.h │ ├── TimerQueue.cc │ ├── TimerQueue.h │ ├── poller │ ├── EpollPoller.cc │ ├── EpollPoller.h │ ├── KQueue.cc │ ├── KQueue.h │ ├── PollPoller.cc │ └── PollPoller.h │ └── tlsprovider │ ├── BotanTLSProvider.cc │ └── OpenSSLProvider.cc ├── tests ├── AsyncFileLoggerTest.cc ├── AsyncFileLoggerTest1.cc ├── CMakeLists.txt ├── ConcurrentTaskQueueTest.cc ├── DelayedSSLClientTest.cc ├── DelayedSSLServerTest.cc ├── DnsTest.cc ├── KickoffTest.cc ├── LoggerMacroTest.cc ├── LoggerTest.cc ├── MTLSClient.cc ├── MTLSServer.cc ├── PathConversionTest.cc ├── RunInLoopTest1.cc ├── RunInLoopTest2.cc ├── RunOnQuitTest.cc ├── SSLClientTest.cc ├── SSLServerTest.cc ├── SendfileTest.cc ├── SendstreamTest.cc ├── SerialTaskQueueTest1.cc ├── SerialTaskQueueTest2.cc ├── SpdLoggerTest.cc ├── TcpAsyncStreamServerTest.cc ├── TcpClientTest.cc ├── TcpServerTest.cc ├── TimerTest.cc ├── TimerTest1.cc ├── TimingWheelTest.cc ├── server.crt └── server.key ├── unittests ├── CMakeLists.txt ├── DateUnittest.cc ├── HashUnittest.cc ├── InetAddressUnittest.cc ├── MsgBufferUnittest.cc ├── splitStringUnittest.cc ├── sslNameVerifyUnittest.cc └── stringEncodingUnittest.cc └── utils ├── AsyncFileLogger.cc ├── AsyncFileLogger.h ├── ConcurrentTaskQueue.cc ├── ConcurrentTaskQueue.h ├── Date.cc ├── Date.h ├── Funcs.h ├── LockFreeQueue.h ├── LogStream.cc ├── LogStream.h ├── Logger.cc ├── Logger.h ├── MsgBuffer.cc ├── MsgBuffer.h ├── NonCopyable.h ├── ObjectPool.h ├── SerialTaskQueue.cc ├── SerialTaskQueue.h ├── TaskQueue.h ├── TimingWheel.cc ├── TimingWheel.h ├── Utilities.cc ├── Utilities.h ├── WindowsSupport.cc ├── WindowsSupport.h └── crypto ├── blake2.cc ├── blake2.h ├── botan.cc ├── md5.cc ├── md5.h ├── openssl.cc ├── sha1.cc ├── sha1.h ├── sha256.cc ├── sha256.h ├── sha3.cc └── sha3.h /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: Google 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Left 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: false 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: None 15 | AllowShortIfStatementsOnASingleLine: false 16 | AllowShortLoopsOnASingleLine: false 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: true 20 | AlwaysBreakTemplateDeclarations: true 21 | BinPackArguments: false 22 | BinPackParameters: false 23 | BraceWrapping: 24 | AfterClass: true 25 | AfterControlStatement: Always 26 | AfterEnum: true 27 | AfterFunction: true 28 | AfterNamespace: true 29 | AfterObjCDeclaration: false 30 | AfterStruct: true 31 | AfterUnion: true 32 | AfterExternBlock: true 33 | BeforeCatch: true 34 | BeforeElse: true 35 | IndentBraces: false 36 | SplitEmptyFunction: true 37 | SplitEmptyRecord: true 38 | SplitEmptyNamespace: true 39 | AfterCaseLabel: true 40 | BreakBeforeBinaryOperators: None 41 | BreakBeforeBraces: Custom 42 | BreakBeforeInheritanceComma: false 43 | BreakInheritanceList: BeforeColon 44 | BreakBeforeTernaryOperators: true 45 | BreakConstructorInitializersBeforeComma: false 46 | BreakConstructorInitializers: BeforeColon 47 | BreakAfterJavaFieldAnnotations: false 48 | BreakStringLiterals: true 49 | ColumnLimit: 80 50 | CommentPragmas: '^ IWYU pragma:' 51 | CompactNamespaces: false 52 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 53 | ConstructorInitializerIndentWidth: 4 54 | ContinuationIndentWidth: 4 55 | Cpp11BracedListStyle: true 56 | DerivePointerAlignment: true 57 | DisableFormat: false 58 | FixNamespaceComments: true 59 | ForEachMacros: 60 | - foreach 61 | - Q_FOREACH 62 | - BOOST_FOREACH 63 | IncludeBlocks: Preserve 64 | IncludeCategories: 65 | - Regex: '^' 66 | Priority: 2 67 | - Regex: '^<.*\.h>' 68 | Priority: 1 69 | - Regex: '^<.*' 70 | Priority: 2 71 | - Regex: '.*' 72 | Priority: 3 73 | IncludeIsMainRegex: '([-_](test|unittest))?$' 74 | IndentCaseLabels: true 75 | IndentPPDirectives: None 76 | IndentWidth: 4 77 | IndentWrappedFunctionNames: false 78 | JavaScriptQuotes: Leave 79 | JavaScriptWrapImports: true 80 | KeepEmptyLinesAtTheStartOfBlocks: false 81 | MacroBlockBegin: '' 82 | MacroBlockEnd: '' 83 | MaxEmptyLinesToKeep: 1 84 | NamespaceIndentation: None 85 | ObjCBinPackProtocolList: Never 86 | ObjCBlockIndentWidth: 2 87 | ObjCSpaceAfterProperty: false 88 | ObjCSpaceBeforeProtocolList: true 89 | PenaltyBreakAssignment: 2 90 | PenaltyBreakBeforeFirstCallParameter: 100 91 | PenaltyBreakComment: 300 92 | PenaltyBreakFirstLessLess: 120 93 | PenaltyBreakString: 1000 94 | PenaltyBreakTemplateDeclaration: 10 95 | PenaltyExcessCharacter: 1000000 96 | PenaltyReturnTypeOnItsOwnLine: 2000 97 | PointerAlignment: Left 98 | RawStringFormats: 99 | - Language: Cpp 100 | Delimiters: 101 | - cc 102 | - CC 103 | - cpp 104 | - Cpp 105 | - CPP 106 | - 'c++' 107 | - 'C++' 108 | CanonicalDelimiter: '' 109 | BasedOnStyle: google 110 | - Language: TextProto 111 | Delimiters: 112 | - pb 113 | - PB 114 | - proto 115 | - PROTO 116 | EnclosingFunctions: 117 | - EqualsProto 118 | - EquivToProto 119 | - PARSE_PARTIAL_TEXT_PROTO 120 | - PARSE_TEST_PROTO 121 | - PARSE_TEXT_PROTO 122 | - ParseTextOrDie 123 | - ParseTextProtoOrDie 124 | CanonicalDelimiter: '' 125 | BasedOnStyle: google 126 | ReflowComments: true 127 | SortIncludes: false 128 | SortUsingDeclarations: true 129 | SpaceAfterCStyleCast: false 130 | SpaceAfterTemplateKeyword: true 131 | SpaceBeforeAssignmentOperators: true 132 | SpaceBeforeCpp11BracedList: false 133 | SpaceBeforeCtorInitializerColon: true 134 | SpaceBeforeInheritanceColon: true 135 | SpaceBeforeParens: ControlStatements 136 | SpaceBeforeRangeBasedForLoopColon: true 137 | SpaceInEmptyParentheses: false 138 | SpacesBeforeTrailingComments: 2 139 | SpacesInAngles: false 140 | SpacesInContainerLiterals: true 141 | SpacesInCStyleCastParentheses: false 142 | SpacesInParentheses: false 143 | SpacesInSquareBrackets: false 144 | Standard: Auto 145 | StatementMacros: 146 | - Q_UNUSED 147 | - QT_REQUIRE_VERSION 148 | TabWidth: 8 149 | UseTab: Never 150 | ... 151 | 152 | -------------------------------------------------------------------------------- /.cmake-format: -------------------------------------------------------------------------------- 1 | # notes for additional commands 2 | # 3 | # nargs: '*' to allow multiple arguments 4 | # kwargs: &fookwargs to definite keyword arguments 5 | # kwargs: *fookwargs to use the same keyword arguments as fookwargs 6 | # NAME: 1 to allow single keyword arguments 7 | # NAME: + to allow multiple keyword arguments 8 | # NAME: * to allow multiple keyword arguments 9 | # spelling: FOO to use foo to FOO spelling 10 | 11 | parse: 12 | additional_commands: 13 | FetchContent_Declare: 14 | pargs: 15 | nargs: '*' 16 | flags: [] 17 | kwargs: 18 | GIT_TAG: 1 19 | GITHUB_REPOSITORY: 1 20 | GITLAB_REPOSITORY: 1 21 | GIT_REPOSITORY: 1 22 | SVN_REPOSITORY: 1 23 | SVN_REVISION: 1 24 | URL: 1 25 | URL_HASH: 1 26 | URL_MD5: 1 27 | FIND_PACKAGE_ARGS: + 28 | FetchContent_MakeAvailable: 29 | pargs: 30 | nargs: '*' 31 | flags: [] 32 | execute_process: 33 | pargs: 34 | nargs: '*' 35 | flags: [] 36 | kwargs: 37 | COMMAND: + 38 | WORKING_DIRECTORY: 1 39 | set_target_properties: 40 | pargs: 41 | nargs: '*' 42 | flags: [] 43 | kwargs: 44 | PROPERTIES: + 45 | IMPORTED_LOCATION: 1 46 | INTERFACE_INCLUDE_DIRECTORIES: 1 47 | format: 48 | tab_size: 2 49 | line_width: 120 50 | autosort: true 51 | dangle_parens: true 52 | max_subgroups_hwrap: 2 53 | max_pargs_hwrap: 3 -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint source code 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | jobs: 10 | unix: 11 | name: Lint 12 | runs-on: ubuntu-latest 13 | strategy: 14 | fail-fast: false 15 | 16 | steps: 17 | - name: Checkout Trantor source code 18 | uses: actions/checkout@v4 19 | with: 20 | submodules: true 21 | fetch-depth: 0 22 | 23 | - name: (Linux) Install dependencies 24 | run: | 25 | # Installing packages might fail as the github image becomes outdated 26 | sudo apt update 27 | sudo apt install dos2unix clang-format 28 | pip install cmake-format 29 | 30 | - name: Lint 31 | run: ./format.sh && git diff --exit-code 32 | -------------------------------------------------------------------------------- /.github/workflows/macos-clang.yml: -------------------------------------------------------------------------------- 1 | name: Build macos-clang 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | name: '${{matrix.link}}-${{matrix.build-type}}-${{matrix.tls-provider}}' 12 | runs-on: macos-latest 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | link: [ 'STATIC', 'SHARED' ] 17 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 18 | build-type: ['Debug', 'Release'] 19 | # Botan needs std::ranges but clang on macOS doesn't support it yet 20 | #tls-provider: ['', 'openssl', 'botan'] 21 | tls-provider: ['', 'openssl'] 22 | 23 | steps: 24 | - name: Install dependencies 25 | # botan v3 26 | run: | 27 | brew install botan spdlog 28 | 29 | - name: Install gtest 30 | run: | 31 | wget https://github.com/google/googletest/archive/refs/tags/v1.13.0.tar.gz 32 | tar xf v1.13.0.tar.gz 33 | cd googletest-1.13.0 34 | cmake . 35 | make && sudo make install 36 | 37 | - name: Checkout Trantor source code 38 | uses: actions/checkout@v4 39 | with: 40 | submodules: true 41 | fetch-depth: 0 42 | 43 | - name: Create build directory 44 | run: | 45 | mkdir build 46 | 47 | - name: Create Build Environment & Configure Cmake 48 | shell: bash 49 | working-directory: ./build 50 | run: | 51 | [[ ${{ matrix.link }} == "SHARED" ]] && shared="ON" || shared="OFF" 52 | cmake .. \ 53 | -DTRANTOR_USE_TLS=${{matrix.tls-provider}} \ 54 | -DCMAKE_BUILD_TYPE=${{matrix.build-type}} \ 55 | -DBUILD_SHARED_LIBS=$shared \ 56 | -DCMAKE_INSTALL_PREFIX=../install \ 57 | -DUSE_SPDLOG=ON \ 58 | -DBUILD_TESTING=ON \ 59 | 60 | - name: Build 61 | shell: bash 62 | working-directory: ./build 63 | # Execute the build. You can specify a specific target with "--target " 64 | run: | 65 | sudo make && sudo make install 66 | 67 | - name: Test 68 | working-directory: ./build 69 | shell: bash 70 | # Execute tests defined by the CMake configuration. 71 | # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail 72 | run: | 73 | make test 74 | -------------------------------------------------------------------------------- /.github/workflows/rockylinux-gcc.yml: -------------------------------------------------------------------------------- 1 | name: Build rockylinux-gcc 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | name: '${{matrix.link}}-${{matrix.build-type}}-${{matrix.tls-provider}}' 12 | runs-on: ubuntu-latest 13 | container: 14 | image: rockylinux:9.3 15 | options: --user root 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | link: [ 'STATIC', 'SHARED' ] 20 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 21 | build-type: ['Debug', 'Release'] 22 | # TODO: ubuntu botan is v2, v2 support is removed 23 | # tls-provider: ['', 'openssl', 'botan'] 24 | tls-provider: ['', 'openssl'] 25 | 26 | steps: 27 | - name: Install dependencies 28 | run: | 29 | dnf install gcc-c++ cmake git wget -y 30 | 31 | - name: Install dependencies - spdlog 32 | run: | 33 | git clone https://github.com/gabime/spdlog.git 34 | cd spdlog && mkdir build && cd build 35 | cmake .. && make -j 36 | 37 | - name: Install dependencies - OpenSSL 38 | if: matrix.tls-provider == 'openssl' 39 | run: | 40 | dnf install openssl-devel -y 41 | 42 | - name: Install gtest 43 | run: | 44 | wget https://github.com/google/googletest/archive/refs/tags/v1.13.0.tar.gz 45 | tar xf v1.13.0.tar.gz 46 | cd googletest-1.13.0 47 | cmake . 48 | make -j && make install 49 | 50 | - name: Checkout Trantor source code 51 | uses: actions/checkout@v4 52 | with: 53 | submodules: true 54 | fetch-depth: 0 55 | 56 | - name: Create build directory 57 | run: | 58 | mkdir build 59 | 60 | - name: Create Build Environment & Configure Cmake 61 | shell: bash 62 | working-directory: ./build 63 | if: ${{matrix.link}} == "SHARED" 64 | run: | 65 | [[ ${{ matrix.link }} == "SHARED" ]] && shared="ON" || shared="OFF" 66 | cmake .. \ 67 | -DTRANTOR_USE_TLS=${{matrix.tls-provider}} \ 68 | -DCMAKE_BUILD_TYPE=${{matrix.build-type}} \ 69 | -DBUILD_SHARED_LIBS=$shared \ 70 | -DCMAKE_INSTALL_PREFIX=../install \ 71 | -DUSE_SPDLOG=ON \ 72 | -DBUILD_TESTING=ON 73 | 74 | - name: Build 75 | shell: bash 76 | working-directory: ./build 77 | # Execute the build. You can specify a specific target with "--target " 78 | run: | 79 | make && make install 80 | 81 | - name: Test 82 | working-directory: ./build 83 | shell: bash 84 | # Execute tests defined by the CMake configuration. 85 | # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail 86 | run: | 87 | make test 88 | 89 | -------------------------------------------------------------------------------- /.github/workflows/ubuntu-gcc.yml: -------------------------------------------------------------------------------- 1 | name: Build ubuntu-gcc 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | name: '${{matrix.link}}-${{matrix.build-type}}-${{matrix.tls-provider}}' 12 | runs-on: ubuntu-latest 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | link: [ 'STATIC', 'SHARED' ] 17 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 18 | build-type: ['Debug', 'Release'] 19 | # TODO: ubuntu botan is v2, v2 support is removed 20 | # tls-provider: ['', 'openssl', 'botan'] 21 | tls-provider: ['', 'openssl'] 22 | 23 | steps: 24 | - name: Install dependencies 25 | run: | 26 | # Installing packages might fail as the github image becomes outdated 27 | sudo apt update 28 | sudo apt install libspdlog-dev libfmt-dev 29 | 30 | - name: Install dependencies - OpenSSL 31 | if: matrix.tls-provider == 'openssl' 32 | run: | 33 | sudo apt install openssl libssl-dev 34 | 35 | - name: Install gtest 36 | run: | 37 | wget https://github.com/google/googletest/archive/refs/tags/v1.13.0.tar.gz 38 | tar xf v1.13.0.tar.gz 39 | cd googletest-1.13.0 40 | cmake . 41 | make -j && sudo make install 42 | 43 | - name: Checkout Trantor source code 44 | uses: actions/checkout@v4 45 | with: 46 | submodules: true 47 | fetch-depth: 0 48 | 49 | - name: Create build directory 50 | run: | 51 | mkdir build 52 | 53 | - name: Create Build Environment & Configure Cmake 54 | shell: bash 55 | working-directory: ./build 56 | if: ${{matrix.link}} == "SHARED" 57 | run: | 58 | [[ ${{ matrix.link }} == "SHARED" ]] && shared="ON" || shared="OFF" 59 | cmake .. \ 60 | -DTRANTOR_USE_TLS=${{matrix.tls-provider}} \ 61 | -DCMAKE_BUILD_TYPE=${{matrix.build-type}} \ 62 | -DBUILD_SHARED_LIBS=$shared \ 63 | -DCMAKE_INSTALL_PREFIX=../install \ 64 | -DUSE_SPDLOG=ON \ 65 | -DBUILD_TESTING=ON 66 | 67 | - name: Build 68 | shell: bash 69 | working-directory: ./build 70 | # Execute the build. You can specify a specific target with "--target " 71 | run: | 72 | sudo make && sudo make install 73 | 74 | - name: Test 75 | working-directory: ./build 76 | shell: bash 77 | # Execute tests defined by the CMake configuration. 78 | # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail 79 | run: | 80 | make test 81 | 82 | -------------------------------------------------------------------------------- /.github/workflows/windows-msvc.yml: -------------------------------------------------------------------------------- 1 | name: Build windows-msvc 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | name: '${{matrix.link}}-${{matrix.build-type}}-${{matrix.tls-provider}}' 12 | runs-on: windows-latest 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | link: [ 'STATIC', 'SHARED' ] 17 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 18 | build-type: ['Debug', 'Release'] 19 | # TODO: conan botan is v2, v2 support is removed 20 | # tls-provider: ['', 'openssl', 'botan'] 21 | tls-provider: ['', 'openssl'] 22 | 23 | steps: 24 | - name: Checkout Trantor source code 25 | uses: actions/checkout@v4 26 | with: 27 | submodules: false 28 | 29 | - name: Create build directory 30 | working-directory: ${{env.GITHUB_WORKSPACE}} 31 | run: | 32 | mkdir build 33 | 34 | - name: Install conan packages 35 | shell: bash 36 | working-directory: ./build 37 | run: | 38 | pip install conan 39 | conan profile detect --force 40 | conan install .. --output-folder=. --build=missing --settings=build_type=${{matrix.build-type}} --settings=compiler="msvc" 41 | 42 | - name: Create Build Environment & Configure Cmake 43 | shell: bash 44 | working-directory: ./build 45 | # -DBUILD_TESTING=ON Removed, 46 | # Due to unittest by GTest in windows runner will comes out 'error MSB3073' 47 | run: | 48 | [[ ${{ matrix.link }} == "SHARED" ]] && shared="ON" || shared="OFF" 49 | cmake .. -G "Visual Studio 17 2022" -T host=x64 -A x64 \ 50 | -DTRANTOR_USE_TLS=${{matrix.tls-provider}} \ 51 | -DCMAKE_BUILD_TYPE=${{matrix.build-type}} \ 52 | -DBUILD_SHARED_LIBS=$shared \ 53 | -DCMAKE_INSTALL_PREFIX=../install \ 54 | -DUSE_SPDLOG=ON \ 55 | -DCMAKE_POLICY_DEFAULT_CMP0091=NEW 56 | 57 | - name: Build 58 | working-directory: ./build 59 | shell: bash 60 | # multi config build using --config to switch Release|Debug 61 | run: | 62 | cmake --build . --config ${{matrix.build-type}} --parallel 63 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | build 3 | cmake-build-debug 4 | .vscode 5 | .vs 6 | CMakeSettings.json 7 | .cache 8 | -------------------------------------------------------------------------------- /License: -------------------------------------------------------------------------------- 1 | // Trantor - A non-blocking I/O based TCP network library, using C++14/17, 2 | // Copyright (c) 2016-2021, Tao An. All rights reserved. 3 | // https://github.com/an-tao/trantor 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions 7 | // are met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above copyright 12 | // notice, this list of conditions and the following disclaimer in the 13 | // documentation and/or other materials provided with the distribution. 14 | // * Neither the name of Tao An nor the names of other contributors 15 | // may be used to endorse or promote products derived from this software 16 | // without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // Muduo - A reactor-based C++ network library for Linux 31 | // Copyright (c) 2010, Shuo Chen. All rights reserved. 32 | // http://code.google.com/p/muduo/ 33 | // 34 | // Redistribution and use in source and binary forms, with or without 35 | // modification, are permitted provided that the following conditions 36 | // are met: 37 | // 38 | // * Redistributions of source code must retain the above copyright 39 | // notice, this list of conditions and the following disclaimer. 40 | // * Redistributions in binary form must reproduce the above copyright 41 | // notice, this list of conditions and the following disclaimer in the 42 | // documentation and/or other materials provided with the distribution. 43 | // * Neither the name of Shuo Chen nor the names of other contributors 44 | // may be used to endorse or promote products derived from this software 45 | // without specific prior written permission. 46 | // 47 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 48 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 49 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 50 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 51 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 52 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 53 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 54 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 55 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 56 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 57 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TRANTOR 2 | [![Build Ubuntu gcc](../../actions/workflows/ubuntu-gcc.yml/badge.svg)](../../actions/workflows/ubuntu-gcc.yml/badge.svg) 3 | [![Build Macos clang](../../actions/workflows/macos-clang.yml/badge.svg)](../../actions/workflows/macos-clang.yml/badge.svg) 4 | [![Build RockyLinux gcc](../../actions/workflows/rockylinux-gcc.yml/badge.svg)](../../actions/workflows/rockylinux-gcc.yml/badge.svg) 5 | [![Build Windows msvc](../../actions/workflows/windows-msvc.yml/badge.svg)](../../actions/workflows/windows-msvc.yml/badge.svg) 6 | 7 | ## Overview 8 | A non-blocking I/O cross-platform TCP network library, using C++14. 9 | Drawing on the design of Muduo Library 10 | 11 | ## Supported platforms 12 | - Linux 13 | - MacOS 14 | - UNIX(BSD) 15 | - Windows 16 | 17 | ## Feature highlights 18 | - Non-blocking I/O 19 | - cross-platform 20 | - Thread pool 21 | - Lock free design 22 | - Support SSL 23 | - Server and Client 24 | 25 | 26 | ## Build 27 | ```shell 28 | git clone https://github.com/an-tao/trantor.git 29 | cd trantor 30 | cmake -B build -H. 31 | cd build 32 | make -j 33 | ``` 34 | 35 | ## Licensing 36 | Trantor - A non-blocking I/O based TCP network library, using C++14. 37 | 38 | Copyright (c) 2016-2021, Tao An. All rights reserved. 39 | 40 | https://github.com/an-tao/trantor 41 | 42 | For more information see [License](License) 43 | 44 | ## Community 45 | [Gitter](https://gitter.im/drogon-web/community) 46 | 47 | ## Documentation 48 | [DocsForge](https://trantor.docsforge.com/) 49 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #building trantor 4 | function build_trantor() { 5 | 6 | #Saving current directory 7 | current_dir="${PWD}" 8 | 9 | #The folder we will build 10 | build_dir='./build' 11 | if [ -d $build_dir ]; then 12 | echo "Deleted folder: ${build_dir}" 13 | rm -rf $build_dir 14 | fi 15 | 16 | #Creating building folder 17 | echo "Created building folder: ${build_dir}" 18 | mkdir $build_dir 19 | 20 | echo "Entering folder: ${build_dir}" 21 | cd $build_dir 22 | 23 | echo "Start building trantor ..." 24 | if [ $1 -eq 1 ]; then 25 | cmake .. -DBUILD_TESTING=on 26 | else 27 | cmake .. 28 | fi 29 | 30 | #If errors then exit 31 | if [ "$?" != "0" ]; then 32 | exit -1 33 | fi 34 | 35 | make 36 | 37 | #If errors then exit 38 | if [ "$?" != "0" ]; then 39 | exit -1 40 | fi 41 | 42 | echo "Installing ..." 43 | sudo make install 44 | 45 | #Reback current directory 46 | cd $current_dir 47 | exit 0 48 | #Ok! 49 | } 50 | 51 | if [ "$1" = "-t" ]; then 52 | build_trantor 1 53 | else 54 | build_trantor 0 55 | fi 56 | -------------------------------------------------------------------------------- /cmake/templates/TrantorConfig.cmake.in: -------------------------------------------------------------------------------- 1 | #[[ 2 | # - Config file for the Trantor package 3 | # It defines the following variables 4 | # TRANTOR_INCLUDE_DIRS - include directories for Trantor 5 | # TRANTOR_LIBRARIES - libraries to link against 6 | # Trantor_FOUND 7 | # This module defines the following IMPORTED target: 8 | # Trantor::Trantor 9 | #]] 10 | 11 | @PACKAGE_INIT@ 12 | 13 | include(CMakeFindDependencyMacro) 14 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) 15 | if(@OpenSSL_FOUND@) 16 | find_dependency(OpenSSL) 17 | endif() 18 | if(@Botan_FOUND@) 19 | find_dependency(Botan) 20 | endif() 21 | if(@c-ares_FOUND@) 22 | find_dependency(c-ares) 23 | endif() 24 | find_dependency(Threads) 25 | if(@spdlog_FOUND@) 26 | find_dependency(spdlog) 27 | endif() 28 | # Compute paths 29 | 30 | # Our library dependencies (contains definitions for IMPORTED targets) 31 | get_filename_component(TRANTOR_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 32 | if(NOT TARGET Trantor::Trantor) 33 | include("${TRANTOR_CMAKE_DIR}/TrantorTargets.cmake") 34 | endif() 35 | 36 | get_target_property(TRANTOR_INCLUDE_DIRS Trantor::Trantor INTERFACE_INCLUDE_DIRECTORIES) 37 | set(TRANTOR_LIBRARIES Trantor::Trantor) 38 | -------------------------------------------------------------------------------- /cmake_modules/FindBotan.cmake: -------------------------------------------------------------------------------- 1 | function(find_botan_pkgconfig package_name botan_ver) 2 | if(TARGET Botan::Botan) 3 | return() 4 | endif() 5 | 6 | pkg_check_modules( 7 | Botan 8 | QUIET 9 | IMPORTED_TARGET 10 | ${package_name} 11 | ) 12 | if(TARGET PkgConfig::Botan) 13 | add_library(Botan::Botan ALIAS PkgConfig::Botan) 14 | 15 | if(botan_ver EQUAL 3) 16 | target_compile_features(PkgConfig::Botan INTERFACE cxx_std_20) 17 | endif() 18 | endif() 19 | endfunction() 20 | 21 | function(find_botan_search package_name botan_ver) 22 | if(TARGET Botan::Botan) 23 | return() 24 | endif() 25 | find_path( 26 | Botan_INCLUDE_DIRS 27 | NAMES botan/botan.h 28 | PATH_SUFFIXES ${package_name} 29 | DOC "The Botan include directory" 30 | ) 31 | 32 | find_library( 33 | Botan_LIBRARIES 34 | NAMES botan ${package_name} 35 | DOC "The Botan library" 36 | ) 37 | 38 | mark_as_advanced(Botan_INCLUDE_DIRS Botan_LIBRARIES) 39 | 40 | add_library(Botan::Botan IMPORTED UNKNOWN) 41 | set_target_properties( 42 | Botan::Botan 43 | PROPERTIES 44 | IMPORTED_LOCATION "${Botan_LIBRARIES}" 45 | INTERFACE_INCLUDE_DIRECTORIES "${Botan_INCLUDE_DIRS}" 46 | ) 47 | if(botan_ver EQUAL 3) 48 | target_compile_features(Botan::Botan INTERFACE cxx_std_20) 49 | endif() 50 | 51 | if(WIN32) 52 | target_compile_definitions(Botan::Botan INTERFACE -DNOMINMAX=1) 53 | endif() 54 | endfunction() 55 | 56 | find_package(PkgConfig) 57 | if(NOT WIN32 AND PKG_CONFIG_FOUND) 58 | # find_botan_pkgconfig(botan-2 2) 59 | find_botan_pkgconfig(botan-3 3) 60 | endif() 61 | 62 | if(NOT TARGET Botan::Botan) 63 | # find_botan_search(botan-2 2) 64 | find_botan_search(botan-3 3) 65 | endif() 66 | 67 | include(FindPackageHandleStandardArgs) 68 | find_package_handle_standard_args(Botan REQUIRED_VARS Botan_LIBRARIES Botan_INCLUDE_DIRS) 69 | -------------------------------------------------------------------------------- /cmake_modules/Findc-ares.cmake: -------------------------------------------------------------------------------- 1 | #[[ 2 | # Try to find c-ares library Once done this will define 3 | # 4 | # c-ares_FOUND - system has c-ares 5 | # C-ARES_INCLUDE_DIRS - The c-ares include directory 6 | # C-ARES_LIBRARIES - Link these to use c-ares 7 | # c-ares_lib - Imported Targets 8 | # 9 | # Copyright (c) 2020 antao 10 | #]] 11 | 12 | find_path(C-ARES_INCLUDE_DIRS ares.h) 13 | find_library(C-ARES_LIBRARIES NAMES cares) 14 | if(C-ARES_INCLUDE_DIRS AND C-ARES_LIBRARIES) 15 | add_library(c-ares_lib INTERFACE IMPORTED) 16 | set_target_properties( 17 | c-ares_lib 18 | PROPERTIES 19 | INTERFACE_INCLUDE_DIRECTORIES "${C-ARES_INCLUDE_DIRS}" INTERFACE_LINK_LIBRARIES "${C-ARES_LIBRARIES}" 20 | ) 21 | endif() 22 | 23 | include(FindPackageHandleStandardArgs) 24 | find_package_handle_standard_args( 25 | c-ares 26 | DEFAULT_MSG 27 | C-ARES_INCLUDE_DIRS 28 | C-ARES_LIBRARIES 29 | ) 30 | mark_as_advanced(C-ARES_INCLUDE_DIRS C-ARES_LIBRARIES) 31 | -------------------------------------------------------------------------------- /conanfile.txt: -------------------------------------------------------------------------------- 1 | [requires] 2 | gtest/1.10.0 3 | openssl/1.1.1t 4 | #c-ares/1.17.1 5 | spdlog/1.12.0 6 | 7 | [generators] 8 | CMakeToolchain 9 | 10 | [options] 11 | 12 | [imports] 13 | -------------------------------------------------------------------------------- /format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | clang-format --version 4 | 5 | find trantor -name *.h -o -name *.cc -exec dos2unix {} \; 6 | find trantor -name *.h -o -name *.cc|xargs clang-format -i -style=file 7 | 8 | cmake-format --version 9 | find . -maxdepth 1 -name CMakeLists.txt|xargs cmake-format -i 10 | find trantor -name CMakeLists.txt|xargs cmake-format -i 11 | find cmake -name *.cmake -o -name *.cmake.in|xargs cmake-format -i 12 | find cmake_modules -name *.cmake -o -name *.cmake.in|xargs cmake-format -i -------------------------------------------------------------------------------- /third_party/wepoll/LICENSE: -------------------------------------------------------------------------------- 1 | wepoll - epoll for Windows 2 | https://github.com/piscisaureus/wepoll 3 | 4 | Copyright 2012-2020, Bert Belder 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | 14 | * Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /third_party/wepoll/README.md: -------------------------------------------------------------------------------- 1 | ## wepoll 2 | 3 | This library is based on [wepoll v1.5.8](https://github.com/piscisaureus/wepoll/commit/0598a791bf9cbbf480793d778930fc635b044980). 4 | 5 | An eventfd-like mechanism is added to it. After making the changes, we can wake up `trantor::EventLoop` from the epoll_wait() function. 6 | 7 | ## Modifications 8 | 9 | ```shell 10 | diff wepoll.h Wepoll.h 11 | 53a54 12 | > EPOLLEVENT = (int)(1U << 14), 13 | 67a69 14 | > #define EPOLLEVENT (1U << 14) 15 | 111a114 16 | > WEPOLL_EXPORT void epoll_post_signal(HANDLE ephnd, uint64_t event); 17 | ``` 18 | 19 | ```shell 20 | diff wepoll.c Wepoll.c 21 | 50a51 22 | > EPOLLEVENT = (int)(1U << 14), 23 | 64a66 24 | > #define EPOLLEVENT (1U << 14) 25 | 1262a1265,1271 26 | > if (iocp_events[i].lpCompletionKey) 27 | > { 28 | > struct epoll_event* ev = &epoll_events[epoll_event_count++]; 29 | > ev->data.u64 = (uint64_t)iocp_events[i].lpCompletionKey; 30 | > ev->events = EPOLLEVENT; 31 | > continue; 32 | > } 33 | 2441a2451,2457 34 | > void epoll_post_signal(HANDLE port_handle, uint64_t event) 35 | > { 36 | > ULONG_PTR ev; 37 | > ev = (ULONG_PTR)event; 38 | > PostQueuedCompletionStatus(port_handle, 1, ev, NULL); 39 | > } 40 | > 41 | ``` 42 | -------------------------------------------------------------------------------- /third_party/wepoll/Wepoll.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wepoll - epoll for Windows 3 | * https://github.com/piscisaureus/wepoll 4 | * 5 | * Copyright 2012-2020, Bert Belder 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are 10 | * met: 11 | * 12 | * * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 15 | * * Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #ifndef WEPOLL_H_ 33 | #define WEPOLL_H_ 34 | 35 | #ifndef WEPOLL_EXPORT 36 | #define WEPOLL_EXPORT 37 | #endif 38 | 39 | #include 40 | 41 | enum EPOLL_EVENTS 42 | { 43 | EPOLLIN = (int)(1U << 0), 44 | EPOLLPRI = (int)(1U << 1), 45 | EPOLLOUT = (int)(1U << 2), 46 | EPOLLERR = (int)(1U << 3), 47 | EPOLLHUP = (int)(1U << 4), 48 | EPOLLRDNORM = (int)(1U << 6), 49 | EPOLLRDBAND = (int)(1U << 7), 50 | EPOLLWRNORM = (int)(1U << 8), 51 | EPOLLWRBAND = (int)(1U << 9), 52 | EPOLLMSG = (int)(1U << 10), /* Never reported. */ 53 | EPOLLRDHUP = (int)(1U << 13), 54 | EPOLLEVENT = (int)(1U << 14), 55 | EPOLLONESHOT = (int)(1U << 31) 56 | }; 57 | 58 | #define EPOLLIN (1U << 0) 59 | #define EPOLLPRI (1U << 1) 60 | #define EPOLLOUT (1U << 2) 61 | #define EPOLLERR (1U << 3) 62 | #define EPOLLHUP (1U << 4) 63 | #define EPOLLRDNORM (1U << 6) 64 | #define EPOLLRDBAND (1U << 7) 65 | #define EPOLLWRNORM (1U << 8) 66 | #define EPOLLWRBAND (1U << 9) 67 | #define EPOLLMSG (1U << 10) 68 | #define EPOLLRDHUP (1U << 13) 69 | #define EPOLLEVENT (1U << 14) 70 | #define EPOLLONESHOT (1U << 31) 71 | 72 | #define EPOLL_CTL_ADD 1 73 | #define EPOLL_CTL_MOD 2 74 | #define EPOLL_CTL_DEL 3 75 | 76 | typedef void* HANDLE; 77 | typedef uintptr_t SOCKET; 78 | 79 | typedef union epoll_data 80 | { 81 | void* ptr; 82 | int fd; 83 | uint32_t u32; 84 | uint64_t u64; 85 | SOCKET sock; /* Windows specific */ 86 | HANDLE hnd; /* Windows specific */ 87 | } epoll_data_t; 88 | 89 | struct epoll_event 90 | { 91 | uint32_t events; /* Epoll events and flags */ 92 | epoll_data_t data; /* User data variable */ 93 | }; 94 | 95 | #ifdef __cplusplus 96 | extern "C" 97 | { 98 | #endif 99 | 100 | WEPOLL_EXPORT HANDLE epoll_create(int size); 101 | WEPOLL_EXPORT HANDLE epoll_create1(int flags); 102 | 103 | WEPOLL_EXPORT int epoll_close(HANDLE ephnd); 104 | 105 | WEPOLL_EXPORT int epoll_ctl(HANDLE ephnd, 106 | int op, 107 | SOCKET sock, 108 | struct epoll_event* event); 109 | 110 | WEPOLL_EXPORT int epoll_wait(HANDLE ephnd, 111 | struct epoll_event* events, 112 | int maxevents, 113 | int timeout); 114 | WEPOLL_EXPORT void epoll_post_signal(HANDLE ephnd, uint64_t event); 115 | 116 | #ifdef __cplusplus 117 | } /* extern "C" */ 118 | #endif 119 | 120 | #endif /* WEPOLL_H_ */ 121 | -------------------------------------------------------------------------------- /trantor/net/AsyncStream.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @file AsyncStream.h 4 | * @author An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2023, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | 20 | namespace trantor 21 | { 22 | /** 23 | * @brief This class represents a data stream that can be sent asynchronously. 24 | * The data is sent in chunks, and the chunks are sent in order, and all the 25 | * chunks are sent continuously. 26 | */ 27 | class TRANTOR_EXPORT AsyncStream : public NonCopyable 28 | { 29 | public: 30 | virtual ~AsyncStream() = default; 31 | /** 32 | * @brief Send data asynchronously. 33 | * 34 | * @param data The data to be sent 35 | * @param len The length of the data 36 | * @return true if the data is sent successfully or at least is put in the 37 | * send buffer. 38 | * @return false if the connection is closed. 39 | */ 40 | virtual bool send(const char *data, size_t len) = 0; 41 | bool send(const std::string &data) 42 | { 43 | return send(data.data(), data.length()); 44 | } 45 | /** 46 | * @brief Terminate the stream. 47 | */ 48 | virtual void close() = 0; 49 | }; 50 | using AsyncStreamPtr = std::unique_ptr; 51 | } // namespace trantor -------------------------------------------------------------------------------- /trantor/net/Certificate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace trantor 6 | { 7 | struct Certificate 8 | { 9 | virtual ~Certificate() = default; 10 | virtual std::string sha1Fingerprint() const = 0; 11 | virtual std::string sha256Fingerprint() const = 0; 12 | virtual std::string pem() const = 0; 13 | }; 14 | using CertificatePtr = std::shared_ptr; 15 | 16 | } // namespace trantor -------------------------------------------------------------------------------- /trantor/net/Channel.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Channel.cc 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #include "Channel.h" 16 | #include 17 | #ifdef _WIN32 18 | #include "Wepoll.h" 19 | #define POLLIN EPOLLIN 20 | #define POLLPRI EPOLLPRI 21 | #define POLLOUT EPOLLOUT 22 | #define POLLHUP EPOLLHUP 23 | #define POLLNVAL 0 24 | #define POLLERR EPOLLERR 25 | #else 26 | #include 27 | #endif 28 | #include 29 | namespace trantor 30 | { 31 | const int Channel::kNoneEvent = 0; 32 | 33 | const int Channel::kReadEvent = POLLIN | POLLPRI; 34 | const int Channel::kWriteEvent = POLLOUT; 35 | 36 | Channel::Channel(EventLoop *loop, int fd) 37 | : loop_(loop), fd_(fd), events_(0), revents_(0), index_(-1), tied_(false) 38 | { 39 | } 40 | 41 | void Channel::remove() 42 | { 43 | assert(events_ == kNoneEvent); 44 | addedToLoop_ = false; 45 | loop_->removeChannel(this); 46 | } 47 | 48 | void Channel::update() 49 | { 50 | loop_->updateChannel(this); 51 | } 52 | 53 | void Channel::handleEvent() 54 | { 55 | // LOG_TRACE<<"revents_="< guard = tie_.lock(); 61 | if (guard) 62 | { 63 | handleEventSafely(); 64 | } 65 | } 66 | else 67 | { 68 | handleEventSafely(); 69 | } 70 | } 71 | void Channel::handleEventSafely() 72 | { 73 | if (eventCallback_) 74 | { 75 | eventCallback_(); 76 | return; 77 | } 78 | if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) 79 | { 80 | // LOG_TRACE<<"handle close"; 81 | if (closeCallback_) 82 | closeCallback_(); 83 | } 84 | if (revents_ & (POLLNVAL | POLLERR)) 85 | { 86 | // LOG_TRACE<<"handle error"; 87 | if (errorCallback_) 88 | errorCallback_(); 89 | } 90 | #ifdef __linux__ 91 | if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)) 92 | #else 93 | if (revents_ & (POLLIN | POLLPRI)) 94 | #endif 95 | { 96 | // LOG_TRACE<<"handle read"; 97 | if (readCallback_) 98 | readCallback_(); 99 | } 100 | #ifdef _WIN32 101 | if ((revents_ & POLLOUT) && !(revents_ & POLLHUP)) 102 | #else 103 | if (revents_ & POLLOUT) 104 | #endif 105 | { 106 | // LOG_TRACE<<"handle write"; 107 | if (writeCallback_) 108 | writeCallback_(); 109 | } 110 | } 111 | 112 | } // namespace trantor 113 | -------------------------------------------------------------------------------- /trantor/net/EventLoopThread.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @file EventLoopThread.cc 4 | * @author An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #include 16 | #include 17 | #ifdef __linux__ 18 | #include 19 | #endif 20 | 21 | using namespace trantor; 22 | EventLoopThread::EventLoopThread(const std::string &threadName) 23 | : loop_(nullptr), 24 | loopThreadName_(threadName), 25 | thread_([this]() { loopFuncs(); }) 26 | { 27 | auto f = promiseForLoopPointer_.get_future(); 28 | loop_ = f.get(); 29 | } 30 | 31 | EventLoopThread::~EventLoopThread() 32 | { 33 | run(); 34 | std::shared_ptr loop; 35 | { 36 | std::unique_lock lk(loopMutex_); 37 | loop = loop_; 38 | } 39 | if (loop) 40 | { 41 | loop->quit(); 42 | } 43 | if (thread_.joinable()) 44 | { 45 | thread_.join(); 46 | } 47 | } 48 | 49 | void EventLoopThread::wait() 50 | { 51 | thread_.join(); 52 | } 53 | 54 | void EventLoopThread::loopFuncs() 55 | { 56 | #ifdef __linux__ 57 | ::prctl(PR_SET_NAME, loopThreadName_.c_str()); 58 | #endif 59 | thread_local static std::shared_ptr loop = 60 | std::make_shared(); 61 | loop->queueInLoop([this]() { promiseForLoop_.set_value(1); }); 62 | promiseForLoopPointer_.set_value(loop); 63 | auto f = promiseForRun_.get_future(); 64 | (void)f.get(); 65 | loop->loop(); 66 | { 67 | std::unique_lock lk(loopMutex_); 68 | loop_ = nullptr; 69 | } 70 | } 71 | 72 | void EventLoopThread::run() 73 | { 74 | std::call_once(once_, [this]() { 75 | auto f = promiseForLoop_.get_future(); 76 | promiseForRun_.set_value(1); 77 | // Make sure the event loop loops before returning. 78 | (void)f.get(); 79 | }); 80 | } 81 | -------------------------------------------------------------------------------- /trantor/net/EventLoopThread.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @file EventLoopThread.h 4 | * @author An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | namespace trantor 27 | { 28 | /** 29 | * @brief This class represents an event loop thread. 30 | * 31 | */ 32 | class TRANTOR_EXPORT EventLoopThread : NonCopyable 33 | { 34 | public: 35 | explicit EventLoopThread(const std::string &threadName = "EventLoopThread"); 36 | ~EventLoopThread(); 37 | 38 | /** 39 | * @brief Wait for the event loop to exit. 40 | * @note This method blocks the current thread until the event loop exits. 41 | */ 42 | void wait(); 43 | 44 | /** 45 | * @brief Get the pointer of the event loop of the thread. 46 | * 47 | * @return EventLoop* 48 | */ 49 | EventLoop *getLoop() const 50 | { 51 | return loop_.get(); 52 | } 53 | 54 | /** 55 | * @brief Run the event loop of the thread. This method doesn't block the 56 | * current thread. 57 | * 58 | */ 59 | void run(); 60 | 61 | private: 62 | // With C++20, use std::atomic> 63 | std::shared_ptr loop_; 64 | std::mutex loopMutex_; 65 | 66 | std::string loopThreadName_; 67 | void loopFuncs(); 68 | std::promise> promiseForLoopPointer_; 69 | std::promise promiseForRun_; 70 | std::promise promiseForLoop_; 71 | std::once_flag once_; 72 | std::thread thread_; 73 | }; 74 | 75 | } // namespace trantor 76 | -------------------------------------------------------------------------------- /trantor/net/EventLoopThreadPool.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * EventLoopThreadPool.cc 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #include 16 | using namespace trantor; 17 | EventLoopThreadPool::EventLoopThreadPool(size_t threadNum, 18 | const std::string &name) 19 | : loopIndex_(0) 20 | { 21 | for (size_t i = 0; i < threadNum; ++i) 22 | { 23 | loopThreadVector_.emplace_back(std::make_shared(name)); 24 | } 25 | } 26 | void EventLoopThreadPool::start() 27 | { 28 | for (unsigned int i = 0; i < loopThreadVector_.size(); ++i) 29 | { 30 | loopThreadVector_[i]->run(); 31 | } 32 | } 33 | // void EventLoopThreadPool::stop(){ 34 | // for(unsigned int i=0;iwait(); 44 | } 45 | } 46 | EventLoop *EventLoopThreadPool::getNextLoop() 47 | { 48 | if (loopThreadVector_.size() > 0) 49 | { 50 | size_t index = loopIndex_.fetch_add(1, std::memory_order_relaxed); 51 | EventLoop *loop = 52 | loopThreadVector_[index % loopThreadVector_.size()]->getLoop(); 53 | return loop; 54 | } 55 | return nullptr; 56 | } 57 | EventLoop *EventLoopThreadPool::getLoop(size_t id) 58 | { 59 | if (id < loopThreadVector_.size()) 60 | return loopThreadVector_[id]->getLoop(); 61 | return nullptr; 62 | } 63 | std::vector EventLoopThreadPool::getLoops() const 64 | { 65 | std::vector ret; 66 | for (auto &loopThread : loopThreadVector_) 67 | { 68 | ret.push_back(loopThread->getLoop()); 69 | } 70 | return ret; 71 | } -------------------------------------------------------------------------------- /trantor/net/EventLoopThreadPool.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @file EventLoopThreadPool.h 4 | * @author An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace trantor 24 | { 25 | /** 26 | * @brief This class represents a pool of EventLoopThread objects 27 | * 28 | */ 29 | class TRANTOR_EXPORT EventLoopThreadPool : NonCopyable 30 | { 31 | public: 32 | EventLoopThreadPool() = delete; 33 | 34 | /** 35 | * @brief Construct a new event loop thread pool instance. 36 | * 37 | * @param threadNum The number of threads 38 | * @param name The name of the EventLoopThreadPool object. 39 | */ 40 | EventLoopThreadPool(size_t threadNum, 41 | const std::string &name = "EventLoopThreadPool"); 42 | 43 | /** 44 | * @brief Run all event loops in the pool. 45 | * @note This function doesn't block the current thread. 46 | */ 47 | void start(); 48 | 49 | /** 50 | * @brief Wait for all event loops in the pool to quit. 51 | * 52 | * @note This function blocks the current thread. 53 | */ 54 | void wait(); 55 | 56 | /** 57 | * @brief Return the number of the event loop. 58 | * 59 | * @return size_t 60 | */ 61 | size_t size() 62 | { 63 | return loopThreadVector_.size(); 64 | } 65 | 66 | /** 67 | * @brief Get the next event loop in the pool. 68 | * 69 | * @return EventLoop* 70 | */ 71 | EventLoop *getNextLoop(); 72 | 73 | /** 74 | * @brief Get the event loop in the `id` position in the pool. 75 | * 76 | * @param id The id of the first event loop is zero. If the id >= the number 77 | * of event loops, nullptr is returned. 78 | * @return EventLoop* 79 | */ 80 | EventLoop *getLoop(size_t id); 81 | 82 | /** 83 | * @brief Get all event loops in the pool. 84 | * 85 | * @return std::vector 86 | */ 87 | std::vector getLoops() const; 88 | 89 | private: 90 | std::vector> loopThreadVector_; 91 | std::atomic loopIndex_{0}; 92 | }; 93 | } // namespace trantor 94 | -------------------------------------------------------------------------------- /trantor/net/Resolver.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016, Tao An. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style license 4 | // that can be found in the License file. 5 | 6 | // Author: Tao An 7 | 8 | #pragma once 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace trantor 15 | { 16 | /** 17 | * @brief This class represents an asynchronous DNS resolver. 18 | * @note Although the c-ares library is not essential, it is recommended to 19 | * install it for higher performance 20 | */ 21 | class TRANTOR_EXPORT Resolver 22 | { 23 | public: 24 | using Callback = std::function; 25 | using ResolverResultsCallback = 26 | std::function&)>; 27 | 28 | /** 29 | * @brief Create a new DNS resolver. 30 | * 31 | * @param loop The event loop in which the DNS resolver runs. 32 | * @param timeout The timeout in seconds for DNS. 33 | * @return std::shared_ptr 34 | */ 35 | static std::shared_ptr newResolver(EventLoop* loop = nullptr, 36 | size_t timeout = 60); 37 | 38 | /** 39 | * @brief Resolve an address asynchronously. 40 | * 41 | * @param hostname 42 | * @param callback 43 | */ 44 | virtual void resolve(const std::string& hostname, 45 | const Callback& callback) = 0; 46 | 47 | /** 48 | * @brief Resolve an address array asynchronously. 49 | * 50 | * @param hostname 51 | * @param callback 52 | */ 53 | virtual void resolve(const std::string& hostname, 54 | const ResolverResultsCallback& callback) = 0; 55 | 56 | virtual ~Resolver() 57 | { 58 | } 59 | 60 | /** 61 | * @brief Check whether the c-ares library is used. 62 | * 63 | * @return true 64 | * @return false 65 | */ 66 | static bool isCAresUsed(); 67 | }; 68 | } // namespace trantor -------------------------------------------------------------------------------- /trantor/net/callbacks.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * callbacks.h 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | namespace trantor 20 | { 21 | enum class SSLError 22 | { 23 | kSSLHandshakeError, 24 | kSSLInvalidCertificate, 25 | kSSLProtocolError 26 | }; 27 | using TimerCallback = std::function; 28 | 29 | // the data has been read to (buf, len) 30 | class TcpConnection; 31 | class MsgBuffer; 32 | using TcpConnectionPtr = std::shared_ptr; 33 | // tcp server and connection callback 34 | using RecvMessageCallback = 35 | std::function; 36 | using ConnectionErrorCallback = std::function; 37 | using ConnectionCallback = std::function; 38 | using CloseCallback = std::function; 39 | using WriteCompleteCallback = std::function; 40 | using HighWaterMarkCallback = 41 | std::function; 42 | using SSLErrorCallback = std::function; 43 | using SockOptCallback = std::function; 44 | 45 | } // namespace trantor 46 | -------------------------------------------------------------------------------- /trantor/net/inner/Acceptor.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Acceptor.cc 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #include "Acceptor.h" 16 | using namespace trantor; 17 | 18 | #ifndef O_CLOEXEC 19 | #define O_CLOEXEC O_NOINHERIT 20 | #endif 21 | 22 | Acceptor::Acceptor(EventLoop *loop, 23 | const InetAddress &addr, 24 | bool reUseAddr, 25 | bool reUsePort) 26 | 27 | : 28 | #ifndef _WIN32 29 | idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC)), 30 | #endif 31 | sock_( 32 | Socket::createNonblockingSocketOrDie(addr.getSockAddr()->sa_family)), 33 | addr_(addr), 34 | loop_(loop), 35 | acceptChannel_(loop, sock_.fd()) 36 | { 37 | sock_.setReuseAddr(reUseAddr); 38 | sock_.setReusePort(reUsePort); 39 | sock_.bindAddress(addr_); 40 | acceptChannel_.setReadCallback(std::bind(&Acceptor::readCallback, this)); 41 | if (addr_.toPort() == 0) 42 | { 43 | addr_ = InetAddress{Socket::getLocalAddr(sock_.fd())}; 44 | } 45 | } 46 | Acceptor::~Acceptor() 47 | { 48 | acceptChannel_.disableAll(); 49 | acceptChannel_.remove(); 50 | #ifndef _WIN32 51 | ::close(idleFd_); 52 | #endif 53 | } 54 | void Acceptor::listen() 55 | { 56 | loop_->assertInLoopThread(); 57 | if (beforeListenSetSockOptCallback_) 58 | beforeListenSetSockOptCallback_(sock_.fd()); 59 | sock_.listen(); 60 | acceptChannel_.enableReading(); 61 | } 62 | 63 | void Acceptor::readCallback() 64 | { 65 | InetAddress peer; 66 | int newsock = sock_.accept(&peer); 67 | if (newsock >= 0) 68 | { 69 | if (afterAcceptSetSockOptCallback_) 70 | afterAcceptSetSockOptCallback_(newsock); 71 | if (newConnectionCallback_) 72 | { 73 | newConnectionCallback_(newsock, peer); 74 | } 75 | else 76 | { 77 | #ifndef _WIN32 78 | ::close(newsock); 79 | #else 80 | closesocket(newsock); 81 | #endif 82 | } 83 | } 84 | else 85 | { 86 | LOG_SYSERR << "Acceptor::readCallback"; 87 | // Read the section named "The special problem of 88 | // accept()ing when you can't" in libev's doc. 89 | // By Marc Lehmann, author of libev. 90 | /// errno is thread safe 91 | #ifndef _WIN32 92 | if (errno == EMFILE) 93 | { 94 | ::close(idleFd_); 95 | idleFd_ = sock_.accept(&peer); 96 | ::close(idleFd_); 97 | idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC); 98 | } 99 | #endif 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /trantor/net/inner/Acceptor.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Acceptor.h 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include "Socket.h" 20 | #include 21 | #include "Channel.h" 22 | #include 23 | 24 | namespace trantor 25 | { 26 | using NewConnectionCallback = std::function; 27 | using AcceptorSockOptCallback = std::function; 28 | class Acceptor : NonCopyable 29 | { 30 | public: 31 | Acceptor(EventLoop *loop, 32 | const InetAddress &addr, 33 | bool reUseAddr = true, 34 | bool reUsePort = true); 35 | ~Acceptor(); 36 | const InetAddress &addr() const 37 | { 38 | return addr_; 39 | } 40 | void setNewConnectionCallback(const NewConnectionCallback &cb) 41 | { 42 | newConnectionCallback_ = cb; 43 | }; 44 | void listen(); 45 | 46 | void setBeforeListenSockOptCallback(AcceptorSockOptCallback cb) 47 | { 48 | beforeListenSetSockOptCallback_ = std::move(cb); 49 | } 50 | 51 | void setAfterAcceptSockOptCallback(AcceptorSockOptCallback cb) 52 | { 53 | afterAcceptSetSockOptCallback_ = std::move(cb); 54 | } 55 | 56 | protected: 57 | #ifndef _WIN32 58 | int idleFd_; 59 | #endif 60 | Socket sock_; 61 | InetAddress addr_; 62 | EventLoop *loop_; 63 | NewConnectionCallback newConnectionCallback_; 64 | Channel acceptChannel_; 65 | void readCallback(); 66 | AcceptorSockOptCallback beforeListenSetSockOptCallback_; 67 | AcceptorSockOptCallback afterAcceptSetSockOptCallback_; 68 | }; 69 | } // namespace trantor 70 | -------------------------------------------------------------------------------- /trantor/net/inner/AsyncStreamBufferNode.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace trantor 4 | { 5 | class AsyncBufferNode : public BufferNode 6 | { 7 | public: 8 | AsyncBufferNode() = default; 9 | ~AsyncBufferNode() override = default; 10 | bool isAsync() const override 11 | { 12 | return true; 13 | } 14 | bool isStream() const override 15 | { 16 | return true; 17 | } 18 | long long remainingBytes() const override 19 | { 20 | if (msgBufferPtr_) 21 | return static_cast(msgBufferPtr_->readableBytes()); 22 | return 0; 23 | } 24 | bool available() const override 25 | { 26 | return !isDone_; 27 | } 28 | void getData(const char *&data, size_t &len) override 29 | { 30 | if (msgBufferPtr_) 31 | { 32 | data = msgBufferPtr_->peek(); 33 | len = msgBufferPtr_->readableBytes(); 34 | } 35 | else 36 | { 37 | data = nullptr; 38 | len = 0; 39 | } 40 | } 41 | void retrieve(size_t len) override 42 | { 43 | assert(msgBufferPtr_); 44 | if (msgBufferPtr_) 45 | { 46 | msgBufferPtr_->retrieve(len); 47 | } 48 | } 49 | void append(const char *data, size_t len) override 50 | { 51 | if (!msgBufferPtr_) 52 | { 53 | msgBufferPtr_ = std::make_unique(len); 54 | } 55 | msgBufferPtr_->append(data, len); 56 | } 57 | 58 | private: 59 | std::unique_ptr msgBufferPtr_; 60 | }; 61 | BufferNodePtr BufferNode::newAsyncStreamBufferNode() 62 | { 63 | return std::make_shared(); 64 | } 65 | } // namespace trantor 66 | -------------------------------------------------------------------------------- /trantor/net/inner/BufferNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @file BufferNode.h 4 | * @author An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | #ifdef _WIN32 17 | #include 18 | #endif 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | namespace trantor 27 | { 28 | class BufferNode; 29 | using BufferNodePtr = std::shared_ptr; 30 | using StreamCallback = std::function; 31 | class BufferNode : public NonCopyable 32 | { 33 | public: 34 | virtual bool isFile() const 35 | { 36 | return false; 37 | } 38 | virtual ~BufferNode() = default; 39 | virtual bool isStream() const 40 | { 41 | return false; 42 | } 43 | virtual void getData(const char *&data, size_t &len) = 0; 44 | virtual void append(const char *, size_t) 45 | { 46 | LOG_FATAL << "Not a memory buffer node"; 47 | } 48 | virtual void retrieve(size_t len) = 0; 49 | virtual long long remainingBytes() const = 0; 50 | virtual int getFd() const 51 | { 52 | LOG_FATAL << "Not a file buffer node"; 53 | return -1; 54 | } 55 | virtual bool available() const 56 | { 57 | return true; 58 | } 59 | virtual bool isAsync() const 60 | { 61 | return false; 62 | } 63 | 64 | void done() 65 | { 66 | isDone_ = true; 67 | } 68 | static BufferNodePtr newMemBufferNode(); 69 | 70 | static BufferNodePtr newStreamBufferNode(StreamCallback &&cb); 71 | #ifdef _WIN32 72 | static BufferNodePtr newFileBufferNode(const wchar_t *fileName, 73 | long long offset, 74 | long long length); 75 | #else 76 | static BufferNodePtr newFileBufferNode(const char *fileName, 77 | long long offset, 78 | long long length); 79 | #endif 80 | static BufferNodePtr newAsyncStreamBufferNode(); 81 | 82 | protected: 83 | bool isDone_{false}; 84 | }; 85 | 86 | } // namespace trantor -------------------------------------------------------------------------------- /trantor/net/inner/Connector.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Connector.h 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace trantor 24 | { 25 | class Connector : public NonCopyable, 26 | public std::enable_shared_from_this 27 | { 28 | public: 29 | using NewConnectionCallback = std::function; 30 | using ConnectionErrorCallback = std::function; 31 | using SockOptCallback = std::function; 32 | Connector(EventLoop *loop, const InetAddress &addr, bool retry = true); 33 | Connector(EventLoop *loop, InetAddress &&addr, bool retry = true); 34 | ~Connector(); 35 | void setNewConnectionCallback(const NewConnectionCallback &cb) 36 | { 37 | newConnectionCallback_ = cb; 38 | } 39 | void setNewConnectionCallback(NewConnectionCallback &&cb) 40 | { 41 | newConnectionCallback_ = std::move(cb); 42 | } 43 | void setErrorCallback(const ConnectionErrorCallback &cb) 44 | { 45 | errorCallback_ = cb; 46 | } 47 | void setErrorCallback(ConnectionErrorCallback &&cb) 48 | { 49 | errorCallback_ = std::move(cb); 50 | } 51 | void setSockOptCallback(const SockOptCallback &cb) 52 | { 53 | sockOptCallback_ = cb; 54 | } 55 | void setSockOptCallback(SockOptCallback &&cb) 56 | { 57 | sockOptCallback_ = std::move(cb); 58 | } 59 | const InetAddress &serverAddress() const 60 | { 61 | return serverAddr_; 62 | } 63 | void start(); 64 | void restart(); 65 | void stop(); 66 | 67 | private: 68 | NewConnectionCallback newConnectionCallback_; 69 | ConnectionErrorCallback errorCallback_; 70 | SockOptCallback sockOptCallback_; 71 | enum class Status 72 | { 73 | Disconnected, 74 | Connecting, 75 | Connected 76 | }; 77 | static constexpr int kMaxRetryDelayMs = 30 * 1000; 78 | static constexpr int kInitRetryDelayMs = 500; 79 | std::shared_ptr channelPtr_; 80 | EventLoop *loop_; 81 | InetAddress serverAddr_; 82 | 83 | std::atomic_bool connect_{false}; 84 | std::atomic status_{Status::Disconnected}; 85 | 86 | int retryInterval_{kInitRetryDelayMs}; 87 | int maxRetryInterval_{kMaxRetryDelayMs}; 88 | 89 | bool retry_; 90 | bool socketHanded_{false}; 91 | int fd_{-1}; 92 | 93 | void startInLoop(); 94 | void connect(); 95 | void connecting(int sockfd); 96 | int removeAndResetChannel(); 97 | void handleWrite(); 98 | void handleError(); 99 | void retry(int sockfd); 100 | }; 101 | 102 | } // namespace trantor 103 | -------------------------------------------------------------------------------- /trantor/net/inner/FileBufferNodeUnix.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace trantor 8 | { 9 | static const size_t kMaxSendFileBufferSize = 16 * 1024; 10 | class FileBufferNode : public BufferNode 11 | { 12 | public: 13 | FileBufferNode(const char *fileName, long long offset, long long length) 14 | { 15 | assert(offset >= 0); 16 | if (offset < 0) 17 | { 18 | LOG_ERROR << "offset must be greater than or equal to 0"; 19 | isDone_ = true; 20 | return; 21 | } 22 | sendFd_ = open(fileName, O_RDONLY); 23 | 24 | if (sendFd_ < 0) 25 | { 26 | LOG_SYSERR << fileName << " open error"; 27 | isDone_ = true; 28 | return; 29 | } 30 | struct stat filestat; 31 | if (stat(fileName, &filestat) < 0) 32 | { 33 | LOG_SYSERR << fileName << " stat error"; 34 | close(sendFd_); 35 | sendFd_ = -1; 36 | isDone_ = true; 37 | return; 38 | } 39 | if (length == 0) 40 | { 41 | if (offset >= filestat.st_size) 42 | { 43 | LOG_ERROR << "The file size is " << filestat.st_size 44 | << " bytes, but the offset is " << offset 45 | << " bytes and the length is " << length << " bytes"; 46 | close(sendFd_); 47 | sendFd_ = -1; 48 | isDone_ = true; 49 | return; 50 | } 51 | fileBytesToSend_ = filestat.st_size - offset; 52 | } 53 | else 54 | { 55 | if (length > filestat.st_size - offset) 56 | { 57 | LOG_ERROR << "The file size is " << filestat.st_size 58 | << " bytes, but the offset is " << offset 59 | << " bytes and the length is " << length << " bytes"; 60 | close(sendFd_); 61 | sendFd_ = -1; 62 | isDone_ = true; 63 | return; 64 | } 65 | fileBytesToSend_ = length; 66 | } 67 | lseek(sendFd_, offset, SEEK_SET); 68 | } 69 | bool isFile() const override 70 | { 71 | return true; 72 | } 73 | int getFd() const override 74 | { 75 | return sendFd_; 76 | } 77 | void getData(const char *&data, size_t &len) override 78 | { 79 | if (msgBufferPtr_ == nullptr) 80 | { 81 | msgBufferPtr_ = std::make_unique( 82 | (std::min)(kMaxSendFileBufferSize, 83 | static_cast(fileBytesToSend_))); 84 | } 85 | if (msgBufferPtr_->readableBytes() == 0 && fileBytesToSend_ > 0 && 86 | sendFd_ >= 0) 87 | { 88 | msgBufferPtr_->ensureWritableBytes( 89 | (std::min)(kMaxSendFileBufferSize, 90 | static_cast(fileBytesToSend_))); 91 | auto n = read(sendFd_, 92 | msgBufferPtr_->beginWrite(), 93 | msgBufferPtr_->writableBytes()); 94 | if (n > 0) 95 | { 96 | msgBufferPtr_->hasWritten(n); 97 | } 98 | else if (n == 0) 99 | { 100 | LOG_TRACE << "Read the end of file."; 101 | } 102 | else 103 | { 104 | LOG_SYSERR << "FileBufferNode::getData()"; 105 | } 106 | } 107 | data = msgBufferPtr_->peek(); 108 | len = msgBufferPtr_->readableBytes(); 109 | } 110 | void retrieve(size_t len) override 111 | { 112 | if (msgBufferPtr_) 113 | { 114 | msgBufferPtr_->retrieve(len); 115 | } 116 | fileBytesToSend_ -= static_cast(len); 117 | if (fileBytesToSend_ < 0) 118 | fileBytesToSend_ = 0; 119 | } 120 | long long remainingBytes() const override 121 | { 122 | if (isDone_) 123 | return 0; 124 | return fileBytesToSend_; 125 | } 126 | ~FileBufferNode() override 127 | { 128 | if (sendFd_ >= 0) 129 | { 130 | close(sendFd_); 131 | } 132 | } 133 | bool available() const override 134 | { 135 | return sendFd_ >= 0; 136 | } 137 | 138 | private: 139 | int sendFd_{-1}; 140 | long long fileBytesToSend_{0}; 141 | std::unique_ptr msgBufferPtr_; 142 | }; 143 | 144 | BufferNodePtr BufferNode::newFileBufferNode(const char *fileName, 145 | long long offset, 146 | long long length) 147 | { 148 | return std::make_shared(fileName, offset, length); 149 | } 150 | } // namespace trantor -------------------------------------------------------------------------------- /trantor/net/inner/MemBufferNode.cc: -------------------------------------------------------------------------------- 1 | #include 2 | namespace trantor 3 | { 4 | class MemBufferNode : public BufferNode 5 | { 6 | public: 7 | MemBufferNode() = default; 8 | 9 | void getData(const char *&data, size_t &len) override 10 | { 11 | data = buffer_.peek(); 12 | len = buffer_.readableBytes(); 13 | } 14 | void retrieve(size_t len) override 15 | { 16 | buffer_.retrieve(len); 17 | } 18 | long long remainingBytes() const override 19 | { 20 | if (isDone_) 21 | return 0; 22 | return static_cast(buffer_.readableBytes()); 23 | } 24 | void append(const char *data, size_t len) override 25 | { 26 | buffer_.append(data, len); 27 | } 28 | 29 | private: 30 | trantor::MsgBuffer buffer_; 31 | }; 32 | BufferNodePtr BufferNode::newMemBufferNode() 33 | { 34 | return std::make_shared(); 35 | } 36 | } // namespace trantor 37 | -------------------------------------------------------------------------------- /trantor/net/inner/NormalResolver.cc: -------------------------------------------------------------------------------- 1 | #include "NormalResolver.h" 2 | #include 3 | #ifdef _WIN32 4 | #include 5 | #else 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include // memset 11 | #endif 12 | 13 | using namespace trantor; 14 | 15 | std::shared_ptr Resolver::newResolver(trantor::EventLoop *, 16 | size_t timeout) 17 | { 18 | return std::make_shared(timeout); 19 | } 20 | bool Resolver::isCAresUsed() 21 | { 22 | return false; 23 | } 24 | void NormalResolver::resolve(const std::string &hostname, 25 | const Callback &callback) 26 | { 27 | { 28 | std::lock_guard guard(globalMutex()); 29 | auto iter = globalCache().find(hostname); 30 | if (iter != globalCache().end()) 31 | { 32 | auto &cachedAddr = iter->second; 33 | if (timeout_ == 0 || cachedAddr.second.after(static_cast( 34 | timeout_)) > trantor::Date::date()) 35 | { 36 | callback(cachedAddr.first); 37 | return; 38 | } 39 | } 40 | } 41 | 42 | concurrentTaskQueue().runTaskInQueue( 43 | [thisPtr = shared_from_this(), callback, hostname]() { 44 | { 45 | std::lock_guard guard(thisPtr->globalMutex()); 46 | auto iter = thisPtr->globalCache().find(hostname); 47 | if (iter != thisPtr->globalCache().end()) 48 | { 49 | auto &cachedAddr = iter->second; 50 | if (thisPtr->timeout_ == 0 || 51 | cachedAddr.second.after(static_cast( 52 | thisPtr->timeout_)) > trantor::Date::date()) 53 | { 54 | callback(cachedAddr.first); 55 | return; 56 | } 57 | } 58 | } 59 | struct addrinfo hints, *res = nullptr; 60 | memset(&hints, 0, sizeof(hints)); 61 | hints.ai_family = PF_UNSPEC; 62 | hints.ai_socktype = SOCK_STREAM; 63 | hints.ai_flags = AI_PASSIVE; 64 | auto error = getaddrinfo(hostname.data(), nullptr, &hints, &res); 65 | if (error != 0 || res == nullptr) 66 | { 67 | LOG_SYSERR << "InetAddress::resolve"; 68 | if (res != nullptr) 69 | { 70 | freeaddrinfo(res); 71 | } 72 | callback(InetAddress{}); 73 | return; 74 | } 75 | InetAddress inet; 76 | if (res->ai_family == AF_INET) 77 | { 78 | struct sockaddr_in addr; 79 | memset(&addr, 0, sizeof addr); 80 | addr = *reinterpret_cast(res->ai_addr); 81 | inet = InetAddress(addr); 82 | } 83 | else if (res->ai_family == AF_INET6) 84 | { 85 | struct sockaddr_in6 addr; 86 | memset(&addr, 0, sizeof addr); 87 | addr = *reinterpret_cast(res->ai_addr); 88 | inet = InetAddress(addr); 89 | } 90 | freeaddrinfo(res); 91 | callback(inet); 92 | { 93 | std::lock_guard guard(thisPtr->globalMutex()); 94 | auto &addrItem = thisPtr->globalCache()[hostname]; 95 | addrItem.first = inet; 96 | addrItem.second = trantor::Date::date(); 97 | } 98 | return; 99 | }); 100 | } 101 | -------------------------------------------------------------------------------- /trantor/net/inner/NormalResolver.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016, Tao An. All rights reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style license 4 | // that can be found in the License file. 5 | 6 | // Author: Tao An 7 | 8 | #pragma once 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace trantor 17 | { 18 | constexpr size_t kResolveBufferLength{16 * 1024}; 19 | class NormalResolver : public Resolver, 20 | public NonCopyable, 21 | public std::enable_shared_from_this 22 | { 23 | public: 24 | virtual void resolve(const std::string& hostname, 25 | const Callback& callback) override; 26 | virtual void resolve(const std::string& hostname, 27 | const ResolverResultsCallback& callback) override 28 | { 29 | resolve(hostname, [callback](const trantor::InetAddress& inet) { 30 | callback(std::vector{inet}); 31 | }); 32 | } 33 | explicit NormalResolver(size_t timeout) 34 | : timeout_(timeout), resolveBuffer_(kResolveBufferLength) 35 | { 36 | } 37 | virtual ~NormalResolver() 38 | { 39 | } 40 | 41 | private: 42 | static std::unordered_map>& 44 | globalCache() 45 | { 46 | static std::unordered_map< 47 | std::string, 48 | std::pair> 49 | dnsCache_; 50 | return dnsCache_; 51 | } 52 | static std::mutex& globalMutex() 53 | { 54 | static std::mutex mutex_; 55 | return mutex_; 56 | } 57 | static trantor::ConcurrentTaskQueue& concurrentTaskQueue() 58 | { 59 | static trantor::ConcurrentTaskQueue queue( 60 | std::thread::hardware_concurrency() < 8 61 | ? 8 62 | : std::thread::hardware_concurrency(), 63 | "Dns Queue"); 64 | return queue; 65 | } 66 | const size_t timeout_; 67 | std::vector resolveBuffer_; 68 | }; 69 | } // namespace trantor -------------------------------------------------------------------------------- /trantor/net/inner/Poller.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Poller.cc 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #include "Poller.h" 16 | #ifdef __linux__ 17 | #include "poller/EpollPoller.h" 18 | #elif defined _WIN32 19 | #include "Wepoll.h" 20 | #include "poller/EpollPoller.h" 21 | #elif defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ 22 | #include "poller/KQueue.h" 23 | #else 24 | #include "poller/PollPoller.h" 25 | #endif 26 | using namespace trantor; 27 | Poller *Poller::newPoller(EventLoop *loop) 28 | { 29 | #if defined __linux__ || defined _WIN32 30 | return new EpollPoller(loop); 31 | #elif defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ 32 | return new KQueue(loop); 33 | #else 34 | return new PollPoller(loop); 35 | #endif 36 | } 37 | -------------------------------------------------------------------------------- /trantor/net/inner/Poller.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Poller.h 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | #include "NonCopyable.h" 17 | #include "EventLoop.h" 18 | 19 | #include 20 | #include 21 | 22 | namespace trantor 23 | { 24 | class Channel; 25 | #ifdef _WIN32 26 | using EventCallback = std::function; 27 | #endif 28 | class Poller : NonCopyable 29 | { 30 | public: 31 | explicit Poller(EventLoop *loop) : ownerLoop_(loop){}; 32 | virtual ~Poller() 33 | { 34 | } 35 | void assertInLoopThread() 36 | { 37 | ownerLoop_->assertInLoopThread(); 38 | } 39 | virtual void poll(int timeoutMs, ChannelList *activeChannels) = 0; 40 | virtual void updateChannel(Channel *channel) = 0; 41 | virtual void removeChannel(Channel *channel) = 0; 42 | #ifdef _WIN32 43 | virtual void postEvent(uint64_t event) = 0; 44 | virtual void setEventCallback(const EventCallback &cb) = 0; 45 | #endif 46 | virtual void resetAfterFork() 47 | { 48 | } 49 | static Poller *newPoller(EventLoop *loop); 50 | 51 | private: 52 | EventLoop *ownerLoop_; 53 | }; 54 | } // namespace trantor 55 | -------------------------------------------------------------------------------- /trantor/net/inner/Socket.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Socket.h 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #ifndef _WIN32 22 | #include 23 | #endif 24 | #include 25 | 26 | namespace trantor 27 | { 28 | class Socket : NonCopyable 29 | { 30 | public: 31 | static int createNonblockingSocketOrDie(int family) 32 | { 33 | #ifdef __linux__ 34 | int sock = ::socket(family, 35 | SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 36 | IPPROTO_TCP); 37 | #else 38 | int sock = static_cast(::socket(family, SOCK_STREAM, IPPROTO_TCP)); 39 | setNonBlockAndCloseOnExec(sock); 40 | #endif 41 | if (sock < 0) 42 | { 43 | LOG_SYSERR << "sockets::createNonblockingOrDie"; 44 | exit(1); 45 | } 46 | LOG_TRACE << "sock=" << sock; 47 | return sock; 48 | } 49 | 50 | static int getSocketError(int sockfd) 51 | { 52 | int optval; 53 | socklen_t optlen = static_cast(sizeof optval); 54 | #ifdef _WIN32 55 | if (::getsockopt( 56 | sockfd, SOL_SOCKET, SO_ERROR, (char *)&optval, &optlen) < 0) 57 | #else 58 | if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) 59 | #endif 60 | { 61 | return errno; 62 | } 63 | else 64 | { 65 | return optval; 66 | } 67 | } 68 | 69 | static int connect(int sockfd, const InetAddress &addr) 70 | { 71 | if (addr.isIpV6()) 72 | return ::connect(sockfd, 73 | addr.getSockAddr(), 74 | static_cast( 75 | sizeof(struct sockaddr_in6))); 76 | else 77 | return ::connect(sockfd, 78 | addr.getSockAddr(), 79 | static_cast( 80 | sizeof(struct sockaddr_in))); 81 | } 82 | 83 | static bool isSelfConnect(int sockfd); 84 | 85 | explicit Socket(int sockfd) : sockFd_(sockfd) 86 | { 87 | } 88 | ~Socket(); 89 | /// abort if address in use 90 | void bindAddress(const InetAddress &localaddr); 91 | /// abort if address in use 92 | void listen(); 93 | int accept(InetAddress *peeraddr); 94 | void closeWrite(); 95 | int read(char *buffer, uint64_t len); 96 | int fd() 97 | { 98 | return sockFd_; 99 | } 100 | static struct sockaddr_in6 getLocalAddr(int sockfd); 101 | static struct sockaddr_in6 getPeerAddr(int sockfd); 102 | 103 | /// 104 | /// Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). 105 | /// 106 | void setTcpNoDelay(bool on); 107 | 108 | /// 109 | /// Enable/disable SO_REUSEADDR 110 | /// 111 | void setReuseAddr(bool on); 112 | 113 | /// 114 | /// Enable/disable SO_REUSEPORT 115 | /// 116 | void setReusePort(bool on); 117 | 118 | /// 119 | /// Enable/disable SO_KEEPALIVE 120 | /// 121 | void setKeepAlive(bool on); 122 | int getSocketError(); 123 | 124 | protected: 125 | int sockFd_; 126 | 127 | public: 128 | // taken from muduo 129 | static void setNonBlockAndCloseOnExec(int sockfd) 130 | { 131 | #ifdef _WIN32 132 | // TODO how to set FD_CLOEXEC on windows? is it necessary? 133 | u_long arg = 1; 134 | auto ret = ioctlsocket(sockfd, (long)FIONBIO, &arg); 135 | if (ret) 136 | { 137 | LOG_ERROR << "ioctlsocket error"; 138 | } 139 | #else 140 | // non-block 141 | int flags = ::fcntl(sockfd, F_GETFL, 0); 142 | flags |= O_NONBLOCK; 143 | int ret = ::fcntl(sockfd, F_SETFL, flags); 144 | // TODO check 145 | 146 | // close-on-exec 147 | flags = ::fcntl(sockfd, F_GETFD, 0); 148 | flags |= FD_CLOEXEC; 149 | ret = ::fcntl(sockfd, F_SETFD, flags); 150 | // TODO check 151 | 152 | (void)ret; 153 | #endif 154 | } 155 | }; 156 | 157 | } // namespace trantor 158 | -------------------------------------------------------------------------------- /trantor/net/inner/StreamBufferNode.cc: -------------------------------------------------------------------------------- 1 | #include 2 | namespace trantor 3 | { 4 | static const size_t kMaxSendFileBufferSize = 16 * 1024; 5 | class StreamBufferNode : public BufferNode 6 | { 7 | public: 8 | StreamBufferNode(std::function &&callback) 9 | : streamCallback_(std::move(callback)) 10 | { 11 | } 12 | bool isStream() const override 13 | { 14 | return true; 15 | } 16 | void getData(const char *&data, size_t &len) override 17 | { 18 | if (msgBuffer_.readableBytes() == 0) 19 | { 20 | msgBuffer_.ensureWritableBytes(kMaxSendFileBufferSize); 21 | auto n = streamCallback_(msgBuffer_.beginWrite(), 22 | msgBuffer_.writableBytes()); 23 | if (n > 0) 24 | { 25 | msgBuffer_.hasWritten(n); 26 | } 27 | else 28 | { 29 | isDone_ = true; 30 | } 31 | } 32 | data = msgBuffer_.peek(); 33 | len = msgBuffer_.readableBytes(); 34 | } 35 | void retrieve(size_t len) override 36 | { 37 | msgBuffer_.retrieve(len); 38 | #ifndef NDEBUG 39 | dataWritten_ += len; 40 | LOG_TRACE << "send stream in loop: bytes written: " << dataWritten_ 41 | << " / total bytes written: " << dataWritten_; 42 | #endif 43 | } 44 | long long remainingBytes() const override 45 | { 46 | if (isDone_) 47 | return 0; 48 | return 1; 49 | } 50 | ~StreamBufferNode() override 51 | { 52 | if (streamCallback_) 53 | streamCallback_(nullptr, 0); // cleanup callback internals 54 | } 55 | 56 | private: 57 | std::function streamCallback_; 58 | #ifndef NDEBUG // defined by CMake for release build 59 | std::size_t dataWritten_{0}; 60 | #endif 61 | MsgBuffer msgBuffer_; 62 | }; 63 | BufferNodePtr BufferNode::newStreamBufferNode(StreamCallback &&callback) 64 | { 65 | return std::make_shared(std::move(callback)); 66 | } 67 | } // namespace trantor -------------------------------------------------------------------------------- /trantor/net/inner/TLSProvider.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | namespace trantor 12 | { 13 | struct TLSProvider 14 | { 15 | TLSProvider(TcpConnection* conn, TLSPolicyPtr policy, SSLContextPtr ctx) 16 | : conn_(conn), 17 | policyPtr_(std::move(policy)), 18 | contextPtr_(std::move(ctx)), 19 | loop_(conn_->getLoop()) 20 | { 21 | } 22 | virtual ~TLSProvider() = default; 23 | using WriteCallback = ssize_t (*)(TcpConnection*, 24 | const void* data, 25 | size_t len); 26 | using ErrorCallback = void (*)(TcpConnection*, SSLError err); 27 | using HandshakeCallback = void (*)(TcpConnection*); 28 | using MessageCallback = void (*)(TcpConnection*, MsgBuffer* buffer); 29 | using CloseCallback = void (*)(TcpConnection*); 30 | 31 | /** 32 | * @brief Sends data to the TLSProvider to process handshake and decrypt 33 | * data 34 | */ 35 | virtual void recvData(MsgBuffer* buffer) = 0; 36 | 37 | /** 38 | * @brief Encrypt and send data via TLS 39 | * @return the number of bytes sent, or -1 on error, or 0 if EAGAIN or 40 | * EWOULDBLOCK. 41 | */ 42 | virtual ssize_t sendData(const char* ptr, size_t size) = 0; 43 | 44 | /** 45 | * @brief Close the TLS connection 46 | */ 47 | virtual void close() = 0; 48 | 49 | virtual void startEncryption() = 0; 50 | 51 | bool sendBufferedData() 52 | { 53 | if (writeBuffer_.readableBytes() == 0) 54 | return true; 55 | 56 | auto n = writeCallback_(conn_, 57 | writeBuffer_.peek(), 58 | writeBuffer_.readableBytes()); 59 | if (n == -1) 60 | { 61 | LOG_ERROR << "WTF! Failed to send buffered data. Error: " 62 | << strerror(errno); 63 | return false; 64 | } 65 | else if ((size_t)n != writeBuffer_.readableBytes()) 66 | { 67 | writeBuffer_.retrieve(n); 68 | return false; 69 | } 70 | 71 | writeBuffer_.retrieveAll(); 72 | return true; 73 | } 74 | 75 | MsgBuffer& getBufferedData() 76 | { 77 | return writeBuffer_; 78 | } 79 | 80 | void appendToWriteBuffer(const char* ptr, size_t size) 81 | { 82 | writeBuffer_.ensureWritableBytes(size); 83 | writeBuffer_.append(ptr, size); 84 | } 85 | 86 | /** 87 | * @brief Set a function to be called when the TLSProvider wants to send 88 | * data 89 | * 90 | * @note The caller MUST guarantee that it will not make the TLSProvider 91 | * send data after caller is destroyed. std::function used due to 92 | * performance reasons. 93 | */ 94 | void setWriteCallback(WriteCallback cb) 95 | { 96 | writeCallback_ = cb; 97 | } 98 | 99 | void setErrorCallback(ErrorCallback cb) 100 | { 101 | errorCallback_ = cb; 102 | } 103 | 104 | void setHandshakeCallback(HandshakeCallback cb) 105 | { 106 | handshakeCallback_ = cb; 107 | } 108 | 109 | void setMessageCallback(MessageCallback cb) 110 | { 111 | messageCallback_ = cb; 112 | } 113 | void setCloseCallback(CloseCallback cb) 114 | { 115 | closeCallback_ = cb; 116 | } 117 | 118 | MsgBuffer& getRecvBuffer() 119 | { 120 | return recvBuffer_; 121 | } 122 | 123 | const CertificatePtr& peerCertificate() const 124 | { 125 | return peerCertificate_; 126 | } 127 | 128 | const std::string& applicationProtocol() const 129 | { 130 | return applicationProtocol_; 131 | } 132 | 133 | const std::string& sniName() const 134 | { 135 | return sniName_; 136 | } 137 | 138 | protected: 139 | void setPeerCertificate(CertificatePtr cert) 140 | { 141 | peerCertificate_ = std::move(cert); 142 | } 143 | 144 | void setApplicationProtocol(std::string protocol) 145 | { 146 | applicationProtocol_ = std::move(protocol); 147 | } 148 | 149 | void setSniName(std::string name) 150 | { 151 | sniName_ = std::move(name); 152 | } 153 | 154 | WriteCallback writeCallback_ = nullptr; 155 | ErrorCallback errorCallback_ = nullptr; 156 | HandshakeCallback handshakeCallback_ = nullptr; 157 | MessageCallback messageCallback_ = nullptr; 158 | CloseCallback closeCallback_ = nullptr; 159 | TcpConnection* conn_ = nullptr; 160 | const TLSPolicyPtr policyPtr_; 161 | const SSLContextPtr contextPtr_; 162 | MsgBuffer recvBuffer_; 163 | EventLoop* loop_ = nullptr; 164 | CertificatePtr peerCertificate_; 165 | std::string applicationProtocol_; 166 | std::string sniName_; 167 | MsgBuffer writeBuffer_; 168 | }; 169 | 170 | std::shared_ptr newTLSProvider(TcpConnection* conn, 171 | TLSPolicyPtr policy, 172 | SSLContextPtr ctx); 173 | } // namespace trantor 174 | -------------------------------------------------------------------------------- /trantor/net/inner/Timer.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Timer.cc 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #include "Timer.h" 16 | #include 17 | #include 18 | 19 | namespace trantor 20 | { 21 | std::atomic Timer::timersCreated_ = ATOMIC_VAR_INIT(InvalidTimerId); 22 | Timer::Timer(const TimerCallback &cb, 23 | const TimePoint &when, 24 | const TimeInterval &interval) 25 | : callback_(cb), 26 | when_(when), 27 | interval_(interval), 28 | repeat_(interval.count() > 0), 29 | id_(++timersCreated_) 30 | { 31 | } 32 | Timer::Timer(TimerCallback &&cb, 33 | const TimePoint &when, 34 | const TimeInterval &interval) 35 | : callback_(std::move(cb)), 36 | when_(when), 37 | interval_(interval), 38 | repeat_(interval.count() > 0), 39 | id_(++timersCreated_) 40 | { 41 | // LOG_TRACE<<"Timer move contrustor"; 42 | } 43 | void Timer::run() const 44 | { 45 | callback_(); 46 | } 47 | void Timer::restart(const TimePoint &now) 48 | { 49 | if (repeat_) 50 | { 51 | when_ = now + interval_; 52 | } 53 | else 54 | when_ = std::chrono::steady_clock::now(); 55 | } 56 | bool Timer::operator<(const Timer &t) const 57 | { 58 | return when_ < t.when_; 59 | } 60 | bool Timer::operator>(const Timer &t) const 61 | { 62 | return when_ > t.when_; 63 | } 64 | } // namespace trantor 65 | -------------------------------------------------------------------------------- /trantor/net/inner/Timer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Timer.h 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace trantor 25 | { 26 | using TimerId = uint64_t; 27 | using TimePoint = std::chrono::steady_clock::time_point; 28 | using TimeInterval = std::chrono::microseconds; 29 | class Timer : public NonCopyable 30 | { 31 | public: 32 | Timer(const TimerCallback &cb, 33 | const TimePoint &when, 34 | const TimeInterval &interval); 35 | Timer(TimerCallback &&cb, 36 | const TimePoint &when, 37 | const TimeInterval &interval); 38 | ~Timer() 39 | { 40 | // std::cout<<"Timer unconstract!"<(const Timer &t) const; 46 | const TimePoint &when() const 47 | { 48 | return when_; 49 | } 50 | bool isRepeat() 51 | { 52 | return repeat_; 53 | } 54 | TimerId id() 55 | { 56 | return id_; 57 | } 58 | 59 | private: 60 | TimerCallback callback_; 61 | TimePoint when_; 62 | const TimeInterval interval_; 63 | const bool repeat_; 64 | const TimerId id_; 65 | static std::atomic timersCreated_; 66 | }; 67 | 68 | } // namespace trantor 69 | -------------------------------------------------------------------------------- /trantor/net/inner/TimerQueue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * TimerQueue.h 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include "Timer.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | namespace trantor 25 | { 26 | // class Timer; 27 | class EventLoop; 28 | class Channel; 29 | using TimerPtr = std::shared_ptr; 30 | struct TimerPtrComparer 31 | { 32 | bool operator()(const TimerPtr &x, const TimerPtr &y) const 33 | { 34 | return *x > *y; 35 | } 36 | }; 37 | 38 | class TimerQueue : NonCopyable 39 | { 40 | public: 41 | explicit TimerQueue(EventLoop *loop); 42 | ~TimerQueue(); 43 | TimerId addTimer(const TimerCallback &cb, 44 | const TimePoint &when, 45 | const TimeInterval &interval); 46 | TimerId addTimer(TimerCallback &&cb, 47 | const TimePoint &when, 48 | const TimeInterval &interval); 49 | void addTimerInLoop(const TimerPtr &timer); 50 | void invalidateTimer(TimerId id); 51 | #ifdef __linux__ 52 | void reset(); 53 | #else 54 | int64_t getTimeout() const; 55 | void processTimers(); 56 | #endif 57 | protected: 58 | EventLoop *loop_; 59 | #ifdef __linux__ 60 | int timerfd_; 61 | std::shared_ptr timerfdChannelPtr_; 62 | void handleRead(); 63 | #endif 64 | std::priority_queue, TimerPtrComparer> 65 | timers_; 66 | 67 | bool callingExpiredTimers_; 68 | bool insert(const TimerPtr &timePtr); 69 | std::vector getExpired(); 70 | void reset(const std::vector &expired, const TimePoint &now); 71 | std::vector getExpired(const TimePoint &now); 72 | 73 | private: 74 | std::unordered_set timerIdSet_; 75 | }; 76 | } // namespace trantor 77 | -------------------------------------------------------------------------------- /trantor/net/inner/poller/EpollPoller.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * EpollPoller.h 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include "../Poller.h" 18 | #include 19 | #include 20 | 21 | #if defined __linux__ || defined _WIN32 22 | #include 23 | #include 24 | using EventList = std::vector; 25 | #endif 26 | namespace trantor 27 | { 28 | class Channel; 29 | 30 | class EpollPoller : public Poller 31 | { 32 | public: 33 | explicit EpollPoller(EventLoop *loop); 34 | virtual ~EpollPoller(); 35 | virtual void poll(int timeoutMs, ChannelList *activeChannels) override; 36 | virtual void updateChannel(Channel *channel) override; 37 | virtual void removeChannel(Channel *channel) override; 38 | #ifdef _WIN32 39 | virtual void postEvent(uint64_t event) override; 40 | virtual void setEventCallback(const EventCallback &cb) override 41 | { 42 | eventCallback_ = cb; 43 | } 44 | #endif 45 | 46 | private: 47 | #if defined __linux__ || defined _WIN32 48 | static const int kInitEventListSize = 16; 49 | #ifdef _WIN32 50 | void *epollfd_; 51 | EventCallback eventCallback_{[](uint64_t event) {}}; 52 | #else 53 | int epollfd_; 54 | #endif 55 | EventList events_; 56 | void update(int operation, Channel *channel); 57 | #ifndef NDEBUG 58 | using ChannelMap = std::map; 59 | ChannelMap channels_; 60 | #endif 61 | void fillActiveChannels(int numEvents, ChannelList *activeChannels) const; 62 | #endif 63 | }; 64 | } // namespace trantor 65 | -------------------------------------------------------------------------------- /trantor/net/inner/poller/KQueue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * KQueue.h 4 | * An Tao 5 | * 6 | * Copyright 2018, An Tao. All rights reserved. 7 | * https://github.com/an-tao/trantor 8 | * Use of this source code is governed by a BSD-style license 9 | * that can be found in the License file. 10 | * 11 | * Trantor 12 | * 13 | */ 14 | 15 | #pragma once 16 | #include "../Poller.h" 17 | #include 18 | #include 19 | 20 | #if (defined(__unix__) && !defined(__linux__)) || \ 21 | (defined(__APPLE__) && defined(__MACH__)) 22 | #define USE_KQUEUE 23 | #include 24 | #include 25 | #include 26 | using EventList = std::vector; 27 | #endif 28 | namespace trantor 29 | { 30 | class Channel; 31 | 32 | class KQueue : public Poller 33 | { 34 | public: 35 | explicit KQueue(EventLoop *loop); 36 | virtual ~KQueue(); 37 | virtual void poll(int timeoutMs, ChannelList *activeChannels) override; 38 | virtual void updateChannel(Channel *channel) override; 39 | virtual void removeChannel(Channel *channel) override; 40 | virtual void resetAfterFork() override; 41 | 42 | private: 43 | #ifdef USE_KQUEUE 44 | static const int kInitEventListSize = 16; 45 | int kqfd_; 46 | EventList events_; 47 | using ChannelMap = std::unordered_map>; 48 | ChannelMap channels_; 49 | 50 | void fillActiveChannels(int numEvents, ChannelList *activeChannels) const; 51 | void update(Channel *channel); 52 | #endif 53 | }; 54 | 55 | } // namespace trantor 56 | -------------------------------------------------------------------------------- /trantor/net/inner/poller/PollPoller.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * PollPoller.h 4 | * Martin Chang 5 | * 6 | * Copyright 2021, An Tao. All rights reserved. 7 | * https://github.com/an-tao/trantor 8 | * Use of this source code is governed by a BSD-style license 9 | * that can be found in the License file. 10 | * 11 | * Trantor 12 | * 13 | */ 14 | #include "PollPoller.h" 15 | 16 | #include 17 | #include "trantor/net/Channel.h" 18 | 19 | #include 20 | 21 | using namespace trantor; 22 | 23 | #if defined __unix__ || defined __HAIKU__ 24 | 25 | #include 26 | #include 27 | static std::once_flag warning_flag; 28 | 29 | PollPoller::PollPoller(EventLoop* loop) : Poller(loop) 30 | { 31 | std::call_once(warning_flag, []() { 32 | LOG_WARN << "Creating a PollPoller. This poller is slow and should " 33 | "only be used when no other pollers are available"; 34 | }); 35 | } 36 | 37 | PollPoller::~PollPoller() 38 | { 39 | } 40 | 41 | void PollPoller::poll(int timeoutMs, ChannelList* activeChannels) 42 | { 43 | // XXX pollfds_ shouldn't change 44 | int numEvents = ::poll(pollfds_.data(), pollfds_.size(), timeoutMs); 45 | int savedErrno = errno; 46 | if (numEvents > 0) 47 | { 48 | // LOG_TRACE << numEvents << " events happened"; 49 | fillActiveChannels(numEvents, activeChannels); 50 | } 51 | else if (numEvents == 0) 52 | { 53 | // LOG_TRACE << " nothing happened"; 54 | } 55 | else 56 | { 57 | if (savedErrno != EINTR) 58 | { 59 | errno = savedErrno; 60 | LOG_SYSERR << "PollPoller::poll()"; 61 | } 62 | } 63 | } 64 | 65 | void PollPoller::fillActiveChannels(int numEvents, 66 | ChannelList* activeChannels) const 67 | { 68 | int processedEvents = 0; 69 | for (auto pfd : pollfds_) 70 | { 71 | if (pfd.revents > 0) 72 | { 73 | auto ch = channels_.find(pfd.fd); 74 | assert(ch != channels_.end()); 75 | Channel* channel = ch->second; 76 | assert(channel->fd() == pfd.fd); 77 | channel->setRevents(pfd.revents); 78 | // pfd.revents = 0; 79 | activeChannels->push_back(channel); 80 | 81 | processedEvents++; 82 | if (processedEvents == numEvents) 83 | break; 84 | } 85 | } 86 | assert(processedEvents == numEvents); 87 | } 88 | 89 | void PollPoller::updateChannel(Channel* channel) 90 | { 91 | Poller::assertInLoopThread(); 92 | assert(channel->fd() >= 0); 93 | 94 | // LOG_TRACE << "fd = " << channel->fd() << " events = " << 95 | // channel->events(); 96 | if (channel->index() < 0) 97 | { 98 | // a new one, add to pollfds_ 99 | assert(channels_.find(channel->fd()) == channels_.end()); 100 | pollfd pfd; 101 | pfd.fd = channel->fd(); 102 | pfd.events = static_cast(channel->events()); 103 | pfd.revents = 0; 104 | pollfds_.push_back(pfd); 105 | int idx = static_cast(pollfds_.size()) - 1; 106 | channel->setIndex(idx); 107 | channels_[pfd.fd] = channel; 108 | } 109 | else 110 | { 111 | // update existing one 112 | assert(channels_.find(channel->fd()) != channels_.end()); 113 | assert(channels_[channel->fd()] == channel); 114 | int idx = channel->index(); 115 | assert(0 <= idx && idx < static_cast(pollfds_.size())); 116 | pollfd& pfd = pollfds_[idx]; 117 | assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd() - 1); 118 | pfd.fd = channel->fd(); 119 | pfd.events = static_cast(channel->events()); 120 | pfd.revents = 0; 121 | if (channel->isNoneEvent()) 122 | { 123 | // ignore this pollfd 124 | pfd.fd = -channel->fd() - 1; 125 | } 126 | } 127 | } 128 | 129 | void PollPoller::removeChannel(Channel* channel) 130 | { 131 | Poller::assertInLoopThread(); 132 | // LOG_TRACE << "fd = " << channel->fd(); 133 | assert(channels_.find(channel->fd()) != channels_.end()); 134 | assert(channels_[channel->fd()] == channel); 135 | assert(channel->isNoneEvent()); 136 | int idx = channel->index(); 137 | assert(0 <= idx && idx < static_cast(pollfds_.size())); 138 | const pollfd& pfd = pollfds_[idx]; 139 | (void)pfd; 140 | assert(pfd.fd == -channel->fd() - 1 && pfd.events == channel->events()); 141 | size_t n = channels_.erase(channel->fd()); 142 | assert(n == 1); 143 | (void)n; 144 | if (size_t(idx) == pollfds_.size() - 1) 145 | { 146 | pollfds_.pop_back(); 147 | } 148 | else 149 | { 150 | int channelAtEnd = pollfds_.back().fd; 151 | iter_swap(pollfds_.begin() + idx, pollfds_.end() - 1); 152 | if (channelAtEnd < 0) 153 | { 154 | channelAtEnd = -channelAtEnd - 1; 155 | } 156 | channels_[channelAtEnd]->setIndex(idx); 157 | pollfds_.pop_back(); 158 | } 159 | } 160 | #else 161 | PollPoller::PollPoller(EventLoop *loop) : Poller(loop) 162 | { 163 | assert(false); 164 | } 165 | PollPoller::~PollPoller() 166 | { 167 | } 168 | void PollPoller::poll(int, ChannelList *) 169 | { 170 | } 171 | void PollPoller::updateChannel(Channel *) 172 | { 173 | } 174 | void PollPoller::removeChannel(Channel *) 175 | { 176 | } 177 | #endif 178 | -------------------------------------------------------------------------------- /trantor/net/inner/poller/PollPoller.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * PollPoller.h 4 | * Martin Chang 5 | * 6 | * Copyright 2021, An Tao. All rights reserved. 7 | * https://github.com/an-tao/trantor 8 | * Use of this source code is governed by a BSD-style license 9 | * that can be found in the License file. 10 | * 11 | * Trantor 12 | * 13 | */ 14 | #pragma once 15 | 16 | #include "../Poller.h" 17 | #include 18 | 19 | #if defined __unix__ || defined __HAIKU__ 20 | #include 21 | #endif 22 | 23 | namespace trantor 24 | { 25 | class PollPoller : public Poller 26 | { 27 | public: 28 | PollPoller(EventLoop* loop); 29 | ~PollPoller() override; 30 | 31 | void poll(int timeoutMs, ChannelList* activeChannels) override; 32 | void updateChannel(Channel* channel) override; 33 | void removeChannel(Channel* channel) override; 34 | 35 | private: 36 | void fillActiveChannels(int numEvents, ChannelList* activeChannels) const; 37 | 38 | #if defined __unix__ || defined __HAIKU__ 39 | std::vector pollfds_; 40 | std::map channels_; 41 | #endif 42 | }; 43 | 44 | } // namespace trantor 45 | -------------------------------------------------------------------------------- /trantor/tests/AsyncFileLoggerTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | int main() 6 | { 7 | trantor::AsyncFileLogger asyncFileLogger; 8 | asyncFileLogger.setFileName("async_test"); 9 | asyncFileLogger.startLogging(); 10 | trantor::Logger::setOutputFunction( 11 | [&](const char *msg, const uint64_t len) { 12 | asyncFileLogger.output(msg, len); 13 | }, 14 | [&]() { asyncFileLogger.flush(); }); 15 | asyncFileLogger.setFileSizeLimit(100000000); 16 | // LOG_DEBUG<<"debug log!"<<1; 17 | // LOG_TRACE<<"trace log!"<<2; 18 | // LOG_INFO<<"info log!"<<3; 19 | // LOG_WARN<<"warning log!"<<4; 20 | // if(1) 21 | // LOG_ERROR<<"error log!"<<5; 22 | // std::thread thread_([](){ 23 | // LOG_FATAL<<"fatal log!"<<6; 24 | // }); 25 | // 26 | // FILE *fp=fopen("/notexistfile","rb"); 27 | // if(fp==NULL) 28 | // { 29 | // LOG_SYSERR<<"syserr log!"<<7; 30 | // } 31 | 32 | int i = 0; 33 | while (i < 1000000) 34 | { 35 | ++i; 36 | if (i % 100 == 0) 37 | { 38 | LOG_ERROR << "this is the " << i << "th log"; 39 | continue; 40 | } 41 | LOG_INFO << "this is the " << i << "th log"; 42 | ++i; 43 | LOG_DEBUG << "this is the " << i << "th log"; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /trantor/tests/AsyncFileLoggerTest1.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std::chrono_literals; 8 | int main() 9 | { 10 | trantor::AsyncFileLogger asyncFileLogger; 11 | asyncFileLogger.setFileName("async_test"); 12 | asyncFileLogger.startLogging(); 13 | trantor::Logger::setOutputFunction( 14 | [&](const char *msg, const uint64_t len) { 15 | asyncFileLogger.output(msg, len); 16 | }, 17 | [&]() { asyncFileLogger.flush(); }); 18 | asyncFileLogger.setFileSizeLimit(100000000); 19 | int i = 0; 20 | while (i < 1000000) 21 | { 22 | ++i; 23 | if (i % 100 == 0) 24 | { 25 | LOG_ERROR << "this is the " << i << "th log"; 26 | continue; 27 | } 28 | LOG_INFO << "this is the " << i << "th log"; 29 | ++i; 30 | LOG_DEBUG << "this is the " << i << "th log"; 31 | std::this_thread::sleep_for(1s); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /trantor/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(ssl_server_test SSLServerTest.cc) 2 | add_executable(ssl_client_test SSLClientTest.cc) 3 | add_executable(serial_task_queue_test1 SerialTaskQueueTest1.cc) 4 | add_executable(serial_task_queue_test2 SerialTaskQueueTest2.cc) 5 | add_executable(timer_test TimerTest.cc) 6 | add_executable(timer_test1 TimerTest1.cc) 7 | add_executable(run_in_loop_test1 RunInLoopTest1.cc) 8 | add_executable(run_in_loop_test2 RunInLoopTest2.cc) 9 | add_executable(logger_test LoggerTest.cc) 10 | add_executable(async_file_logger_test AsyncFileLoggerTest.cc) 11 | add_executable(tcp_server_test TcpServerTest.cc) 12 | add_executable(concurrent_task_queue_test ConcurrentTaskQueueTest.cc) 13 | add_executable(tcp_client_test TcpClientTest.cc) 14 | add_executable(async_file_logger_test1 AsyncFileLoggerTest1.cc) 15 | add_executable(sendfile_test SendfileTest.cc) 16 | add_executable(sendstream_test SendstreamTest.cc) 17 | add_executable(timing_wheel_test TimingWheelTest.cc) 18 | add_executable(kickoff_test KickoffTest.cc) 19 | add_executable(dns_test DnsTest.cc) 20 | add_executable(run_on_quit_test RunOnQuitTest.cc) 21 | add_executable(path_conversion_test PathConversionTest.cc) 22 | add_executable(logger_macro_test LoggerMacroTest.cc) 23 | add_executable(delayed_ssl_server_test DelayedSSLServerTest.cc) 24 | add_executable(delayed_ssl_client_test DelayedSSLClientTest.cc) 25 | add_executable(tcp_asyncstream_server_test TcpAsyncStreamServerTest.cc) 26 | set(targets_list 27 | ssl_server_test 28 | ssl_client_test 29 | serial_task_queue_test1 30 | serial_task_queue_test2 31 | timer_test 32 | timer_test1 33 | run_in_loop_test1 34 | run_in_loop_test2 35 | logger_test 36 | async_file_logger_test 37 | tcp_server_test 38 | concurrent_task_queue_test 39 | tcp_client_test 40 | async_file_logger_test1 41 | sendfile_test 42 | sendstream_test 43 | timing_wheel_test 44 | kickoff_test 45 | dns_test 46 | run_on_quit_test 47 | path_conversion_test 48 | logger_macro_test 49 | delayed_ssl_server_test 50 | delayed_ssl_client_test 51 | tcp_asyncstream_server_test 52 | ) 53 | 54 | if(HAVE_SPDLOG) 55 | add_executable(spdlogger_test SpdLoggerTest.cc) 56 | list(APPEND targets_list spdlogger_test) 57 | endif(HAVE_SPDLOG) 58 | 59 | set_property(TARGET ${targets_list} PROPERTY CXX_STANDARD 14) 60 | set_property(TARGET ${targets_list} PROPERTY CXX_STANDARD_REQUIRED ON) 61 | set_property(TARGET ${targets_list} PROPERTY CXX_EXTENSIONS OFF) 62 | 63 | foreach(T ${targets_list}) 64 | target_link_libraries(${T} PRIVATE trantor) 65 | endforeach() 66 | -------------------------------------------------------------------------------- /trantor/tests/ConcurrentTaskQueueTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | using namespace std::chrono_literals; 10 | 11 | int main() 12 | { 13 | trantor::ConcurrentTaskQueue queue(5, "concurrT"); 14 | std::atomic_int sum; 15 | sum = 0; 16 | for (int i = 0; i < 4; ++i) 17 | { 18 | queue.runTaskInQueue([&sum]() { 19 | LOG_DEBUG << "add sum"; 20 | for (int i = 0; i < 10000; ++i) 21 | { 22 | ++sum; 23 | } 24 | }); 25 | } 26 | 27 | queue.runTaskInQueue([&sum]() { 28 | for (int i = 0; i < 20; ++i) 29 | { 30 | LOG_DEBUG << "sum=" << sum; 31 | std::this_thread::sleep_for(100us); 32 | } 33 | }); 34 | 35 | getc(stdin); 36 | LOG_DEBUG << "sum=" << sum; 37 | } 38 | -------------------------------------------------------------------------------- /trantor/tests/DelayedSSLClientTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace trantor; 8 | #define USE_IPV6 0 9 | int main() 10 | { 11 | trantor::Logger::setLogLevel(trantor::Logger::kTrace); 12 | LOG_DEBUG << "TcpClient class test!"; 13 | EventLoop loop; 14 | #if USE_IPV6 15 | InetAddress serverAddr("::1", 8888, true); 16 | #else 17 | InetAddress serverAddr("127.0.0.1", 8888); 18 | #endif 19 | std::shared_ptr client[10]; 20 | std::atomic_int connCount; 21 | connCount = 1; 22 | for (int i = 0; i < 1; ++i) 23 | { 24 | client[i] = std::make_shared(&loop, 25 | serverAddr, 26 | "tcpclienttest"); 27 | client[i]->setConnectionCallback( 28 | [i, &loop, &connCount](const TcpConnectionPtr &conn) { 29 | if (conn->connected()) 30 | { 31 | } 32 | else 33 | { 34 | LOG_DEBUG << i << " disconnected"; 35 | --connCount; 36 | if (connCount == 0) 37 | loop.quit(); 38 | } 39 | }); 40 | client[i]->setMessageCallback([](const TcpConnectionPtr &conn, 41 | MsgBuffer *buf) { 42 | auto msg = std::string(buf->peek(), buf->readableBytes()); 43 | 44 | LOG_INFO << msg; 45 | if (msg == "hello") 46 | { 47 | buf->retrieveAll(); 48 | auto policy = TLSPolicy::defaultClientPolicy(); 49 | policy->setValidate(false); 50 | conn->startEncryption( 51 | policy, false, [](const TcpConnectionPtr &encryptedConn) { 52 | LOG_INFO << "SSL established"; 53 | encryptedConn->send("Hello"); 54 | }); 55 | } 56 | if (conn->isSSLConnection()) 57 | { 58 | buf->retrieveAll(); 59 | } 60 | }); 61 | client[i]->connect(); 62 | } 63 | loop.loop(); 64 | } 65 | -------------------------------------------------------------------------------- /trantor/tests/DelayedSSLServerTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace trantor; 7 | #define USE_IPV6 0 8 | int main() 9 | { 10 | LOG_DEBUG << "test start"; 11 | Logger::setLogLevel(Logger::kTrace); 12 | EventLoopThread loopThread; 13 | loopThread.run(); 14 | #if USE_IPV6 15 | InetAddress addr(8888, true, true); 16 | #else 17 | InetAddress addr(8888); 18 | #endif 19 | TcpServer server(loopThread.getLoop(), addr, "test"); 20 | // auto ctx = newSSLServerContext("server.pem", "server.pem", {}); 21 | LOG_INFO << "start"; 22 | server.setRecvMessageCallback( 23 | [](const TcpConnectionPtr &connectionPtr, MsgBuffer *buffer) { 24 | LOG_DEBUG << std::string{buffer->peek(), buffer->readableBytes()}; 25 | connectionPtr->send(*buffer); 26 | buffer->retrieveAll(); 27 | connectionPtr->shutdown(); 28 | }); 29 | server.setConnectionCallback([](const TcpConnectionPtr &connPtr) { 30 | if (connPtr->connected()) 31 | { 32 | LOG_DEBUG << "New connection"; 33 | connPtr->send("hello"); 34 | auto policy = 35 | TLSPolicy::defaultServerPolicy("server.crt", "server.key"); 36 | connPtr->startEncryption(policy, true); 37 | } 38 | else if (connPtr->disconnected()) 39 | { 40 | LOG_DEBUG << "connection disconnected"; 41 | } 42 | }); 43 | server.setIoLoopNum(3); 44 | server.start(); 45 | loopThread.wait(); 46 | } 47 | -------------------------------------------------------------------------------- /trantor/tests/DnsTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | void dns(const std::shared_ptr &resolver) 4 | { 5 | auto now = trantor::Date::now(); 6 | resolver->resolve("www.baidu.com", [now](const trantor::InetAddress &addr) { 7 | auto interval = trantor::Date::now().microSecondsSinceEpoch() - 8 | now.microSecondsSinceEpoch(); 9 | std::cout << "baidu:" << addr.toIp() << " " << interval / 1000 << "ms" 10 | << std::endl; 11 | }); 12 | resolver->resolve("www.baidu.com", 13 | [now](const std::vector &addrs) { 14 | auto interval = 15 | trantor::Date::now().microSecondsSinceEpoch() - 16 | now.microSecondsSinceEpoch(); 17 | for (auto &addr : addrs) 18 | std::cout << "baidu:" << addr.toIp() << " " 19 | << interval / 1000 << "ms" << std::endl; 20 | }); 21 | resolver->resolve("www.google.com", 22 | [now](const trantor::InetAddress &addr) { 23 | auto interval = 24 | trantor::Date::now().microSecondsSinceEpoch() - 25 | now.microSecondsSinceEpoch(); 26 | std::cout << "google:" << addr.toIp() << " " 27 | << interval / 1000 << "ms" << std::endl; 28 | }); 29 | resolver->resolve("www.sina.com", [now](const trantor::InetAddress &addr) { 30 | auto interval = trantor::Date::now().microSecondsSinceEpoch() - 31 | now.microSecondsSinceEpoch(); 32 | std::cout << "sina:" << addr.toIp() << " " << interval / 1000 << "ms" 33 | << std::endl; 34 | }); 35 | resolver->resolve("www.xjfisfjaskfeiakdjfg.com", 36 | [now](const trantor::InetAddress &addr) { 37 | auto interval = 38 | trantor::Date::now().microSecondsSinceEpoch() - 39 | now.microSecondsSinceEpoch(); 40 | std::cout << "bad address:" << addr.toIp() << " " 41 | << interval / 1000 << "ms" << std::endl; 42 | }); 43 | resolver->resolve("localhost", [now](const trantor::InetAddress &addr) { 44 | auto interval = trantor::Date::now().microSecondsSinceEpoch() - 45 | now.microSecondsSinceEpoch(); 46 | std::cout << "localhost:" << addr.toIp() << " " << interval / 1000 47 | << "ms" << std::endl; 48 | }); 49 | } 50 | int main() 51 | { 52 | trantor::EventLoop loop; 53 | auto resolver = trantor::Resolver::newResolver(&loop); 54 | dns(resolver); 55 | loop.runAfter(1.0, [resolver]() { dns(resolver); }); 56 | loop.loop(); 57 | } 58 | -------------------------------------------------------------------------------- /trantor/tests/KickoffTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace trantor; 7 | #define USE_IPV6 0 8 | int main() 9 | { 10 | LOG_DEBUG << "test start"; 11 | Logger::setLogLevel(Logger::kTrace); 12 | EventLoop loop; 13 | #if USE_IPV6 14 | InetAddress addr(8888, true, true); 15 | #else 16 | InetAddress addr(8888); 17 | #endif 18 | TcpServer server(&loop, addr, "test"); 19 | server.kickoffIdleConnections(10); 20 | server.setRecvMessageCallback( 21 | [](const TcpConnectionPtr &connectionPtr, MsgBuffer *buffer) { 22 | // LOG_DEBUG<<"recv callback!"; 23 | std::cout << std::string(buffer->peek(), buffer->readableBytes()); 24 | connectionPtr->send(buffer->peek(), buffer->readableBytes()); 25 | buffer->retrieveAll(); 26 | }); 27 | int n = 0; 28 | server.setConnectionCallback([&n](const TcpConnectionPtr &connPtr) { 29 | if (connPtr->connected()) 30 | { 31 | ++n; 32 | if (n % 2 == 0) 33 | { 34 | connPtr->keepAlive(); 35 | } 36 | LOG_DEBUG << "New connection"; 37 | } 38 | else if (connPtr->disconnected()) 39 | { 40 | LOG_DEBUG << "connection disconnected"; 41 | } 42 | }); 43 | server.setIoLoopNum(3); 44 | server.start(); 45 | loop.loop(); 46 | } 47 | -------------------------------------------------------------------------------- /trantor/tests/LoggerMacroTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace trantor; 4 | 5 | int main() 6 | { 7 | trantor::Logger::setLogLevel(trantor::Logger::kInfo); 8 | if (0) 9 | LOG_INFO << "dummy"; 10 | else 11 | LOG_WARN << "it works"; 12 | } -------------------------------------------------------------------------------- /trantor/tests/MTLSClient.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * # Generate CA file 4 | * openssl req -new -x509 -days 365 -keyout ca-key.pem -out ca-crt.pem 5 | * 6 | * # Generate Key File (ie: same for client and server, but you can create one 7 | * for each one) openssl genrsa -out server-key.pem 4096 8 | * 9 | * # Generate Server certificate: 10 | * openssl req -new -sha256 -key server-key.pem -out ca-csr.pem 11 | * openssl x509 -req -days 365 -in ca-csr.pem -CA ca-crt.pem -CAkey ca-key.pem 12 | * -CAcreateserial -out server-crt.pem openssl verify -CAfile ca-crt.pem 13 | * server-crt.pem 14 | * 15 | * 16 | * # For client (to specify a certificate client mode only - no domain): 17 | * # Create file client_cert_ext.cnf: 18 | * cat client_cert_ext.cnf 19 | * 20 | * keyUsage = critical, digitalSignature, keyEncipherment 21 | * extendedKeyUsage = clientAuth 22 | * basicConstraints = critical, CA:FALSE 23 | * authorityKeyIdentifier = keyid,issuer 24 | * subjectAltName = DNS:Client 25 | * 26 | * Create client cert (using the same serve key and CA) 27 | * openssl x509 -req -in ca-csr.pem -days 1000 -CA ca-crt.pem -CAkey ca-key.pem 28 | * -set_serial 01 -extfile client_cert_ext.cnf > client-crt.pem 29 | * 30 | * openssl verify -CAfile ca-crt.pem client-crt.pem 31 | * openssl x509 -in client-crt.pem -text -noout -purpose 32 | * 33 | * # Compile sample: 34 | * 35 | * g++ -o MTLSClient MTLSClient.cc -ltrantor -lssl -lcrypto -lpthread 36 | * 37 | * # Tests 38 | * 39 | * # Listen generic SSL server 40 | * openssl s_server -accept 8888 -CAfile ./ca-crt.pem -cert ./server-crt.pem 41 | * -key ./server-key.pem -state 42 | * 43 | * # Listen generic SSL server with mTLS verification 44 | * openssl s_server -accept 8888 -CAfile ./ca-crt.pem -cert ./server-crt.pem 45 | * -key ./server-key.pem -state -verify_return_error -Verify 1 46 | * 47 | * # Test the mTLS client bin 48 | * ./MTLSClient 49 | * 50 | * **/ 51 | 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | using namespace trantor; 59 | #define USE_IPV6 0 60 | int main() 61 | { 62 | trantor::Logger::setLogLevel(trantor::Logger::kTrace); 63 | LOG_DEBUG << "TcpClient class test!"; 64 | EventLoop loop; 65 | #if USE_IPV6 66 | InetAddress serverAddr("::1", 8888, true); 67 | #else 68 | InetAddress serverAddr("127.0.0.1", 8888); 69 | #endif 70 | std::shared_ptr client[10]; 71 | std::atomic_int connCount; 72 | connCount = 1; 73 | for (int i = 0; i < connCount; ++i) 74 | { 75 | client[i] = std::make_shared(&loop, 76 | serverAddr, 77 | "tcpclienttest"); 78 | std::vector> sslcmd = {}; 79 | // That key is common for client and server 80 | // The CA file must be the client CA, for this sample the CA is common 81 | // for both 82 | auto policy = TLSPolicy::defaultClientPolicy(); 83 | policy->setCertPath("./client-crt.pem") 84 | .setKeyPath("./server-key.pem") 85 | .setCaPath("./ca-crt.pem") 86 | .setHostname("localhost"); 87 | client[i]->enableSSL(policy); 88 | client[i]->setConnectionCallback( 89 | [i, &loop, &connCount](const TcpConnectionPtr &conn) { 90 | if (conn->connected()) 91 | { 92 | LOG_DEBUG << i << " connected!"; 93 | char tmp[20]; 94 | sprintf(tmp, "%d client!!", i); 95 | conn->send(tmp); 96 | } 97 | else 98 | { 99 | LOG_DEBUG << i << " disconnected"; 100 | --connCount; 101 | if (connCount == 0) 102 | loop.quit(); 103 | } 104 | }); 105 | client[i]->setMessageCallback( 106 | [](const TcpConnectionPtr &conn, MsgBuffer *buf) { 107 | LOG_DEBUG << std::string(buf->peek(), buf->readableBytes()); 108 | buf->retrieveAll(); 109 | conn->shutdown(); 110 | }); 111 | client[i]->connect(); 112 | } 113 | loop.loop(); 114 | } 115 | -------------------------------------------------------------------------------- /trantor/tests/MTLSServer.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * # Generate CA file 4 | * openssl req -new -x509 -days 365 -keyout ca-key.pem -out ca-crt.pem 5 | * 6 | * # Generate Key File (ie: same for client and server, but you can create one 7 | * for each one) openssl genrsa -out server-key.pem 4096 8 | * 9 | * # Generate Server certificate: 10 | * openssl req -new -sha256 -key server-key.pem -out ca-csr.pem 11 | * openssl x509 -req -days 365 -in ca-csr.pem -CA ca-crt.pem -CAkey ca-key.pem 12 | * -CAcreateserial -out server-crt.pem openssl verify -CAfile ca-crt.pem 13 | * server-crt.pem 14 | * 15 | * 16 | * # For client (to specify a certificate client mode only - no domain): 17 | * # Create file client_cert_ext.cnf: 18 | * cat client_cert_ext.cnf 19 | * 20 | * keyUsage = critical, digitalSignature, keyEncipherment 21 | * extendedKeyUsage = clientAuth 22 | * basicConstraints = critical, CA:FALSE 23 | * authorityKeyIdentifier = keyid,issuer 24 | * subjectAltName = DNS:Client 25 | * 26 | * Create client cert (using the same serve key and CA) 27 | * openssl x509 -req -in ca-csr.pem -days 1000 -CA ca-crt.pem -CAkey ca-key.pem 28 | * -set_serial 01 -extfile client_cert_ext.cnf > client-crt.pem 29 | * 30 | * openssl verify -CAfile ca-crt.pem client-crt.pem 31 | * openssl x509 -in client-crt.pem -text -noout -purpose 32 | * 33 | * # Compile sample: 34 | * 35 | * g++ -o MTLSServer MTLSServer.cc -ltrantor -lssl -lcrypto -lpthread 36 | * 37 | * # Tests 38 | * 39 | * # Should Fail 40 | * openssl s_client -connect 0.0.0.0:8888 -state 41 | * 42 | * # Should Connect (the CA file must be the server CA), for this sample the CA 43 | * is common for both openssl s_client -connect 0.0.0.0:8888 -key 44 | * ./server-key.pem -cert ./server-crt.pem -CAfile ./ca-crt.pem -state 45 | * 46 | * **/ 47 | 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | using namespace trantor; 54 | #define USE_IPV6 0 55 | int main() 56 | { 57 | LOG_DEBUG << "test start"; 58 | Logger::setLogLevel(Logger::kTrace); 59 | EventLoopThread loopThread; 60 | loopThread.run(); 61 | #if USE_IPV6 62 | InetAddress addr(8888, true, true); 63 | #else 64 | InetAddress addr(8888); 65 | #endif 66 | TcpServer server(loopThread.getLoop(), addr, "test"); 67 | std::vector> sslcmd = {}; 68 | 69 | // the CA file must be the client CA, for this sample the CA is common for 70 | // both 71 | auto policy = 72 | TLSPolicy::defaultServerPolicy("server-crt.pem", "server-key.pem"); 73 | policy->setCaPath("ca-crt.pem") 74 | .setValidateChain(true) 75 | .setValidateDate(true) 76 | .setValidateDomain(false); // client's don't have a domain name 77 | server.enableSSL(policy); 78 | server.setRecvMessageCallback( 79 | [](const TcpConnectionPtr &connectionPtr, MsgBuffer *buffer) { 80 | // LOG_DEBUG<<"recv callback!"; 81 | std::cout << std::string(buffer->peek(), buffer->readableBytes()); 82 | connectionPtr->send(buffer->peek(), buffer->readableBytes()); 83 | buffer->retrieveAll(); 84 | connectionPtr->forceClose(); 85 | }); 86 | server.setConnectionCallback([](const TcpConnectionPtr &connPtr) { 87 | if (connPtr->connected()) 88 | { 89 | LOG_DEBUG << "New connection"; 90 | connPtr->send("Hello world\r\n"); 91 | } 92 | else if (connPtr->disconnected()) 93 | { 94 | LOG_DEBUG << "connection disconnected"; 95 | } 96 | }); 97 | server.setIoLoopNum(3); 98 | server.start(); 99 | loopThread.wait(); 100 | } 101 | -------------------------------------------------------------------------------- /trantor/tests/PathConversionTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | trantor::Logger::setLogLevel(trantor::Logger::kTrace); 8 | LOG_DEBUG << "PathConversion utils test!"; 9 | 10 | #ifdef _WIN32 11 | std::string utf8PathStandard("C:/Temp/\xE4\xB8\xAD\xE6\x96\x87"); 12 | std::string utf8PathAlt("C:\\Temp\\\xE4\xB8\xAD\xE6\x96\x87"); 13 | std::wstring widePathStandard(L"C:\\Temp\\\u4E2D\u6587"); 14 | std::wstring widePathAlt(L"C:/Temp/\u4E2D\u6587"); 15 | std::string utf8WidePathStandard{utf8PathAlt}; 16 | std::string utf8WidePathAlt{utf8PathStandard}; 17 | #else // _WIN32 18 | std::string utf8PathStandard("/tmp/\xE4\xB8\xAD\xE6\x96\x87"); 19 | std::string utf8PathAlt( 20 | "\\tmp\\\xE4\xB8\xAD\xE6\x96\x87"); // Invalid, won't be changed 21 | std::wstring widePathStandard(L"/tmp/\u4E2D\u6587"); 22 | std::wstring widePathAlt(L"\\tmp\\\u4E2D\u6587"); 23 | std::string utf8WidePathStandard{utf8PathStandard}; 24 | std::string utf8WidePathAlt{utf8PathAlt}; 25 | #endif // _WIN32 26 | 27 | // 1. Check from/to UTF-8 28 | #ifdef _WIN32 29 | if (utf8PathAlt != trantor::utils::toUtf8(widePathStandard)) 30 | #else // _WIN32 31 | if (utf8PathStandard != trantor::utils::toUtf8(widePathStandard)) 32 | #endif // _WIN32 33 | LOG_ERROR << "Error converting " << utf8WidePathStandard 34 | << " from wide string to utf-8"; 35 | #ifdef _WIN32 36 | if (utf8PathStandard != trantor::utils::toUtf8(widePathAlt)) 37 | #else // _WIN32 38 | if (utf8PathAlt != trantor::utils::toUtf8(widePathAlt)) 39 | #endif // _WIN32 40 | LOG_ERROR << "Error converting " << utf8WidePathAlt 41 | << " from wide string to utf-8"; 42 | #ifdef _WIN32 43 | if (widePathAlt != trantor::utils::fromUtf8(utf8PathStandard)) 44 | #else // _WIN32 45 | if (widePathStandard != trantor::utils::fromUtf8(utf8PathStandard)) 46 | #endif // _WIN32 47 | LOG_ERROR << "Error converting " << utf8PathStandard 48 | << " from utf-8 to wide string"; 49 | #ifdef _WIN32 50 | if (widePathStandard != trantor::utils::fromUtf8(utf8PathAlt)) 51 | #else // _WIN32 52 | if (widePathAlt != trantor::utils::fromUtf8(utf8PathAlt)) 53 | #endif // _WIN32 54 | LOG_ERROR << "Error converting " << utf8PathAlt 55 | << " from utf-8 to wide string"; 56 | 57 | // 2. Check path conversion. Note: The directory separator should be changed 58 | // on Windows only 59 | if (utf8PathStandard != trantor::utils::fromWidePath(widePathStandard)) 60 | LOG_ERROR << "Error converting " << utf8WidePathStandard 61 | << " from wide path to utf-8"; 62 | #ifdef _WIN32 63 | if (utf8PathStandard != trantor::utils::fromWidePath(widePathAlt)) 64 | #else // _WIN32 65 | if (utf8PathAlt != trantor::utils::fromWidePath(widePathAlt)) 66 | #endif // _WIN32 67 | LOG_ERROR << "Error converting " << utf8WidePathAlt 68 | << " from wide path to utf-8"; 69 | if (widePathStandard != trantor::utils::toWidePath(utf8PathStandard)) 70 | LOG_ERROR << "Error converting " << utf8WidePathStandard 71 | << " from utf-8 to wide path"; 72 | #ifdef _WIN32 73 | if (widePathStandard != trantor::utils::toWidePath(utf8PathAlt)) 74 | #else // _WIN32 75 | if (widePathAlt != trantor::utils::toWidePath(utf8PathAlt)) 76 | #endif // _WIN32 77 | LOG_ERROR << "Error converting " << utf8PathAlt 78 | << " from utf-8 to wide path"; 79 | 80 | // 3. From/to native path 81 | auto nativePath1 = trantor::utils::toNativePath(widePathStandard); 82 | auto nativePath2 = trantor::utils::toNativePath(utf8PathStandard); 83 | if (nativePath1 != nativePath2) 84 | LOG_ERROR << "Error converting " << utf8PathStandard 85 | << " to native path"; 86 | if (utf8PathStandard != trantor::utils::fromNativePath(nativePath1)) 87 | LOG_ERROR << "Error converting " << utf8PathStandard 88 | << " from native to utf-8 path"; 89 | } 90 | -------------------------------------------------------------------------------- /trantor/tests/RunInLoopTest1.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Created by antao on 1/14/17. 3 | // 4 | 5 | #include 6 | #ifndef _WIN32 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | #include 13 | using namespace std::chrono_literals; 14 | int main() 15 | { 16 | trantor::EventLoop loop; 17 | std::thread thread([&loop]() { 18 | std::this_thread::sleep_for(3s); 19 | loop.runInLoop([&loop]() { 20 | std::cout << "runInLoop called in other thread" << std::endl; 21 | loop.queueInLoop( 22 | []() { std::cout << "queueInLoop in runInLoop" << std::endl; }); 23 | }); 24 | }); 25 | loop.runInLoop([]() { std::cout << "runInLoop 1" << std::endl; }); 26 | loop.runInLoop([]() { std::cout << "runInLoop 2" << std::endl; }); 27 | loop.queueInLoop([]() { std::cout << "queueInLoop 1" << std::endl; }); 28 | loop.runAfter(1.5, []() { std::cout << "run after 1.5" << std::endl; }); 29 | loop.loop(); 30 | } 31 | -------------------------------------------------------------------------------- /trantor/tests/RunInLoopTest2.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #ifndef _WIN32 6 | #include 7 | #endif 8 | 9 | int main() 10 | { 11 | // Local variable to be used within the loopThread 12 | uint64_t counter = 0; 13 | std::promise pro; 14 | auto ft = pro.get_future(); 15 | trantor::EventLoopThread loopThread; 16 | 17 | auto loop = loopThread.getLoop(); 18 | loop->runInLoop([&counter, &pro, loop]() { 19 | for (int i = 0; i < 10000; ++i) 20 | { 21 | loop->queueInLoop([&counter, &pro]() { 22 | ++counter; 23 | if (counter == 110000) 24 | pro.set_value(1); 25 | }); 26 | } 27 | }); 28 | for (int i = 0; i < 10; ++i) 29 | { 30 | std::thread([&counter, loop, &pro]() { 31 | for (int i = 0; i < 10000; ++i) 32 | { 33 | loop->runInLoop([&counter, &pro]() { 34 | ++counter; 35 | if (counter == 110000) 36 | pro.set_value(1); 37 | }); 38 | } 39 | }).detach(); 40 | } 41 | loopThread.run(); 42 | ft.get(); 43 | std::cout << "counter=" << counter << std::endl; 44 | } 45 | -------------------------------------------------------------------------------- /trantor/tests/RunOnQuitTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #ifndef _WIN32 6 | #include 7 | #endif 8 | 9 | int main() 10 | { 11 | std::atomic flag(false); 12 | { 13 | trantor::EventLoopThread thr; 14 | thr.getLoop()->runOnQuit([&]() { flag = true; }); 15 | thr.run(); 16 | thr.getLoop()->quit(); 17 | } 18 | 19 | if (flag == false) 20 | { 21 | std::cerr << "Test failed\n"; 22 | } 23 | else 24 | { 25 | std::cout << "Success\n"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /trantor/tests/SSLClientTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace trantor; 8 | #define USE_IPV6 0 9 | int main() 10 | { 11 | trantor::Logger::setLogLevel(trantor::Logger::kTrace); 12 | LOG_DEBUG << "TcpClient class test!"; 13 | EventLoop loop; 14 | #if USE_IPV6 15 | InetAddress serverAddr("::1", 8888, true); 16 | #else 17 | InetAddress serverAddr("127.0.0.1", 8888); 18 | #endif 19 | std::shared_ptr client[10]; 20 | std::atomic_int connCount; 21 | connCount = 1; 22 | for (int i = 0; i < connCount; ++i) 23 | { 24 | client[i] = std::make_shared(&loop, 25 | serverAddr, 26 | "tcpclienttest"); 27 | auto policy = TLSPolicy::defaultClientPolicy(); 28 | policy->setValidate(false); 29 | client[i]->enableSSL(std::move(policy)); 30 | client[i]->setConnectionCallback( 31 | [i, &loop, &connCount](const TcpConnectionPtr &conn) { 32 | if (conn->connected()) 33 | { 34 | LOG_DEBUG << i << " connected!"; 35 | conn->send(std::to_string(i) + " client!!"); 36 | } 37 | else 38 | { 39 | LOG_DEBUG << i << " disconnected"; 40 | --connCount; 41 | if (connCount == 0) 42 | loop.quit(); 43 | } 44 | }); 45 | client[i]->setMessageCallback( 46 | [](const TcpConnectionPtr &conn, MsgBuffer *buf) { 47 | LOG_DEBUG << std::string(buf->peek(), buf->readableBytes()); 48 | buf->retrieveAll(); 49 | conn->shutdown(); 50 | }); 51 | client[i]->connect(); 52 | } 53 | loop.loop(); 54 | } 55 | -------------------------------------------------------------------------------- /trantor/tests/SSLServerTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace trantor; 7 | #define USE_IPV6 0 8 | int main() 9 | { 10 | LOG_DEBUG << "test start"; 11 | Logger::setLogLevel(Logger::kTrace); 12 | EventLoopThread loopThread; 13 | loopThread.run(); 14 | #if USE_IPV6 15 | InetAddress addr(8888, true, true); 16 | #else 17 | InetAddress addr(8888); 18 | #endif 19 | TcpServer server(loopThread.getLoop(), addr, "test"); 20 | auto policy = TLSPolicy::defaultServerPolicy("server.crt", "server.key"); 21 | server.enableSSL(std::move(policy)); 22 | server.setRecvMessageCallback( 23 | [](const TcpConnectionPtr &connectionPtr, MsgBuffer *buffer) { 24 | // LOG_DEBUG<<"recv callback!"; 25 | std::cout << std::string(buffer->peek(), buffer->readableBytes()); 26 | connectionPtr->send(buffer->peek(), buffer->readableBytes()); 27 | buffer->retrieveAll(); 28 | // connectionPtr->forceClose(); 29 | }); 30 | server.setConnectionCallback([](const TcpConnectionPtr &connPtr) { 31 | if (connPtr->connected()) 32 | { 33 | LOG_DEBUG << "New connection"; 34 | connPtr->send("Hello world\r\n"); 35 | } 36 | else if (connPtr->disconnected()) 37 | { 38 | LOG_DEBUG << "connection disconnected"; 39 | } 40 | }); 41 | server.setIoLoopNum(3); 42 | server.start(); 43 | loopThread.wait(); 44 | } 45 | -------------------------------------------------------------------------------- /trantor/tests/SendfileTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #ifndef _WIN32 10 | #include 11 | #endif 12 | 13 | using namespace trantor; 14 | #define USE_IPV6 0 15 | int main(int argc, char *argv[]) 16 | { 17 | if (argc < 2) 18 | { 19 | std::cout << "usage:" << argv[0] << " filename" << std::endl; 20 | return 1; 21 | } 22 | std::cout << "filename:" << argv[1] << std::endl; 23 | struct stat filestat; 24 | if (stat(argv[1], &filestat) < 0) 25 | { 26 | perror(""); 27 | exit(1); 28 | } 29 | std::cout << "file len=" << filestat.st_size << std::endl; 30 | 31 | auto fp = fopen(argv[1], "rb"); 32 | 33 | if (fp == nullptr) 34 | { 35 | perror(""); 36 | exit(1); 37 | } 38 | fclose(fp); 39 | 40 | LOG_DEBUG << "test start"; 41 | 42 | Logger::setLogLevel(Logger::kTrace); 43 | EventLoopThread loopThread; 44 | loopThread.run(); 45 | 46 | #if USE_IPV6 47 | InetAddress addr(1207, true, true); 48 | #else 49 | InetAddress addr(1207); 50 | #endif 51 | TcpServer server(loopThread.getLoop(), addr, "test"); 52 | server.setRecvMessageCallback( 53 | [](const TcpConnectionPtr &connectionPtr, MsgBuffer *buffer) { 54 | // LOG_DEBUG<<"recv callback!"; 55 | }); 56 | int counter = 0; 57 | server.setConnectionCallback( 58 | [argv, &counter](const TcpConnectionPtr &connPtr) { 59 | if (connPtr->connected()) 60 | { 61 | LOG_DEBUG << "New connection"; 62 | std::thread t([connPtr, argv, &counter]() { 63 | for (int i = 0; i < 5; ++i) 64 | { 65 | connPtr->sendFile(argv[1]); 66 | ++counter; 67 | std::string str = 68 | "\n" + std::to_string(counter) + " files sent!\n"; 69 | connPtr->send(std::move(str)); 70 | } 71 | }); 72 | t.detach(); 73 | 74 | for (int i = 0; i < 3; ++i) 75 | { 76 | connPtr->sendFile(argv[1]); 77 | ++counter; 78 | std::string str = 79 | "\n" + std::to_string(counter) + " files sent!\n"; 80 | connPtr->send(std::move(str)); 81 | } 82 | } 83 | else if (connPtr->disconnected()) 84 | { 85 | LOG_DEBUG << "connection disconnected"; 86 | } 87 | }); 88 | server.setIoLoopNum(3); 89 | server.start(); 90 | loopThread.wait(); 91 | } 92 | -------------------------------------------------------------------------------- /trantor/tests/SendstreamTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #ifndef _WIN32 10 | #include 11 | #else 12 | #include 13 | #endif 14 | 15 | std::size_t fileCallback(const std::string &, int, char *, std::size_t); 16 | 17 | using namespace trantor; 18 | #define USE_IPV6 0 19 | int main(int argc, char *argv[]) 20 | { 21 | if (argc < 2) 22 | { 23 | std::cout << "usage:" << argv[0] << " filename" << std::endl; 24 | return 1; 25 | } 26 | std::cout << "filename:" << argv[1] << std::endl; 27 | struct stat filestat; 28 | if (stat(argv[1], &filestat) < 0) 29 | { 30 | perror(""); 31 | exit(1); 32 | } 33 | std::cout << "file len=" << filestat.st_size << std::endl; 34 | 35 | auto fp = fopen(argv[1], "rb"); 36 | 37 | if (fp == nullptr) 38 | { 39 | perror(""); 40 | exit(1); 41 | } 42 | fclose(fp); 43 | 44 | LOG_DEBUG << "test start"; 45 | 46 | Logger::setLogLevel(Logger::kTrace); 47 | EventLoopThread loopThread; 48 | loopThread.run(); 49 | 50 | #if USE_IPV6 51 | InetAddress addr(1207, true, true); 52 | #else 53 | InetAddress addr(1207); 54 | #endif 55 | TcpServer server(loopThread.getLoop(), addr, "test"); 56 | server.setRecvMessageCallback( 57 | [](const TcpConnectionPtr &connectionPtr, MsgBuffer *buffer) { 58 | // LOG_DEBUG<<"recv callback!"; 59 | }); 60 | int counter = 0; 61 | server.setConnectionCallback([argv, 62 | &counter](const TcpConnectionPtr &connPtr) { 63 | if (connPtr->connected()) 64 | { 65 | LOG_DEBUG << "New connection"; 66 | std::thread t([connPtr, argv, &counter]() { 67 | for (int i = 0; i < 5; ++i) 68 | { 69 | int fd; 70 | #ifdef _WIN32 71 | _sopen_s( 72 | &fd, argv[1], _O_BINARY | _O_RDONLY, _SH_DENYNO, 0); 73 | #else 74 | fd = open(argv[1], O_RDONLY); 75 | #endif 76 | auto callback = std::bind(fileCallback, 77 | argv[1], 78 | fd, 79 | std::placeholders::_1, 80 | std::placeholders::_2); 81 | connPtr->sendStream(callback); 82 | ++counter; 83 | std::string str = 84 | "\n" + std::to_string(counter) + " streams sent!\n"; 85 | connPtr->send(std::move(str)); 86 | } 87 | }); 88 | t.detach(); 89 | 90 | for (int i = 0; i < 3; ++i) 91 | { 92 | int fd; 93 | #ifdef _WIN32 94 | _sopen_s(&fd, argv[1], _O_BINARY | _O_RDONLY, _SH_DENYNO, 0); 95 | #else 96 | fd = open(argv[1], O_RDONLY); 97 | #endif 98 | auto callback = std::bind(fileCallback, 99 | argv[1], 100 | fd, 101 | std::placeholders::_1, 102 | std::placeholders::_2); 103 | connPtr->sendStream(callback); 104 | ++counter; 105 | std::string str = 106 | "\n" + std::to_string(counter) + " streams sent!\n"; 107 | connPtr->send(std::move(str)); 108 | } 109 | } 110 | else if (connPtr->disconnected()) 111 | { 112 | LOG_DEBUG << "connection disconnected"; 113 | } 114 | }); 115 | server.setIoLoopNum(3); 116 | server.start(); 117 | loopThread.wait(); 118 | return 0; 119 | } 120 | 121 | std::size_t fileCallback(const std::string &strFile, 122 | int nFd, 123 | char *pBuffer, 124 | std::size_t nBuffSize) 125 | { 126 | if (nFd < 0) 127 | return 0; 128 | if (pBuffer == nullptr) 129 | { 130 | LOG_DEBUG << strFile.c_str() << " closed."; 131 | #ifdef _WIN32 132 | _close(nFd); 133 | #else 134 | close(nFd); 135 | #endif 136 | return 0; 137 | } 138 | #ifdef _WIN32 139 | int nRead = _read(nFd, pBuffer, (unsigned int)nBuffSize); 140 | #else 141 | ssize_t nRead = read(nFd, pBuffer, nBuffSize); 142 | #endif 143 | if (nRead < 0) 144 | return 0; 145 | return std::size_t(nRead); 146 | } 147 | -------------------------------------------------------------------------------- /trantor/tests/SerialTaskQueueTest1.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std::chrono_literals; 8 | int main() 9 | { 10 | trantor::Logger::setLogLevel(trantor::Logger::kTrace); 11 | trantor::SerialTaskQueue queue1("test queue1"); 12 | trantor::SerialTaskQueue queue2(""); 13 | queue1.runTaskInQueue([&]() { 14 | for (int i = 0; i < 5; ++i) 15 | { 16 | std::this_thread::sleep_for(1s); 17 | printf("task(%s) i=%d\n", queue1.getName().c_str(), i); 18 | } 19 | }); 20 | queue2.runTaskInQueue([&]() { 21 | for (int i = 0; i < 5; ++i) 22 | { 23 | std::this_thread::sleep_for(1s); 24 | printf("task(%s) i=%d\n", queue2.getName().c_str(), i); 25 | } 26 | }); 27 | queue1.waitAllTasksFinished(); 28 | queue2.waitAllTasksFinished(); 29 | } 30 | -------------------------------------------------------------------------------- /trantor/tests/SerialTaskQueueTest2.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #ifndef _WIN32 6 | #include 7 | #endif 8 | 9 | int main() 10 | { 11 | std::atomic counter; 12 | counter = 0; 13 | std::promise pro; 14 | auto ft = pro.get_future(); 15 | trantor::SerialTaskQueue queue(""); 16 | queue.runTaskInQueue([&counter, &pro, &queue]() { 17 | for (int i = 0; i < 10000; ++i) 18 | { 19 | queue.runTaskInQueue([&counter, &pro]() { 20 | ++counter; 21 | if (counter.load() == 110000) 22 | pro.set_value(1); 23 | }); 24 | } 25 | }); 26 | for (int i = 0; i < 10; ++i) 27 | { 28 | std::thread([&counter, &queue, &pro]() { 29 | for (int i = 0; i < 10000; ++i) 30 | { 31 | queue.runTaskInQueue([&counter, &pro]() { 32 | ++counter; 33 | if (counter.load() == 110000) 34 | pro.set_value(1); 35 | }); 36 | } 37 | }).detach(); 38 | } 39 | 40 | ft.get(); 41 | std::cout << "counter=" << counter.load() << std::endl; 42 | } -------------------------------------------------------------------------------- /trantor/tests/TcpAsyncStreamServerTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace trantor; 7 | #define USE_IPV6 0 8 | int main() 9 | { 10 | LOG_DEBUG << "test start"; 11 | Logger::setLogLevel(Logger::kTrace); 12 | EventLoopThread loopThread; 13 | loopThread.run(); 14 | #if USE_IPV6 15 | InetAddress addr(8888, true, true); 16 | #else 17 | InetAddress addr(8888); 18 | #endif 19 | TcpServer server(loopThread.getLoop(), addr, "test"); 20 | 21 | server.setRecvMessageCallback( 22 | [](const TcpConnectionPtr &connectionPtr, MsgBuffer *buffer) { 23 | // LOG_DEBUG<<"recv callback!"; 24 | std::cout << std::string(buffer->peek(), buffer->readableBytes()); 25 | connectionPtr->send(buffer->peek(), buffer->readableBytes()); 26 | buffer->retrieveAll(); 27 | // connectionPtr->forceClose(); 28 | }); 29 | server.setConnectionCallback([](const TcpConnectionPtr &connPtr) { 30 | if (connPtr->connected()) 31 | { 32 | LOG_DEBUG << "New connection"; 33 | auto stream = connPtr->sendAsyncStream(); 34 | stream->send("hello world 1..."); 35 | std::thread([stream = std::move(stream)] { 36 | for (int i = 2; i < 10; i++) 37 | { 38 | std::this_thread::sleep_for(std::chrono::seconds(1)); 39 | stream->send("hello world " + std::to_string(i) + "..."); 40 | } 41 | stream->close(); 42 | }).detach(); 43 | connPtr->send("hello world"); 44 | } 45 | else if (connPtr->disconnected()) 46 | { 47 | LOG_DEBUG << "connection disconnected"; 48 | } 49 | }); 50 | server.setIoLoopNum(3); 51 | server.start(); 52 | loopThread.wait(); 53 | } 54 | -------------------------------------------------------------------------------- /trantor/tests/TcpClientTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #ifdef _WIN32 8 | #include 9 | #else 10 | #include 11 | #include 12 | #endif 13 | 14 | using namespace trantor; 15 | #define USE_IPV6 0 16 | int main() 17 | { 18 | trantor::Logger::setLogLevel(trantor::Logger::kTrace); 19 | LOG_DEBUG << "TcpClient class test!"; 20 | EventLoop loop; 21 | #if USE_IPV6 22 | InetAddress serverAddr("::1", 8888, true); 23 | #else 24 | InetAddress serverAddr("127.0.0.1", 8888); 25 | #endif 26 | std::shared_ptr client[10]; 27 | std::atomic_int connCount; 28 | connCount = 10; 29 | for (int i = 0; i < 10; ++i) 30 | { 31 | client[i] = std::make_shared(&loop, 32 | serverAddr, 33 | "tcpclienttest"); 34 | client[i]->setSockOptCallback([](int fd) { 35 | LOG_DEBUG << "setSockOptCallback!"; 36 | #ifdef _WIN32 37 | #elif __linux__ 38 | int optval = 10; 39 | ::setsockopt(fd, 40 | SOL_TCP, 41 | TCP_KEEPCNT, 42 | &optval, 43 | static_cast(sizeof optval)); 44 | ::setsockopt(fd, 45 | SOL_TCP, 46 | TCP_KEEPIDLE, 47 | &optval, 48 | static_cast(sizeof optval)); 49 | ::setsockopt(fd, 50 | SOL_TCP, 51 | TCP_KEEPINTVL, 52 | &optval, 53 | static_cast(sizeof optval)); 54 | #else 55 | #endif 56 | }); 57 | client[i]->setConnectionCallback( 58 | [i, &loop, &connCount](const TcpConnectionPtr &conn) { 59 | if (conn->connected()) 60 | { 61 | LOG_DEBUG << i << " connected!"; 62 | std::string tmp = std::to_string(i) + " client!!"; 63 | conn->send(tmp); 64 | } 65 | else 66 | { 67 | LOG_DEBUG << i << " disconnected"; 68 | --connCount; 69 | if (connCount == 0) 70 | loop.quit(); 71 | } 72 | }); 73 | client[i]->setMessageCallback( 74 | [](const TcpConnectionPtr &conn, MsgBuffer *buf) { 75 | LOG_DEBUG << std::string(buf->peek(), buf->readableBytes()); 76 | buf->retrieveAll(); 77 | conn->shutdown(); 78 | }); 79 | client[i]->connect(); 80 | } 81 | loop.loop(); 82 | } 83 | -------------------------------------------------------------------------------- /trantor/tests/TcpServerTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace trantor; 7 | #define USE_IPV6 0 8 | int main() 9 | { 10 | LOG_DEBUG << "test start"; 11 | Logger::setLogLevel(Logger::kTrace); 12 | EventLoopThread loopThread; 13 | loopThread.run(); 14 | #if USE_IPV6 15 | InetAddress addr(8888, true, true); 16 | #else 17 | InetAddress addr(8888); 18 | #endif 19 | TcpServer server(loopThread.getLoop(), addr, "test"); 20 | server.setBeforeListenSockOptCallback([](int fd) { 21 | std::cout << "setBeforeListenSockOptCallback:" << fd << std::endl; 22 | }); 23 | server.setAfterAcceptSockOptCallback([](int fd) { 24 | std::cout << "afterAcceptSockOptCallback:" << fd << std::endl; 25 | }); 26 | server.setRecvMessageCallback( 27 | [](const TcpConnectionPtr &connectionPtr, MsgBuffer *buffer) { 28 | // LOG_DEBUG<<"recv callback!"; 29 | std::cout << std::string(buffer->peek(), buffer->readableBytes()); 30 | connectionPtr->send(buffer->peek(), buffer->readableBytes()); 31 | buffer->retrieveAll(); 32 | // connectionPtr->forceClose(); 33 | }); 34 | server.setConnectionCallback([](const TcpConnectionPtr &connPtr) { 35 | if (connPtr->connected()) 36 | { 37 | LOG_DEBUG << "New connection"; 38 | } 39 | else if (connPtr->disconnected()) 40 | { 41 | LOG_DEBUG << "connection disconnected"; 42 | } 43 | }); 44 | server.setIoLoopNum(3); 45 | server.start(); 46 | loopThread.wait(); 47 | } 48 | -------------------------------------------------------------------------------- /trantor/tests/TimerTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std::literals; 7 | 8 | int main() 9 | { 10 | trantor::Logger::setLogLevel(trantor::Logger::kTrace); 11 | trantor::EventLoop loop; 12 | auto id1 = loop.runAfter(1s, []() { 13 | LOG_ERROR << "This info shouldn't be displayed!"; 14 | }); 15 | loop.invalidateTimer(id1); 16 | auto id2 = loop.runEvery(0.3s, []() { 17 | LOG_ERROR << "This timer will be invalidated after 3 second;"; 18 | }); 19 | std::thread thread([id2, &loop]() { 20 | std::this_thread::sleep_for(3s); 21 | loop.invalidateTimer(id2); 22 | }); 23 | thread.detach(); 24 | loop.runEvery(3, []() { LOG_DEBUG << " runEvery 3s"; }); 25 | loop.runAt(trantor::Date::date().after(10), 26 | []() { LOG_DEBUG << "runAt 10s later"; }); 27 | loop.runAfter(5, []() { std::cout << "runAt 5s later" << std::endl; }); 28 | loop.runEvery(1, []() { std::cout << "runEvery 1s" << std::endl; }); 29 | loop.runAfter(4, []() { std::cout << "runAfter 4s" << std::endl; }); 30 | loop.runAfter(10min, 31 | []() { std::cout << "*********** run after 10 min\n"; }); 32 | loop.loop(); 33 | } 34 | -------------------------------------------------------------------------------- /trantor/tests/TimerTest1.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | int main() 5 | { 6 | trantor::EventLoop loop; 7 | LOG_FATAL << trantor::Date::date().roundDay().microSecondsSinceEpoch(); 8 | trantor::Date begin = trantor::Date::date().roundSecond().after(2); 9 | auto id = loop.runAt(begin, [begin, &loop]() { 10 | LOG_DEBUG << "test begin:"; 11 | srand((unsigned int)time(NULL)); 12 | for (int i = 0; i < 10000; ++i) 13 | { 14 | int aa = rand() % 10000; 15 | double s = (double)aa / 1000.0 + 1; 16 | loop.runAt(begin.after(s), 17 | [s]() { LOG_ERROR << "run After:" << s; }); 18 | } 19 | LOG_DEBUG << "timer created!"; 20 | }); 21 | std::cout << "id=" << id << std::endl; 22 | loop.loop(); 23 | } 24 | -------------------------------------------------------------------------------- /trantor/tests/TimingWheelTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | class MyClass 5 | { 6 | public: 7 | MyClass(); 8 | MyClass(MyClass &&) = default; 9 | MyClass(const MyClass &) = default; 10 | MyClass &operator=(MyClass &&) = default; 11 | MyClass &operator=(const MyClass &) = default; 12 | ~MyClass(); 13 | 14 | private: 15 | }; 16 | 17 | MyClass::MyClass() 18 | { 19 | } 20 | 21 | MyClass::~MyClass() 22 | { 23 | LOG_DEBUG << "MyClass destructed!"; 24 | } 25 | 26 | int main() 27 | { 28 | LOG_DEBUG << "start"; 29 | trantor::EventLoop loop; 30 | std::weak_ptr weakEntry; 31 | trantor::TimingWheel wheel(&loop, 75, 0.1, 100); 32 | { 33 | auto entry = std::shared_ptr(new MyClass); 34 | 35 | wheel.insertEntry(75, entry); 36 | weakEntry = entry; 37 | } 38 | // loop.runAfter(5.0, [&]() { 39 | // wheel.insertEntry(10, weakEntry.lock()); 40 | // }); 41 | // loop.runAfter(0.5,[&](){ 42 | // wheel.insertEntry(28,weakEntry.lock()); 43 | // }); 44 | // loop.runEvery(1.0,[](){ 45 | // LOG_DEBUG<<"tick"; 46 | // }); 47 | loop.loop(); 48 | } 49 | -------------------------------------------------------------------------------- /trantor/tests/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFrTCCA5WgAwIBAgIUDWd3k9cUXe271g10ep5vAZzvoL8wDQYJKoZIhvcNAQEL 3 | BQAwYjELMAkGA1UEBhMCVFcxDzANBgNVBAgMBlRhaXBlaTEPMA0GA1UEBwwGVGFp 4 | cGVpMQ8wDQYDVQQKDAZNYXJ0aW4xDzANBgNVBAsMBk1hcnRpbjEPMA0GA1UEAwwG 5 | TWFydGluMCAXDTIzMDIwOTEyMzczNFoYDzIxMjMwMTE2MTIzNzM0WjBiMQswCQYD 6 | VQQGEwJUVzEPMA0GA1UECAwGVGFpcGVpMQ8wDQYDVQQHDAZUYWlwZWkxDzANBgNV 7 | BAoMBk1hcnRpbjEPMA0GA1UECwwGTWFydGluMQ8wDQYDVQQDDAZNYXJ0aW4wggIi 8 | MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/jq9cDERsVm6MrflAuoSYfdRf 9 | dxLQlSUMLcX6w67RPvZHk71CBB8ycjStftcDrVMoXDPVZU8yboHhusmqeWGek8kD 10 | 1m0kKyOkMJ8IsWAobReoD/nNnNAMmnN785QqhhtUwfWEAIF9YJHoCkM9/Q/ysvTg 11 | INtqtZauPi3TVo5019/UJTEKbixp33d8US1JzsPY8ZQ3WPSp3+8joPlXOgqIGZNi 12 | 9n1UWe5lq+/HODVHKG9o9aT6CSQzsKU02Uu/DlkNmK702dQUSnwbevy7qCr/Gms9 13 | MZ/dkY6IfTIPy8lb2iL31XCeMkh8/A9FA+uuInKurH7/DqsxbEZ3NcBXKnijd6+l 14 | /Y2rwttJdEmMKjxVp3TE9b0cvT6MWVe21qI6Q+SqGYpK1sRNHm0OX5xZC2q3NTPi 15 | i4T2IoN8628h80Xt8Pls5fig71t+Mw7/9m97W46WbruLmM945t+Q4rDijqU8gvVW 16 | JYvSjRKO8RGKVj4drvqdzbJASwhyoadJWyD3QhkJhZ/2B1/7Ix153KNgnQ+q8yUB 17 | 4tIxeq3fRlvX5UCjHf/j6A1OCbHlvDUGiKBMt6vwKBhFoFj24Gf7o2rCx/jomduj 18 | XcsX9maZbKnn7gvY+VcNVSydxSGsoBI3a8OBD5K0PrG59Qt/JNQtkAPe4gZP6KsW 19 | vcRKC9nYxT9+2JIGaQIDAQABo1kwVzAUBgNVHREEDTALgglsb2NhbGhvc3QwCwYD 20 | VR0PBAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB0GA1UdDgQWBBRWDkJqcfm9 21 | wvz9w5tDpYTe0SIW0zANBgkqhkiG9w0BAQsFAAOCAgEArsjorf9iq2byicXC/tz+ 22 | ml3ZZc20XjZfmM79yBwM2WpGJjEe+Rm1tZq7fWHO+gohXtQ7qX/5/RoQoBQaaAti 23 | BVqYS+r9ab5Nqyo74wgFyRlCrvqhNgdqLm/itZuDjvAJSEMtQWLety5GhJPEFbOR 24 | WbA4gHNSoh96OYs4s9p6PtJrnZMGflFEtvpXfdKi3Q9gK6/ib1f2zSNQ5vAYuBR4 25 | AzGDUvpEpRRu83OSlpYnPc3pITMyjL8B4EssOZBDYq4Yx2ZZO2xpjXM3Ns77g9Z7 26 | z/YqVDVAO8Fpw+byCBrtJtg9an+LnXuxji/MOYXkNnZqQJMonHuUZM2b3mPtQIgG 27 | pRi0F4tSr3OLYNrffww8I3g5o9O19Bcw4mpNuI1tuLrlcrq67R3ddpi8wgxxzl92 28 | ghNknQJ/T2dpyBptdoh3U7qo/6pluBTH1tv3+FLDvcd7wTT2/lnvmmtG0te2fdvd 29 | cucG+S8/I+OuH6OW0UuGHBdpB+vvMYbepLCri8FVs4x9/g8Wxpxujvd2fLmyKx+w 30 | EGOIVjG5gIKwl0ohlCKOJZ02Oo7EgHoCB1EiHyNQ6zTq0N7P99uL23OSoeoSIPeU 31 | WEPSP2YlVKKSB6+JMBFPFo2oj55mB8cu7y2rffp6G29CORA4FGPyA0So0vhpa32v 32 | QTEL1RJLiGdqE980bxcP/+4= 33 | -----END CERTIFICATE----- 34 | -------------------------------------------------------------------------------- /trantor/tests/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQC/jq9cDERsVm6M 3 | rflAuoSYfdRfdxLQlSUMLcX6w67RPvZHk71CBB8ycjStftcDrVMoXDPVZU8yboHh 4 | usmqeWGek8kD1m0kKyOkMJ8IsWAobReoD/nNnNAMmnN785QqhhtUwfWEAIF9YJHo 5 | CkM9/Q/ysvTgINtqtZauPi3TVo5019/UJTEKbixp33d8US1JzsPY8ZQ3WPSp3+8j 6 | oPlXOgqIGZNi9n1UWe5lq+/HODVHKG9o9aT6CSQzsKU02Uu/DlkNmK702dQUSnwb 7 | evy7qCr/Gms9MZ/dkY6IfTIPy8lb2iL31XCeMkh8/A9FA+uuInKurH7/DqsxbEZ3 8 | NcBXKnijd6+l/Y2rwttJdEmMKjxVp3TE9b0cvT6MWVe21qI6Q+SqGYpK1sRNHm0O 9 | X5xZC2q3NTPii4T2IoN8628h80Xt8Pls5fig71t+Mw7/9m97W46WbruLmM945t+Q 10 | 4rDijqU8gvVWJYvSjRKO8RGKVj4drvqdzbJASwhyoadJWyD3QhkJhZ/2B1/7Ix15 11 | 3KNgnQ+q8yUB4tIxeq3fRlvX5UCjHf/j6A1OCbHlvDUGiKBMt6vwKBhFoFj24Gf7 12 | o2rCx/jomdujXcsX9maZbKnn7gvY+VcNVSydxSGsoBI3a8OBD5K0PrG59Qt/JNQt 13 | kAPe4gZP6KsWvcRKC9nYxT9+2JIGaQIDAQABAoICAEni4OvZxXiePATiQ/5+Ew/4 14 | lPZ/qM+wf3o7m542ZVNLfFYue7UffuMH3x6+inPeInGyYsHgUlRrAIkPcaLiL8+p 15 | RENJLY7iXtyBbo49UJA3SAUoqFtxLWR3HK1GTjO6x4cBS1Bvm4K/QXgloTsjRcgA 16 | 0+gxdECsKyMpU6atP8R80dZzw/84cMQjkGRwsU3DRZKD1/4jPzfY6tYszJAjEJXf 17 | e5ST69Kh34zy7UlD+nToeVScT1asOP0BGTAR0qAuihXu+yjxblanRkiZPyuo2XDN 18 | gWi4n+eoMbiexbUHDzNxJ8S9XLOARKqE1OTzdrATlHWgjlmWEF0/XMy1fGuCs8X6 19 | I1TiKB2zbVT9vQ1aoTcGjHCJUDjWu5VU3xU/ARPz/IxE6okWdsYfAno+gWvLr3w9 20 | VqHbD5JsIhaKr03PIMblCvB2jYzrVOo5tWd+W5d/354a3zh8BA7n8dTHLeugJw0U 21 | HP7kL+FgcOlHTx++Gm8Fl6my4YVRkKiIEEErurfNsvPJK5LlUoPTD5G/3LXUspyP 22 | K/8v/RMSEREonmCPqIDJRbqB64egA9f8F0uCcIAUsbiG+TeSC91tGvfgj2CxJHNz 23 | ieyPx9kJC6xWECEexQrD3YSUe26p3Bgf4RJ8FG5LEEhOQQm5jAI6QWd2LJFPWwW+ 24 | XE1+CM4v8Y/n+txSOU07AoIBAQDyrIyXxfBNvCoRK88ZHmFvUXvDnWqQYdfp1nJl 25 | kmy3exXscwiac+QehFPnsPJoj8+8D7lb/rA7oDWPNamlKQWwmyndGZp+Z8G5cXXN 26 | T5dHUZY9tuAoyn8JAjDDTwsV1h6p2K5JuErHPhglRFp25h0Oc9GnogTGIB6zCBDZ 27 | trA6yDUqNTrUxB+f9Ul4SE3k5pd3tw1AWtqCs3ra699NX01cKRFyL+bOWOmoScT4 28 | q3pyO5BufWB7Lv/8EG1wqr6gNxiSMVrKlKupC/B7UBVnXnX4W5nfPfSoUK/nCciW 29 | Mgj/v82QqPP+i4j/VfI5Kt6zv0WFxDUyH1GtNqhOHJihtgzbAoIBAQDKE4z0NC+K 30 | N1ZoTlAJKAYdzW1C3dJ7PgQq1qS0Z3q85CfYlNxv6ds7PPqao4+J7JeSTwCAtwFW 31 | u3japhQ4B5wKiKYsvyE/ws+syWdOJ1x2E2ibn7FnuENvgFmYc15mlA1yCWYYkkpX 32 | 1KOYtfrjyGHtw8PlA6hXBsyxA/F9IzWpStl9htVgpJC7gXZKX/e4oxNfeQ0lyvbe 33 | 0h6GaSihl26z5NSKQCCs36ahX2TEYS1Nck5UYaKz/5Uaq5x7ex0HB5aEjL8d4UU/ 34 | bVnRE20snAsoEf6jeBHeyOVPGw2bT/4zk7vuv6FC2KhcqNrbVhOe5LrdIvJkydiZ 35 | InWK3xrYKzsLAoIBAQC9anVq2fNRmbd0I6/IuW/wBbgG3c4Z2GVBfkNYiMwXAxn/ 36 | r2JdvGuobj1XsUPk3auV7OgPqGJCiDCGEarS4YwxZ0tr6touJCqP5sG+eYto/YO5 37 | tA6PiE9T5sPNDttmNfVFOX4AyLqFfjA2ln3OJJs1dq2EnPAA/X043OjaJsCzgSYO 38 | RfIftN3CayDno/g43MwJg3Xyb3fzYMhaLJXlvKeTcfLOIBmVoszusHXwa1ht5ZQ8 39 | ydwPCoaAZwolUQDt6VNieOeXDChZEJqqhb3PK2oFaupV1/QplKFYQsiwg2mGxl1b 40 | tqSMYLmUI6+nc5DU2E0ZtiaXct67xtfj8GoqfwDVAoIBAQCTLsY9oDz4GPIwqsmU 41 | wbgiwNtSFqsV5Me4Q/pXA//b0PpMv7AHO3fYn8OQGo2T0eVcRXqCRckN2SJfbxPO 42 | 84vuCDWw5c1b2ZLVsSQzQmwP/Hb20suuVgGYFw4rAezCHhfk9X+NahAIBPLbacDB 43 | Y9QgD7SA+7cDHAq+67ZahOiy07exvCFycKqSR+tWpKuTqgOUSGERI9HH3ZcqIzHa 44 | 8KdLE+LSh37FK2j8pLSKbJVIkXcH8s1E+WUqtdAWCEfONPKmvLT/GHMNjaIbrGCa 45 | W1Ws695iRjQN5plOks/ITe1Ct9nsPVtBivil9L7jfsBvvP11z9xpGLNQZk7ixTmS 46 | NXqdAoIBAQCw87D8u+2j0Gcy3xTRAgL6I50hAqrqv0LcclR+d6M4hDe/VssUJ721 47 | Xs+lVX8JDO6CjzISMZ5uRWFXWFFquPmNav6eZf9SXb9mEXy5qFaoSrU7JgHKXyKS 48 | 1F0fMkSv3E3s2Iw8qQkHCI6D6Fza5fWiXvDaJBRRbxcxSakMB3PB//my1/h6rZY/ 49 | i8PatPOMBY180PC2RtkWWjN4XeH0Ra8j7NXdtvZaFLYVJVrLYjUhzX2e6TstyGbH 50 | k1Ert/B0+RxXCBMj5n36fGSw9lBFh1UiiE3Pfra7JOTs0PJG40T90UfJnQ93NUlT 51 | AyBDBVOh3ubATMFsBx5bwp26rFaTcdg5 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /trantor/unittests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(GTest REQUIRED) 2 | add_executable(msgbuffer_unittest MsgBufferUnittest.cc) 3 | add_executable(inetaddress_unittest InetAddressUnittest.cc) 4 | add_executable(date_unittest DateUnittest.cc) 5 | add_executable(split_string_unittest splitStringUnittest.cc) 6 | add_executable(string_encoding_unittest stringEncodingUnittest.cc) 7 | add_executable(ssl_name_verify_unittest sslNameVerifyUnittest.cc) 8 | add_executable(hash_unittest HashUnittest.cc) 9 | set(UNITTEST_TARGETS 10 | msgbuffer_unittest 11 | inetaddress_unittest 12 | date_unittest 13 | split_string_unittest 14 | string_encoding_unittest 15 | ssl_name_verify_unittest 16 | hash_unittest 17 | ) 18 | set_property(TARGET ${UNITTEST_TARGETS} PROPERTY CXX_STANDARD 14) 19 | set_property(TARGET ${UNITTEST_TARGETS} PROPERTY CXX_STANDARD_REQUIRED ON) 20 | set_property(TARGET ${UNITTEST_TARGETS} PROPERTY CXX_EXTENSIONS OFF) 21 | 22 | include(GoogleTest) 23 | foreach(T ${UNITTEST_TARGETS}) 24 | target_link_libraries(${T} PRIVATE trantor GTest::GTest) 25 | gtest_discover_tests(${T}) 26 | endforeach() 27 | -------------------------------------------------------------------------------- /trantor/unittests/DateUnittest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace trantor; 6 | TEST(Date, constructorTest) 7 | { 8 | EXPECT_STREQ("1985-01-01 00:00:00", 9 | trantor::Date(1985, 1, 1) 10 | .toCustomFormattedStringLocal("%Y-%m-%d %H:%M:%S") 11 | .c_str()); 12 | EXPECT_STREQ("2004-02-29 00:00:00.000000", 13 | trantor::Date(2004, 2, 29) 14 | .toCustomFormattedStringLocal("%Y-%m-%d %H:%M:%S", true) 15 | .c_str()); 16 | EXPECT_STRNE("2001-02-29 00:00:00.000000", 17 | trantor::Date(2001, 2, 29) 18 | .toCustomFormattedStringLocal("%Y-%m-%d %H:%M:%S", true) 19 | .c_str()); 20 | EXPECT_STREQ("2018-01-01 00:00:00.000000", 21 | trantor::Date(2018, 1, 1, 12, 12, 12, 2321) 22 | .roundDay() 23 | .toCustomFormattedStringLocal("%Y-%m-%d %H:%M:%S", true) 24 | .c_str()); 25 | } 26 | TEST(Date, DatabaseStringTest) 27 | { 28 | auto now = trantor::Date::now(); 29 | EXPECT_EQ(now, trantor::Date::fromDbStringLocal(now.toDbStringLocal())); 30 | EXPECT_EQ(now, trantor::Date::fromDbString(now.toDbString())); 31 | std::string dbString = "2018-01-01 00:00:00.123"; 32 | auto dbDate = trantor::Date::fromDbStringLocal(dbString); 33 | auto ms = (dbDate.microSecondsSinceEpoch() % 1000000) / 1000; 34 | EXPECT_EQ(ms, 123); 35 | EXPECT_EQ(dbDate, 36 | trantor::Date::fromDbStringLocal(dbDate.toDbStringLocal())); 37 | EXPECT_EQ(dbDate, trantor::Date::fromDbString(dbDate.toDbString())); 38 | dbString = "2018-01-01 00:00:00.023"; 39 | dbDate = trantor::Date::fromDbStringLocal(dbString); 40 | ms = (dbDate.microSecondsSinceEpoch() % 1000000) / 1000; 41 | EXPECT_EQ(ms, 23); 42 | EXPECT_EQ(dbDate, 43 | trantor::Date::fromDbStringLocal(dbDate.toDbStringLocal())); 44 | EXPECT_EQ(dbDate, trantor::Date::fromDbString(dbDate.toDbString())); 45 | dbString = "2018-01-01 00:00:00.003"; 46 | dbDate = trantor::Date::fromDbStringLocal(dbString); 47 | ms = (dbDate.microSecondsSinceEpoch() % 1000000) / 1000; 48 | EXPECT_EQ(ms, 3); 49 | EXPECT_EQ(dbDate, 50 | trantor::Date::fromDbStringLocal(dbDate.toDbStringLocal())); 51 | EXPECT_EQ(dbDate, trantor::Date::fromDbString(dbDate.toDbString())); 52 | dbString = "2018-01-01 00:00:00.000123"; 53 | dbDate = trantor::Date::fromDbStringLocal(dbString); 54 | auto us = (dbDate.microSecondsSinceEpoch() % 1000000); 55 | EXPECT_EQ(us, 123); 56 | EXPECT_EQ(dbDate, 57 | trantor::Date::fromDbStringLocal(dbDate.toDbStringLocal())); 58 | EXPECT_EQ(dbDate, trantor::Date::fromDbString(dbDate.toDbString())); 59 | dbString = "2018-01-01 00:00:00.000023"; 60 | dbDate = trantor::Date::fromDbStringLocal(dbString); 61 | us = (dbDate.microSecondsSinceEpoch() % 1000000); 62 | EXPECT_EQ(us, 23); 63 | EXPECT_EQ(dbDate, 64 | trantor::Date::fromDbStringLocal(dbDate.toDbStringLocal())); 65 | EXPECT_EQ(dbDate, trantor::Date::fromDbString(dbDate.toDbString())); 66 | dbString = "2018-01-01 00:00:00.000003"; 67 | dbDate = trantor::Date::fromDbStringLocal(dbString); 68 | us = (dbDate.microSecondsSinceEpoch() % 1000000); 69 | EXPECT_EQ(us, 3); 70 | 71 | dbString = "2018-01-01 00:00:00"; 72 | dbDate = trantor::Date::fromDbStringLocal(dbString); 73 | ms = (dbDate.microSecondsSinceEpoch() % 1000000) / 1000; 74 | EXPECT_EQ(ms, 0); 75 | 76 | dbString = "2018-01-01 00:00:00"; 77 | dbDate = trantor::Date::fromDbStringLocal(dbString); 78 | auto dbDateGMT = trantor::Date::fromDbString(dbString); 79 | auto secLocal = (dbDate.microSecondsSinceEpoch() / 1000000); 80 | auto secGMT = (dbDateGMT.microSecondsSinceEpoch() / 1000000); 81 | // timeZone at least 1 minute (can be >=1 hour, 30 min, 15 min. Error if 82 | // difference less then minute) 83 | auto timeZoneOffsetMinutePart = (secLocal - secGMT) % 60; 84 | EXPECT_EQ(timeZoneOffsetMinutePart, 0); 85 | dbString = "2018-01-01 00:00:00.123"; 86 | dbDate = trantor::Date::fromDbString(dbString); 87 | ms = (dbDate.microSecondsSinceEpoch() % 1000000) / 1000; 88 | EXPECT_EQ(ms, 123); 89 | dbString = "2018-01-01 00:00:00.023"; 90 | dbDate = trantor::Date::fromDbString(dbString); 91 | ms = (dbDate.microSecondsSinceEpoch() % 1000000) / 1000; 92 | EXPECT_EQ(ms, 23); 93 | dbString = "2018-01-01 00:00:00.003"; 94 | dbDate = trantor::Date::fromDbString(dbString); 95 | ms = (dbDate.microSecondsSinceEpoch() % 1000000) / 1000; 96 | EXPECT_EQ(ms, 3); 97 | dbString = "2018-01-01 00:00:00.000123"; 98 | dbDate = trantor::Date::fromDbString(dbString); 99 | us = (dbDate.microSecondsSinceEpoch() % 1000000); 100 | EXPECT_EQ(us, 123); 101 | dbString = "2018-01-01 00:00:00.000023"; 102 | dbDate = trantor::Date::fromDbString(dbString); 103 | us = (dbDate.microSecondsSinceEpoch() % 1000000); 104 | EXPECT_EQ(us, 23); 105 | dbString = "2018-01-01 00:00:00.000003"; 106 | dbDate = trantor::Date::fromDbString(dbString); 107 | us = (dbDate.microSecondsSinceEpoch() % 1000000); 108 | EXPECT_EQ(us, 3); 109 | } 110 | int main(int argc, char **argv) 111 | { 112 | testing::InitGoogleTest(&argc, argv); 113 | return RUN_ALL_TESTS(); 114 | } -------------------------------------------------------------------------------- /trantor/unittests/HashUnittest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | using namespace trantor; 8 | using namespace trantor::utils; 9 | 10 | TEST(Hash, MD5) 11 | { 12 | EXPECT_EQ(toHexString(md5("hello")), "5D41402ABC4B2A76B9719D911017C592"); 13 | EXPECT_EQ(toHexString(md5("trantor")), "95FC641C9E629D2854B0B60F5A51E1FD"); 14 | } 15 | 16 | TEST(Hash, SHA1) 17 | { 18 | EXPECT_EQ(toHexString(sha1("hello")), 19 | "AAF4C61DDCC5E8A2DABEDE0F3B482CD9AEA9434D"); 20 | EXPECT_EQ(toHexString(sha1("trantor")), 21 | "A9E084054D439FCD87D2438FB5FE4DDD7D8CC204"); 22 | } 23 | 24 | TEST(Hash, SHA256) 25 | { 26 | EXPECT_EQ( 27 | toHexString(sha256("hello")), 28 | "2CF24DBA5FB0A30E26E83B2AC5B9E29E1B161E5C1FA7425E73043362938B9824"); 29 | EXPECT_EQ( 30 | toHexString(sha256("trantor")), 31 | "C72002E712A3BA6D60125D4B3D0B816758FBDCA98F2A892077BD4182E71CF6F5"); 32 | } 33 | 34 | TEST(Hash, SHA3) 35 | { 36 | EXPECT_EQ( 37 | toHexString(sha3("hello")), 38 | "3338BE694F50C5F338814986CDF0686453A888B84F424D792AF4B9202398F392"); 39 | EXPECT_EQ( 40 | toHexString(sha3("trantor")), 41 | "135E1D2372F0A48525E09D47C6FFCA14077D8C5A0905410FA81C30ED9AFF696A"); 42 | } 43 | 44 | TEST(Hash, BLAKE2b) 45 | { 46 | EXPECT_EQ( 47 | toHexString(blake2b("hello")), 48 | "324DCF027DD4A30A932C441F365A25E86B173DEFA4B8E58948253471B81B72CF"); 49 | EXPECT_EQ( 50 | toHexString(blake2b("trantor")), 51 | "2D03B3D7E76C52DD7A32689ADE4406798B50BC5B09428E3F90F56182898873C8"); 52 | } 53 | 54 | int main(int argc, char **argv) 55 | { 56 | testing::InitGoogleTest(&argc, argv); 57 | return RUN_ALL_TESTS(); 58 | } -------------------------------------------------------------------------------- /trantor/unittests/InetAddressUnittest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace trantor; 6 | TEST(InetAddress, innerIpTest) 7 | { 8 | EXPECT_EQ(true, InetAddress("192.168.0.1", 0).isIntranetIp()); 9 | EXPECT_EQ(true, InetAddress("192.168.12.1", 0).isIntranetIp()); 10 | EXPECT_EQ(true, InetAddress("10.168.0.1", 0).isIntranetIp()); 11 | EXPECT_EQ(true, InetAddress("10.0.0.1", 0).isIntranetIp()); 12 | EXPECT_EQ(true, InetAddress("172.31.10.1", 0).isIntranetIp()); 13 | EXPECT_EQ(true, InetAddress("127.0.0.1", 0).isIntranetIp()); 14 | EXPECT_EQ(true, InetAddress("example.com", 0).isUnspecified()); 15 | EXPECT_EQ(false, InetAddress("127.0.0.2", 0).isUnspecified()); 16 | EXPECT_EQ(false, InetAddress("0.0.0.0", 0).isUnspecified()); 17 | } 18 | TEST(InetAddress, toIpPortNetEndianTest) 19 | { 20 | EXPECT_EQ(std::string({char(192), char(168), 0, 1, 0, 80}), 21 | InetAddress("192.168.0.1", 80).toIpPortNetEndian()); 22 | EXPECT_EQ(std::string({0x20, 23 | 0x01, 24 | 0x0d, 25 | char(0xb8), 26 | 0x33, 27 | 0x33, 28 | 0x44, 29 | 0x44, 30 | 0x55, 31 | 0x55, 32 | 0x66, 33 | 0x66, 34 | 0x77, 35 | 0x77, 36 | char(0x88), 37 | char(0x88), 38 | 1, 39 | char(187)}), 40 | InetAddress("2001:0db8:3333:4444:5555:6666:7777:8888", 443, true) 41 | .toIpPortNetEndian()); 42 | } 43 | int main(int argc, char **argv) 44 | { 45 | testing::InitGoogleTest(&argc, argv); 46 | return RUN_ALL_TESTS(); 47 | } 48 | -------------------------------------------------------------------------------- /trantor/unittests/MsgBufferUnittest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace trantor; 6 | TEST(MsgBufferTest, readableTest) 7 | { 8 | MsgBuffer buffer; 9 | 10 | EXPECT_EQ(0, buffer.readableBytes()); 11 | buffer.append(std::string(128, 'a')); 12 | EXPECT_EQ(128, buffer.readableBytes()); 13 | buffer.retrieve(100); 14 | EXPECT_EQ(28, buffer.readableBytes()); 15 | EXPECT_EQ('a', buffer.peekInt8()); 16 | buffer.retrieveAll(); 17 | EXPECT_EQ(0, buffer.readableBytes()); 18 | } 19 | TEST(MsgBufferTest, writableTest) 20 | { 21 | MsgBuffer buffer(100); 22 | 23 | EXPECT_EQ(100, buffer.writableBytes()); 24 | buffer.append("abcde"); 25 | EXPECT_EQ(95, buffer.writableBytes()); 26 | buffer.append(std::string(100, 'x')); 27 | EXPECT_EQ(111, buffer.writableBytes()); 28 | buffer.retrieve(100); 29 | EXPECT_EQ(111, buffer.writableBytes()); 30 | buffer.append(std::string(112, 'c')); 31 | EXPECT_EQ(99, buffer.writableBytes()); 32 | buffer.retrieveAll(); 33 | EXPECT_EQ(216, buffer.writableBytes()); 34 | } 35 | 36 | TEST(MsgBufferTest, addInFrontTest) 37 | { 38 | MsgBuffer buffer(100); 39 | 40 | EXPECT_EQ(100, buffer.writableBytes()); 41 | buffer.addInFrontInt8('a'); 42 | EXPECT_EQ(100, buffer.writableBytes()); 43 | buffer.addInFrontInt64(123); 44 | EXPECT_EQ(92, buffer.writableBytes()); 45 | buffer.addInFrontInt64(100); 46 | EXPECT_EQ(84, buffer.writableBytes()); 47 | buffer.addInFrontInt8(1); 48 | EXPECT_EQ(84, buffer.writableBytes()); 49 | } 50 | 51 | TEST(MsgBuffer, MoveContrustor) 52 | { 53 | MsgBuffer buf1(100); 54 | const char *bufptr1 = buf1.peek(); 55 | MsgBuffer buffnew1 = std::move(buf1); 56 | EXPECT_EQ(bufptr1, buffnew1.peek()); 57 | 58 | MsgBuffer buf2(100); 59 | const char *bufptr2 = buf2.peek(); 60 | MsgBuffer buffnew2(std::move(buf2)); 61 | EXPECT_EQ(bufptr2, buffnew2.peek()); 62 | } 63 | 64 | TEST(Msgbuffer, MoveAssignmentOperator) 65 | { 66 | MsgBuffer buf(100); 67 | const char *bufptr = buf.peek(); 68 | size_t writable = buf.writableBytes(); 69 | MsgBuffer buffnew(1000); 70 | buffnew = std::move(buf); 71 | EXPECT_EQ(bufptr, buffnew.peek()); 72 | EXPECT_EQ(writable, buffnew.writableBytes()); 73 | } 74 | int main(int argc, char **argv) 75 | { 76 | testing::InitGoogleTest(&argc, argv); 77 | return RUN_ALL_TESTS(); 78 | } -------------------------------------------------------------------------------- /trantor/unittests/sslNameVerifyUnittest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace trantor; 5 | using namespace trantor::utils; 6 | 7 | TEST(sslNameCheck, baseCases) 8 | { 9 | EXPECT_EQ(verifySslName("example.com", "example.com"), true); 10 | EXPECT_EQ(verifySslName("example.com", "example.org"), false); 11 | EXPECT_EQ(verifySslName("example.com", "www.example.com"), false); 12 | } 13 | 14 | TEST(sslNameCheck, rfc6125Examples) 15 | { 16 | EXPECT_EQ(verifySslName("*.example.com", "foo.example.com"), true); 17 | EXPECT_EQ(verifySslName("*.example.com", "foo.bar.example.com"), false); 18 | EXPECT_EQ(verifySslName("*.example.com", "example.com"), false); 19 | EXPECT_EQ(verifySslName("*bar.example.com", "foobar.example.com"), true); 20 | EXPECT_EQ(verifySslName("baz*.example.com", "baz1.example.com"), true); 21 | EXPECT_EQ(verifySslName("b*z.example.com", "buzz.example.com"), true); 22 | } 23 | 24 | TEST(sslNameCheck, rfcCounterExamples) 25 | { 26 | EXPECT_EQ(verifySslName("buz*.example.com", "buaz.example.com"), false); 27 | EXPECT_EQ(verifySslName("*bar.example.com", "aaasdasbaz.example.com"), 28 | false); 29 | EXPECT_EQ(verifySslName("b*z.example.com", "baaaaaa.example.com"), false); 30 | } 31 | 32 | TEST(sslNameCheck, wildExamples) 33 | { 34 | EXPECT_EQ(verifySslName("datatracker.ietf.org", "datatracker.ietf.org"), 35 | true); 36 | EXPECT_EQ(verifySslName("*.nsysu.edu.tw", "nsysu.edu.tw"), false); 37 | EXPECT_EQ(verifySslName("nsysu.edu.tw", "nsysu.edu.tw"), true); 38 | } 39 | 40 | TEST(sslNameCheck, edgeCase) 41 | { 42 | EXPECT_EQ(verifySslName(".example.com", "example.com"), false); 43 | EXPECT_EQ(verifySslName("example.com.", "example.com."), true); 44 | } 45 | 46 | int main(int argc, char **argv) 47 | { 48 | testing::InitGoogleTest(&argc, argv); 49 | return RUN_ALL_TESTS(); 50 | } 51 | -------------------------------------------------------------------------------- /trantor/utils/ConcurrentTaskQueue.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * ConcurrentTaskQueue.cc 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #ifdef __linux__ 19 | #include 20 | #endif 21 | using namespace trantor; 22 | ConcurrentTaskQueue::ConcurrentTaskQueue(size_t threadNum, 23 | const std::string &name) 24 | : queueCount_(threadNum), queueName_(name), stop_(false) 25 | { 26 | assert(threadNum > 0); 27 | for (unsigned int i = 0; i < queueCount_; ++i) 28 | { 29 | threads_.push_back( 30 | std::thread(std::bind(&ConcurrentTaskQueue::queueFunc, this, i))); 31 | } 32 | } 33 | void ConcurrentTaskQueue::runTaskInQueue(const std::function &task) 34 | { 35 | LOG_TRACE << "copy task into queue"; 36 | std::lock_guard lock(taskMutex_); 37 | taskQueue_.push(task); 38 | taskCond_.notify_one(); 39 | } 40 | void ConcurrentTaskQueue::runTaskInQueue(std::function &&task) 41 | { 42 | LOG_TRACE << "move task into queue"; 43 | std::lock_guard lock(taskMutex_); 44 | taskQueue_.push(std::move(task)); 45 | taskCond_.notify_one(); 46 | } 47 | void ConcurrentTaskQueue::queueFunc(int queueNum) 48 | { 49 | char tmpName[32]; 50 | snprintf(tmpName, sizeof(tmpName), "%s%d", queueName_.c_str(), queueNum); 51 | #ifdef __linux__ 52 | ::prctl(PR_SET_NAME, tmpName); 53 | #endif 54 | while (!stop_) 55 | { 56 | std::function r; 57 | { 58 | std::unique_lock lock(taskMutex_); 59 | while (!stop_ && taskQueue_.size() == 0) 60 | { 61 | taskCond_.wait(lock); 62 | } 63 | if (taskQueue_.size() > 0) 64 | { 65 | LOG_TRACE << "got a new task!"; 66 | r = std::move(taskQueue_.front()); 67 | taskQueue_.pop(); 68 | } 69 | else 70 | continue; 71 | } 72 | r(); 73 | } 74 | } 75 | 76 | size_t ConcurrentTaskQueue::getTaskCount() 77 | { 78 | std::lock_guard guard(taskMutex_); 79 | return taskQueue_.size(); 80 | } 81 | 82 | void ConcurrentTaskQueue::stop() 83 | { 84 | if (!stop_) 85 | { 86 | stop_ = true; 87 | taskCond_.notify_all(); 88 | for (auto &t : threads_) 89 | t.join(); 90 | } 91 | } 92 | ConcurrentTaskQueue::~ConcurrentTaskQueue() 93 | { 94 | stop(); 95 | } 96 | -------------------------------------------------------------------------------- /trantor/utils/ConcurrentTaskQueue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @file ConcurrentTaskQueue.h 4 | * @author An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | namespace trantor 26 | { 27 | /** 28 | * @brief This class implements a task queue running in parallel. Basically this 29 | * can be called a threads pool. 30 | * 31 | */ 32 | class TRANTOR_EXPORT ConcurrentTaskQueue : public TaskQueue 33 | { 34 | public: 35 | /** 36 | * @brief Construct a new concurrent task queue instance. 37 | * 38 | * @param threadNum The number of threads in the queue. 39 | * @param name The name of the queue. 40 | */ 41 | ConcurrentTaskQueue(size_t threadNum, const std::string &name); 42 | 43 | /** 44 | * @brief Run a task in the queue. 45 | * 46 | * @param task 47 | */ 48 | virtual void runTaskInQueue(const std::function &task); 49 | virtual void runTaskInQueue(std::function &&task); 50 | 51 | /** 52 | * @brief Get the name of the queue. 53 | * 54 | * @return std::string 55 | */ 56 | virtual std::string getName() const 57 | { 58 | return queueName_; 59 | }; 60 | 61 | /** 62 | * @brief Get the number of tasks to be executed in the queue. 63 | * 64 | * @return size_t 65 | */ 66 | size_t getTaskCount(); 67 | 68 | /** 69 | * @brief Stop all threads in the queue. 70 | * 71 | */ 72 | void stop(); 73 | 74 | ~ConcurrentTaskQueue(); 75 | 76 | private: 77 | size_t queueCount_; 78 | std::string queueName_; 79 | 80 | std::queue> taskQueue_; 81 | std::vector threads_; 82 | 83 | std::mutex taskMutex_; 84 | std::condition_variable taskCond_; 85 | std::atomic_bool stop_; 86 | void queueFunc(int queueNum); 87 | }; 88 | 89 | } // namespace trantor 90 | -------------------------------------------------------------------------------- /trantor/utils/Funcs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Funcs.h 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | #include 17 | #include 18 | #include 19 | namespace trantor 20 | { 21 | inline uint64_t hton64(uint64_t n) 22 | { 23 | static const int one = 1; 24 | static const char sig = *(char *)&one; 25 | if (sig == 0) 26 | return n; // for big endian machine just return the input 27 | char *ptr = reinterpret_cast(&n); 28 | std::reverse(ptr, ptr + sizeof(uint64_t)); 29 | return n; 30 | } 31 | inline uint64_t ntoh64(uint64_t n) 32 | { 33 | return hton64(n); 34 | } 35 | inline std::vector splitString(const std::string &s, 36 | const std::string &delimiter, 37 | bool acceptEmptyString = false) 38 | { 39 | if (delimiter.empty()) 40 | return std::vector{}; 41 | std::vector v; 42 | size_t last = 0; 43 | size_t next = 0; 44 | while ((next = s.find(delimiter, last)) != std::string::npos) 45 | { 46 | if (next > last || acceptEmptyString) 47 | v.push_back(s.substr(last, next - last)); 48 | last = next + delimiter.length(); 49 | } 50 | if (s.length() > last || acceptEmptyString) 51 | v.push_back(s.substr(last)); 52 | return v; 53 | } 54 | } // namespace trantor 55 | -------------------------------------------------------------------------------- /trantor/utils/LockFreeQueue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @file LockFreeQueue.h 4 | * @author An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | namespace trantor 22 | { 23 | /** 24 | * @brief This class template represents a lock-free multiple producers single 25 | * consumer queue 26 | * 27 | * @tparam T The type of the items in the queue. 28 | */ 29 | template 30 | class MpscQueue : public NonCopyable 31 | { 32 | public: 33 | MpscQueue() 34 | : head_(new BufferNode), tail_(head_.load(std::memory_order_relaxed)) 35 | { 36 | } 37 | ~MpscQueue() 38 | { 39 | T output; 40 | while (this->dequeue(output)) 41 | { 42 | } 43 | BufferNode *front = head_.load(std::memory_order_relaxed); 44 | delete front; 45 | } 46 | 47 | /** 48 | * @brief Put a item into the queue. 49 | * 50 | * @param input 51 | * @note This method can be called in multiple threads. 52 | */ 53 | void enqueue(T &&input) 54 | { 55 | BufferNode *node{new BufferNode(std::move(input))}; 56 | BufferNode *prevhead{head_.exchange(node, std::memory_order_acq_rel)}; 57 | prevhead->next_.store(node, std::memory_order_release); 58 | } 59 | void enqueue(const T &input) 60 | { 61 | BufferNode *node{new BufferNode(input)}; 62 | BufferNode *prevhead{head_.exchange(node, std::memory_order_acq_rel)}; 63 | prevhead->next_.store(node, std::memory_order_release); 64 | } 65 | 66 | /** 67 | * @brief Get a item from the queue. 68 | * 69 | * @param output 70 | * @return false if the queue is empty. 71 | * @note This method must be called in a single thread. 72 | */ 73 | bool dequeue(T &output) 74 | { 75 | BufferNode *tail = tail_.load(std::memory_order_relaxed); 76 | BufferNode *next = tail->next_.load(std::memory_order_acquire); 77 | 78 | if (next == nullptr) 79 | { 80 | return false; 81 | } 82 | output = std::move(*(next->dataPtr_)); 83 | delete next->dataPtr_; 84 | tail_.store(next, std::memory_order_release); 85 | delete tail; 86 | return true; 87 | } 88 | 89 | bool empty() 90 | { 91 | BufferNode *tail = tail_.load(std::memory_order_relaxed); 92 | BufferNode *next = tail->next_.load(std::memory_order_acquire); 93 | return next == nullptr; 94 | } 95 | 96 | private: 97 | struct BufferNode 98 | { 99 | BufferNode() = default; 100 | BufferNode(const T &data) : dataPtr_(new T(data)) 101 | { 102 | } 103 | BufferNode(T &&data) : dataPtr_(new T(std::move(data))) 104 | { 105 | } 106 | T *dataPtr_; 107 | std::atomic next_{nullptr}; 108 | }; 109 | 110 | std::atomic head_; 111 | std::atomic tail_; 112 | }; 113 | 114 | } // namespace trantor 115 | -------------------------------------------------------------------------------- /trantor/utils/NonCopyable.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @file NonCopyable.h 4 | * @author An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | 19 | namespace trantor 20 | { 21 | /** 22 | * @brief This class represents a non-copyable object. 23 | * 24 | */ 25 | class TRANTOR_EXPORT NonCopyable 26 | { 27 | protected: 28 | NonCopyable() 29 | { 30 | } 31 | ~NonCopyable() 32 | { 33 | } 34 | NonCopyable(const NonCopyable &) = delete; 35 | NonCopyable &operator=(const NonCopyable &) = delete; 36 | // some uncopyable classes maybe support move constructor.... 37 | NonCopyable(NonCopyable &&) noexcept(true) = default; 38 | NonCopyable &operator=(NonCopyable &&) noexcept(true) = default; 39 | }; 40 | 41 | } // namespace trantor 42 | -------------------------------------------------------------------------------- /trantor/utils/ObjectPool.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @file ObjectPool.h 4 | * @author An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace trantor 24 | { 25 | /** 26 | * @brief This class template represents a object pool. 27 | * 28 | * @tparam T 29 | */ 30 | template 31 | class ObjectPool : public NonCopyable, 32 | public std::enable_shared_from_this> 33 | { 34 | public: 35 | std::shared_ptr getObject() 36 | { 37 | static_assert(!std::is_pointer::value, 38 | "The parameter type of the ObjectPool template can't be " 39 | "pointer type"); 40 | T *p{nullptr}; 41 | { 42 | std::lock_guard lock(mtx_); 43 | if (!objs_.empty()) 44 | { 45 | p = objs_.back(); 46 | objs_.pop_back(); 47 | } 48 | } 49 | 50 | if (p == nullptr) 51 | { 52 | p = new T; 53 | } 54 | 55 | assert(p); 56 | std::weak_ptr> weakPtr = this->shared_from_this(); 57 | auto obj = std::shared_ptr(p, [weakPtr](T *ptr) { 58 | auto self = weakPtr.lock(); 59 | if (self) 60 | { 61 | std::lock_guard lock(self->mtx_); 62 | self->objs_.push_back(ptr); 63 | } 64 | else 65 | { 66 | delete ptr; 67 | } 68 | }); 69 | return obj; 70 | } 71 | 72 | private: 73 | std::vector objs_; 74 | std::mutex mtx_; 75 | }; 76 | } // namespace trantor -------------------------------------------------------------------------------- /trantor/utils/SerialTaskQueue.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * SerialTaskQueue.cc 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #include 16 | #include 17 | #ifdef __linux__ 18 | #include 19 | #endif 20 | namespace trantor 21 | { 22 | SerialTaskQueue::SerialTaskQueue(const std::string &name) 23 | : queueName_(name.empty() ? "SerialTaskQueue" : name), 24 | loopThread_(queueName_) 25 | { 26 | loopThread_.run(); 27 | } 28 | void SerialTaskQueue::stop() 29 | { 30 | stop_ = true; 31 | loopThread_.getLoop()->quit(); 32 | loopThread_.wait(); 33 | } 34 | SerialTaskQueue::~SerialTaskQueue() 35 | { 36 | if (!stop_) 37 | stop(); 38 | LOG_TRACE << "destruct SerialTaskQueue('" << queueName_ << "')"; 39 | } 40 | void SerialTaskQueue::runTaskInQueue(const std::function &task) 41 | { 42 | loopThread_.getLoop()->runInLoop(task); 43 | } 44 | void SerialTaskQueue::runTaskInQueue(std::function &&task) 45 | { 46 | loopThread_.getLoop()->runInLoop(std::move(task)); 47 | } 48 | 49 | void SerialTaskQueue::waitAllTasksFinished() 50 | { 51 | syncTaskInQueue([]() { 52 | 53 | }); 54 | } 55 | 56 | } // namespace trantor 57 | -------------------------------------------------------------------------------- /trantor/utils/SerialTaskQueue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * SerialTaskQueue.h 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include "TaskQueue.h" 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | namespace trantor 25 | { 26 | /** 27 | * @brief This class represents a task queue in which all tasks are executed one 28 | * by one. 29 | * 30 | */ 31 | class TRANTOR_EXPORT SerialTaskQueue : public TaskQueue 32 | { 33 | public: 34 | /** 35 | * @brief Run a task in the queue. 36 | * 37 | * @param task 38 | */ 39 | virtual void runTaskInQueue(const std::function &task); 40 | virtual void runTaskInQueue(std::function &&task); 41 | 42 | /** 43 | * @brief Get the name of the queue. 44 | * 45 | * @return std::string 46 | */ 47 | virtual std::string getName() const 48 | { 49 | return queueName_; 50 | }; 51 | 52 | /** 53 | * @brief Wait until all tasks in the queue are finished. 54 | * 55 | */ 56 | void waitAllTasksFinished(); 57 | 58 | SerialTaskQueue() = delete; 59 | 60 | /** 61 | * @brief Construct a new serial task queue instance. 62 | * 63 | * @param name 64 | */ 65 | explicit SerialTaskQueue(const std::string &name); 66 | 67 | virtual ~SerialTaskQueue(); 68 | 69 | /* clang-format off */ 70 | /** 71 | * @brief Check whether a task is running in the queue. 72 | * 73 | * @return true 74 | * @return false 75 | * @deprecated Use isRunningTask instead 76 | */ 77 | [[deprecated("Use isRunningTask instead")]] 78 | bool isRuningTask() 79 | { 80 | return isRunningTask(); 81 | } 82 | /* clang-format on */ 83 | 84 | /** 85 | * @brief Check whether a task is running in the queue. 86 | * 87 | * @return true 88 | * @return false 89 | */ 90 | bool isRunningTask() 91 | { 92 | return loopThread_.getLoop() 93 | ? loopThread_.getLoop()->isCallingFunctions() 94 | : false; 95 | } 96 | 97 | /** 98 | * @brief Get the number of tasks in the queue. 99 | * 100 | * @return size_t 101 | */ 102 | size_t getTaskCount(); 103 | 104 | /** 105 | * @brief Stop the queue. 106 | * 107 | */ 108 | void stop(); 109 | 110 | protected: 111 | std::string queueName_; 112 | EventLoopThread loopThread_; 113 | bool stop_{false}; 114 | }; 115 | } // namespace trantor 116 | -------------------------------------------------------------------------------- /trantor/utils/TaskQueue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @file TaskQueue.h 4 | * @author An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include "NonCopyable.h" 18 | #include 19 | #include 20 | #include 21 | namespace trantor 22 | { 23 | /** 24 | * @brief This class is a pure virtual class that can be implemented as a 25 | * SerialTaskQueue or a ConcurrentTaskQueue. 26 | * 27 | */ 28 | class TaskQueue : public NonCopyable 29 | { 30 | public: 31 | virtual void runTaskInQueue(const std::function &task) = 0; 32 | virtual void runTaskInQueue(std::function &&task) = 0; 33 | virtual std::string getName() const 34 | { 35 | return ""; 36 | }; 37 | 38 | /** 39 | * @brief Run a task in the queue synchronously. This means that the task is 40 | * executed before the method returns. 41 | * 42 | * @param task 43 | */ 44 | void syncTaskInQueue(const std::function &task) 45 | { 46 | std::promise prom; 47 | std::future fut = prom.get_future(); 48 | runTaskInQueue([&]() { 49 | task(); 50 | prom.set_value(1); 51 | }); 52 | fut.get(); 53 | }; 54 | virtual ~TaskQueue() 55 | { 56 | } 57 | }; 58 | } // namespace trantor 59 | -------------------------------------------------------------------------------- /trantor/utils/TimingWheel.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * TimingWheel.cc 4 | * An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #include 16 | 17 | using namespace trantor; 18 | 19 | TimingWheel::TimingWheel(trantor::EventLoop *loop, 20 | size_t maxTimeout, 21 | float ticksInterval, 22 | size_t bucketsNumPerWheel) 23 | : loop_(loop), 24 | ticksInterval_(ticksInterval), 25 | bucketsNumPerWheel_(bucketsNumPerWheel) 26 | { 27 | assert(maxTimeout > 1); 28 | assert(ticksInterval > 0); 29 | assert(bucketsNumPerWheel_ > 1); 30 | size_t maxTickNum = static_cast(maxTimeout / ticksInterval); 31 | auto ticksNum = bucketsNumPerWheel; 32 | wheelsNum_ = 1; 33 | while (maxTickNum > ticksNum) 34 | { 35 | ++wheelsNum_; 36 | ticksNum *= bucketsNumPerWheel_; 37 | } 38 | wheels_.resize(wheelsNum_); 39 | for (size_t i = 0; i < wheelsNum_; ++i) 40 | { 41 | wheels_[i].resize(bucketsNumPerWheel_); 42 | } 43 | timerId_ = loop_->runEvery(ticksInterval_, [this]() { 44 | ++ticksCounter_; 45 | size_t t = ticksCounter_; 46 | size_t pow = 1; 47 | for (size_t i = 0; i < wheelsNum_; ++i) 48 | { 49 | if ((t % pow) == 0) 50 | { 51 | EntryBucket tmp; 52 | { 53 | // use tmp val to make this critical area as short as 54 | // possible. 55 | wheels_[i].front().swap(tmp); 56 | wheels_[i].pop_front(); 57 | wheels_[i].push_back(EntryBucket()); 58 | } 59 | } 60 | pow = pow * bucketsNumPerWheel_; 61 | } 62 | }); 63 | } 64 | 65 | TimingWheel::~TimingWheel() 66 | { 67 | loop_->assertInLoopThread(); 68 | loop_->invalidateTimer(timerId_); 69 | for (auto iter = wheels_.rbegin(); iter != wheels_.rend(); ++iter) 70 | { 71 | iter->clear(); 72 | } 73 | LOG_TRACE << "TimingWheel destruct!"; 74 | } 75 | 76 | void TimingWheel::insertEntry(size_t delay, EntryPtr entryPtr) 77 | { 78 | if (delay <= 0) 79 | return; 80 | if (!entryPtr) 81 | return; 82 | if (loop_->isInLoopThread()) 83 | { 84 | insertEntryInloop(delay, entryPtr); 85 | } 86 | else 87 | { 88 | loop_->runInLoop( 89 | [this, delay, entryPtr]() { insertEntryInloop(delay, entryPtr); }); 90 | } 91 | } 92 | 93 | void TimingWheel::insertEntryInloop(size_t delay, EntryPtr entryPtr) 94 | { 95 | loop_->assertInLoopThread(); 96 | 97 | delay = static_cast(delay / ticksInterval_ + 1); 98 | size_t t = ticksCounter_; 99 | for (size_t i = 0; i < wheelsNum_; ++i) 100 | { 101 | if (delay <= bucketsNumPerWheel_) 102 | { 103 | wheels_[i][delay - 1].insert(entryPtr); 104 | break; 105 | } 106 | if (i < (wheelsNum_ - 1)) 107 | { 108 | entryPtr = std::make_shared( 109 | [this, delay, i, t, entryPtr]() { 110 | if (delay > 0) 111 | { 112 | wheels_[i][(delay + (t % bucketsNumPerWheel_) - 1) % 113 | bucketsNumPerWheel_] 114 | .insert(entryPtr); 115 | } 116 | }); 117 | } 118 | else 119 | { 120 | // delay is too long to put entry at valid position in wheels; 121 | wheels_[i][bucketsNumPerWheel_ - 1].insert(entryPtr); 122 | } 123 | delay = (delay + (t % bucketsNumPerWheel_) - 1) / bucketsNumPerWheel_; 124 | t = t / bucketsNumPerWheel_; 125 | } 126 | } -------------------------------------------------------------------------------- /trantor/utils/TimingWheel.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @file TimingWheel.h 4 | * @author An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #define TIMING_BUCKET_NUM_PER_WHEEL 100 31 | #define TIMING_TICK_INTERVAL 1.0 32 | 33 | namespace trantor 34 | { 35 | using EntryPtr = std::shared_ptr; 36 | 37 | using EntryBucket = std::unordered_set; 38 | using BucketQueue = std::deque; 39 | 40 | /** 41 | * @brief This class implements a timer strategy with high performance and low 42 | * accuracy. This is usually used internally. 43 | * 44 | */ 45 | class TRANTOR_EXPORT TimingWheel 46 | { 47 | public: 48 | class CallbackEntry 49 | { 50 | public: 51 | CallbackEntry(std::function cb) : cb_(std::move(cb)) 52 | { 53 | } 54 | ~CallbackEntry() 55 | { 56 | cb_(); 57 | } 58 | 59 | private: 60 | std::function cb_; 61 | }; 62 | 63 | /** 64 | * @brief Construct a new timing wheel instance. 65 | * 66 | * @param loop The event loop in which the timing wheel runs. 67 | * @param maxTimeout The maximum timeout of the timing wheel. 68 | * @param ticksInterval The internal timer tick interval. It affects the 69 | * accuracy of the timing wheel. 70 | * @param bucketsNumPerWheel The number of buckets per wheel. 71 | * @note The max delay of the timing wheel is about 72 | * ticksInterval*(bucketsNumPerWheel^wheelsNum) seconds. 73 | * @note 74 | * Example: Four wheels with 200 buckets per wheel means the timing wheel 75 | * can work with a timeout up to 200^4 seconds, about 50 years; 76 | */ 77 | TimingWheel(trantor::EventLoop *loop, 78 | size_t maxTimeout, 79 | float ticksInterval = TIMING_TICK_INTERVAL, 80 | size_t bucketsNumPerWheel = TIMING_BUCKET_NUM_PER_WHEEL); 81 | 82 | void insertEntry(size_t delay, EntryPtr entryPtr); 83 | 84 | void insertEntryInloop(size_t delay, EntryPtr entryPtr); 85 | 86 | EventLoop *getLoop() 87 | { 88 | return loop_; 89 | } 90 | 91 | ~TimingWheel(); 92 | 93 | private: 94 | std::vector wheels_; 95 | 96 | std::atomic ticksCounter_{0}; 97 | 98 | trantor::TimerId timerId_; 99 | trantor::EventLoop *loop_; 100 | 101 | float ticksInterval_; 102 | size_t wheelsNum_; 103 | size_t bucketsNumPerWheel_; 104 | }; 105 | } // namespace trantor 106 | -------------------------------------------------------------------------------- /trantor/utils/WindowsSupport.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * WindowsSupport.cc 4 | * An Tao 5 | * 6 | * Implementation of Windows support functions. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #include 16 | #include 17 | 18 | // from polipo 19 | int win32_read_socket(int fd, void *buf, int n) 20 | { 21 | int rc = recv(fd, reinterpret_cast(buf), n, 0); 22 | if (rc == SOCKET_ERROR) 23 | { 24 | _set_errno(WSAGetLastError()); 25 | } 26 | return rc; 27 | } 28 | 29 | int readv(int fd, const struct iovec *vector, int count) 30 | { 31 | int ret = 0; /* Return value */ 32 | int i; 33 | for (i = 0; i < count; i++) 34 | { 35 | int n = vector[i].iov_len; 36 | int rc = win32_read_socket(fd, vector[i].iov_base, n); 37 | if (rc == n) 38 | { 39 | ret += rc; 40 | } 41 | else 42 | { 43 | if (rc < 0) 44 | { 45 | ret = (ret == 0 ? rc : ret); 46 | } 47 | else 48 | { 49 | ret += rc; 50 | } 51 | break; 52 | } 53 | } 54 | return ret; 55 | } 56 | -------------------------------------------------------------------------------- /trantor/utils/WindowsSupport.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @file WindowsSupport.h 4 | * @author An Tao 5 | * 6 | * Public header file in trantor lib. 7 | * 8 | * Copyright 2018, An Tao. All rights reserved. 9 | * Use of this source code is governed by a BSD-style license 10 | * that can be found in the License file. 11 | * 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | 20 | struct iovec 21 | { 22 | void *iov_base; /* Starting address */ 23 | int iov_len; /* Number of bytes */ 24 | }; 25 | 26 | TRANTOR_EXPORT int readv(int fd, const struct iovec *vector, int count); 27 | -------------------------------------------------------------------------------- /trantor/utils/crypto/blake2.h: -------------------------------------------------------------------------------- 1 | void trantor_blake2b(void* output, 2 | size_t outlen, 3 | const void* input, 4 | size_t inlen, 5 | const void* key, 6 | size_t keylen); 7 | -------------------------------------------------------------------------------- /trantor/utils/crypto/botan.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace trantor 7 | { 8 | namespace utils 9 | { 10 | Hash128 md5(const void* data, size_t len) 11 | { 12 | Hash128 hash; 13 | auto md5 = Botan::HashFunction::create("MD5"); 14 | md5->update((const unsigned char*)data, len); 15 | md5->final((unsigned char*)&hash); 16 | return hash; 17 | } 18 | 19 | Hash160 sha1(const void* data, size_t len) 20 | { 21 | Hash160 hash; 22 | auto sha1 = Botan::HashFunction::create("SHA-1"); 23 | sha1->update((const unsigned char*)data, len); 24 | sha1->final((unsigned char*)&hash); 25 | return hash; 26 | } 27 | 28 | Hash256 sha256(const void* data, size_t len) 29 | { 30 | Hash256 hash; 31 | auto sha256 = Botan::HashFunction::create("SHA-256"); 32 | sha256->update((const unsigned char*)data, len); 33 | sha256->final((unsigned char*)&hash); 34 | return hash; 35 | } 36 | 37 | Hash256 sha3(const void* data, size_t len) 38 | { 39 | Hash256 hash; 40 | auto sha3 = Botan::HashFunction::create("SHA-3(256)"); 41 | assert(sha3 != nullptr); 42 | sha3->update((const unsigned char*)data, len); 43 | sha3->final((unsigned char*)&hash); 44 | return hash; 45 | } 46 | 47 | Hash256 blake2b(const void* data, size_t len) 48 | { 49 | Hash256 hash; 50 | auto blake2b = Botan::HashFunction::create("BLAKE2b(256)"); 51 | assert(blake2b != nullptr); 52 | blake2b->update((const unsigned char*)data, len); 53 | blake2b->final((unsigned char*)&hash); 54 | return hash; 55 | } 56 | 57 | } // namespace utils 58 | } // namespace trantor -------------------------------------------------------------------------------- /trantor/utils/crypto/md5.h: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Filename: md5.h 3 | * Author: Brad Conte (brad AT bradconte.com) 4 | * Copyright: 5 | * Disclaimer: This code is presented "as is" without any guarantees. 6 | * Details: Defines the API for the corresponding MD5 implementation. 7 | *********************************************************************/ 8 | 9 | #ifndef MD5_H 10 | #define MD5_H 11 | 12 | /*************************** HEADER FILES ***************************/ 13 | #include 14 | #include 15 | 16 | /****************************** MACROS ******************************/ 17 | #define MD5_BLOCK_SIZE 32 // MD5 outputs a 32 byte digest 18 | 19 | typedef struct 20 | { 21 | uint8_t data[64]; 22 | uint32_t datalen; 23 | uint64_t bitlen; 24 | uint32_t state[4]; 25 | } MD5_CTX; 26 | 27 | /*********************** FUNCTION DECLARATIONS **********************/ 28 | void trantor_md5_init(MD5_CTX *ctx); 29 | void trantor_md5_update(MD5_CTX *ctx, const uint8_t data[], size_t len); 30 | void trantor_md5_final(MD5_CTX *ctx, uint8_t hash[]); 31 | 32 | #endif // MD5_H -------------------------------------------------------------------------------- /trantor/utils/crypto/openssl.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #if OPENSSL_VERSION_MAJOR < 3 6 | #include 7 | #include 8 | #endif 9 | 10 | #include "sha3.h" 11 | #include "sha3.cc" 12 | 13 | // Some OpenSSL installations does not come with BLAKE2b-256 14 | // We use our own implementation in such case 15 | #include "blake2.h" 16 | #include "blake2.cc" 17 | 18 | namespace trantor 19 | { 20 | namespace utils 21 | { 22 | Hash128 md5(const void* data, size_t len) 23 | { 24 | #if OPENSSL_VERSION_MAJOR >= 3 25 | Hash128 hash; 26 | auto md5 = EVP_MD_fetch(nullptr, "MD5", nullptr); 27 | auto ctx = EVP_MD_CTX_new(); 28 | EVP_DigestInit_ex(ctx, md5, nullptr); 29 | EVP_DigestUpdate(ctx, data, len); 30 | EVP_DigestFinal_ex(ctx, (unsigned char*)&hash, nullptr); 31 | EVP_MD_CTX_free(ctx); 32 | EVP_MD_free(md5); 33 | return hash; 34 | #else 35 | Hash128 hash; 36 | MD5_CTX ctx; 37 | MD5_Init(&ctx); 38 | MD5_Update(&ctx, data, len); 39 | MD5_Final((unsigned char*)&hash, &ctx); 40 | return hash; 41 | #endif 42 | } 43 | 44 | Hash160 sha1(const void* data, size_t len) 45 | { 46 | #if OPENSSL_VERSION_MAJOR >= 3 47 | Hash160 hash; 48 | auto sha1 = EVP_MD_fetch(nullptr, "SHA1", nullptr); 49 | auto ctx = EVP_MD_CTX_new(); 50 | EVP_DigestInit_ex(ctx, sha1, nullptr); 51 | EVP_DigestUpdate(ctx, data, len); 52 | EVP_DigestFinal_ex(ctx, (unsigned char*)&hash, nullptr); 53 | EVP_MD_CTX_free(ctx); 54 | EVP_MD_free(sha1); 55 | return hash; 56 | #else 57 | Hash160 hash; 58 | SHA_CTX ctx; 59 | SHA1_Init(&ctx); 60 | SHA1_Update(&ctx, data, len); 61 | SHA1_Final((unsigned char*)&hash, &ctx); 62 | return hash; 63 | #endif 64 | } 65 | 66 | Hash256 sha256(const void* data, size_t len) 67 | { 68 | #if OPENSSL_VERSION_MAJOR >= 3 69 | Hash256 hash; 70 | auto sha256 = EVP_MD_fetch(nullptr, "SHA256", nullptr); 71 | auto ctx = EVP_MD_CTX_new(); 72 | EVP_DigestInit_ex(ctx, sha256, nullptr); 73 | EVP_DigestUpdate(ctx, data, len); 74 | EVP_DigestFinal_ex(ctx, (unsigned char*)&hash, nullptr); 75 | EVP_MD_CTX_free(ctx); 76 | EVP_MD_free(sha256); 77 | return hash; 78 | #else 79 | Hash256 hash; 80 | SHA256_CTX ctx; 81 | SHA256_Init(&ctx); 82 | SHA256_Update(&ctx, data, len); 83 | SHA256_Final((unsigned char*)&hash, &ctx); 84 | return hash; 85 | #endif 86 | } 87 | 88 | Hash256 sha3(const void* data, size_t len) 89 | { 90 | Hash256 hash; 91 | #if OPENSSL_VERSION_MAJOR >= 3 92 | auto sha3 = EVP_MD_fetch(nullptr, "SHA3-256", nullptr); 93 | if (sha3 != nullptr) 94 | { 95 | auto ctx = EVP_MD_CTX_new(); 96 | EVP_DigestInit_ex(ctx, sha3, nullptr); 97 | EVP_DigestUpdate(ctx, data, len); 98 | EVP_DigestFinal_ex(ctx, (unsigned char*)&hash, nullptr); 99 | EVP_MD_CTX_free(ctx); 100 | EVP_MD_free(sha3); 101 | return hash; 102 | } 103 | #elif !defined(LIBRESSL_VERSION_NUMBER) 104 | auto sha3 = EVP_sha3_256(); 105 | if (sha3 != nullptr) 106 | { 107 | EVP_MD_CTX* ctx = EVP_MD_CTX_new(); 108 | EVP_DigestInit_ex(ctx, sha3, nullptr); 109 | EVP_DigestUpdate(ctx, data, len); 110 | EVP_DigestFinal_ex(ctx, (unsigned char*)&hash, nullptr); 111 | EVP_MD_CTX_free(ctx); 112 | return hash; 113 | } 114 | #endif 115 | trantor_sha3((const unsigned char*)data, len, &hash, sizeof(hash)); 116 | return hash; 117 | } 118 | 119 | Hash256 blake2b(const void* data, size_t len) 120 | { 121 | Hash256 hash; 122 | #if OPENSSL_VERSION_MAJOR >= 3 123 | auto blake2b = EVP_MD_fetch(nullptr, "BLAKE2b-256", nullptr); 124 | if (blake2b != nullptr) 125 | { 126 | auto ctx = EVP_MD_CTX_new(); 127 | EVP_DigestInit_ex(ctx, blake2b, nullptr); 128 | EVP_DigestUpdate(ctx, data, len); 129 | EVP_DigestFinal_ex(ctx, (unsigned char*)&hash, nullptr); 130 | EVP_MD_CTX_free(ctx); 131 | EVP_MD_free(blake2b); 132 | return hash; 133 | } 134 | #endif 135 | trantor_blake2b(&hash, sizeof(hash), data, len, nullptr, 0); 136 | return hash; 137 | } 138 | 139 | } // namespace utils 140 | } // namespace trantor 141 | -------------------------------------------------------------------------------- /trantor/utils/crypto/sha1.h: -------------------------------------------------------------------------------- 1 | /* ================ sha1.h ================ */ 2 | /* 3 | SHA-1 in C 4 | By Steve Reid 5 | 100% Public Domain 6 | 7 | Last modified by Martin Chang for the Trantor project 8 | */ 9 | 10 | #pragma once 11 | 12 | #include 13 | 14 | typedef struct 15 | { 16 | uint32_t state[5]; 17 | size_t count[2]; 18 | unsigned char buffer[64]; 19 | } SHA1_CTX; 20 | 21 | void trantor_sha1_transform(uint32_t state[5], const unsigned char buffer[64]); 22 | void trantor_sha1_init(SHA1_CTX* context); 23 | void trantor_sha1_update(SHA1_CTX* context, 24 | const unsigned char* data, 25 | size_t len); 26 | void trantor_sha1_final(unsigned char digest[20], SHA1_CTX* context); 27 | -------------------------------------------------------------------------------- /trantor/utils/crypto/sha256.h: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Filename: sha256.h 3 | * Author: Brad Conte (brad AT bradconte.com) 4 | * Copyright: 5 | * Disclaimer: This code is presented "as is" without any guarantees. 6 | * Details: Defines the API for the corresponding SHA1 implementation. 7 | *********************************************************************/ 8 | 9 | #ifndef SHA256_H 10 | #define SHA256_H 11 | 12 | /*************************** HEADER FILES ***************************/ 13 | #include 14 | 15 | /****************************** MACROS ******************************/ 16 | #define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest 17 | 18 | typedef struct 19 | { 20 | uint8_t data[64]; 21 | uint32_t datalen; 22 | uint64_t bitlen; 23 | uint32_t state[8]; 24 | } SHA256_CTX; 25 | 26 | /*********************** FUNCTION DECLARATIONS **********************/ 27 | void trantor_sha256_init(SHA256_CTX *ctx); 28 | void trantor_sha256_update(SHA256_CTX *ctx, const uint8_t data[], size_t len); 29 | void trantor_sha256_final(SHA256_CTX *ctx, uint8_t hash[]); 30 | 31 | #endif // SHA256_H -------------------------------------------------------------------------------- /trantor/utils/crypto/sha3.h: -------------------------------------------------------------------------------- 1 | // sha3.h 2 | // 19-Nov-11 Markku-Juhani O. Saarinen 3 | 4 | #ifndef SHA3_H 5 | #define SHA3_H 6 | 7 | #include 8 | #include 9 | 10 | #ifndef KECCAKF_ROUNDS 11 | #define KECCAKF_ROUNDS 24 12 | #endif 13 | 14 | #ifndef ROTL64 15 | #define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) 16 | #endif 17 | 18 | // state context 19 | typedef struct 20 | { 21 | union 22 | { // state: 23 | uint8_t b[200]; // 8-bit bytes 24 | uint64_t q[25]; // 64-bit words 25 | } st; 26 | int pt, rsiz, mdlen; // these don't overflow 27 | } sha3_ctx_t; 28 | 29 | // Compression function. 30 | void trantor_sha3_keccakf(uint64_t st[25]); 31 | 32 | // OpenSSL - like interface 33 | int trantor_sha3_init(sha3_ctx_t *c, 34 | int mdlen); // mdlen = hash output in bytes 35 | int trantor_sha3_update(sha3_ctx_t *c, const void *data, size_t len); 36 | int trantor_sha3_final(void *md, sha3_ctx_t *c); // digest goes to md 37 | 38 | // compute a sha3 hash (md) of given byte length from "in" 39 | void *trantor_sha3(const void *in, size_t inlen, void *md, int mdlen); 40 | 41 | // SHAKE128 and SHAKE256 extensible-output functions 42 | #define trantor_shake128_init(c) trantor_sha3_init(c, 16) 43 | #define trantor_shake256_init(c) trantor_sha3_init(c, 32) 44 | #define trantor_shake_update trantor_sha3_update 45 | 46 | void trantor_shake_xof(sha3_ctx_t *c); 47 | void trantor_shake_out(sha3_ctx_t *c, void *out, size_t len); 48 | 49 | #endif 50 | --------------------------------------------------------------------------------