├── .bazelrc ├── .clang-format ├── .github └── workflows │ ├── ci.yaml │ ├── codeql.yaml │ ├── snapshot_tag.yaml │ └── super-linter.yaml ├── .gitignore ├── BUILD ├── CPPLINT.cfg ├── LICENSE ├── README.md ├── WORKSPACE ├── bazel ├── boringssl.BUILD ├── jemalloc.BUILD ├── mbedtls.BUILD ├── mimalloc.BUILD ├── nanopb.BUILD └── spdlog.BUILD ├── bazelrc.linux ├── bazelrc.macos ├── bazelrc.windows ├── scripts ├── build.sh ├── ci_build.sh └── delete_tag.sh ├── snova ├── BUILD.bazel ├── app │ ├── BUILD.bazel │ └── snova.cc ├── copts │ └── configure_copts.bzl ├── io │ ├── BUILD.bazel │ ├── buffered_io.cc │ ├── buffered_io.h │ ├── io.cc │ ├── io.h │ ├── io_util.cc │ ├── io_util.h │ ├── tcp_socket.cc │ ├── tcp_socket.h │ ├── tls_socket.cc │ ├── tls_socket.h │ ├── tls_socket_test.cc │ ├── transfer.cc │ ├── transfer.h │ ├── ws_socket.cc │ ├── ws_socket.h │ └── ws_socket_test.cc ├── log │ ├── BUILD.bazel │ └── log_macros.h ├── mux │ ├── BUILD.bazel │ ├── CPPLINT.cfg │ ├── cipher_context.cc │ ├── cipher_context.h │ ├── cipher_context_test.cc │ ├── mux_client.cc │ ├── mux_client.h │ ├── mux_conn_manager.cc │ ├── mux_conn_manager.h │ ├── mux_connection.cc │ ├── mux_connection.h │ ├── mux_event.cc │ ├── mux_event.h │ ├── mux_event.options │ ├── mux_event.pb.c │ ├── mux_event.pb.h │ ├── mux_event.proto │ ├── mux_event_test.cc │ ├── mux_stream.cc │ └── mux_stream.h ├── server │ ├── BUILD.bazel │ ├── dns_proxy_server.cc │ ├── dns_proxy_server.h │ ├── entry_server.cc │ ├── entry_server.h │ ├── http.cc │ ├── mux_server.cc │ ├── mux_server.h │ ├── relay.cc │ ├── relay.h │ ├── socks5.cc │ ├── tls.cc │ ├── tunnel_server.cc │ └── tunnel_server.h └── util │ ├── BUILD.bazel │ ├── address.cc │ ├── address.h │ ├── async_channel_mutex.cc │ ├── async_channel_mutex.h │ ├── dns_options.cc │ ├── dns_options.h │ ├── endian.h │ ├── flags.cc │ ├── flags.h │ ├── http_helper.cc │ ├── http_helper.h │ ├── misc_helper.cc │ ├── misc_helper.h │ ├── net_helper.cc │ ├── net_helper.h │ ├── sni.cc │ ├── sni.h │ ├── stat.cc │ ├── stat.h │ ├── time_wheel.cc │ ├── time_wheel.h │ ├── tunnel_opt.cc │ └── tunnel_opt.h ├── snova_asio.bzl └── toolchains ├── BUILD ├── aarch64_linux_musl.BUILD ├── arm_linux_musleabi.BUILD ├── arm_linux_musleabihf.BUILD ├── gcc_arm_linux_gnueabihf.BUILD ├── gcc_arm_toolchain.bzl ├── linux-musl.bzl ├── x86_64-linux-musl.BUILD └── x86_64-linux-musl.bzl /.bazelrc: -------------------------------------------------------------------------------- 1 | #build --cxxopt=-std=c++20 2 | #build --features=fully_static_link 3 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: Google 4 | ColumnLimit: 100 5 | 6 | DerivePointerAlignment: true 7 | 8 | PointerAlignment: Left 9 | 10 | # Only sort headers in each include block 11 | SortIncludes: true 12 | IncludeBlocks: Preserve 13 | --- 14 | Language: Proto 15 | BasedOnStyle: Google 16 | 17 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CIBuild 2 | # jscpd:ignore-start 3 | on: 4 | push: 5 | # Sequence of patterns matched against refs/heads 6 | branches: 7 | - dev 8 | # Sequence of patterns matched against refs/tags 9 | tags: 10 | - '*' 11 | pull_request: 12 | types: [ assigned, opened, synchronize, reopened, labeled ] 13 | jobs: 14 | ci_matrix: 15 | strategy: 16 | matrix: 17 | os: [ubuntu-latest, windows-latest, macos-latest] 18 | # cpu: [amd64] 19 | cpu: [amd64, arm_eabi, arm_eabihf, aarch64] 20 | exclude: 21 | - os: windows-latest 22 | cpu: arm_eabi 23 | - os: windows-latest 24 | cpu: arm_eabihf 25 | - os: windows-latest 26 | cpu: aarch64 27 | - os: macos-latest 28 | cpu: arm_eabi 29 | - os: macos-latest 30 | cpu: arm_eabihf 31 | - os: macos-latest 32 | cpu: aarch64 33 | runs-on: ${{ matrix.os }} 34 | steps: 35 | - uses: actions/checkout@v3 36 | - name: Get the tag version 37 | id: get_version 38 | if: startsWith(github.ref, 'refs/tags/') 39 | run: echo BUILD_VERSION="$(echo "${GITHUB_REF}" | cut -d / -f 3)" >> "$GITHUB_ENV" 40 | shell: bash 41 | - name: Get the commit version 42 | if: startsWith(github.ref, 'refs/tags/') != true 43 | run: echo BUILD_VERSION="${GITHUB_SHA}" >> "$GITHUB_ENV" 44 | shell: bash 45 | - uses: bazelbuild/setup-bazelisk@v2 46 | - name: Build 47 | run: sh ./scripts/ci_build.sh ${{ matrix.cpu }} 48 | shell: bash 49 | - name: Release 50 | uses: softprops/action-gh-release@v1 51 | if: startsWith(github.ref, 'refs/tags/') 52 | with: 53 | fail_on_unmatched_files: true 54 | files: snova_asio_**.tar.bz2 55 | # jscpd:ignore-end 56 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yaml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "dev" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "main" ] 20 | schedule: 21 | - cron: '45 12 * * 6' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'cpp' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | # - name: Autobuild 59 | # uses: github/codeql-action/autobuild@v2 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | - uses: bazelbuild/setup-bazelisk@v2 68 | - run: | 69 | echo "Run, Build Application using script" 70 | bazel build --features=fully_static_link --cxxopt=-std=c++20 --cxxopt=-DSNOVA_VERSION=${BUILD_VERSION} --incompatible_enable_cc_toolchain_resolution --platforms=//toolchains:linux_musl_x64 //... 71 | 72 | - name: Perform CodeQL Analysis 73 | uses: github/codeql-action/analyze@v2 74 | -------------------------------------------------------------------------------- /.github/workflows/snapshot_tag.yaml: -------------------------------------------------------------------------------- 1 | name: SnapshotTag 2 | 3 | on: 4 | # Triggers the workflow every 5 minutes 5 | schedule: 6 | - cron: "0 12 * * *" 7 | 8 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 9 | jobs: 10 | # This workflow contains a single job called "cron" 11 | cron: 12 | # The type of runner that the job will run on 13 | runs-on: ubuntu-latest 14 | environment: workflow 15 | 16 | # Steps represent a sequence of tasks that will be executed as part of the job 17 | steps: 18 | - name: Get yesterday date 19 | id: yesterday 20 | run: echo "::set-output name=date::$(date -d 'yesterday' '+%Y%m%d')" 21 | - name: Get today date 22 | id: today 23 | run: echo "::set-output name=date::$(date +'%Y%m%d')" 24 | - name: Checkout 25 | uses: actions/checkout@v3 26 | with: 27 | token: ${{ secrets.TAG_TOKEN }} 28 | - name: Delete Tag 29 | uses: dev-drprasad/delete-tag-and-release@v0.2.0 30 | with: 31 | delete_release: true # default: false 32 | tag_name: ${{ env.TAG_NAME }} # tag name to delete 33 | env: 34 | GITHUB_TOKEN: ${{ secrets.TAG_TOKEN }} 35 | TAG_NAME: snapshot_${{ steps.yesterday.outputs.date }} 36 | - name: Create Tag 37 | uses: rickstaa/action-create-tag@v1 38 | if: always() 39 | with: 40 | tag : ${{ env.TAG_NAME }} 41 | message: "Latest Build Release" 42 | github_token: ${{ secrets.TAG_TOKEN }} 43 | env: 44 | TAG_NAME: snapshot_${{ steps.today.outputs.date }} 45 | GITHUB_TOKEN: ${{ secrets.TAG_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/super-linter.yaml: -------------------------------------------------------------------------------- 1 | # This workflow executes several linters on changed files based on languages used in your code base whenever 2 | # you push a code or open a pull request. 3 | # 4 | # You can adjust the behavior by modifying this file. 5 | # For more information, see: 6 | # https://github.com/github/super-linter 7 | name: Lint Code Base 8 | 9 | on: 10 | push: 11 | branches: [ "dev" ] 12 | pull_request: 13 | branches: [ "main" ] 14 | jobs: 15 | run-lint: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout code 19 | uses: actions/checkout@v3 20 | with: 21 | # Full git history is needed to get a proper list of changed files within `super-linter` 22 | fetch-depth: 0 23 | 24 | - name: Lint Code Base 25 | uses: github/super-linter@v4 26 | env: 27 | VALIDATE_ALL_CODEBASE: false 28 | DEFAULT_BRANCH: "main" 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | VALIDATE_MARKDOWN: false 31 | VALIDATE_YAML: false 32 | FILTER_REGEX_EXCLUDE: ./snova/mux/mux_event.pb.* 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # test files 35 | test.cc 36 | -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- 1 | package( 2 | default_visibility = ["//visibility:public"], 3 | ) 4 | 5 | config_setting( 6 | name = "local_musl", 7 | define_values = {"local_musl": "true"}, 8 | ) 9 | -------------------------------------------------------------------------------- /CPPLINT.cfg: -------------------------------------------------------------------------------- 1 | linelength=100 2 | filter=-build/c++11,-build/include_subdir,-runtime/references -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "snova_asio") 2 | 3 | load("//:snova_asio.bzl", "snova_workspace") 4 | 5 | snova_workspace() 6 | 7 | load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies") 8 | 9 | # Don't use preinstalled tools to ensure builds are as hermetic as possible 10 | rules_foreign_cc_dependencies() 11 | 12 | register_toolchains( 13 | "//toolchains:x64_linux_musl_gcc_compile_toolchain", 14 | "//toolchains:arm_linux_musleabi_gcc_compile_toolchain", 15 | "//toolchains:arm_linux_musleabihf_gcc_compile_toolchain", 16 | "//toolchains:aarch64_linux_musl_gcc_compile_toolchain", 17 | ) 18 | 19 | # register_execution_platforms("//toolchains:linux_armv7") 20 | -------------------------------------------------------------------------------- /bazel/jemalloc.BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | load("@rules_foreign_cc//foreign_cc:defs.bzl", "configure_make") 4 | 5 | filegroup( 6 | name = "all_srcs", 7 | srcs = glob(["**"]), 8 | visibility = ["//visibility:public"], 9 | ) 10 | 11 | configure_make( 12 | name = "jemalloc_build", 13 | # args = ["-j 6"], 14 | # autogen = True, 15 | configure_in_place = True, 16 | configure_options = [ 17 | # "--enable-prof", 18 | # "--enable-prof-libunwind", 19 | "--disable-libdl", 20 | ], 21 | lib_source = ":all_srcs", 22 | out_static_libs = select({ 23 | "@bazel_tools//src/conditions:windows": [ 24 | "jemalloc.lib", 25 | ], 26 | "//conditions:default": [ 27 | "libjemalloc.a", 28 | ], 29 | }), 30 | # out_binaries = ["jeprof"], 31 | targets = [ 32 | "build_lib_static", 33 | "install_include", 34 | "install_lib_static", 35 | ], 36 | ) 37 | 38 | cc_library( 39 | name = "jemalloc", 40 | tags = ["no-cache"], 41 | deps = [ 42 | ":jemalloc_build", 43 | ], 44 | ) 45 | -------------------------------------------------------------------------------- /bazel/mimalloc.BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | MIMALLOC_COPTS = select({ 4 | "@bazel_tools//src/conditions:windows": [ 5 | "/O2 /Zc:__cplusplus /DMI_MALLOC_OVERRIDE /DDMI_STATIC_LIB", 6 | ], 7 | "//conditions:default": [ 8 | "-O3", 9 | "-std=gnu11", 10 | # "-fPIC", 11 | "-Wall -Wextra -Wno-unknown-pragmas", 12 | "-fvisibility=hidden", 13 | "-Wstrict-prototypes", 14 | "-ftls-model=initial-exec", 15 | "-fno-builtin-malloc", 16 | "-DMI_MALLOC_OVERRIDE", 17 | "-DMI_STATIC_LIB", 18 | "-DNDEBUG", 19 | ], 20 | }) + select({ 21 | "@bazel_tools//src/conditions:darwin": [ 22 | "-DMI_OSX_ZONE=1 -DMI_OSX_INTERPOSE=1", 23 | "-Wpedantic -Wno-static-in-inline", 24 | ], 25 | "//conditions:default": [ 26 | ], 27 | }) 28 | 29 | cc_library( 30 | name = "mimalloc_headers", 31 | hdrs = glob([ 32 | "include/*.h", 33 | ]), 34 | strip_include_prefix = "include", 35 | ) 36 | 37 | cc_library( 38 | name = "libmimalloc", 39 | srcs = [ 40 | "src/static.c", 41 | ], 42 | hdrs = [ 43 | "src/alloc-override.c", 44 | "src/bitmap.h", 45 | "src/page-queue.c", 46 | "src/alloc.c", 47 | "src/alloc-aligned.c", 48 | "src/alloc-posix.c", 49 | "src/arena.c", 50 | "src/bitmap.c", 51 | "src/heap.c", 52 | "src/init.c", 53 | "src/options.c", 54 | "src/os.c", 55 | "src/page.c", 56 | "src/random.c", 57 | "src/segment.c", 58 | "src/segment-cache.c", 59 | "src/stats.c", 60 | ] + select({ 61 | "@bazel_tools//src/conditions:darwin": [ 62 | "src/alloc-override-osx.c", 63 | ], 64 | "//conditions:default": [ 65 | ], 66 | }), 67 | copts = MIMALLOC_COPTS, 68 | deps = [":mimalloc_headers"], 69 | ) 70 | -------------------------------------------------------------------------------- /bazel/nanopb.BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "@snova_asio//snova:copts/configure_copts.bzl", 3 | "SNOVA_DEFAULT_COPTS", 4 | ) 5 | 6 | licenses(["notice"]) 7 | 8 | exports_files(["LICENSE.txt"]) 9 | 10 | package(default_visibility = ["//visibility:public"]) 11 | 12 | cc_library( 13 | name = "nanopb", 14 | srcs = [ 15 | "pb_common.c", 16 | "pb_decode.c", 17 | "pb_encode.c", 18 | ], 19 | hdrs = [ 20 | "pb.h", 21 | "pb_common.h", 22 | "pb_decode.h", 23 | "pb_encode.h", 24 | ], 25 | copts = SNOVA_DEFAULT_COPTS, 26 | visibility = ["//visibility:public"], 27 | ) 28 | -------------------------------------------------------------------------------- /bazel/spdlog.BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | # load("@rules_foreign_cc//foreign_cc:defs.bzl", "cmake") 4 | 5 | # filegroup( 6 | # name = "all_srcs", 7 | # srcs = glob(["**"]), 8 | # visibility = ["//visibility:public"], 9 | # ) 10 | 11 | # cmake( 12 | # name = "spdlog", 13 | # generate_args = [ 14 | # # "-DSPDLOG_USE_STD_FORMAT=ON", 15 | # "-DCMAKE_CXX_STANDARD=20", 16 | # ], 17 | # lib_source = ":all_srcs", 18 | # out_lib_dir = "lib64", 19 | # # targets = ["spdlog_header_only"], 20 | # ) 21 | 22 | cc_library( 23 | name = "spdlog", 24 | hdrs = glob([ 25 | "include/**/*.h", 26 | ]), 27 | includes = ["include"], 28 | visibility = ["//visibility:public"], 29 | # deps = ["@com_github_fmtlib_fmt//:fmtlib"], 30 | ) 31 | -------------------------------------------------------------------------------- /bazelrc.linux: -------------------------------------------------------------------------------- 1 | build --cxxopt=-std=c++20 2 | build --features=fully_static_link 3 | #build --copt=-Os 4 | build --copt=-fvisibility=hidden 5 | build --copt=-ffunction-sections 6 | build --copt=-fdata-sections 7 | build --copt=-DNDEBUG 8 | build --copt=-finline-limit=64 9 | build --incompatible_enable_cc_toolchain_resolution -------------------------------------------------------------------------------- /bazelrc.macos: -------------------------------------------------------------------------------- 1 | build --cxxopt=-std=c++20 2 | build --copt=-flto 3 | build --linkopt=-flto -------------------------------------------------------------------------------- /bazelrc.windows: -------------------------------------------------------------------------------- 1 | build --features=fully_static_link 2 | build --cxxopt=/O2 3 | build --cxxopt=/std:c++20 4 | build --copt=/GL 5 | build --copt=/GF 6 | build --copt=/Gy 7 | build --copt=/GA 8 | build --cxxopt=/MT 9 | build --linkopt=/LTCG -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | unameOut="$(uname -s)" 4 | case "${unameOut}" in 5 | Linux*) machine=Linux;; 6 | Darwin*) machine=Mac;; 7 | CYGWIN*) machine=Cygwin;; 8 | MINGW*) machine=Windows;; 9 | *) machine="UNKNOWN:${unameOut}" 10 | esac 11 | 12 | platform="linux_musl_x64" 13 | gcc_opts="--copt=-O2" 14 | if [ "$#" -ge 1 ]; then 15 | arch=$1 16 | case "${arch}" in 17 | x64) 18 | platform="linux_musl_x64" 19 | ;; 20 | arm_eabi) 21 | platform="linux_musl_arm_eabi" 22 | gcc_opts="--copt=-Os --copt=-Wno-stringop-overflow --per_file_copt=.*/curve25519.c@-DOPENSSL_NO_ASM" 23 | ;; 24 | arm_eabihf) 25 | platform="linux_musl_arm_eabihf" 26 | gcc_opts="--copt=-Os --copt=-Wno-stringop-overflow" 27 | ;; 28 | aarch64) 29 | platform="linux_musl_aarch64" 30 | ;; 31 | *) 32 | platform="linux_musl_x64" 33 | ;; 34 | esac 35 | fi 36 | 37 | echo "${machine}" "${platform}" "${gcc_opts}" 38 | 39 | if [ "$machine" = "Linux" ]; then 40 | # shellcheck disable=SC2086 41 | bazel --bazelrc=bazelrc.linux build --define local_musl=true ${gcc_opts} --platforms=//toolchains:"${platform}" //... 42 | #bazel --bazelrc=bazelrc.linux build --define local_musl=true --stripopt=--strip-all --platforms=//toolchains:"${platform}" //snova/app:snova.stripped 43 | elif [ "$machine" = "Windows" ]; then 44 | bazel --bazelrc=bazelrc.windows build //... 45 | else 46 | if [ "$(uname -m)" = "arm64" ]; then 47 | bazel --bazelrc=bazelrc.macos build //... 48 | else 49 | bazel --bazelrc=bazelrc.macos build --features=fully_static_link //... 50 | fi 51 | fi 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /scripts/ci_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | unameOut="$(uname -s)" 4 | case "${unameOut}" in 5 | Linux*) machine=linux;; 6 | Darwin*) machine=darwin;; 7 | CYGWIN*) machine=windows;; 8 | MINGW*) machine=windows;; 9 | *) machine="UNKNOWN:${unameOut}" 10 | esac 11 | 12 | platform="linux_musl_x64" 13 | gcc_opts="--copt=-O2" 14 | if [ "$#" -ge 1 ]; then 15 | arch=$1 16 | case "${arch}" in 17 | x64) 18 | platform="linux_musl_x64" 19 | ;; 20 | arm_eabi) 21 | platform="linux_musl_arm_eabi" 22 | gcc_opts="--copt=-Os --copt=-Wno-stringop-overflow --per_file_copt=.*/curve25519.c@-DOPENSSL_NO_ASM" 23 | ;; 24 | arm_eabihf) 25 | platform="linux_musl_arm_eabihf" 26 | gcc_opts="--copt=-Os --copt=-Wno-stringop-overflow" 27 | ;; 28 | aarch64) 29 | platform="linux_musl_aarch64" 30 | ;; 31 | *) 32 | platform="linux_musl_x64" 33 | ;; 34 | esac 35 | fi 36 | 37 | echo "${BUILD_VERSION}" "${machine}" "${arch}" 38 | 39 | if [ "$machine" = "linux" ] 40 | then 41 | # shellcheck disable=SC2086 42 | bazel --bazelrc=bazelrc.linux build ${gcc_opts} --stripopt=--strip-all --cxxopt=-DSNOVA_VERSION="${BUILD_VERSION}" --platforms=//toolchains:"${platform}" //snova/app:snova.stripped 43 | mv ./bazel-bin/snova/app/snova.stripped ./bazel-bin/snova/app/snova 44 | elif [ "$machine" = "windows" ] 45 | then 46 | vcpkg install boringssl:x64-windows-static 47 | export MSYS2_ARG_CONV_EXCL="*" 48 | bazel.exe --bazelrc=bazelrc.windows build --cxxopt=/DSNOVA_VERSION="${BUILD_VERSION}" //... 49 | else 50 | if [ "$(uname -m)" = "arm64" ]; then 51 | bazel --bazelrc=bazelrc.macos build --cxxopt=-DSNOVA_VERSION="${BUILD_VERSION}" //... 52 | else 53 | bazel --bazelrc=bazelrc.macos build --features=fully_static_link --cxxopt=-DSNOVA_VERSION="${BUILD_VERSION}" //... 54 | fi 55 | fi 56 | 57 | retval=$? 58 | if [ $retval -ne 0 ]; then 59 | echo "Build failed!" >&2 60 | exit 1 61 | fi 62 | 63 | tar -cjf snova_asio_"${BUILD_VERSION}"_"${machine}"_"${arch}".tar.bz2 -C ./bazel-bin/snova/app/ snova 64 | # ls -l ./bazel-bin/snova/app/snova 65 | # ls -l snova_asio_"${BUILD_VERSION}"_"${machine}"_"${arch}".tar.bz2 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /scripts/delete_tag.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [ "$#" -ne 1 ]; then 3 | echo "Usage: $0 TAG_NAME" >&2 4 | exit 1 5 | fi 6 | 7 | TAG_NAME=$1 8 | 9 | echo -n "Are you sure to delete tag:${TAG_NAME} (Y/N)? " 10 | while read -r -n 1 -s answer; do 11 | if [[ $answer = [YyNn] ]]; then 12 | [[ $answer = [Yy] ]] && retval=0 13 | [[ $answer = [Nn] ]] && retval=1 14 | break 15 | fi 16 | done 17 | 18 | if [ $retval -eq 1 ]; then 19 | exit 1 20 | fi 21 | 22 | echo "" 23 | echo "Start to delete tag:${TAG_NAME}." 24 | 25 | git tag -d ${TAG_NAME} 26 | if [ $? -ne 0 ]; then 27 | echo "Delete local tag:${TAG_NAME} failed!" >&2 28 | exit 1 29 | fi 30 | git push --delete origin ${TAG_NAME} 31 | if [ $? -ne 0 ]; then 32 | echo "Delete remote tag:${TAG_NAME} failed!" >&2 33 | exit 1 34 | fi 35 | echo "Success to delete tag:${TAG_NAME}!" -------------------------------------------------------------------------------- /snova/BUILD.bazel: -------------------------------------------------------------------------------- 1 | package( 2 | default_visibility = ["//visibility:public"], 3 | ) 4 | -------------------------------------------------------------------------------- /snova/app/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load( 2 | "//snova:copts/configure_copts.bzl", 3 | "SNOVA_DEFAULT_COPTS", 4 | "SNOVA_DEFAULT_LINKOPTS", 5 | ) 6 | 7 | package( 8 | default_visibility = ["//visibility:public"], 9 | ) 10 | 11 | cc_binary( 12 | name = "snova", 13 | srcs = [ 14 | "snova.cc", 15 | ], 16 | copts = SNOVA_DEFAULT_COPTS, 17 | linkopts = SNOVA_DEFAULT_LINKOPTS, 18 | # malloc = select({ 19 | # "@bazel_tools//src/conditions:windows": "@bazel_tools//tools/cpp:malloc", 20 | # "//conditions:default": "@com_github_microsoft_mimalloc//:libmimalloc", 21 | # }), 22 | deps = [ 23 | "//snova/log:log_api", 24 | "//snova/mux:mux_client", 25 | "//snova/server:dns_proxy_server", 26 | "//snova/server:entry_server", 27 | "//snova/server:mux_server", 28 | "//snova/server:tunnel_server", 29 | "//snova/util:address", 30 | "//snova/util:dns_options", 31 | "//snova/util:flags", 32 | "//snova/util:misc_helper", 33 | "//snova/util:stat", 34 | "//snova/util:time_wheel", 35 | "@com_github_CLIUtils_CLI11//:CLI11", 36 | "@com_google_absl//absl/strings", 37 | ], 38 | ) 39 | 40 | # cc_binary( 41 | # name = "test", 42 | # srcs = [ 43 | # "test.cc", 44 | # ], 45 | # copts = SNOVA_DEFAULT_COPTS, 46 | # linkopts = SNOVA_DEFAULT_LINKOPTS, 47 | # deps = [ 48 | # "@asio", 49 | # "@com_github_google_borringssl//:ssl", 50 | # ], 51 | # ) 52 | -------------------------------------------------------------------------------- /snova/copts/configure_copts.bzl: -------------------------------------------------------------------------------- 1 | SNOVA_DEFAULT_COPTS = select({ 2 | "@bazel_tools//src/conditions:windows": [ 3 | # "/std:c++20", 4 | "/O2", 5 | "/W3", 6 | "/DNOMINMAX", 7 | "/DWIN32_LEAN_AND_MEAN", 8 | "/D_CRT_SECURE_NO_WARNINGS", 9 | "/D_SCL_SECURE_NO_WARNINGS", 10 | "/D_ENABLE_EXTENDED_ALIGNED_STORAGE", 11 | "/bigobj", 12 | "/wd4005", 13 | "/wd4068", 14 | "/wd4180", 15 | "/wd4244", 16 | "/wd4267", 17 | "/wd4503", 18 | "/wd4800", 19 | # used for nanopb 20 | "/DPB_C99_STATIC_ASSERT", 21 | "/Gy", 22 | ], 23 | "//conditions:default": [ 24 | # "-std=c++20", 25 | "-Werror=return-type", 26 | # "-fcoroutines", 27 | # "-DASIO_HAS_IO_URING", 28 | # "-DASIO_DISABLE_EPOLL", 29 | # "-O2", 30 | # "-fvisibility=hidden", 31 | # "-ffunction-sections", 32 | # "-fdata-sections", 33 | # "-g", 34 | ], 35 | }) 36 | 37 | SNOVA_DEFAULT_LINKOPTS = select({ 38 | "@bazel_tools//src/conditions:windows": [ 39 | "/OPT:REF", 40 | ], 41 | "@bazel_tools//src/conditions:darwin": ["-dead_strip"], 42 | "//conditions:default": [ 43 | "-Wl,--gc-sections", 44 | "-Wl,--strip-all", 45 | ], 46 | }) 47 | -------------------------------------------------------------------------------- /snova/io/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load( 2 | "//snova:copts/configure_copts.bzl", 3 | "SNOVA_DEFAULT_COPTS", 4 | "SNOVA_DEFAULT_LINKOPTS", 5 | ) 6 | load("@rules_cc//cc:defs.bzl", "cc_test") 7 | 8 | package( 9 | default_visibility = ["//visibility:public"], 10 | ) 11 | 12 | cc_library( 13 | name = "io", 14 | srcs = ["io.cc"], 15 | hdrs = [ 16 | "io.h", 17 | ], 18 | deps = [ 19 | "//snova/util:flags", 20 | "//snova/util:stat", 21 | "@asio", 22 | "@com_google_absl//absl/types:span", 23 | ], 24 | ) 25 | 26 | cc_library( 27 | name = "buffered_io", 28 | srcs = ["buffered_io.cc"], 29 | hdrs = ["buffered_io.h"], 30 | copts = SNOVA_DEFAULT_COPTS, 31 | deps = [ 32 | ":io", 33 | "//snova/log:log_api", 34 | ] + select({ 35 | "@bazel_tools//src/conditions:windows": [ 36 | "@local_windows_borringssl//:headers", 37 | "@local_windows_borringssl//:ssl", 38 | ], 39 | "//conditions:default": [ 40 | "@com_github_google_borringssl//:ssl", 41 | ], 42 | }), 43 | ) 44 | 45 | cc_library( 46 | name = "tls_socket", 47 | srcs = ["tls_socket.cc"], 48 | hdrs = ["tls_socket.h"], 49 | copts = SNOVA_DEFAULT_COPTS, 50 | deps = [ 51 | ":io", 52 | "//snova/log:log_api", 53 | "//snova/util:net_helper", 54 | ] + select({ 55 | "@bazel_tools//src/conditions:windows": [ 56 | "@local_windows_borringssl//:headers", 57 | "@local_windows_borringssl//:ssl", 58 | ], 59 | "//conditions:default": [ 60 | "@com_github_google_borringssl//:ssl", 61 | ], 62 | }), 63 | ) 64 | 65 | cc_test( 66 | name = "tls_socket_test", 67 | srcs = ["tls_socket_test.cc"], 68 | copts = SNOVA_DEFAULT_COPTS, 69 | linkopts = SNOVA_DEFAULT_LINKOPTS, 70 | deps = [ 71 | ":tls_socket", 72 | "//snova/log:log_api", 73 | "//snova/util:http_helper", 74 | "//snova/util:net_helper", 75 | "@com_google_googletest//:gtest_main", 76 | ] + select({ 77 | "@bazel_tools//src/conditions:windows": [ 78 | "@local_windows_borringssl//:headers", 79 | "@local_windows_borringssl//:ssl", 80 | ], 81 | "//conditions:default": [ 82 | "@com_github_google_borringssl//:ssl", 83 | ], 84 | }), 85 | ) 86 | 87 | cc_library( 88 | name = "tcp_socket", 89 | srcs = ["tcp_socket.cc"], 90 | hdrs = ["tcp_socket.h"], 91 | copts = SNOVA_DEFAULT_COPTS, 92 | deps = [ 93 | ":io", 94 | "//snova/log:log_api", 95 | ], 96 | ) 97 | 98 | cc_library( 99 | name = "ws_socket", 100 | srcs = ["ws_socket.cc"], 101 | hdrs = ["ws_socket.h"], 102 | copts = SNOVA_DEFAULT_COPTS, 103 | deps = [ 104 | ":buffered_io", 105 | ":io", 106 | ":io_util", 107 | "//snova/log:log_api", 108 | "//snova/util:address", 109 | "//snova/util:endian", 110 | "//snova/util:http_helper", 111 | "//snova/util:misc_helper", 112 | "@com_google_absl//absl/strings", 113 | ], 114 | ) 115 | 116 | cc_test( 117 | name = "ws_socket_test", 118 | srcs = ["ws_socket_test.cc"], 119 | copts = SNOVA_DEFAULT_COPTS, 120 | linkopts = SNOVA_DEFAULT_LINKOPTS, 121 | deps = [ 122 | ":tcp_socket", 123 | ":ws_socket", 124 | "//snova/log:log_api", 125 | "//snova/util:http_helper", 126 | "//snova/util:net_helper", 127 | "@com_google_googletest//:gtest_main", 128 | ], 129 | ) 130 | 131 | cc_library( 132 | name = "transfer", 133 | srcs = ["transfer.cc"], 134 | hdrs = ["transfer.h"], 135 | copts = SNOVA_DEFAULT_COPTS, 136 | deps = [ 137 | ":io", 138 | "//snova/log:log_api", 139 | ], 140 | ) 141 | 142 | cc_library( 143 | name = "io_util", 144 | srcs = ["io_util.cc"], 145 | hdrs = ["io_util.h"], 146 | copts = SNOVA_DEFAULT_COPTS, 147 | deps = [ 148 | ":io", 149 | ":tcp_socket", 150 | "//snova/log:log_api", 151 | ], 152 | ) 153 | -------------------------------------------------------------------------------- /snova/io/buffered_io.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/io/buffered_io.h" 30 | #include 31 | 32 | #include "asio/experimental/as_tuple.hpp" 33 | 34 | namespace snova { 35 | BufferedIO::BufferedIO(IOConnectionPtr&& io) : io_(std::move(io)), offset_(0), length_(0) { 36 | recv_buffer_ = get_iobuf(kMaxChunkSize); 37 | } 38 | 39 | asio::any_io_executor BufferedIO::GetExecutor() { return io_->GetExecutor(); } 40 | asio::awaitable BufferedIO::AsyncWrite(const asio::const_buffer& buffers) { 41 | co_return co_await io_->AsyncWrite(buffers); 42 | } 43 | asio::awaitable BufferedIO::AsyncWrite(const std::vector<::asio::const_buffer>& buffers) { 44 | co_return co_await io_->AsyncWrite(buffers); 45 | } 46 | asio::awaitable BufferedIO::AsyncRead(const asio::mutable_buffer& buffers) { 47 | if (offset_ >= length_) { 48 | offset_ = 0; 49 | length_ = 0; 50 | auto [n, ec] = co_await io_->AsyncRead(::asio::buffer(recv_buffer_->data(), kMaxChunkSize)); 51 | if (ec) { 52 | co_return IOResult{0, ec}; 53 | } 54 | length_ = n; 55 | } 56 | if (offset_ < length_) { 57 | size_t read_len = (length_ - offset_); 58 | if (buffers.size() < read_len) { 59 | read_len = buffers.size(); 60 | } 61 | memcpy(buffers.data(), recv_buffer_->data() + offset_, read_len); 62 | offset_ += read_len; 63 | co_return IOResult{read_len, std::error_code{}}; 64 | } 65 | co_return IOResult{0, std::error_code{}}; 66 | } 67 | void BufferedIO::Close() { io_->Close(); } 68 | } // namespace snova 69 | -------------------------------------------------------------------------------- /snova/io/buffered_io.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | #include "asio.hpp" 34 | #include "snova/io/io.h" 35 | namespace snova { 36 | class BufferedIO : public IOConnection { 37 | public: 38 | explicit BufferedIO(IOConnectionPtr&& io); 39 | 40 | asio::any_io_executor GetExecutor() override; 41 | asio::awaitable AsyncWrite(const asio::const_buffer& buffers) override; 42 | asio::awaitable AsyncWrite(const std::vector<::asio::const_buffer>& buffers) override; 43 | asio::awaitable AsyncRead(const asio::mutable_buffer& buffers) override; 44 | void Close() override; 45 | 46 | private: 47 | IOBufPtr recv_buffer_; 48 | IOConnectionPtr io_; 49 | size_t offset_; 50 | size_t length_; 51 | }; 52 | 53 | } // namespace snova 54 | -------------------------------------------------------------------------------- /snova/io/io.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/io/io.h" 30 | #include 31 | #include "snova/util/flags.h" 32 | #include "snova/util/stat.h" 33 | 34 | namespace snova { 35 | static std::stack g_io_bufs; 36 | // static constexpr uint32_t kIOBufPoolSize = 64; 37 | static uint64_t g_iobuf_pool_bytes = 0; 38 | static uint64_t g_active_iobuf_bytes = 0; 39 | static uint32_t g_active_iobuf_num = 0; 40 | 41 | void register_io_stat() { 42 | register_stat_func([]() -> StatValues { 43 | StatValues vals; 44 | auto& kv = vals["IOBuf"]; 45 | kv["pool_size"] = std::to_string(g_io_bufs.size()); 46 | kv["pool_bytes"] = std::to_string(g_iobuf_pool_bytes); 47 | kv["active_iobuf_num"] = std::to_string(g_active_iobuf_num); 48 | kv["active_iobuf_bytes"] = std::to_string(g_active_iobuf_bytes); 49 | return vals; 50 | }); 51 | } 52 | 53 | void IOBufDeleter::operator()(IOBuf* v) const { 54 | g_active_iobuf_num--; 55 | g_active_iobuf_bytes -= v->capacity(); 56 | if (g_io_bufs.size() < g_iobuf_max_pool_size) { 57 | g_io_bufs.push(v); 58 | g_iobuf_pool_bytes += v->capacity(); 59 | return; 60 | } 61 | delete v; 62 | } 63 | static IOBuf* get_raw_iobuf(size_t n) { 64 | IOBuf* p = nullptr; 65 | if (g_io_bufs.empty()) { 66 | p = new IOBuf; 67 | } else { 68 | p = g_io_bufs.top(); 69 | g_io_bufs.pop(); 70 | g_iobuf_pool_bytes -= p->capacity(); 71 | } 72 | if (n < (kMaxChunkSize + kReservedBufferSize)) { 73 | n = kMaxChunkSize + kReservedBufferSize; 74 | } 75 | if (p->size() < n) { 76 | p->resize(n); 77 | } 78 | g_active_iobuf_num++; 79 | g_active_iobuf_bytes += p->capacity(); 80 | return p; 81 | } 82 | 83 | IOBufPtr get_iobuf(size_t n) { 84 | IOBufDeleter deleter; 85 | IOBufPtr ptr(get_raw_iobuf(n), deleter); 86 | return ptr; 87 | } 88 | IOBufSharedPtr get_shared_iobuf(size_t n) { 89 | IOBufDeleter deleter; 90 | IOBufSharedPtr ptr(get_raw_iobuf(n), deleter); 91 | return ptr; 92 | } 93 | 94 | } // namespace snova 95 | -------------------------------------------------------------------------------- /snova/io/io.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "absl/types/span.h" 36 | #include "asio.hpp" 37 | #include "asio/experimental/awaitable_operators.hpp" 38 | #include "snova/io/io.h" 39 | 40 | namespace snova { 41 | using IOResult = std::pair; 42 | using MutableBytes = absl::Span; 43 | using Bytes = absl::Span; 44 | using IOBuf = std::vector; 45 | static constexpr uint16_t kMaxChunkSize = 8192; 46 | static constexpr uint16_t kReservedBufferSize = 256; 47 | struct IOBufDeleter { 48 | void operator()(IOBuf* v) const; 49 | }; 50 | using IOBufSharedPtr = std::shared_ptr; 51 | using IOBufPtr = std::unique_ptr; 52 | 53 | IOBufPtr get_iobuf(size_t n); 54 | IOBufSharedPtr get_shared_iobuf(size_t n); 55 | 56 | struct IOConnection { 57 | virtual asio::any_io_executor GetExecutor() = 0; 58 | virtual asio::awaitable AsyncWrite(const asio::const_buffer& buffers) = 0; 59 | virtual asio::awaitable AsyncWrite( 60 | const std::vector<::asio::const_buffer>& buffers) = 0; 61 | 62 | virtual asio::awaitable AsyncRead(const asio::mutable_buffer& buffers) = 0; 63 | virtual void Close() = 0; 64 | virtual ~IOConnection() = default; 65 | }; 66 | using IOConnectionPtr = std::unique_ptr; 67 | 68 | using StreamReadResult = std::tuple; 69 | struct Stream { 70 | virtual uint32_t GetID() const = 0; 71 | virtual bool IsTLS() const = 0; 72 | virtual asio::awaitable Read() = 0; 73 | virtual asio::awaitable Write(IOBufPtr&& buf, size_t len) = 0; 74 | virtual asio::awaitable Close(bool close_by_remote) = 0; 75 | virtual ~Stream() = default; 76 | }; 77 | using StreamPtr = std::shared_ptr; 78 | using SocketRef = ::asio::ip::tcp::socket&; 79 | using TCPServerSocket = ::asio::ip::tcp::acceptor; 80 | using TCPServerSocketPtr = std::shared_ptr; 81 | using UDPSocket = ::asio::ip::udp::socket; 82 | using UDPSocketPtr = std::shared_ptr; 83 | using TCPListenResult = std::pair; 84 | using IOBufRef = IOBuf&; 85 | 86 | void register_io_stat(); 87 | 88 | } // namespace snova 89 | -------------------------------------------------------------------------------- /snova/io/io_util.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/io/io_util.h" 30 | #include "snova/io/tcp_socket.h" 31 | #include "snova/log/log_macros.h" 32 | 33 | namespace snova { 34 | asio::awaitable read_until(IOConnection& socket, IOBufRef buf, size_t& readed_len, 35 | std::string_view until) { 36 | int rc = 0; 37 | while (true) { 38 | std::string_view readed_view((const char*)buf.data(), readed_len); 39 | auto pos = readed_view.find(until); 40 | if (pos != std::string_view::npos) { 41 | co_return pos; 42 | } 43 | size_t rest = buf.size() - readed_len; 44 | if (rest < until.size()) { 45 | buf.resize(buf.size() * 2); 46 | } 47 | auto [n, ec] = 48 | co_await socket.AsyncRead(::asio::buffer(buf.data() + readed_len, buf.size() - readed_len)); 49 | if (n > 0) { 50 | readed_len += n; 51 | } else { 52 | SNOVA_ERROR("read socket error:{} with n:{}", ec, n); 53 | rc = -1; 54 | break; 55 | } 56 | } 57 | co_return rc; 58 | } 59 | asio::awaitable read_until(SocketRef socket, IOBufRef buf, size_t& readed_len, 60 | std::string_view until) { 61 | TcpSocket tcp(socket); 62 | co_return co_await read_until(tcp, buf, readed_len, until); 63 | } 64 | asio::awaitable read_exact(IOConnection& socket, 65 | const asio::mutable_buffer& buffers) { 66 | size_t pos = 0; 67 | size_t rest = buffers.size(); 68 | uint8_t* read_buffer = reinterpret_cast(buffers.data()); 69 | while (rest > 0) { 70 | auto [n, ec] = co_await socket.AsyncRead(::asio::buffer(read_buffer + pos, rest)); 71 | if (ec) { 72 | co_return ec; 73 | } 74 | rest -= n; 75 | pos += n; 76 | } 77 | co_return std::error_code{}; 78 | } 79 | 80 | } // namespace snova 81 | -------------------------------------------------------------------------------- /snova/io/io_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include "asio.hpp" 33 | #include "snova/io/io.h" 34 | 35 | namespace snova { 36 | asio::awaitable read_until(SocketRef socket, IOBufRef buf, size_t& readed_len, 37 | std::string_view until); 38 | asio::awaitable read_until(IOConnection& socket, IOBufRef buf, size_t& readed_len, 39 | std::string_view until); 40 | asio::awaitable read_exact(IOConnection& socket, 41 | const asio::mutable_buffer& buffers); 42 | } // namespace snova 43 | -------------------------------------------------------------------------------- /snova/io/tcp_socket.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/io/tcp_socket.h" 30 | #include 31 | 32 | namespace snova { 33 | TcpSocket::TcpSocket(::asio::ip::tcp::socket& sock) : socket_(sock) {} 34 | TcpSocket::TcpSocket(::asio::ip::tcp::socket&& sock) 35 | : own_socket_{std::make_unique<::asio::ip::tcp::socket>(std::move(sock))}, 36 | socket_(*own_socket_) {} 37 | asio::any_io_executor TcpSocket::GetExecutor() { return socket_.get_executor(); } 38 | 39 | asio::awaitable TcpSocket::AsyncRead(const asio::mutable_buffer& buffers) { 40 | auto [ec, n] = co_await socket_.async_read_some( 41 | buffers, ::asio::experimental::as_tuple(::asio::use_awaitable)); 42 | co_return IOResult{n, ec}; 43 | } 44 | void TcpSocket::Close() { socket_.close(); } 45 | } // namespace snova 46 | -------------------------------------------------------------------------------- /snova/io/tcp_socket.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | #include "asio.hpp" 34 | #include "asio/experimental/as_tuple.hpp" 35 | #include "snova/io/io.h" 36 | namespace snova { 37 | class TcpSocket : public IOConnection { 38 | public: 39 | explicit TcpSocket(::asio::ip::tcp::socket& sock); 40 | explicit TcpSocket(::asio::ip::tcp::socket&& sock); 41 | 42 | asio::any_io_executor GetExecutor() override; 43 | asio::awaitable AsyncWrite(const asio::const_buffer& buffers) override { 44 | co_return co_await DoAsyncWrite(buffers); 45 | } 46 | asio::awaitable AsyncWrite(const std::vector<::asio::const_buffer>& buffers) override { 47 | co_return co_await DoAsyncWrite(buffers); 48 | } 49 | asio::awaitable AsyncRead(const asio::mutable_buffer& buffers) override; 50 | void Close() override; 51 | 52 | private: 53 | template 54 | asio::awaitable DoAsyncWrite(const T& buffers) { 55 | auto [ec, n] = co_await ::asio::async_write( 56 | socket_, buffers, ::asio::experimental::as_tuple(::asio::use_awaitable)); 57 | co_return IOResult{n, ec}; 58 | } 59 | std::unique_ptr<::asio::ip::tcp::socket> own_socket_; 60 | ::asio::ip::tcp::socket& socket_; 61 | }; 62 | 63 | } // namespace snova 64 | -------------------------------------------------------------------------------- /snova/io/tls_socket.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/io/tls_socket.h" 30 | #include 31 | #include 32 | #include "openssl/ssl.h" 33 | 34 | namespace snova { 35 | TlsSocket::TlsSocket(::asio::ip::tcp::socket&& sock) 36 | : tls_ctx_(::asio::ssl::context::tls), tls_socket_(std::move(sock), tls_ctx_) {} 37 | TlsSocket::TlsSocket(const ASIOTlsSocketExecutor& ex) 38 | : tls_ctx_(::asio::ssl::context::tls), tls_socket_(ex, tls_ctx_) {} 39 | asio::any_io_executor TlsSocket::GetExecutor() { return tls_socket_.get_executor(); } 40 | asio::awaitable TlsSocket::ClientHandshake() { 41 | auto [handshake_ec] = co_await tls_socket_.async_handshake( 42 | ::asio::ssl::stream_base::client, ::asio::experimental::as_tuple(::asio::use_awaitable)); 43 | if (handshake_ec) { 44 | co_return handshake_ec; 45 | } 46 | co_return std::error_code{}; 47 | } 48 | 49 | asio::awaitable TlsSocket::AsyncConnect( 50 | const ::asio::ip::tcp::endpoint& endpoint) { 51 | // tls_ctx_.set_options(::asio::ssl::context::default_workarounds | ::asio::ssl::context::no_sslv2 52 | // | 53 | // ::asio::ssl::context::no_sslv3 | ::asio::ssl::context::single_dh_use); 54 | // tls_ctx_.set_verify_mode(::asio::ssl::verify_none); 55 | // tls_socket_.set_verify_mode(::asio::ssl::verify_none); 56 | 57 | if (!tls_host_.empty()) { 58 | if (!SSL_set_tlsext_host_name(tls_socket_.native_handle(), tls_host_.c_str())) { 59 | std::error_code ec{static_cast(::ERR_get_error()), ::asio::error::get_ssl_category()}; 60 | co_return ec; 61 | } 62 | } 63 | auto [connect_ec] = co_await tls_socket_.next_layer().async_connect( 64 | endpoint, ::asio::experimental::as_tuple(::asio::use_awaitable)); 65 | if (connect_ec) { 66 | co_return connect_ec; 67 | } 68 | 69 | co_return co_await ClientHandshake(); 70 | } 71 | 72 | asio::awaitable TlsSocket::AsyncConnect(const std::string& host, uint16_t port) { 73 | ::asio::ip::tcp::endpoint endpoint; 74 | auto ec = co_await resolve_endpoint(host, port, &endpoint); 75 | if (ec) { 76 | co_return ec; 77 | } 78 | co_return co_await AsyncConnect(endpoint); 79 | } 80 | 81 | asio::awaitable TlsSocket::AsyncRead(const asio::mutable_buffer& buffers) { 82 | auto [ec, n] = co_await tls_socket_.async_read_some( 83 | buffers, ::asio::experimental::as_tuple(::asio::use_awaitable)); 84 | co_return IOResult{n, ec}; 85 | } 86 | void TlsSocket::Close() { 87 | tls_socket_.shutdown(); 88 | tls_socket_.next_layer().close(); 89 | } 90 | } // namespace snova 91 | -------------------------------------------------------------------------------- /snova/io/tls_socket.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | #include 34 | #include "asio.hpp" 35 | #include "asio/experimental/as_tuple.hpp" 36 | #include "asio/ssl.hpp" 37 | #include "snova/io/io.h" 38 | #include "snova/util/net_helper.h" 39 | namespace snova { 40 | using ASIOTlsSocket = ::asio::ssl::stream<::asio::ip::tcp::socket>; 41 | using ASIOTlsSocketExecutor = typename ASIOTlsSocket::executor_type; 42 | class TlsSocket : public IOConnection { 43 | public: 44 | explicit TlsSocket(::asio::ip::tcp::socket&& sock); 45 | explicit TlsSocket(const ASIOTlsSocketExecutor& ex); 46 | void SetHost(const std::string& v) { tls_host_ = v; } 47 | asio::any_io_executor GetExecutor() override; 48 | asio::awaitable ClientHandshake(); 49 | asio::awaitable AsyncConnect(const ::asio::ip::tcp::endpoint& endpoint); 50 | asio::awaitable AsyncConnect(const std::string& host, uint16_t port); 51 | asio::awaitable AsyncWrite(const asio::const_buffer& buffers) override { 52 | co_return co_await DoAsyncWrite(buffers); 53 | } 54 | asio::awaitable AsyncWrite(const std::vector<::asio::const_buffer>& buffers) override { 55 | co_return co_await DoAsyncWrite(buffers); 56 | } 57 | asio::awaitable AsyncRead(const asio::mutable_buffer& buffers) override; 58 | void Close() override; 59 | 60 | private: 61 | template 62 | asio::awaitable DoAsyncWrite(const T& buffers) { 63 | auto [ec, n] = co_await ::asio::async_write( 64 | tls_socket_, buffers, ::asio::experimental::as_tuple(::asio::use_awaitable)); 65 | co_return IOResult{n, ec}; 66 | } 67 | ::asio::ssl::context tls_ctx_; 68 | ASIOTlsSocket tls_socket_; 69 | std::string tls_host_; 70 | }; 71 | } // namespace snova 72 | -------------------------------------------------------------------------------- /snova/io/tls_socket_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, qiyingwang 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/io/tls_socket.h" 30 | #include 31 | #include 32 | #include "snova/log/log_macros.h" 33 | #include "snova/util/net_helper.h" 34 | using namespace snova; // NOLINT 35 | 36 | TEST(TlsSocket, Simple) { 37 | ::asio::io_context ctx; 38 | TlsSocket socket(ctx.get_executor()); 39 | 40 | ::asio::co_spawn( 41 | ctx, 42 | [socket = std::move(socket)]() mutable -> asio::awaitable { 43 | co_await socket.AsyncConnect("www.baidu.com", 443); 44 | std::string req = "GET / HTTP/1.0\r\n\r\n"; 45 | co_await socket.AsyncWrite(::asio::buffer(req.data(), req.size())); 46 | char buffer[4096]; 47 | auto [n, ec] = co_await socket.AsyncRead(::asio::buffer(buffer, 4096)); 48 | if (n > 0) { 49 | SNOVA_INFO("Recv:{}", std::string_view(buffer, n)); 50 | } 51 | }, 52 | ::asio::detached); 53 | ctx.run(); 54 | } 55 | 56 | // TEST(TlsSocket, Simple2) { 57 | // ::asio::io_context ctx; 58 | 59 | // ::asio::co_spawn( 60 | // ctx, 61 | // []() mutable -> asio::awaitable { 62 | // auto ex = co_await asio::this_coro::executor; 63 | // ::asio::ip::tcp::socket sock(ex); 64 | // TlsSocket socket(std::move(sock)); 65 | // co_await socket.AsyncConnect("www.baidu.com", 443); 66 | // std::string req = "GET / HTTP/1.0\r\n\r\n"; 67 | // co_await socket.AsyncWrite(::asio::buffer(req.data(), req.size())); 68 | // char buffer[4096]; 69 | // auto [n, ec] = co_await socket.AsyncRead(::asio::buffer(buffer, 4096)); 70 | // if (n > 0) { 71 | // SNOVA_INFO("Recv:{}", std::string_view(buffer, n)); 72 | // } 73 | // }, 74 | // ::asio::detached); 75 | // ctx.run(); 76 | // } 77 | -------------------------------------------------------------------------------- /snova/io/transfer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/io/transfer.h" 30 | #include 31 | #include 32 | #include "asio/experimental/as_tuple.hpp" 33 | 34 | namespace snova { 35 | using namespace asio::experimental::awaitable_operators; // NOLINT 36 | 37 | asio::awaitable transfer(StreamPtr from, StreamPtr to, const TransferRoutineFunc& routine) { 38 | while (true) { 39 | auto [data, len, ec] = co_await from->Read(); 40 | if (ec) { 41 | // co_await from->Close(false); 42 | // SNOVA_ERROR("Read ERROR {} {}", len, ec); 43 | break; 44 | } 45 | if (routine) { 46 | routine(); 47 | } 48 | auto wec = co_await to->Write(std::move(data), len); 49 | if (wec) { 50 | // co_await from->Close(false); 51 | // SNOVA_ERROR("async_write ERROR {} ", wec); 52 | break; 53 | } 54 | if (routine) { 55 | routine(); 56 | } 57 | } 58 | co_await to->Close(false); 59 | co_return; 60 | } 61 | 62 | asio::awaitable transfer(StreamPtr from, SocketRef to, const TransferRoutineFunc& routine) { 63 | while (true) { 64 | auto [data, len, ec] = co_await from->Read(); 65 | if (ec) { 66 | // co_await from->Close(false); 67 | // SNOVA_ERROR("[{}]Read ERROR {}", from->GetID(), ec); 68 | break; 69 | } 70 | if (routine) { 71 | routine(); 72 | } 73 | auto [wec, wn] = 74 | co_await ::asio::async_write(to, ::asio::buffer(data->data(), len), 75 | ::asio::experimental::as_tuple(::asio::use_awaitable)); 76 | data.reset(); 77 | if (wec) { 78 | // co_await from->Close(false); 79 | // SNOVA_ERROR("async_write ERROR {} ", wec); 80 | break; 81 | } 82 | if (routine) { 83 | routine(); 84 | } 85 | } 86 | co_await from->Close(false); 87 | to.close(); 88 | co_return; 89 | } 90 | asio::awaitable transfer(SocketRef from, StreamPtr to, const TransferRoutineFunc& routine) { 91 | while (true) { 92 | IOBufPtr buf = get_iobuf(kMaxChunkSize); 93 | auto [ec, n] = 94 | co_await from.async_read_some(::asio::buffer(buf->data(), kMaxChunkSize), 95 | ::asio::experimental::as_tuple(::asio::use_awaitable)); 96 | if (ec) { 97 | break; 98 | } 99 | if (routine) { 100 | routine(); 101 | } 102 | 103 | auto wec = co_await to->Write(std::move(buf), n); 104 | if (wec) { 105 | break; 106 | } 107 | if (routine) { 108 | routine(); 109 | } 110 | } 111 | co_await to->Close(false); 112 | co_return; 113 | } 114 | asio::awaitable transfer(SocketRef from, SocketRef to, const TransferRoutineFunc& routine) { 115 | IOBufPtr buf = get_iobuf(kMaxChunkSize); 116 | while (true) { 117 | auto [ec, n] = 118 | co_await from.async_read_some(::asio::buffer(buf->data(), kMaxChunkSize), 119 | ::asio::experimental::as_tuple(::asio::use_awaitable)); 120 | if (ec) { 121 | break; 122 | } 123 | if (routine) { 124 | routine(); 125 | } 126 | auto [wec, wn] = co_await ::asio::async_write( 127 | to, ::asio::buffer(buf->data(), n), ::asio::experimental::as_tuple(::asio::use_awaitable)); 128 | if (wec) { 129 | break; 130 | } 131 | if (routine) { 132 | routine(); 133 | } 134 | } 135 | co_return; 136 | } 137 | 138 | } // namespace snova 139 | -------------------------------------------------------------------------------- /snova/io/transfer.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include "snova/io/io.h" 33 | 34 | namespace snova { 35 | using TransferRoutineFunc = std::function; 36 | asio::awaitable transfer(StreamPtr from, StreamPtr to, 37 | const TransferRoutineFunc& routine = {}); 38 | asio::awaitable transfer(StreamPtr from, ::asio::ip::tcp::socket& to, 39 | const TransferRoutineFunc& routine = {}); 40 | asio::awaitable transfer(SocketRef from, StreamPtr to, 41 | const TransferRoutineFunc& routine = {}); 42 | asio::awaitable transfer(SocketRef from, SocketRef to, 43 | const TransferRoutineFunc& routine = {}); 44 | 45 | } // namespace snova 46 | -------------------------------------------------------------------------------- /snova/io/ws_socket.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | #include "asio.hpp" 34 | #include "snova/io/io.h" 35 | namespace snova { 36 | class WebSocket : public IOConnection { 37 | public: 38 | explicit WebSocket(IOConnectionPtr&& io); 39 | asio::any_io_executor GetExecutor() override; 40 | asio::awaitable AsyncConnect(const std::string& host); 41 | asio::awaitable AsyncAccept(); 42 | asio::awaitable AsyncWrite(const asio::const_buffer& buffers) override; 43 | asio::awaitable AsyncWrite(const std::vector<::asio::const_buffer>& buffers) override; 44 | asio::awaitable AsyncRead(const asio::mutable_buffer& buffers) override; 45 | void Close() override; 46 | 47 | private: 48 | IOConnectionPtr io_; 49 | bool is_server_ = false; 50 | }; 51 | } // namespace snova 52 | -------------------------------------------------------------------------------- /snova/io/ws_socket_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, qiyingwang 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/io/ws_socket.h" 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include "snova/io/tcp_socket.h" 35 | #include "snova/log/log_macros.h" 36 | #include "snova/util/address.h" 37 | #include "snova/util/net_helper.h" 38 | using namespace snova; // NOLINT 39 | 40 | TEST(WebSocket, Simple) { 41 | ::asio::io_context ctx; 42 | ::asio::ip::tcp::socket socket(ctx); 43 | PaserAddressResult parse_result = NetAddress::Parse("127.0.0.1:8080"); 44 | if (parse_result.second) { 45 | SNOVA_INFO("Parse failed:{}", parse_result.second); 46 | return; 47 | } 48 | auto remote_addr = std::move(parse_result.first); 49 | ::asio::co_spawn( 50 | ctx, 51 | [socket = std::move(socket), 52 | remote_addr = std::move(remote_addr)]() mutable -> asio::awaitable { 53 | ::asio::ip::tcp::endpoint remote_endpoint; 54 | co_await remote_addr->GetEndpoint(&remote_endpoint); 55 | SNOVA_INFO("endpoint:{}", remote_endpoint); 56 | co_await socket.async_connect(remote_endpoint, ::asio::use_awaitable); 57 | 58 | IOConnectionPtr io = std::make_unique(std::move(socket)); 59 | WebSocket ws(std::move(io)); 60 | auto ec = co_await ws.AsyncConnect("localhost:8080"); 61 | size_t i = 0; 62 | while (true) { 63 | std::string s = "hello,world!"; 64 | s.append(std::to_string(i)); 65 | // SNOVA_INFO("Try send:{}", s.size()); 66 | co_await ws.AsyncWrite(::asio::buffer(s.data(), s.size())); 67 | s.clear(); 68 | char buffer[1024]; 69 | auto [n, ec] = co_await ws.AsyncRead(::asio::buffer(buffer, 1024)); 70 | if (n > 0) { 71 | // SNOVA_INFO("[{}]Recv:{}", n, std::string_view(buffer, n)); 72 | } 73 | i++; 74 | } 75 | }, 76 | ::asio::detached); 77 | ctx.run(); 78 | } 79 | -------------------------------------------------------------------------------- /snova/log/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load( 2 | "//snova:copts/configure_copts.bzl", 3 | "SNOVA_DEFAULT_COPTS", 4 | "SNOVA_DEFAULT_LINKOPTS", 5 | ) 6 | 7 | package( 8 | default_visibility = ["//visibility:public"], 9 | ) 10 | 11 | cc_library( 12 | name = "log_api", 13 | hdrs = [ 14 | "log_macros.h", 15 | ], 16 | deps = [ 17 | "@com_github_spdlog//:spdlog", 18 | ], 19 | ) 20 | -------------------------------------------------------------------------------- /snova/log/log_macros.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include "spdlog/spdlog.h" 32 | 33 | #include "spdlog/fmt/bundled/ostream.h" // do NOT put this line before spdlog 34 | 35 | #define SNOVA_DEBUG(...) \ 36 | do { \ 37 | auto logger = spdlog::default_logger_raw(); \ 38 | if (nullptr != logger && logger->should_log(spdlog::level::debug)) { \ 39 | SPDLOG_DEBUG(__VA_ARGS__); \ 40 | } \ 41 | } while (0) 42 | 43 | #define SNOVA_INFO(...) \ 44 | do { \ 45 | auto logger = spdlog::default_logger_raw(); \ 46 | if (nullptr != logger && logger->should_log(spdlog::level::info)) { \ 47 | SPDLOG_INFO(__VA_ARGS__); \ 48 | } \ 49 | } while (0) 50 | 51 | #define SNOVA_WARN(...) \ 52 | do { \ 53 | auto logger = spdlog::default_logger_raw(); \ 54 | if (nullptr != logger && logger->should_log(spdlog::level::warn)) { \ 55 | SPDLOG_WARN(__VA_ARGS__); \ 56 | } \ 57 | } while (0) 58 | 59 | #define SNOVA_ERROR(...) \ 60 | do { \ 61 | auto logger = spdlog::default_logger_raw(); \ 62 | if (nullptr != logger && logger->should_log(spdlog::level::err)) { \ 63 | SPDLOG_ERROR(__VA_ARGS__); \ 64 | } \ 65 | } while (0) 66 | 67 | #define SNOVA_CRITICAL(...) \ 68 | do { \ 69 | auto logger = spdlog::default_logger_raw(); \ 70 | if (nullptr != logger && logger->should_log(spdlog::level::critical)) { \ 71 | SPDLOG_CRITICAL(__VA_ARGS__); \ 72 | } \ 73 | } while (0) 74 | -------------------------------------------------------------------------------- /snova/mux/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load( 2 | "//snova:copts/configure_copts.bzl", 3 | "SNOVA_DEFAULT_COPTS", 4 | "SNOVA_DEFAULT_LINKOPTS", 5 | ) 6 | load("@rules_cc//cc:defs.bzl", "cc_test") 7 | 8 | package( 9 | default_visibility = ["//visibility:public"], 10 | ) 11 | 12 | cc_library( 13 | name = "mux_client", 14 | srcs = [ 15 | "mux_client.cc", 16 | ], 17 | hdrs = [ 18 | "mux_client.h", 19 | ], 20 | copts = SNOVA_DEFAULT_COPTS, 21 | deps = [ 22 | ":mux_conn_manager", 23 | "//snova/io", 24 | "//snova/io:tcp_socket", 25 | "//snova/io:tls_socket", 26 | "//snova/io:ws_socket", 27 | "//snova/log:log_api", 28 | "//snova/util:address", 29 | "//snova/util:flags", 30 | "//snova/util:net_helper", 31 | "//snova/util:stat", 32 | "//snova/util:time_wheel", 33 | "@asio", 34 | "@com_google_absl//absl/strings", 35 | ], 36 | ) 37 | 38 | cc_library( 39 | name = "cipher_context", 40 | srcs = [ 41 | "cipher_context.cc", 42 | ], 43 | hdrs = [ 44 | "cipher_context.h", 45 | ], 46 | copts = SNOVA_DEFAULT_COPTS, 47 | deps = [ 48 | ":mux_event", 49 | "//snova/io", 50 | "//snova/log:log_api", 51 | "//snova/util:endian", 52 | # "@com_github_mbedtls//:mbedtls", 53 | ] + select({ 54 | "@bazel_tools//src/conditions:windows": [ 55 | "@local_windows_borringssl//:headers", 56 | "@local_windows_borringssl//:ssl", 57 | ], 58 | "//conditions:default": [ 59 | "@com_github_google_borringssl//:ssl", 60 | ], 61 | }), 62 | ) 63 | 64 | # cc_test( 65 | # name = "cipher_context_test", 66 | # # size = "small", 67 | # srcs = ["cipher_context_test.cc"], 68 | # copts = SNOVA_DEFAULT_COPTS, 69 | # linkopts = SNOVA_DEFAULT_LINKOPTS, 70 | # deps = [ 71 | # ":cipher_context", 72 | # "@com_google_googletest//:gtest_main", 73 | # ], 74 | # ) 75 | 76 | # cc_test( 77 | # name = "mux_event_test", 78 | # # size = "small", 79 | # srcs = ["mux_event_test.cc"], 80 | # copts = SNOVA_DEFAULT_COPTS, 81 | # linkopts = SNOVA_DEFAULT_LINKOPTS, 82 | # deps = [ 83 | # ":mux_event", 84 | # "@com_google_googletest//:gtest_main", 85 | # ], 86 | # ) 87 | 88 | cc_library( 89 | name = "mux_event", 90 | srcs = [ 91 | "mux_event.cc", 92 | "mux_event.pb.c", 93 | ], 94 | hdrs = [ 95 | "mux_event.h", 96 | "mux_event.pb.h", 97 | ], 98 | copts = SNOVA_DEFAULT_COPTS, 99 | deps = [ 100 | "//snova/io", 101 | "//snova/log:log_api", 102 | "//snova/util:endian", 103 | "@com_github_nanopb//:nanopb", 104 | ], 105 | ) 106 | 107 | cc_library( 108 | name = "mux_stream", 109 | srcs = [ 110 | "mux_stream.cc", 111 | ], 112 | hdrs = [ 113 | "mux_stream.h", 114 | ], 115 | copts = SNOVA_DEFAULT_COPTS, 116 | deps = [ 117 | ":mux_event", 118 | "//snova/io", 119 | "//snova/log:log_api", 120 | "@com_google_absl//absl/container:flat_hash_map", 121 | ], 122 | ) 123 | 124 | cc_library( 125 | name = "mux_connection", 126 | srcs = [ 127 | "mux_connection.cc", 128 | ], 129 | hdrs = [ 130 | "mux_connection.h", 131 | ], 132 | copts = SNOVA_DEFAULT_COPTS, 133 | deps = [ 134 | ":cipher_context", 135 | ":mux_stream", 136 | "//snova/server:tunnel_server_api", 137 | "//snova/util:async_mutex", 138 | "//snova/util:misc_helper", 139 | "//snova/util:stat", 140 | "//snova/util:time_wheel", 141 | "@asio", 142 | ], 143 | ) 144 | 145 | cc_library( 146 | name = "mux_conn_manager", 147 | srcs = [ 148 | "mux_conn_manager.cc", 149 | ], 150 | hdrs = [ 151 | "mux_conn_manager.h", 152 | ], 153 | copts = SNOVA_DEFAULT_COPTS, 154 | deps = [ 155 | ":mux_connection", 156 | "//snova/server:tunnel_server_api", 157 | "//snova/util:flags", 158 | ], 159 | ) 160 | -------------------------------------------------------------------------------- /snova/mux/CPPLINT.cfg: -------------------------------------------------------------------------------- 1 | exclude_files=mux_event\.pb\.* -------------------------------------------------------------------------------- /snova/mux/cipher_context.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | #include 34 | #include "openssl/aead.h" 35 | // #include "mbedtls/cipher.h" 36 | #include "snova/io/io.h" 37 | #include "snova/mux/mux_event.h" 38 | namespace snova { 39 | class CipherContext { 40 | public: 41 | ~CipherContext(); 42 | static std::unique_ptr New(const std::string& cipher_method, 43 | const std::string& cipher_key); 44 | size_t GetTagLength() const { return cipher_tag_len_; } 45 | void UpdateNonce(uint64_t nonce); 46 | int Encrypt(std::unique_ptr& in, MutableBytes& out); 47 | int Decrypt(const Bytes& in, std::unique_ptr& out, size_t& decrypt_len); 48 | 49 | private: 50 | CipherContext(); 51 | // const EVP_AEAD* cipher_aead_ = nullptr; 52 | EVP_AEAD_CTX* encrypt_ctx_ = nullptr; 53 | EVP_AEAD_CTX* decrypt_ctx_ = nullptr; 54 | uint64_t encrypt_iv_ = 0; 55 | uint64_t decrypt_iv_ = 0; 56 | size_t cipher_nonce_len_ = 0; 57 | size_t cipher_tag_len_ = 0; 58 | std::string cipher_key_; 59 | 60 | // mbedtls_cipher_type_t cipher_type_; 61 | // mbedtls_cipher_context_t encrypt_ctx_; 62 | // mbedtls_cipher_context_t decrypt_ctx_; 63 | std::vector encode_buffer_; 64 | std::vector decode_buffer_; 65 | }; 66 | 67 | } // namespace snova 68 | -------------------------------------------------------------------------------- /snova/mux/cipher_context_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/mux/cipher_context.h" 30 | #include 31 | #include 32 | #include "snova/log/log_macros.h" 33 | using namespace snova; // NOLINT 34 | 35 | TEST(CipherContext, Chacha20Poly1305) { 36 | std::unique_ptr ctx = CipherContext::New("chacha20_poly1305", "hello,world"); 37 | std::unique_ptr auth = std::make_unique(); 38 | auth->head.sid = 101; 39 | std::string user = "test_user"; 40 | auth->user = user; 41 | std::unique_ptr event = std::move(auth); 42 | std::vector buffer(8192 * 2); 43 | MutableBytes mbuffer(buffer.data(), buffer.size()); 44 | int rc = ctx->Encrypt(event, mbuffer); 45 | EXPECT_EQ(0, rc); 46 | SNOVA_INFO("Encrypt event size:{}", mbuffer.size()); 47 | 48 | Bytes rbuffer(mbuffer.data(), mbuffer.size()); 49 | std::unique_ptr decrypt_event; 50 | size_t decrypt_len; 51 | rc = ctx->Decrypt(rbuffer, decrypt_event, decrypt_len); 52 | EXPECT_EQ(0, rc); 53 | EXPECT_EQ(decrypt_len, mbuffer.size()); 54 | AuthRequest* req = dynamic_cast(decrypt_event.get()); 55 | EXPECT_EQ(req->user, user); 56 | } 57 | -------------------------------------------------------------------------------- /snova/mux/mux_client.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | #include 34 | 35 | #include "asio.hpp" 36 | #include "snova/mux/mux_conn_manager.h" 37 | #include "snova/util/address.h" 38 | #include "snova/util/stat.h" 39 | namespace snova { 40 | class MuxClient { 41 | public: 42 | static std::shared_ptr& GetInstance(); 43 | EventWriterFactory GetEventWriterFactory(); 44 | void SetClientId(uint64_t client_id); 45 | uint64_t GetClientId() const { return client_id_; } 46 | asio::awaitable Init(const std::string& user, const std::string& cipher_method, 47 | const std::string& cipher_key); 48 | 49 | private: 50 | asio::awaitable NewConnection(uint32_t idx); 51 | asio::awaitable CheckConnections(); 52 | MuxConnectionType conn_type_ = MUX_EXIT_CONN; 53 | MuxSessionPtr remote_session_; 54 | // std::vector remote_conns_; 55 | std::unique_ptr remote_mux_address_; 56 | // ::asio::ip::tcp::endpoint remote_endpoint_; 57 | std::string auth_user_; 58 | std::string cipher_method_; 59 | std::string cipher_key_; 60 | // uint32_t select_cursor_ = 0; 61 | uint64_t client_id_ = 0; 62 | }; 63 | 64 | } // namespace snova 65 | -------------------------------------------------------------------------------- /snova/mux/mux_conn_manager.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "absl/container/flat_hash_map.h" 37 | #include "asio.hpp" 38 | #include "snova/mux/mux_connection.h" 39 | #include "snova/util/stat.h" 40 | namespace snova { 41 | constexpr uint32_t kMuxConnTypeNum = 2; 42 | struct MuxSession : public std::enable_shared_from_this { 43 | using MuxConnArray = std::vector; 44 | MuxConnArray conns; 45 | std::vector tunnel_servers; 46 | EventWriterFactory GetEventWriterFactory(); 47 | void ReportStatInfo(StatKeyValue& kv); 48 | ~MuxSession(); 49 | }; 50 | using MuxSessionPtr = std::shared_ptr; 51 | struct UserMuxConn { 52 | using MuxConnTable = absl::flat_hash_map; 53 | std::string user; 54 | MuxConnTable sessions[kMuxConnTypeNum]; // 0:entry 1:exit 55 | }; 56 | 57 | using UserMuxConnPtr = std::shared_ptr; 58 | 59 | class MuxConnManager { 60 | public: 61 | static std::shared_ptr& GetInstance(); 62 | 63 | void RegisterStat(); 64 | 65 | MuxSessionPtr GetSession(std::string_view user, uint64_t client_id, MuxConnectionType type); 66 | MuxSessionPtr Add(std::string_view user, uint64_t client_id, MuxConnectionPtr conn, 67 | uint32_t* idx); 68 | void Remove(std::string_view user, uint64_t client_id, MuxConnectionPtr conn); 69 | void Remove(std::string_view user, uint64_t client_id, MuxConnection* conn); 70 | 71 | EventWriterFactory GetEventWriterFactory(std::string_view user, uint64_t client_id, 72 | MuxConnectionType type); 73 | EventWriterFactory GetRelayEventWriterFactory(std::string_view user, uint64_t* client_id); 74 | 75 | private: 76 | void ReportStatInfo(StatValues& stats); 77 | UserMuxConnPtr GetUserMuxConn(std::string_view user); 78 | using UserMuxConnTable = absl::flat_hash_map; 79 | UserMuxConnTable mux_conns_; 80 | }; 81 | 82 | } // namespace snova 83 | -------------------------------------------------------------------------------- /snova/mux/mux_event.options: -------------------------------------------------------------------------------- 1 | snova.AuthRequest.user max_size:256 2 | snova.StreamOpenRequest.remote_host max_size:512 3 | snova.TunnelOpenRequest.local_host max_size:512 4 | snova.CommonResponse.reason max_size:512 -------------------------------------------------------------------------------- /snova/mux/mux_event.pb.c: -------------------------------------------------------------------------------- 1 | /* Automatically generated nanopb constant definitions */ 2 | /* Generated by nanopb-0.4.7-dev */ 3 | 4 | #include "mux_event.pb.h" 5 | #if PB_PROTO_HEADER_VERSION != 40 6 | #error Regenerate this file with the current version of nanopb generator. 7 | #endif 8 | 9 | PB_BIND(snova_CommonResponse, snova_CommonResponse, 2) 10 | 11 | 12 | PB_BIND(snova_AuthRequest, snova_AuthRequest, 2) 13 | 14 | 15 | PB_BIND(snova_AuthResponse, snova_AuthResponse, AUTO) 16 | 17 | 18 | PB_BIND(snova_StreamOpenRequest, snova_StreamOpenRequest, 2) 19 | 20 | 21 | PB_BIND(snova_TunnelOpenRequest, snova_TunnelOpenRequest, 2) 22 | 23 | 24 | PB_BIND(snova_TunnelOpenResponse, snova_TunnelOpenResponse, AUTO) 25 | 26 | 27 | PB_BIND(snova_TunnelCloseRequest, snova_TunnelCloseRequest, AUTO) 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /snova/mux/mux_event.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package snova; 4 | 5 | message CommonResponse { 6 | bool success = 1; 7 | int32 errc = 2; 8 | string reason = 3; 9 | } 10 | 11 | message AuthRequest { 12 | string user = 1; 13 | uint64 client_id = 2; 14 | bool is_entry = 3; 15 | bool is_exit = 4; 16 | bool is_middle = 5; 17 | } 18 | 19 | message AuthResponse { 20 | bool success = 1; 21 | uint64 iv = 2; 22 | } 23 | 24 | message StreamOpenRequest { 25 | string remote_host = 1; 26 | uint32 remote_port = 2; 27 | bool is_tcp = 3; 28 | bool is_tls = 4; 29 | } 30 | 31 | message TunnelOpenRequest { 32 | string local_host = 1; 33 | uint32 local_port = 2; 34 | uint32 remote_port = 3; 35 | bool is_tcp = 4; 36 | } 37 | message TunnelOpenResponse { 38 | bool success = 1; 39 | uint64 tunnel_id = 2; 40 | int32 errc = 3; 41 | } 42 | 43 | message TunnelCloseRequest { 44 | uint64 tunnel_id = 1; 45 | } 46 | -------------------------------------------------------------------------------- /snova/mux/mux_event_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/mux/mux_event.h" 30 | #include 31 | #include 32 | #include "pb_decode.h" 33 | #include "pb_encode.h" 34 | #include "snova/log/log_macros.h" 35 | using namespace snova; // NOLINT 36 | 37 | TEST(MuxEvent, nanopb) { 38 | snova_AuthRequest message = snova_AuthRequest_init_default; 39 | message.client_id = 121; 40 | snprintf(message.user, sizeof(message.user), "%s", "jeeeeee"); 41 | 42 | unsigned char buf[256]; 43 | pb_ostream_t output = pb_ostream_from_buffer(buf, sizeof(buf)); 44 | if (!pb_encode_delimited(&output, snova_AuthRequest_fields, &message)) { 45 | printf("Encoding failed: %s\n", PB_GET_ERROR(&output)); 46 | return; 47 | } 48 | size_t n = output.bytes_written; 49 | 50 | snova_AuthRequest decode_msg = snova_AuthRequest_init_default; 51 | pb_istream_t input = pb_istream_from_buffer(buf, n); 52 | if (!pb_decode_delimited(&input, snova_AuthRequest_fields, &decode_msg)) { 53 | printf("Decode failed: %s\n", PB_GET_ERROR(&input)); 54 | return; 55 | } 56 | printf("%s %llu %d\n", decode_msg.user, decode_msg.client_id, input.bytes_left); 57 | } 58 | -------------------------------------------------------------------------------- /snova/mux/mux_stream.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "asio.hpp" 36 | #include "snova/io/io.h" 37 | #include "snova/mux/mux_event.h" 38 | namespace snova { 39 | using StreamDataChannel = asio::experimental::channel; 40 | using StreamDataChannelExecutor = typename StreamDataChannel::executor_type; 41 | class MuxStream; 42 | using MuxStreamPtr = std::shared_ptr; 43 | class MuxStream : public Stream { 44 | public: 45 | asio::awaitable Open(const std::string& host, uint16_t port, bool is_tcp, 46 | bool is_tls); 47 | asio::awaitable Offer(IOBufPtr&& buf, size_t len); 48 | asio::awaitable Read() override; 49 | asio::awaitable Write(IOBufPtr&& buf, size_t len) override; 50 | asio::awaitable Close(bool close_by_remote) override; 51 | uint32_t GetID() const override { return sid_; } 52 | bool IsTLS() const override { return is_tls_; } 53 | 54 | void SetTLS(bool v) { is_tls_ = v; } 55 | 56 | ~MuxStream(); 57 | 58 | static uint32_t NextID(bool is_client); 59 | static MuxStreamPtr New(EventWriterFactory&& factory, const StreamDataChannelExecutor& ex, 60 | uint64_t client_id, uint32_t sid); 61 | static MuxStreamPtr Get(uint64_t client_id, uint32_t sid); 62 | static void Remove(uint64_t client_id, uint32_t sid); 63 | static size_t Size(); 64 | static size_t ActiveSize(); 65 | 66 | private: 67 | MuxStream(EventWriterFactory&& factory, const StreamDataChannelExecutor& ex, uint64_t client_id, 68 | uint32_t sid); 69 | template 70 | asio::awaitable WriteEvent(std::unique_ptr&& event) { 71 | std::unique_ptr write_ev = std::move(event); 72 | for (size_t i = 0; i < 3; i++) { // try 3 times 73 | bool success = false; 74 | if (event_writer_) { 75 | success = co_await event_writer_(std::move(write_ev)); 76 | if (success) { 77 | co_return true; 78 | } 79 | } 80 | event_writer_ = event_writer_factory_(); 81 | } 82 | // close if failed 3 times 83 | co_await Close(false); 84 | co_return false; 85 | } 86 | EventWriterFactory event_writer_factory_; 87 | EventWriter event_writer_; 88 | StreamDataChannel data_channel_; 89 | size_t write_bytes_; 90 | uint64_t client_id_; 91 | uint32_t sid_; 92 | bool is_tls_; 93 | bool closed_; 94 | }; 95 | 96 | } // namespace snova 97 | -------------------------------------------------------------------------------- /snova/server/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load( 2 | "//snova:copts/configure_copts.bzl", 3 | "SNOVA_DEFAULT_COPTS", 4 | "SNOVA_DEFAULT_LINKOPTS", 5 | ) 6 | 7 | package( 8 | default_visibility = ["//visibility:public"], 9 | ) 10 | 11 | cc_library( 12 | name = "dns_proxy_server", 13 | srcs = [ 14 | "dns_proxy_server.cc", 15 | ], 16 | hdrs = [ 17 | "dns_proxy_server.h", 18 | ], 19 | copts = SNOVA_DEFAULT_COPTS, 20 | deps = [ 21 | ":relay", 22 | "//snova/io", 23 | "//snova/io:io_util", 24 | "//snova/io:tls_socket", 25 | "//snova/log:log_api", 26 | "//snova/util:address", 27 | "//snova/util:dns_options", 28 | "//snova/util:endian", 29 | "//snova/util:flags", 30 | "//snova/util:http_helper", 31 | "//snova/util:net_helper", 32 | "//snova/util:time_wheel", 33 | "@asio", 34 | "@com_google_absl//absl/cleanup", 35 | "@com_google_absl//absl/container:flat_hash_map", 36 | "@com_google_absl//absl/strings", 37 | ], 38 | ) 39 | 40 | cc_library( 41 | name = "entry_server", 42 | srcs = [ 43 | "entry_server.cc", 44 | "http.cc", 45 | "socks5.cc", 46 | "tls.cc", 47 | ], 48 | hdrs = [ 49 | "entry_server.h", 50 | ], 51 | copts = SNOVA_DEFAULT_COPTS, 52 | deps = [ 53 | ":relay", 54 | "//snova/io", 55 | "//snova/io:io_util", 56 | "//snova/log:log_api", 57 | "//snova/util:address", 58 | "//snova/util:flags", 59 | "//snova/util:http_helper", 60 | "//snova/util:net_helper", 61 | "//snova/util:sni", 62 | "@asio", 63 | "@com_google_absl//absl/cleanup", 64 | "@com_google_absl//absl/strings", 65 | ], 66 | ) 67 | 68 | cc_library( 69 | name = "tunnel_server_api", 70 | hdrs = [ 71 | "tunnel_server.h", 72 | ], 73 | copts = SNOVA_DEFAULT_COPTS, 74 | deps = [ 75 | "//snova/io", 76 | "//snova/mux:mux_event", 77 | "//snova/util:address", 78 | "@asio", 79 | ], 80 | ) 81 | 82 | cc_library( 83 | name = "tunnel_server", 84 | srcs = [ 85 | "tunnel_server.cc", 86 | ], 87 | copts = SNOVA_DEFAULT_COPTS, 88 | deps = [ 89 | ":relay", 90 | ":tunnel_server_api", 91 | "//snova/io", 92 | "//snova/io:io_util", 93 | "//snova/log:log_api", 94 | "//snova/mux:mux_conn_manager", 95 | "//snova/util:flags", 96 | "//snova/util:net_helper", 97 | "//snova/util:sni", 98 | "@asio", 99 | "@com_google_absl//absl/cleanup", 100 | "@com_google_absl//absl/container:flat_hash_map", 101 | "@com_google_absl//absl/strings", 102 | ], 103 | ) 104 | 105 | cc_library( 106 | name = "mux_server", 107 | srcs = [ 108 | "mux_server.cc", 109 | ], 110 | hdrs = [ 111 | "mux_server.h", 112 | ], 113 | copts = SNOVA_DEFAULT_COPTS, 114 | deps = [ 115 | ":relay", 116 | "//snova/io", 117 | "//snova/io:tcp_socket", 118 | "//snova/io:ws_socket", 119 | "//snova/log:log_api", 120 | "//snova/mux:mux_conn_manager", 121 | "//snova/mux:mux_connection", 122 | "//snova/util:net_helper", 123 | "//snova/util:time_wheel", 124 | "@asio", 125 | "@com_google_absl//absl/cleanup", 126 | "@com_google_absl//absl/strings", 127 | ], 128 | ) 129 | 130 | cc_library( 131 | name = "relay", 132 | srcs = [ 133 | "relay.cc", 134 | ], 135 | hdrs = [ 136 | "relay.h", 137 | ], 138 | copts = SNOVA_DEFAULT_COPTS, 139 | deps = [ 140 | "//snova/io:transfer", 141 | "//snova/log:log_api", 142 | "//snova/mux:mux_client", 143 | "//snova/mux:mux_event", 144 | "//snova/util:flags", 145 | "//snova/util:time_wheel", 146 | "@asio", 147 | "@com_google_absl//absl/cleanup", 148 | ], 149 | ) 150 | -------------------------------------------------------------------------------- /snova/server/dns_proxy_server.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include "asio.hpp" 31 | #include "asio/experimental/awaitable_operators.hpp" 32 | #include "snova/io/io.h" 33 | #include "snova/util/dns_options.h" 34 | 35 | #pragma once 36 | namespace snova { 37 | asio::awaitable start_dns_proxy_server(const NetAddress& addr, 38 | DNSOptions& options); 39 | } 40 | -------------------------------------------------------------------------------- /snova/server/entry_server.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "asio.hpp" 37 | #include "asio/experimental/awaitable_operators.hpp" 38 | #include "snova/io/io.h" 39 | #include "snova/util/address.h" 40 | namespace snova { 41 | asio::awaitable start_entry_server(const NetAddress& addr); 42 | 43 | asio::awaitable handle_socks5_connection(::asio::ip::tcp::socket&& sock, 44 | IOBufPtr&& read_buffer, const Bytes& readable_data); 45 | asio::awaitable handle_tls_connection( 46 | ::asio::ip::tcp::socket&& sock, IOBufPtr&& read_buffer, const Bytes& readable_data, 47 | std::unique_ptr<::asio::ip::tcp::endpoint>&& orig_remote_endpoint); 48 | asio::awaitable handle_http_connection(::asio::ip::tcp::socket&& sock, IOBufPtr&& read_buffer, 49 | Bytes& readable_data); 50 | 51 | } // namespace snova 52 | -------------------------------------------------------------------------------- /snova/server/mux_server.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | 33 | #include "asio.hpp" 34 | #include "snova/util/address.h" 35 | 36 | namespace snova { 37 | asio::awaitable start_mux_server(const NetAddress& addr, 38 | const std::string& cipher_method, 39 | const std::string& cipher_key); 40 | 41 | } // namespace snova 42 | -------------------------------------------------------------------------------- /snova/server/relay.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | 32 | #include 33 | #include 34 | #include 35 | #include "asio.hpp" 36 | #include "snova/io/io.h" 37 | #include "snova/mux/mux_event.h" 38 | #include "snova/mux/mux_stream.h" 39 | 40 | namespace snova { 41 | 42 | struct RelayContext { 43 | std::string user; 44 | std::string remote_host; 45 | uint16_t remote_port = 0; 46 | bool is_tls = false; 47 | bool is_tcp = false; 48 | bool direct = false; 49 | }; 50 | 51 | asio::awaitable relay_direct(::asio::ip::tcp::socket&& sock, const Bytes& readed_data, 52 | RelayContext& relay_ctx); 53 | asio::awaitable relay(::asio::ip::tcp::socket&& sock, const Bytes& readed_data, 54 | RelayContext& relay_ctx); 55 | asio::awaitable relay(StreamPtr stream, const Bytes& readed_data, RelayContext& relay_ctx); 56 | 57 | asio::awaitable relay_handler(const std::string& user, uint64_t client_id, 58 | std::unique_ptr&& open_request); 59 | } // namespace snova 60 | -------------------------------------------------------------------------------- /snova/server/tls.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/log/log_macros.h" 30 | #include "snova/server/entry_server.h" 31 | #include "snova/server/relay.h" 32 | #include "snova/util/flags.h" 33 | #include "snova/util/sni.h" 34 | 35 | namespace snova { 36 | asio::awaitable handle_tls_connection( 37 | ::asio::ip::tcp::socket&& s, IOBufPtr&& rbuf, const Bytes& readable_data, 38 | std::unique_ptr<::asio::ip::tcp::endpoint>&& orig_remote_endpoint) { 39 | // SNOVA_INFO("Handle proxy connection by tls."); 40 | uint16_t remote_port = 443; 41 | if (orig_remote_endpoint) { 42 | remote_port = orig_remote_endpoint->port(); 43 | } 44 | ::asio::ip::tcp::socket sock(std::move(s)); // make rvalue sock not release after co_await 45 | IOBufPtr conn_read_buffer = std::move(rbuf); 46 | IOBuf& read_buffer = *conn_read_buffer; 47 | std::string remote_host; 48 | int rc = parse_sni(readable_data.data(), readable_data.size(), &remote_host); 49 | if (0 != rc) { 50 | SNOVA_ERROR("Failed to read sni with rc:{}", rc); 51 | co_return false; 52 | } 53 | 54 | SNOVA_INFO("Retrive SNI:{} from tls connection with port:{}", remote_host, remote_port); 55 | if (remote_host == "courier.push.apple.com") { // special case 56 | co_return false; 57 | } 58 | RelayContext relay_ctx; 59 | relay_ctx.user = GlobalFlags::GetIntance()->GetUser(); 60 | relay_ctx.remote_host = std::move(remote_host); 61 | relay_ctx.remote_port = remote_port; 62 | relay_ctx.is_tcp = true; 63 | relay_ctx.is_tls = true; 64 | co_await relay(std::move(sock), readable_data, relay_ctx); 65 | co_return true; 66 | } 67 | } // namespace snova 68 | -------------------------------------------------------------------------------- /snova/server/tunnel_server.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | #include 34 | 35 | #include "asio.hpp" 36 | #include "snova/io/io.h" 37 | #include "snova/mux/mux_event.h" 38 | #include "snova/util/address.h" 39 | 40 | namespace snova { 41 | using TunnelServerListenResult = std::pair; 42 | asio::awaitable start_tunnel_server(const NetAddress& listen_addr, 43 | const NetAddress& dst_addr); 44 | void close_tunnel_server(uint32_t server_id); 45 | asio::awaitable> tunnel_server_handler( 46 | const std::string& user, uint64_t client_id, std::unique_ptr&& tunnel_request); 47 | 48 | } // namespace snova 49 | -------------------------------------------------------------------------------- /snova/util/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load( 2 | "//snova:copts/configure_copts.bzl", 3 | "SNOVA_DEFAULT_COPTS", 4 | "SNOVA_DEFAULT_LINKOPTS", 5 | ) 6 | 7 | package( 8 | default_visibility = ["//visibility:public"], 9 | ) 10 | 11 | cc_library( 12 | name = "tunnel_opt", 13 | srcs = [ 14 | "tunnel_opt.cc", 15 | ], 16 | hdrs = [ 17 | "tunnel_opt.h", 18 | ], 19 | copts = SNOVA_DEFAULT_COPTS, 20 | deps = [ 21 | "@com_google_absl//absl/strings", 22 | ], 23 | ) 24 | 25 | cc_library( 26 | name = "time_wheel", 27 | srcs = [ 28 | "time_wheel.cc", 29 | ], 30 | hdrs = [ 31 | "time_wheel.h", 32 | ], 33 | copts = SNOVA_DEFAULT_COPTS, 34 | deps = [ 35 | ":flags", 36 | "//snova/log:log_api", 37 | "@asio", 38 | ], 39 | ) 40 | 41 | cc_library( 42 | name = "stat", 43 | srcs = [ 44 | "stat.cc", 45 | ], 46 | hdrs = [ 47 | "stat.h", 48 | ], 49 | copts = SNOVA_DEFAULT_COPTS, 50 | deps = [ 51 | "//snova/log:log_api", 52 | "@asio", 53 | "@com_google_absl//absl/container:btree", 54 | ], 55 | ) 56 | 57 | cc_library( 58 | name = "flags", 59 | srcs = [ 60 | "flags.cc", 61 | ], 62 | hdrs = [ 63 | "flags.h", 64 | ], 65 | copts = SNOVA_DEFAULT_COPTS, 66 | deps = [ 67 | ":tunnel_opt", 68 | "//snova/log:log_api", 69 | "@asio", 70 | "@com_google_absl//absl/container:btree", 71 | ], 72 | ) 73 | 74 | cc_library( 75 | name = "async_mutex", 76 | srcs = [ 77 | "async_channel_mutex.cc", 78 | ], 79 | hdrs = [ 80 | "async_channel_mutex.h", 81 | ], 82 | copts = SNOVA_DEFAULT_COPTS, 83 | deps = [ 84 | "@asio", 85 | ], 86 | ) 87 | 88 | cc_library( 89 | name = "address", 90 | srcs = [ 91 | "address.cc", 92 | ], 93 | hdrs = [ 94 | "address.h", 95 | ], 96 | copts = SNOVA_DEFAULT_COPTS, 97 | deps = [ 98 | ":net_helper", 99 | "//snova/log:log_api", 100 | "@asio", 101 | "@com_google_absl//absl/strings", 102 | ], 103 | ) 104 | 105 | cc_library( 106 | name = "dns_options", 107 | srcs = [ 108 | "dns_options.cc", 109 | ], 110 | hdrs = [ 111 | "dns_options.h", 112 | ], 113 | copts = SNOVA_DEFAULT_COPTS, 114 | deps = [ 115 | ":address", 116 | "@asio", 117 | "@com_google_absl//absl/container:btree", 118 | "@com_google_absl//absl/strings", 119 | ], 120 | ) 121 | 122 | cc_library( 123 | name = "net_helper", 124 | srcs = [ 125 | "net_helper.cc", 126 | ], 127 | hdrs = [ 128 | "net_helper.h", 129 | ], 130 | copts = SNOVA_DEFAULT_COPTS, 131 | deps = [ 132 | ":endian", 133 | "//snova/io:io_util", 134 | "//snova/log:log_api", 135 | "@asio", 136 | "@com_google_absl//absl/strings", 137 | ], 138 | ) 139 | 140 | cc_library( 141 | name = "sni", 142 | srcs = [ 143 | "sni.cc", 144 | ], 145 | hdrs = [ 146 | "sni.h", 147 | ], 148 | copts = SNOVA_DEFAULT_COPTS, 149 | deps = [ 150 | "//snova/log:log_api", 151 | ], 152 | ) 153 | 154 | cc_library( 155 | name = "endian", 156 | hdrs = [ 157 | "endian.h", 158 | ], 159 | copts = SNOVA_DEFAULT_COPTS, 160 | deps = [ 161 | "@com_google_absl//absl/base:endian", 162 | ], 163 | ) 164 | 165 | cc_library( 166 | name = "http_helper", 167 | srcs = [ 168 | "http_helper.cc", 169 | ], 170 | hdrs = [ 171 | "http_helper.h", 172 | ], 173 | copts = SNOVA_DEFAULT_COPTS, 174 | deps = [ 175 | ":misc_helper", 176 | "@com_google_absl//absl/strings", 177 | ], 178 | ) 179 | 180 | cc_library( 181 | name = "misc_helper", 182 | srcs = [ 183 | "misc_helper.cc", 184 | ], 185 | hdrs = [ 186 | "misc_helper.h", 187 | ], 188 | copts = SNOVA_DEFAULT_COPTS, 189 | deps = select({ 190 | "@bazel_tools//src/conditions:windows": [ 191 | "@local_windows_borringssl//:headers", 192 | "@local_windows_borringssl//:crypto", 193 | ], 194 | "//conditions:default": [ 195 | "@com_github_google_borringssl//:crypto", 196 | ], 197 | }), 198 | ) 199 | -------------------------------------------------------------------------------- /snova/util/address.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/util/address.h" 30 | #include 31 | #include "absl/strings/str_split.h" 32 | #include "snova/log/log_macros.h" 33 | #include "snova/util/net_helper.h" 34 | 35 | namespace snova { 36 | PaserAddressResult NetAddress::Parse(const std::string& addr) { 37 | absl::string_view url_part = addr; 38 | std::vector schema_url_parts = absl::StrSplit(addr, "://"); 39 | absl::string_view schema; 40 | if (schema_url_parts.size() == 2) { 41 | url_part = schema_url_parts[1]; 42 | schema = schema_url_parts[0]; 43 | } 44 | absl::string_view host_port_part = url_part; 45 | absl::string_view path; 46 | auto pos = url_part.find('/'); 47 | if (pos != absl::string_view::npos) { 48 | host_port_part = url_part.substr(0, pos); 49 | if (url_part.size() > (pos + 1)) { 50 | path = url_part.substr(pos + 1); 51 | } 52 | } 53 | uint16_t port = 0; 54 | absl::string_view host_view; 55 | std::vector host_ports = absl::StrSplit(host_port_part, ':'); 56 | if (host_ports.size() != 2) { 57 | host_view = host_port_part; 58 | } else { 59 | host_view = host_ports[0]; 60 | try { 61 | port = std::stoi(std::string(host_ports[1])); 62 | } catch (...) { 63 | // SNOVA_ERROR("{}", host_ports[1]); 64 | return PaserAddressResult{nullptr, std::make_error_code(std::errc::invalid_argument)}; 65 | } 66 | } 67 | if (host_view.empty()) { 68 | host_view = "0.0.0.0"; 69 | } 70 | std::unique_ptr net_addr = std::make_unique(); 71 | if (!schema.empty()) { 72 | net_addr->schema.assign(schema.data(), schema.size()); 73 | } 74 | if (!path.empty()) { 75 | net_addr->path.assign(path.data(), path.size()); 76 | } 77 | net_addr->host.assign(host_view.data(), host_view.size()); 78 | if (net_addr->schema == "https" || net_addr->schema == "tls" || net_addr->schema == "doh") { 79 | if (port == 0) { 80 | port = 443; 81 | } 82 | } else if (net_addr->schema == "http") { 83 | if (port == 0) { 84 | port = 80; 85 | } 86 | } else if (net_addr->schema == "dns") { 87 | if (port == 0) { 88 | port = 53; 89 | } 90 | } else if (net_addr->schema == "dot") { 91 | if (port == 0) { 92 | port = 853; 93 | } 94 | } 95 | net_addr->port = port; 96 | return PaserAddressResult{std::move(net_addr), std::error_code{}}; 97 | } 98 | 99 | std::string NetAddress::String() const { 100 | std::string s; 101 | if (!schema.empty()) { 102 | s.append(schema).append("://"); 103 | } 104 | s.append(host).append(":").append(std::to_string(port)); 105 | if (!path.empty()) { 106 | s.append("/").append(path); 107 | } 108 | return s; 109 | } 110 | 111 | asio::awaitable NetAddress::GetEndpoint( 112 | ::asio::ip::tcp::endpoint* endpoint) const { 113 | return resolve_endpoint(host, port, endpoint); 114 | } 115 | asio::awaitable NetAddress::GetEndpoint( 116 | ::asio::ip::udp::endpoint* endpoint) const { 117 | return resolve_endpoint(host, port, endpoint); 118 | } 119 | } // namespace snova 120 | -------------------------------------------------------------------------------- /snova/util/address.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "asio.hpp" 36 | 37 | namespace snova { 38 | struct NetAddress; 39 | using PaserAddressResult = std::pair, std::error_code>; 40 | struct NetAddress { 41 | std::string schema; 42 | std::string host; 43 | uint16_t port = 0; 44 | std::string path; 45 | asio::awaitable GetEndpoint(::asio::ip::tcp::endpoint* endpoint) const; 46 | asio::awaitable GetEndpoint(::asio::ip::udp::endpoint* endpoint) const; 47 | 48 | std::string String() const; 49 | static PaserAddressResult Parse(const std::string& addr); 50 | }; 51 | 52 | } // namespace snova 53 | -------------------------------------------------------------------------------- /snova/util/async_channel_mutex.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/util/async_channel_mutex.h" 30 | #include "asio/experimental/as_tuple.hpp" 31 | 32 | namespace snova { 33 | AsyncChannelMutex::AsyncChannelMutex(const AsyncChannelMutexExecutor& ex) 34 | : channel_(ex, 1), wait_count_(0), locked_(false) {} 35 | void AsyncChannelMutex::Close() { 36 | channel_.cancel(); 37 | channel_.close(); 38 | } 39 | asio::awaitable AsyncChannelMutex::Lock() { 40 | if (!channel_.is_open()) { 41 | co_return std::error_code{}; 42 | } 43 | while (locked_) { 44 | wait_count_++; 45 | auto [ec, v] = 46 | co_await channel_.async_receive(::asio::experimental::as_tuple(::asio::use_awaitable)); 47 | wait_count_--; 48 | if (ec) { 49 | co_return ec; 50 | } 51 | } 52 | locked_ = true; 53 | co_return std::error_code{}; 54 | } 55 | asio::awaitable AsyncChannelMutex::Unlock() { 56 | if (!channel_.is_open()) { 57 | co_return std::error_code{}; 58 | } 59 | locked_ = false; 60 | if (wait_count_ > 0) { 61 | auto [ec] = co_await channel_.async_send(std::error_code{}, true, 62 | ::asio::experimental::as_tuple(::asio::use_awaitable)); 63 | co_return ec; 64 | } 65 | co_return std::error_code{}; 66 | } 67 | 68 | // AsyncSpinMutex::AsyncSpinMutex(const typename ::asio::steady_timer::executor_type& ex) 69 | // : locked_(false) {} 70 | // asio::awaitable AsyncSpinMutex::Lock() { 71 | // std::chrono::milliseconds wait_period(1); 72 | // std::unique_ptr<::asio::steady_timer> timer; 73 | // while (locked_) { 74 | // if (!timer) { 75 | // auto ex = co_await asio::this_coro::executor; 76 | // timer = std::make_unique<::asio::steady_timer>(ex); 77 | // } 78 | // timer->expires_after(wait_period); 79 | // co_await timer->async_wait(::asio::use_awaitable); 80 | // } 81 | // locked_ = true; 82 | // co_return std::error_code{}; 83 | // } 84 | // asio::awaitable AsyncSpinMutex::Unlock() { 85 | // locked_ = false; 86 | // co_return std::error_code{}; 87 | // } 88 | // void AsyncSpinMutex::Close() {} 89 | 90 | } // namespace snova 91 | -------------------------------------------------------------------------------- /snova/util/async_channel_mutex.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include "asio.hpp" 32 | #include "asio/experimental/channel.hpp" 33 | namespace snova { 34 | using AsyncChannelMutexExecutor = 35 | typename asio::experimental::channel::executor_type; 36 | class AsyncChannelMutex { 37 | public: 38 | explicit AsyncChannelMutex(const AsyncChannelMutexExecutor& ex); 39 | asio::awaitable Lock(); 40 | asio::awaitable Unlock(); 41 | void Close(); 42 | size_t GetWaitCount() const { return wait_count_; } 43 | bool IsLocked() const { return locked_; } 44 | 45 | private: 46 | asio::experimental::channel channel_; 47 | size_t wait_count_; 48 | bool locked_; 49 | }; 50 | 51 | // class AsyncSpinMutex { 52 | // public: 53 | // AsyncSpinMutex(const typename ::asio::steady_timer::executor_type& ex); 54 | // asio::awaitable Lock(); 55 | // asio::awaitable Unlock(); 56 | // void Close(); 57 | 58 | // private: 59 | // bool locked_; 60 | // }; 61 | } // namespace snova 62 | -------------------------------------------------------------------------------- /snova/util/dns_options.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/util/dns_options.h" 30 | #include 31 | #include 32 | #include "absl/strings/match.h" 33 | #include "absl/strings/str_split.h" 34 | #include "absl/strings/strip.h" 35 | 36 | namespace snova { 37 | asio::awaitable DNSOptions::Init() { 38 | auto ec = co_await default_ns->GetEndpoint(&default_ns_endpoint); 39 | if (ec) { 40 | co_return ec; 41 | } 42 | ec = co_await trusted_ns->GetEndpoint(&trusted_ns_endpoint); 43 | if (ec) { 44 | co_return ec; 45 | } 46 | ec = co_await trusted_ns->GetEndpoint(&trusted_ns_tcp_endpoint); 47 | if (ec) { 48 | co_return ec; 49 | } 50 | co_return std::error_code{}; 51 | } 52 | bool DNSOptions::LoadIPRangeFromFile(const std::string& file) { 53 | std::ifstream input(file.c_str()); 54 | if (input.fail()) { 55 | return false; 56 | } 57 | bool success = true; 58 | std::string line; 59 | while (std::getline(input, line)) { 60 | auto line_view = absl::StripAsciiWhitespace(line); 61 | auto v4_network = ::asio::ip::make_network_v4(line_view); 62 | ::asio::ip::address_v4_range r = v4_network.hosts(); 63 | auto ret = ip_range_map.emplace(v4_network.network().to_uint(), r); 64 | if (!ret.second) { 65 | // printf("###Failed to emplace:%s\n", v4_network.network().to_string().c_str()); 66 | success = false; 67 | break; 68 | } 69 | // printf("###%s %u %u %u\n", v4_network.network().to_string().c_str(), r.size(), 70 | // r.begin()->to_uint(), r.end()->to_uint()); 71 | // break; 72 | } 73 | input.close(); 74 | return success; 75 | } 76 | bool DNSOptions::MatchIPRanges(uint32_t ip) const { 77 | auto found = ip_range_map.upper_bound(ip); 78 | if (found == ip_range_map.end()) { 79 | return false; 80 | } 81 | if (found == ip_range_map.begin()) { 82 | return false; 83 | } 84 | found--; 85 | const ::asio::ip::address_v4_range& range = found->second; 86 | if (range.find(::asio::ip::make_address_v4(ip)) != range.end()) { 87 | return true; 88 | } 89 | return false; 90 | } 91 | } // namespace snova 92 | -------------------------------------------------------------------------------- /snova/util/dns_options.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | #include 34 | #include "absl/container/btree_map.h" 35 | #include "asio/ip/address_v4_range.hpp" 36 | #include "asio/ip/tcp.hpp" 37 | #include "asio/ip/udp.hpp" 38 | #include "snova/util/address.h" 39 | 40 | namespace snova { 41 | struct DNSOptions { 42 | ::asio::ip::udp::endpoint default_ns_endpoint; 43 | ::asio::ip::udp::endpoint trusted_ns_endpoint; 44 | ::asio::ip::tcp::endpoint trusted_ns_tcp_endpoint; 45 | std::unique_ptr default_ns; 46 | std::unique_ptr trusted_ns; 47 | 48 | std::vector trusted_ns_domains; 49 | // std::vector<::asio::ip::address_v4_range> ip_ranges; 50 | absl::btree_map ip_range_map; 51 | 52 | asio::awaitable Init(); 53 | 54 | bool LoadIPRangeFromFile(const std::string& file); 55 | 56 | bool MatchIPRanges(uint32_t ip) const; 57 | }; 58 | } // namespace snova 59 | -------------------------------------------------------------------------------- /snova/util/endian.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include "absl/base/internal/endian.h" 32 | namespace snova { 33 | template 34 | static T native_to_big(T v) { 35 | if constexpr (std::is_same_v) { 36 | return absl::ghtonll(v); 37 | } else if constexpr (std::is_same_v) { 38 | return absl::ghtonl(v); 39 | } else if constexpr (std::is_same_v) { 40 | return absl::ghtons(v); 41 | } else { 42 | static_assert(sizeof(T) == std::size_t(-1), "Not support integer type."); 43 | } 44 | } 45 | 46 | template 47 | static T big_to_native(T v) { 48 | if constexpr (std::is_same_v) { 49 | return absl::gntohll(v); 50 | } else if constexpr (std::is_same_v) { 51 | return absl::gntohl(v); 52 | } else if constexpr (std::is_same_v) { 53 | return absl::gntohs(v); 54 | } else { 55 | static_assert(sizeof(T) == std::size_t(-1), "Not support integer type."); 56 | } 57 | } 58 | } // namespace snova 59 | -------------------------------------------------------------------------------- /snova/util/flags.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/util/flags.h" 30 | #include 31 | 32 | namespace snova { 33 | bool g_is_middle_node = false; 34 | bool g_is_entry_node = false; 35 | bool g_is_exit_node = false; 36 | bool g_is_redirect_node = false; 37 | // std::string g_remote_server; 38 | // std::string g_http_proxy_host; 39 | uint16_t g_http_proxy_port = 0; 40 | uint32_t g_conn_num_per_server = 5; 41 | uint32_t g_iobuf_max_pool_size = 64; 42 | uint32_t g_stream_io_timeout_secs = 120; 43 | uint32_t g_connection_expire_secs = 1800; 44 | uint32_t g_connection_max_inactive_secs = 300; 45 | uint32_t g_tcp_write_timeout_secs = 10; 46 | uint32_t g_entry_socket_send_buffer_size = 0; 47 | uint32_t g_entry_socket_recv_buffer_size = 0; 48 | uint32_t g_dns_query_timeout_msecs = 800; 49 | 50 | std::shared_ptr& GlobalFlags::GetIntance() { 51 | static std::shared_ptr s = std::make_shared(); 52 | return s; 53 | } 54 | 55 | void GlobalFlags::SetHttpProxyHost(const std::string& s) { http_proxy_host_ = s; } 56 | const std::string& GlobalFlags::GetHttpProxyHost() { return http_proxy_host_; } 57 | void GlobalFlags::SetRemoteServer(const std::string& s) { remote_server_ = s; } 58 | const std::string& GlobalFlags::GetRemoteServer() { return remote_server_; } 59 | void GlobalFlags::SetUser(const std::string& s) { user_ = s; } 60 | const std::string& GlobalFlags::GetUser() { return user_; } 61 | 62 | void GlobalFlags::AddLocalTunnelOption(const LocalTunnelOption& opt) { 63 | local_tunnels_.emplace_back(opt); 64 | } 65 | void GlobalFlags::AddRemoteTunnelOption(const RemoteTunnelOption& opt) { 66 | remote_tunnels_.emplace_back(opt); 67 | } 68 | 69 | const std::vector& GlobalFlags::GetLocalTunnelOptions() const { 70 | return local_tunnels_; 71 | } 72 | const std::vector& GlobalFlags::GetRemoteTunnelOptions() const { 73 | return remote_tunnels_; 74 | } 75 | 76 | } // namespace snova 77 | -------------------------------------------------------------------------------- /snova/util/flags.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "snova/util/tunnel_opt.h" 36 | 37 | namespace snova { 38 | extern bool g_is_middle_node; 39 | extern bool g_is_entry_node; 40 | extern bool g_is_exit_node; 41 | extern bool g_is_redirect_node; 42 | 43 | extern uint16_t g_http_proxy_port; 44 | extern uint32_t g_conn_num_per_server; 45 | extern uint32_t g_connection_expire_secs; 46 | extern uint32_t g_connection_max_inactive_secs; 47 | extern uint32_t g_iobuf_max_pool_size; 48 | extern uint32_t g_stream_io_timeout_secs; 49 | extern uint32_t g_tcp_write_timeout_secs; 50 | extern uint32_t g_entry_socket_send_buffer_size; 51 | extern uint32_t g_entry_socket_recv_buffer_size; 52 | extern uint32_t g_dns_query_timeout_msecs; 53 | 54 | class GlobalFlags { 55 | public: 56 | static std::shared_ptr& GetIntance(); 57 | void SetHttpProxyHost(const std::string& s); 58 | const std::string& GetHttpProxyHost(); 59 | void SetRemoteServer(const std::string& s); 60 | const std::string& GetRemoteServer(); 61 | void SetUser(const std::string& s); 62 | const std::string& GetUser(); 63 | 64 | void AddLocalTunnelOption(const LocalTunnelOption& opt); 65 | void AddRemoteTunnelOption(const RemoteTunnelOption& opt); 66 | const std::vector& GetLocalTunnelOptions() const; 67 | const std::vector& GetRemoteTunnelOptions() const; 68 | 69 | private: 70 | std::string http_proxy_host_; 71 | std::string remote_server_; 72 | std::string user_; 73 | std::vector local_tunnels_; 74 | std::vector remote_tunnels_; 75 | }; 76 | 77 | } // namespace snova 78 | -------------------------------------------------------------------------------- /snova/util/http_helper.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/util/http_helper.h" 30 | #include "absl/strings/escaping.h" 31 | #include "absl/strings/str_split.h" 32 | #include "snova/util/misc_helper.h" 33 | 34 | namespace snova { 35 | int parse_http_hostport(absl::string_view recv_data, absl::string_view* hostport) { 36 | return http_get_header(recv_data, "Host:", hostport); 37 | } 38 | int http_get_header(absl::string_view recv_data, absl::string_view header, absl::string_view* val) { 39 | auto pos = recv_data.find(header); 40 | if (pos == absl::string_view::npos) { 41 | return -1; 42 | } 43 | absl::string_view crlf = "\r\n"; 44 | auto end_pos = recv_data.find(crlf, pos); 45 | if (end_pos == absl::string_view::npos) { 46 | return -1; 47 | } 48 | size_t n = (end_pos - pos - header.size()); 49 | 50 | absl::string_view tmp(recv_data.data() + pos + header.size(), n); 51 | 52 | *val = absl::StripAsciiWhitespace(tmp); 53 | // printf("#### n:%d %d %s\n", n, val->size(), tmp.data()); 54 | return 0; 55 | } 56 | 57 | void ws_get_accept_secret_key(absl::string_view key, std::string* accept_key) { 58 | std::string encode_key(key.data(), key.size()); 59 | encode_key.append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); 60 | std::string resp_bin_key; 61 | sha1_sum(encode_key, resp_bin_key); 62 | std::string resp_text_key; 63 | absl::Base64Escape(resp_bin_key, accept_key); 64 | } 65 | 66 | } // namespace snova 67 | -------------------------------------------------------------------------------- /snova/util/http_helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include "absl/strings/string_view.h" 33 | 34 | namespace snova { 35 | int parse_http_hostport(absl::string_view recv_data, absl::string_view* hostport); 36 | int http_get_header(absl::string_view recv_data, absl::string_view header, absl::string_view* val); 37 | 38 | void ws_get_accept_secret_key(absl::string_view key, std::string* accept_key); 39 | } // namespace snova 40 | -------------------------------------------------------------------------------- /snova/util/misc_helper.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/util/misc_helper.h" 30 | #include 31 | // #include "mbedtls/sha1.h" 32 | #include "openssl/sha.h" 33 | 34 | namespace snova { 35 | uint64_t random_uint64(uint64_t min, uint64_t max) { 36 | std::random_device rd; // Get a random seed from the OS entropy device, or whatever 37 | std::mt19937_64 eng(rd()); // Use the 64-bit Mersenne Twister 19937 generator 38 | // and seed it with entropy. 39 | 40 | // Define the distribution, by default it goes from 0 to MAX(unsigned long long) 41 | // or what have you. 42 | std::uniform_int_distribution distr(min, max); 43 | return distr(eng); 44 | } 45 | 46 | void sha1_sum(const std::string& src, std::string& dst) { 47 | // mbedtls_sha1_context ctx; 48 | // mbedtls_sha1_init(&ctx); 49 | // mbedtls_sha1_starts(&ctx); 50 | // mbedtls_sha1_update(&ctx, reinterpret_cast(src.data()), src.size()); 51 | // unsigned char output[20]; 52 | // mbedtls_sha1_finish(&ctx, output); 53 | // mbedtls_sha1_free(&ctx); 54 | // dst.append(reinterpret_cast(output), 20); 55 | 56 | SHA_CTX ctx; 57 | uint8_t hash[SHA_DIGEST_LENGTH]; 58 | 59 | SHA1_Init(&ctx); 60 | SHA1_Update(&ctx, src.data(), src.size()); 61 | SHA1_Final(hash, &ctx); 62 | dst.append(reinterpret_cast(hash), SHA_DIGEST_LENGTH); 63 | } 64 | } // namespace snova 65 | -------------------------------------------------------------------------------- /snova/util/misc_helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | namespace snova { 34 | uint64_t random_uint64(uint64_t min, uint64_t max); 35 | 36 | void sha1_sum(const std::string& src, std::string& dst); 37 | 38 | } // namespace snova 39 | -------------------------------------------------------------------------------- /snova/util/net_helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include "asio.hpp" 39 | namespace snova { 40 | 41 | bool is_private_address(const ::asio::ip::address& addr); 42 | 43 | int get_orig_dst(int fd, ::asio::ip::tcp::endpoint* endpoint); 44 | 45 | using SocketPtr = std::unique_ptr<::asio::ip::tcp::socket>; 46 | asio::awaitable get_connected_socket(const std::string& host, uint16_t port, 47 | bool is_tcp); 48 | 49 | using SocketRef = ::asio::ip::tcp::socket&; 50 | asio::awaitable connect_remote_via_http_proxy(SocketRef socket, 51 | const std::string& remote_host, 52 | uint16_t remote_port, 53 | const std::string& proxy_host, 54 | uint16_t proxy_port); 55 | asio::awaitable resolve_endpoint(const std::string& host, uint16_t port, 56 | ::asio::ip::tcp::endpoint* endpoint); 57 | asio::awaitable resolve_endpoint(const std::string& host, uint16_t port, 58 | ::asio::ip::udp::endpoint* endpoint); 59 | 60 | struct DNSAnswer { 61 | uint16_t nm; 62 | uint16_t type; 63 | uint16_t cls; 64 | uint16_t ttl1; // if using uint32, compiler will pad struct. 65 | uint16_t ttl2; 66 | uint16_t datalen; 67 | asio::ip::address_v4 v4_ip; 68 | asio::ip::address_v6 v6_ip; 69 | bool IsV4() const; 70 | bool IsV6() const; 71 | }; 72 | int dns_parse_name(const uint8_t* payload, int payload_offset, int payload_len, std::string& name); 73 | 74 | int dns_parse_answers(const uint8_t* payload, int payload_offset, int payload_len, 75 | std::vector& answers); 76 | } // namespace snova 77 | -------------------------------------------------------------------------------- /snova/util/sni.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | 33 | namespace snova { 34 | int parse_sni(const uint8_t* data, size_t data_len, std::string* sni); 35 | } 36 | -------------------------------------------------------------------------------- /snova/util/stat.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/util/stat.h" 30 | #include 31 | #include 32 | #include 33 | #include "absl/container/btree_map.h" 34 | #include "absl/container/btree_set.h" 35 | #include "snova/log/log_macros.h" 36 | 37 | namespace snova { 38 | using StatMap = absl::btree_map; 39 | using StatTable = absl::btree_map; 40 | 41 | static StatTable g_stat_table; 42 | static std::vector g_stat_funcs; 43 | 44 | void register_stat_func(CollectStatFunc&& func) { g_stat_funcs.emplace_back(std::move(func)); } 45 | 46 | static void print_stats() { 47 | g_stat_table.clear(); 48 | for (auto& f : g_stat_funcs) { 49 | auto stat_vals = f(); 50 | for (const auto& [sec, kvs] : stat_vals) { 51 | for (const auto& [k, v] : kvs) { 52 | g_stat_table[sec][k] = v; 53 | } 54 | } 55 | } 56 | if (g_stat_table.empty()) { 57 | return; 58 | } 59 | std::string buffer; 60 | buffer.append("======================Stats=====================\n"); 61 | for (const auto& [section, map] : g_stat_table) { 62 | buffer.append("[").append(section).append("]:\n"); 63 | for (const auto& [key, value] : map) { 64 | buffer.append(" ").append(key).append(": ").append(value).append("\n"); 65 | } 66 | buffer.append("\n"); 67 | } 68 | SNOVA_INFO("{}", buffer); 69 | } 70 | asio::awaitable start_stat_timer(uint32_t period_secs) { 71 | auto ex = co_await asio::this_coro::executor; 72 | ::asio::steady_timer timer(ex); 73 | std::chrono::seconds period(period_secs); 74 | while (true) { 75 | timer.expires_after(period); 76 | co_await timer.async_wait(::asio::use_awaitable); 77 | print_stats(); 78 | } 79 | co_return; 80 | } 81 | 82 | } // namespace snova 83 | -------------------------------------------------------------------------------- /snova/util/stat.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "asio.hpp" 36 | namespace snova { 37 | using StatKeyValue = std::unordered_map; 38 | using StatValues = std::unordered_map; 39 | using CollectStatFunc = std::function; 40 | void register_stat_func(CollectStatFunc&& func); 41 | 42 | asio::awaitable start_stat_timer(uint32_t period_secs); 43 | 44 | } // namespace snova 45 | -------------------------------------------------------------------------------- /snova/util/time_wheel.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include "snova/util/time_wheel.h" 31 | #include 32 | #include 33 | 34 | #include "asio/experimental/as_tuple.hpp" 35 | #include "snova/util/flags.h" 36 | 37 | namespace snova { 38 | using std::chrono::milliseconds; 39 | 40 | struct TimerTask { 41 | TimeoutFunc timeout_callback; 42 | GetActiveTimeFunc get_active_time; 43 | uint64_t timeout_msecs = 0; 44 | uint64_t create_time = 0; 45 | bool canceled = false; 46 | }; 47 | 48 | std::shared_ptr& TimeWheel::GetInstance() { 49 | static std::shared_ptr g_instance = std::make_shared(128); 50 | return g_instance; 51 | } 52 | 53 | TimeWheel::TimeWheel(uint32_t slot_size) { time_wheel_.resize(slot_size); } 54 | 55 | CancelFunc TimeWheel::Add(TimeoutFunc&& func, GetActiveTimeFunc&& active, uint64_t timeout_msecs) { 56 | TimerTaskPtr task = std::make_shared(); 57 | task->timeout_callback = std::move(func); 58 | task->get_active_time = std::move(active); 59 | task->timeout_msecs = timeout_msecs; 60 | return DoRegister(task); 61 | } 62 | CancelFunc TimeWheel::Add(TimeoutFunc&& func, uint64_t timeout_msecs) { 63 | TimerTaskPtr task = std::make_shared(); 64 | task->timeout_callback = std::move(func); 65 | task->timeout_msecs = timeout_msecs; 66 | return DoRegister(task); 67 | } 68 | 69 | CancelFunc TimeWheel::DoRegister(const TimerTaskPtr& rtask) { 70 | TimerTaskPtr task = rtask; 71 | if (task->timeout_msecs == 0) { 72 | task->timeout_msecs = 500; 73 | } 74 | auto now = 75 | std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) 76 | .count(); 77 | // uint32_t now = time(nullptr); 78 | task->create_time = now; 79 | size_t idx = GetIdxByMillsecs(now + task->timeout_msecs); 80 | auto cancel_func = [task]() { 81 | task->canceled = true; 82 | task->timeout_callback = {}; 83 | task->get_active_time = {}; 84 | }; 85 | time_wheel_[idx].emplace_back(task); 86 | return cancel_func; 87 | } 88 | 89 | size_t TimeWheel::GetIdxByMillsecs(uint64_t ms) { return (ms / 10) % time_wheel_.size(); } 90 | 91 | asio::awaitable TimeWheel::Run() { 92 | auto ex = co_await asio::this_coro::executor; 93 | ::asio::steady_timer timer(ex); 94 | std::chrono::milliseconds period(99); // run every 99ms 95 | while (true) { 96 | timer.expires_after(period); 97 | co_await timer.async_wait(::asio::experimental::as_tuple(::asio::use_awaitable)); 98 | auto now = std::chrono::duration_cast( 99 | std::chrono::system_clock::now().time_since_epoch()) 100 | .count(); 101 | size_t idx = GetIdxByMillsecs(now); 102 | if (time_wheel_[idx].empty()) { 103 | continue; 104 | } 105 | TimerTaskQueue routine_queue = std::move(time_wheel_[idx]); 106 | for (auto& task : routine_queue) { 107 | if (task->canceled) { 108 | continue; 109 | } 110 | uint64_t active_time = task->create_time; 111 | if (task->get_active_time) { 112 | active_time = task->get_active_time(); 113 | } 114 | if (now - active_time > task->timeout_msecs) { 115 | co_await task->timeout_callback(); 116 | } else { 117 | uint32_t next_idx = GetIdxByMillsecs(active_time + task->timeout_msecs + 100); 118 | time_wheel_[next_idx].emplace_back(std::move(task)); 119 | } 120 | } 121 | routine_queue.clear(); 122 | } 123 | } 124 | } // namespace snova 125 | -------------------------------------------------------------------------------- /snova/util/time_wheel.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "asio.hpp" 36 | 37 | namespace snova { 38 | using TimeoutFunc = std::function()>; 39 | using GetActiveTimeFunc = std::function; 40 | using CancelFunc = std::function; 41 | 42 | struct TimerTask; 43 | using TimerTaskPtr = std::shared_ptr; 44 | 45 | class TimeWheel { 46 | public: 47 | static std::shared_ptr& GetInstance(); 48 | explicit TimeWheel(uint32_t slot_size = 128); 49 | CancelFunc Add(TimeoutFunc&& func, GetActiveTimeFunc&& active, uint64_t timeout_msecs); 50 | CancelFunc Add(TimeoutFunc&& func, uint64_t timeout_msecs); 51 | 52 | asio::awaitable Run(); 53 | 54 | private: 55 | size_t GetIdxByMillsecs(uint64_t ms); 56 | CancelFunc DoRegister(const TimerTaskPtr& task); 57 | using TimerTaskQueue = std::vector; 58 | using TimeWheelQueue = std::vector; 59 | TimeWheelQueue time_wheel_; 60 | }; 61 | } // namespace snova 62 | -------------------------------------------------------------------------------- /snova/util/tunnel_opt.cc: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #include "snova/util/tunnel_opt.h" 30 | #include 31 | #include 32 | #include "absl/strings/numbers.h" 33 | #include "absl/strings/str_split.h" 34 | 35 | namespace snova { 36 | 37 | static bool parse_tunnel_opt(const std::string& addr, 38 | std::tuple* opt) { 39 | std::vector parts = absl::StrSplit(addr, ":"); 40 | if (parts.size() != 3) { 41 | return false; 42 | } 43 | uint32_t port0, port2 = 0; 44 | if (!absl::SimpleAtoi(parts[0], &port0) || !absl::SimpleAtoi(parts[2], &port2)) { 45 | return false; 46 | } 47 | std::string host(parts[1].data(), parts[1].size()); 48 | *opt = std::make_tuple(static_cast(port0), host, static_cast(port2)); 49 | return true; 50 | } 51 | 52 | bool LocalTunnelOption::Parse(const std::string& addr, LocalTunnelOption* opt) { 53 | std::tuple result; 54 | if (!parse_tunnel_opt(addr, &result)) { 55 | return false; 56 | } 57 | opt->local_port = std::get<0>(result); 58 | opt->remote_host = std::get<1>(result); 59 | opt->remote_port = std::get<2>(result); 60 | return true; 61 | } 62 | 63 | bool RemoteTunnelOption::Parse(const std::string& addr, RemoteTunnelOption* opt) { 64 | std::tuple result; 65 | if (!parse_tunnel_opt(addr, &result)) { 66 | return false; 67 | } 68 | opt->remote_port = std::get<0>(result); 69 | opt->local_host = std::get<1>(result); 70 | opt->local_port = std::get<2>(result); 71 | return true; 72 | } 73 | } // namespace snova 74 | -------------------------------------------------------------------------------- /snova/util/tunnel_opt.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright (c) 2022, yinqiwen 3 | *All rights reserved. 4 | * 5 | *Redistribution and use in source and binary forms, with or without 6 | *modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of rimos nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 | *THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #pragma once 31 | #include 32 | #include 33 | 34 | namespace snova { 35 | struct LocalTunnelOption { 36 | std::string remote_host; 37 | uint16_t remote_port = 0; 38 | uint16_t local_port = 0; 39 | static bool Parse(const std::string& addr, LocalTunnelOption* opt); 40 | }; 41 | struct RemoteTunnelOption { 42 | std::string local_host; 43 | uint16_t local_port = 0; 44 | uint16_t remote_port = 0; 45 | static bool Parse(const std::string& addr, RemoteTunnelOption* opt); 46 | }; 47 | 48 | } // namespace snova 49 | -------------------------------------------------------------------------------- /toolchains/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | constraint_setting(name = "libc") 4 | 5 | constraint_value( 6 | name = "musl", 7 | constraint_setting = ":libc", 8 | ) 9 | 10 | constraint_setting(name = "abi") 11 | 12 | constraint_value( 13 | name = "eabi", 14 | constraint_setting = ":abi", 15 | ) 16 | 17 | constraint_value( 18 | name = "eabihf", 19 | constraint_setting = ":abi", 20 | ) 21 | 22 | platform( 23 | name = "linux_musl_x64", 24 | constraint_values = [ 25 | "@platforms//cpu:x86_64", 26 | "@platforms//os:linux", 27 | ":musl", 28 | ], 29 | ) 30 | 31 | platform( 32 | name = "linux_musl_arm_eabi", 33 | constraint_values = [ 34 | "@platforms//cpu:arm", 35 | "@platforms//os:linux", 36 | ":eabi", 37 | ], 38 | ) 39 | 40 | platform( 41 | name = "linux_musl_arm_eabihf", 42 | constraint_values = [ 43 | "@platforms//cpu:arm", 44 | "@platforms//os:linux", 45 | ":eabihf", 46 | ], 47 | ) 48 | 49 | platform( 50 | name = "linux_musl_aarch64", 51 | constraint_values = [ 52 | "@platforms//cpu:aarch64", 53 | "@platforms//os:linux", 54 | ], 55 | ) 56 | 57 | toolchain( 58 | name = "x64_linux_musl_gcc_compile_toolchain", 59 | exec_compatible_with = [ 60 | "@platforms//cpu:x86_64", 61 | "@platforms//os:linux", 62 | ], 63 | target_compatible_with = [ 64 | "@platforms//cpu:x86_64", 65 | "@platforms//os:linux", 66 | ], 67 | # toolchain = "@x64_linux_musl_gcc//:cc_toolchain", 68 | toolchain = select({ 69 | "//:local_musl": "@local_x64_linux_musl_gcc//:cc_toolchain", 70 | "//conditions:default": "@x64_linux_musl_gcc//:cc_toolchain", 71 | }), 72 | toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", 73 | ) 74 | 75 | # toolchain_type(name = "armv7l_linux_musleabihf_toolchain_type") 76 | 77 | toolchain( 78 | name = "arm_linux_musleabi_gcc_compile_toolchain", 79 | exec_compatible_with = [ 80 | "@platforms//cpu:x86_64", 81 | "@platforms//os:linux", 82 | ], 83 | target_compatible_with = [ 84 | "@platforms//cpu:arm", 85 | "@platforms//os:linux", 86 | ":eabi", 87 | ], 88 | toolchain = select({ 89 | "//:local_musl": "@local_arm_linux_musleabi//:cc_toolchain", 90 | "//conditions:default": "@arm_linux_musleabi//:cc_toolchain", 91 | }), 92 | toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", 93 | ) 94 | 95 | toolchain( 96 | name = "arm_linux_musleabihf_gcc_compile_toolchain", 97 | exec_compatible_with = [ 98 | "@platforms//cpu:x86_64", 99 | "@platforms//os:linux", 100 | ], 101 | target_compatible_with = [ 102 | "@platforms//cpu:arm", 103 | "@platforms//os:linux", 104 | ":eabihf", 105 | ], 106 | toolchain = select({ 107 | "//:local_musl": "@local_arm_linux_musleabihf//:cc_toolchain", 108 | "//conditions:default": "@arm_linux_musleabihf//:cc_toolchain", 109 | }), 110 | toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", 111 | ) 112 | 113 | toolchain( 114 | name = "aarch64_linux_musl_gcc_compile_toolchain", 115 | exec_compatible_with = [ 116 | "@platforms//cpu:x86_64", 117 | "@platforms//os:linux", 118 | ], 119 | target_compatible_with = [ 120 | "@platforms//cpu:aarch64", 121 | "@platforms//os:linux", 122 | ], 123 | toolchain = select({ 124 | "//:local_musl": "@local_aarch64_linux_musl_gcc//:cc_toolchain", 125 | "//conditions:default": "@aarch64_linux_musl//:cc_toolchain", 126 | }), 127 | toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", 128 | ) 129 | -------------------------------------------------------------------------------- /toolchains/aarch64_linux_musl.BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | filegroup( 4 | name = "all", 5 | srcs = glob( 6 | [ 7 | "bin/**", 8 | "include/**", 9 | "lib/**", 10 | "libexec/**", 11 | "share/**", 12 | "aarch64-linux-musl/**", 13 | "usr/include/**", 14 | ], 15 | ), 16 | ) 17 | 18 | filegroup( 19 | name = "ar", 20 | srcs = glob(["bin/aarch64-linux-musl-ar"]), 21 | ) 22 | 23 | filegroup( 24 | name = "as", 25 | srcs = glob(["bin/aarch64-linux-musl-as"]), 26 | ) 27 | 28 | filegroup( 29 | name = "cpp", 30 | srcs = glob(["bin/aarch64-linux-musl-cpp"]), 31 | ) 32 | 33 | filegroup( 34 | name = "dwp", 35 | srcs = glob(["bin/aarch64-linux-musl-dwp"]), 36 | ) 37 | 38 | filegroup( 39 | name = "gcc", 40 | srcs = glob(["bin/aarch64-linux-musl-gcc"]), 41 | ) 42 | 43 | filegroup( 44 | name = "g++", 45 | srcs = glob(["bin/aarch64-linux-musl-g++"]), 46 | ) 47 | 48 | filegroup( 49 | name = "gcov", 50 | srcs = glob(["bin/aarch64-linux-musl-gcov"]), 51 | ) 52 | 53 | filegroup( 54 | name = "ld", 55 | srcs = glob(["bin/aarch64-linux-musl-ld"]), 56 | ) 57 | 58 | filegroup( 59 | name = "nm", 60 | srcs = glob(["bin/aarch64-linux-musl-nm"]), 61 | ) 62 | 63 | filegroup( 64 | name = "objcopy", 65 | srcs = glob(["bin/aarch64-linux-musl-objcopy"]), 66 | ) 67 | 68 | filegroup( 69 | name = "objdump", 70 | srcs = glob(["bin/aarch64-linux-musl-objdump"]), 71 | ) 72 | 73 | filegroup( 74 | name = "strip", 75 | srcs = glob(["bin/aarch64-linux-musl-strip"]), 76 | ) 77 | 78 | filegroup( 79 | name = "compiler_components", 80 | srcs = [ 81 | "ar", 82 | "as", 83 | "cpp", 84 | "dwp", 85 | "g++", 86 | "gcc", 87 | "gcov", 88 | "ld", 89 | "nm", 90 | "objcopy", 91 | "objdump", 92 | "strip", 93 | ], 94 | ) 95 | 96 | load("@snova_asio//toolchains:linux-musl.bzl", "cc_toolchain_config") 97 | 98 | # cc_toolchain_suite( 99 | # name = "buildroot", 100 | # toolchains = { 101 | # "armv7": ":armv7-toolchain", 102 | # }, 103 | # ) 104 | 105 | cc_toolchain_config( 106 | name = "aarch64-toolchain-config", 107 | # cxx_builtin_include_directories = [ 108 | # "external/armv7l-linux-musleabihf-cross/include", 109 | # "external/armv7l-linux-musleabihf-cross/include/c++/11.2.1/", 110 | # ], 111 | # target_libc = "musl", 112 | cpu = "aarch64", 113 | tool_paths = ":compiler_components", 114 | ) 115 | 116 | cc_toolchain( 117 | name = "cc_toolchain", 118 | all_files = ":all", 119 | ar_files = ":all", 120 | compiler_files = ":all", 121 | dwp_files = ":all", 122 | linker_files = ":all", 123 | objcopy_files = ":all", 124 | strip_files = ":all", 125 | supports_param_files = False, 126 | toolchain_config = ":aarch64-toolchain-config", 127 | toolchain_identifier = "aarch64-toolchain", 128 | ) 129 | -------------------------------------------------------------------------------- /toolchains/arm_linux_musleabi.BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | filegroup( 4 | name = "all", 5 | srcs = glob( 6 | [ 7 | "bin/**", 8 | "include/**", 9 | "lib/**", 10 | "libexec/**", 11 | "share/**", 12 | "arm-linux-musleabi/**", 13 | "usr/include/**", 14 | ], 15 | ), 16 | ) 17 | 18 | filegroup( 19 | name = "ar", 20 | srcs = glob(["bin/arm-linux-musleabi-ar"]), 21 | ) 22 | 23 | filegroup( 24 | name = "as", 25 | srcs = glob(["bin/arm-linux-musleabi-as"]), 26 | ) 27 | 28 | filegroup( 29 | name = "cpp", 30 | srcs = glob(["bin/arm-linux-musleabi-cpp"]), 31 | ) 32 | 33 | filegroup( 34 | name = "dwp", 35 | srcs = glob(["bin/arm-linux-musleabi-dwp"]), 36 | ) 37 | 38 | filegroup( 39 | name = "gcc", 40 | srcs = glob(["bin/arm-linux-musleabi-gcc"]), 41 | ) 42 | 43 | filegroup( 44 | name = "g++", 45 | srcs = glob(["bin/arm-linux-musleabi-g++"]), 46 | ) 47 | 48 | filegroup( 49 | name = "gcov", 50 | srcs = glob(["bin/arm-linux-musleabi-gcov"]), 51 | ) 52 | 53 | filegroup( 54 | name = "ld", 55 | srcs = glob(["bin/arm-linux-musleabi-ld"]), 56 | ) 57 | 58 | filegroup( 59 | name = "nm", 60 | srcs = glob(["bin/arm-linux-musleabi-nm"]), 61 | ) 62 | 63 | filegroup( 64 | name = "objcopy", 65 | srcs = glob(["bin/arm-linux-musleabi-objcopy"]), 66 | ) 67 | 68 | filegroup( 69 | name = "objdump", 70 | srcs = glob(["bin/arm-linux-musleabi-objdump"]), 71 | ) 72 | 73 | filegroup( 74 | name = "strip", 75 | srcs = glob(["bin/arm-linux-musleabi-strip"]), 76 | ) 77 | 78 | filegroup( 79 | name = "compiler_components", 80 | srcs = [ 81 | "ar", 82 | "as", 83 | "cpp", 84 | "dwp", 85 | "g++", 86 | "gcc", 87 | "gcov", 88 | "ld", 89 | "nm", 90 | "objcopy", 91 | "objdump", 92 | "strip", 93 | ], 94 | ) 95 | 96 | load("@snova_asio//toolchains:linux-musl.bzl", "cc_toolchain_config") 97 | 98 | # cc_toolchain_suite( 99 | # name = "buildroot", 100 | # toolchains = { 101 | # "armv7": ":armv7-toolchain", 102 | # }, 103 | # ) 104 | 105 | cc_toolchain_config( 106 | name = "arm-toolchain-config", 107 | # cxx_builtin_include_directories = [ 108 | # "external/armv7l-linux-musleabihf-cross/include", 109 | # "external/armv7l-linux-musleabihf-cross/include/c++/11.2.1/", 110 | # ], 111 | # target_libc = "musl", 112 | cpu = "arm", 113 | tool_paths = ":compiler_components", 114 | ) 115 | 116 | cc_toolchain( 117 | name = "cc_toolchain", 118 | all_files = ":all", 119 | ar_files = ":all", 120 | compiler_files = ":all", 121 | dwp_files = ":all", 122 | linker_files = ":all", 123 | objcopy_files = ":all", 124 | strip_files = ":all", 125 | supports_param_files = False, 126 | toolchain_config = ":arm-toolchain-config", 127 | toolchain_identifier = "arm-toolchain", 128 | ) 129 | -------------------------------------------------------------------------------- /toolchains/arm_linux_musleabihf.BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | filegroup( 4 | name = "all", 5 | srcs = glob( 6 | [ 7 | "bin/**", 8 | "include/**", 9 | "lib/**", 10 | "libexec/**", 11 | "share/**", 12 | "arm-linux-musleabihf/**", 13 | "usr/include/**", 14 | ], 15 | ), 16 | ) 17 | 18 | filegroup( 19 | name = "ar", 20 | srcs = glob(["bin/arm-linux-musleabihf-ar"]), 21 | ) 22 | 23 | filegroup( 24 | name = "as", 25 | srcs = glob(["bin/arm-linux-musleabihf-as"]), 26 | ) 27 | 28 | filegroup( 29 | name = "cpp", 30 | srcs = glob(["bin/arm-linux-musleabihf-cpp"]), 31 | ) 32 | 33 | filegroup( 34 | name = "dwp", 35 | srcs = glob(["bin/arm-linux-musleabihf-dwp"]), 36 | ) 37 | 38 | filegroup( 39 | name = "gcc", 40 | srcs = glob(["bin/arm-linux-musleabihf-gcc"]), 41 | ) 42 | 43 | filegroup( 44 | name = "g++", 45 | srcs = glob(["bin/arm-linux-musleabihf-g++"]), 46 | ) 47 | 48 | filegroup( 49 | name = "gcov", 50 | srcs = glob(["bin/arm-linux-musleabihf-gcov"]), 51 | ) 52 | 53 | filegroup( 54 | name = "ld", 55 | srcs = glob(["bin/arm-linux-musleabihf-ld"]), 56 | ) 57 | 58 | filegroup( 59 | name = "nm", 60 | srcs = glob(["bin/arm-linux-musleabihf-nm"]), 61 | ) 62 | 63 | filegroup( 64 | name = "objcopy", 65 | srcs = glob(["bin/arm-linux-musleabihf-objcopy"]), 66 | ) 67 | 68 | filegroup( 69 | name = "objdump", 70 | srcs = glob(["bin/arm-linux-musleabihf-objdump"]), 71 | ) 72 | 73 | filegroup( 74 | name = "strip", 75 | srcs = glob(["bin/arm-linux-musleabihf-strip"]), 76 | ) 77 | 78 | filegroup( 79 | name = "compiler_components", 80 | srcs = [ 81 | "ar", 82 | "as", 83 | "cpp", 84 | "dwp", 85 | "g++", 86 | "gcc", 87 | "gcov", 88 | "ld", 89 | "nm", 90 | "objcopy", 91 | "objdump", 92 | "strip", 93 | ], 94 | ) 95 | 96 | load("@snova_asio//toolchains:linux-musl.bzl", "cc_toolchain_config") 97 | 98 | # cc_toolchain_suite( 99 | # name = "buildroot", 100 | # toolchains = { 101 | # "armv7": ":armv7-toolchain", 102 | # }, 103 | # ) 104 | 105 | cc_toolchain_config( 106 | name = "arm-toolchain-config", 107 | # cxx_builtin_include_directories = [ 108 | # "external/armv7l-linux-musleabihf-cross/include", 109 | # "external/armv7l-linux-musleabihf-cross/include/c++/11.2.1/", 110 | # ], 111 | # target_libc = "musl", 112 | cpu = "arm", 113 | tool_paths = ":compiler_components", 114 | ) 115 | 116 | cc_toolchain( 117 | name = "cc_toolchain", 118 | all_files = ":all", 119 | ar_files = ":all", 120 | compiler_files = ":all", 121 | dwp_files = ":all", 122 | linker_files = ":all", 123 | objcopy_files = ":all", 124 | strip_files = ":all", 125 | supports_param_files = False, 126 | toolchain_config = ":arm-toolchain-config", 127 | toolchain_identifier = "arm-toolchain", 128 | ) 129 | -------------------------------------------------------------------------------- /toolchains/gcc_arm_linux_gnueabihf.BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | filegroup( 4 | name = "all", 5 | srcs = glob(["**/**"]), 6 | # srcs = [], 7 | ) 8 | 9 | filegroup( 10 | name = "ar", 11 | srcs = glob(["bin/arm-none-linux-gnueabihf-ar"]), 12 | ) 13 | 14 | filegroup( 15 | name = "as", 16 | srcs = glob(["bin/arm-none-linux-gnueabihf-as"]), 17 | ) 18 | 19 | filegroup( 20 | name = "cpp", 21 | srcs = glob(["bin/arm-none-linux-gnueabihf-cpp"]), 22 | ) 23 | 24 | filegroup( 25 | name = "dwp", 26 | srcs = glob(["bin/arm-none-linux-gnueabihf-dwp"]), 27 | ) 28 | 29 | filegroup( 30 | name = "gcc", 31 | srcs = glob(["bin/arm-none-linux-gnueabihf-gcc"]), 32 | ) 33 | 34 | filegroup( 35 | name = "g++", 36 | srcs = glob(["bin/arm-none-linux-gnueabihf-g++"]), 37 | ) 38 | 39 | filegroup( 40 | name = "gcov", 41 | srcs = glob(["bin/arm-none-linux-gnueabihf-gcov"]), 42 | ) 43 | 44 | filegroup( 45 | name = "ld", 46 | srcs = glob(["bin/arm-none-linux-gnueabihf-ld"]), 47 | ) 48 | 49 | filegroup( 50 | name = "nm", 51 | srcs = glob(["bin/arm-none-linux-gnueabihf-nm"]), 52 | ) 53 | 54 | filegroup( 55 | name = "objcopy", 56 | srcs = glob(["bin/arm-none-linux-gnueabihf-objcopy"]), 57 | ) 58 | 59 | filegroup( 60 | name = "objdump", 61 | srcs = glob(["bin/arm-none-linux-gnueabihf-objdump"]), 62 | ) 63 | 64 | filegroup( 65 | name = "strip", 66 | srcs = glob(["bin/arm-none-linux-gnueabihf-strip"]), 67 | ) 68 | 69 | filegroup( 70 | name = "compiler_components", 71 | srcs = [ 72 | "ar", 73 | "as", 74 | "cpp", 75 | "dwp", 76 | "g++", 77 | "gcc", 78 | "gcov", 79 | "ld", 80 | "nm", 81 | "objcopy", 82 | "objdump", 83 | "strip", 84 | ], 85 | ) 86 | 87 | load("@snova_asio//toolchains:gcc_arm_toolchain.bzl", "cc_toolchain_config") 88 | 89 | cc_toolchain_config( 90 | name = "toolchain_config", 91 | abi_libc_version = "unknown", 92 | abi_version = "eabi", 93 | c_version = "c99", 94 | compile_flags = [ 95 | # "-mthumb", 96 | # "-mcpu=cortex-a9", 97 | ], 98 | compiler = "gcc", 99 | cpp_version = "c++2a", 100 | cpu = "armv7a", 101 | cxx_builtin_include_directories = [ 102 | ], 103 | dbg_compile_flags = [], 104 | link_flags = [ 105 | # "--specs=rdimon.specs", 106 | # "-lrdimon", 107 | # "-mcpu=cortex-a9", 108 | #"-march=armv7-a", 109 | # "-mthumb", 110 | ], 111 | link_libs = [], 112 | opt_compile_flags = [], 113 | opt_link_flags = [], 114 | target_libc = "unknown", 115 | tool_paths = ":compiler_components", 116 | unfiltered_compile_flags = [], 117 | ) 118 | 119 | cc_toolchain( 120 | name = "cc_toolchain", 121 | all_files = ":all", 122 | ar_files = ":all", 123 | as_files = ":all", 124 | compiler_files = ":all", 125 | dwp_files = ":all", 126 | linker_files = ":all", 127 | objcopy_files = ":all", 128 | strip_files = ":all", 129 | supports_param_files = 0, 130 | toolchain_config = ":toolchain_config", 131 | ) 132 | -------------------------------------------------------------------------------- /toolchains/linux-musl.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") 2 | load( 3 | "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", 4 | "feature", 5 | "flag_group", 6 | "flag_set", 7 | "tool_path", 8 | ) 9 | 10 | all_compile_actions = [ 11 | ACTION_NAMES.assemble, 12 | ACTION_NAMES.c_compile, 13 | ACTION_NAMES.clif_match, 14 | ACTION_NAMES.cpp_compile, 15 | ACTION_NAMES.cpp_header_parsing, 16 | ACTION_NAMES.cpp_module_codegen, 17 | ACTION_NAMES.cpp_module_compile, 18 | ACTION_NAMES.linkstamp_compile, 19 | ACTION_NAMES.lto_backend, 20 | ACTION_NAMES.preprocess_assemble, 21 | ] 22 | 23 | all_link_actions = [ 24 | ACTION_NAMES.cpp_link_executable, 25 | ACTION_NAMES.cpp_link_dynamic_library, 26 | ACTION_NAMES.cpp_link_nodeps_dynamic_library, 27 | ] 28 | 29 | target_system_name = { 30 | "k8": "x86_64-linux-gnu", 31 | "armv7l": "armv7l-linux-musleabihf", 32 | "armv5l": "armv5l-linux-musleabi", 33 | "arm": "arm-linux-musleabi", 34 | "aarch64": "aarch64-linux-musl", 35 | } 36 | 37 | def _toolchain_config_impl(ctx): 38 | support_tools = ["ar", "as", "compat-ld", "cpp", "dwp", "gcc", "g++", "gcov", "ld", "nm", "objcopy", "objdump", "strip"] 39 | tool_paths = [] 40 | for k in ctx.attr.tool_paths.files.to_list(): 41 | name = k.basename.split("-")[-1] # Attempts to get toolname 42 | if name in support_tools: 43 | tool_paths.append(tool_path(name = name, path = "/".join(k.path.split("/")[2:]))) 44 | else: 45 | fail("Not a tool: {} \nParsed from: {}".format(name, k.basename)) 46 | 47 | unfiltered_compile_flags_feature = feature( 48 | name = "unfiltered_compile_flags", 49 | enabled = True, 50 | flag_sets = [ 51 | flag_set( 52 | actions = all_compile_actions, 53 | flag_groups = [ 54 | flag_group( 55 | flags = [ 56 | # These make sure that paths included in .d dependency files are relative to the execroot 57 | # (e.g. start with "external/"). 58 | "-no-canonical-prefixes", 59 | "-fno-canonical-system-headers", 60 | ], 61 | ), 62 | ], 63 | ), 64 | ], 65 | ) 66 | 67 | dbg_feature = feature(name = "dbg") 68 | opt_feature = feature(name = "opt") 69 | 70 | default_link_flags_feature = feature( 71 | name = "default_link_flags", 72 | enabled = True, 73 | flag_sets = [ 74 | flag_set( 75 | actions = all_link_actions, 76 | flag_groups = [ 77 | flag_group( 78 | flags = [ 79 | "-Wl,-no-as-needed", 80 | "-Wl,-z,relro,-z,now", 81 | "-lstdc++", 82 | "-lm", 83 | "-pass-exit-codes", 84 | ], 85 | ), 86 | ], 87 | ), 88 | ], 89 | ) 90 | 91 | return cc_common.create_cc_toolchain_config_info( 92 | ctx = ctx, 93 | toolchain_identifier = ctx.attr.cpu + "-toolchain", 94 | host_system_name = "x86_64-unknown-linux-gnu", 95 | # target_system_name = "x86_64-buildroot-linux-musl", 96 | target_system_name = target_system_name[ctx.attr.cpu], 97 | cxx_builtin_include_directories = ctx.attr.cxx_builtin_include_directories, 98 | target_cpu = ctx.attr.cpu, 99 | target_libc = "musl", 100 | compiler = "gcc", 101 | abi_version = "unknown", 102 | abi_libc_version = "unknown", 103 | tool_paths = tool_paths, 104 | features = [ 105 | default_link_flags_feature, 106 | unfiltered_compile_flags_feature, 107 | ], 108 | ) 109 | 110 | cc_toolchain_config = rule( 111 | implementation = _toolchain_config_impl, 112 | attrs = { 113 | "tool_paths": attr.label(mandatory = True, allow_files = True), 114 | "cxx_builtin_include_directories": attr.string_list(), 115 | "cpu": attr.string(mandatory = True, values = ["armv7l", "aarch64", "arm", "k8"]), 116 | }, 117 | provides = [CcToolchainConfigInfo], 118 | ) 119 | -------------------------------------------------------------------------------- /toolchains/x86_64-linux-musl.BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | filegroup( 4 | name = "all", 5 | srcs = glob( 6 | [ 7 | "bin/**", 8 | "include/**", 9 | "lib/**", 10 | "libexec/**", 11 | "share/**", 12 | "x86_64-linux-musl/**", 13 | "usr/include/**", 14 | ], 15 | ), 16 | ) 17 | 18 | filegroup( 19 | name = "ar", 20 | srcs = glob(["bin/ar"]), 21 | ) 22 | 23 | filegroup( 24 | name = "as", 25 | srcs = glob(["bin/as"]), 26 | ) 27 | 28 | filegroup( 29 | name = "cpp", 30 | srcs = glob(["bin/cpp"]), 31 | ) 32 | 33 | filegroup( 34 | name = "dwp", 35 | srcs = glob(["bin/dwp"]), 36 | ) 37 | 38 | filegroup( 39 | name = "gcc", 40 | srcs = glob(["bin/x86_64-linux-musl-gcc"]), 41 | ) 42 | 43 | filegroup( 44 | name = "g++", 45 | srcs = glob(["bin/x86_64-linux-musl-g++"]), 46 | ) 47 | 48 | filegroup( 49 | name = "gcov", 50 | srcs = glob(["bin/gcov"]), 51 | ) 52 | 53 | filegroup( 54 | name = "ld", 55 | srcs = glob(["bin/ld"]), 56 | ) 57 | 58 | filegroup( 59 | name = "nm", 60 | srcs = glob(["bin/nm"]), 61 | ) 62 | 63 | filegroup( 64 | name = "objcopy", 65 | srcs = glob(["bin/objcopy"]), 66 | ) 67 | 68 | filegroup( 69 | name = "objdump", 70 | srcs = glob(["bin/objdump"]), 71 | ) 72 | 73 | filegroup( 74 | name = "strip", 75 | srcs = glob(["bin/strip"]), 76 | ) 77 | 78 | filegroup( 79 | name = "compiler_components", 80 | srcs = [ 81 | "ar", 82 | "as", 83 | "cpp", 84 | "dwp", 85 | "g++", 86 | "gcc", 87 | "gcov", 88 | "ld", 89 | "nm", 90 | "objcopy", 91 | "objdump", 92 | "strip", 93 | ], 94 | ) 95 | 96 | load("@snova_asio//toolchains:linux-musl.bzl", "cc_toolchain_config") 97 | 98 | # cc_toolchain_suite( 99 | # name = "buildroot", 100 | # toolchains = { 101 | # "x86_64": ":x86_64-toolchain", 102 | # }, 103 | # ) 104 | 105 | cc_toolchain_config( 106 | name = "x86_64-toolchain-config", 107 | # target_libc = "musl", 108 | cpu = "k8", 109 | cxx_builtin_include_directories = [ 110 | "include", 111 | ], 112 | tool_paths = ":compiler_components", 113 | ) 114 | 115 | cc_toolchain( 116 | name = "cc_toolchain", 117 | all_files = ":all", 118 | ar_files = ":all", 119 | compiler_files = ":all", 120 | dwp_files = ":all", 121 | linker_files = ":all", 122 | objcopy_files = ":all", 123 | strip_files = ":all", 124 | supports_param_files = False, 125 | toolchain_config = ":x86_64-toolchain-config", 126 | toolchain_identifier = "k8-toolchain", 127 | ) 128 | -------------------------------------------------------------------------------- /toolchains/x86_64-linux-musl.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") 2 | load( 3 | "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", 4 | "feature", 5 | "flag_group", 6 | "flag_set", 7 | "tool_path", 8 | ) 9 | 10 | all_compile_actions = [ 11 | ACTION_NAMES.assemble, 12 | ACTION_NAMES.c_compile, 13 | ACTION_NAMES.clif_match, 14 | ACTION_NAMES.cpp_compile, 15 | ACTION_NAMES.cpp_header_parsing, 16 | ACTION_NAMES.cpp_module_codegen, 17 | ACTION_NAMES.cpp_module_compile, 18 | ACTION_NAMES.linkstamp_compile, 19 | ACTION_NAMES.lto_backend, 20 | ACTION_NAMES.preprocess_assemble, 21 | ] 22 | 23 | all_link_actions = [ 24 | ACTION_NAMES.cpp_link_executable, 25 | ACTION_NAMES.cpp_link_dynamic_library, 26 | ACTION_NAMES.cpp_link_nodeps_dynamic_library, 27 | ] 28 | 29 | def _toolchain_config_impl(ctx): 30 | support_tools = ["ar", "as", "compat-ld", "cpp", "dwp", "gcc", "g++", "gcov", "ld", "nm", "objcopy", "objdump", "strip"] 31 | tool_paths = [] 32 | for k in ctx.attr.tool_paths.files.to_list(): 33 | name = k.basename.split("-")[-1] # Attempts to get toolname 34 | if name in support_tools: 35 | tool_paths.append(tool_path(name = name, path = "/".join(k.path.split("/")[2:]))) 36 | else: 37 | fail("Not a tool: {} \nParsed from: {}".format(name, k.basename)) 38 | 39 | unfiltered_compile_flags_feature = feature( 40 | name = "unfiltered_compile_flags", 41 | enabled = True, 42 | flag_sets = [ 43 | flag_set( 44 | actions = all_compile_actions, 45 | flag_groups = [ 46 | flag_group( 47 | flags = [ 48 | # These make sure that paths included in .d dependency files are relative to the execroot 49 | # (e.g. start with "external/"). 50 | "-no-canonical-prefixes", 51 | "-fno-canonical-system-headers", 52 | ], 53 | ), 54 | ], 55 | ), 56 | ], 57 | ) 58 | 59 | dbg_feature = feature(name = "dbg") 60 | opt_feature = feature(name = "opt") 61 | 62 | default_link_flags_feature = feature( 63 | name = "default_link_flags", 64 | enabled = True, 65 | flag_sets = [ 66 | flag_set( 67 | actions = all_link_actions, 68 | flag_groups = [ 69 | flag_group( 70 | flags = [ 71 | "-Wl,-no-as-needed", 72 | "-Wl,-z,relro,-z,now", 73 | "-lstdc++", 74 | "-lm", 75 | "-pass-exit-codes", 76 | ], 77 | ), 78 | ], 79 | ), 80 | ], 81 | ) 82 | 83 | return cc_common.create_cc_toolchain_config_info( 84 | ctx = ctx, 85 | toolchain_identifier = "x86_64-toolchain", 86 | host_system_name = "x86_64-unknown-linux-gnu", 87 | target_system_name = "x86_64-buildroot-linux-musl", 88 | target_cpu = "x86_64", 89 | target_libc = "musl", 90 | compiler = "gcc", 91 | abi_version = "unknown", 92 | abi_libc_version = "unknown", 93 | tool_paths = tool_paths, 94 | features = [ 95 | default_link_flags_feature, 96 | unfiltered_compile_flags_feature, 97 | ], 98 | ) 99 | 100 | cc_toolchain_config = rule( 101 | implementation = _toolchain_config_impl, 102 | attrs = { 103 | "tool_paths": attr.label(mandatory = True, allow_files = True), 104 | "cxx_builtin_include_directories": attr.string_list(), 105 | }, 106 | provides = [CcToolchainConfigInfo], 107 | ) 108 | --------------------------------------------------------------------------------