1
0
Fork 0
mirror of https://gitee.com/fantix/kloop.git synced 2024-05-19 16:58:13 +00:00

WIP resolver

This commit is contained in:
Fantix King 2022-05-08 09:55:41 -04:00
parent 3b4b6c5c67
commit dd4a38a610
No known key found for this signature in database
GPG key ID: 95304B04071CCDB4
22 changed files with 1900 additions and 45 deletions

View file

@ -1,5 +1,8 @@
include Makefile include Makefile
include architecture.png include architecture.png
recursive-include src *.pyx *.pxd *.h recursive-include src *.pyx *.pxd *.h
include resolver/Cargo.toml
include resolver/Cargo.lock
recursive-include resolver *.rs
graft tests graft tests
global-exclude *.py[cod] *.c global-exclude *.py[cod] *.c

701
resolver/Cargo.lock generated Normal file
View file

@ -0,0 +1,701 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "async-trait"
version = "0.1.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bytes"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "data-encoding"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
[[package]]
name = "enum-as-inner"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "form_urlencoded"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
dependencies = [
"matches",
"percent-encoding",
]
[[package]]
name = "futures-channel"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
dependencies = [
"futures-core",
]
[[package]]
name = "futures-core"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
[[package]]
name = "futures-executor"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"
[[package]]
name = "futures-macro"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-task"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a"
[[package]]
name = "futures-util"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
dependencies = [
"futures-core",
"futures-macro",
"futures-task",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
name = "getrandom"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
dependencies = [
"cfg-if",
"libc",
"wasi 0.10.2+wasi-snapshot-preview1",
]
[[package]]
name = "heck"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "hostname"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
dependencies = [
"libc",
"match_cfg",
"winapi",
]
[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "ipconfig"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "723519edce41262b05d4143ceb95050e4c614f483e78e9fd9e39a8275a84ad98"
dependencies = [
"socket2",
"widestring",
"winapi",
"winreg",
]
[[package]]
name = "ipnet"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.124"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50"
[[package]]
name = "linked-hash-map"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "lock_api"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
dependencies = [
"cfg-if",
]
[[package]]
name = "lru-cache"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
dependencies = [
"linked-hash-map",
]
[[package]]
name = "match_cfg"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
[[package]]
name = "matches"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "mio"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9"
dependencies = [
"libc",
"log",
"miow",
"ntapi",
"wasi 0.11.0+wasi-snapshot-preview1",
"winapi",
]
[[package]]
name = "miow"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
dependencies = [
"winapi",
]
[[package]]
name = "ntapi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
dependencies = [
"winapi",
]
[[package]]
name = "num_cpus"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "once_cell"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "parking_lot"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "995f667a6c822200b0433ac218e05582f0e2efa1b922a3fd2fbaadc5f87bab37"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-sys",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pin-project-lite"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "ppv-lite86"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
[[package]]
name = "proc-macro2"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom",
]
[[package]]
name = "redox_syscall"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
dependencies = [
"bitflags",
]
[[package]]
name = "resolv-conf"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00"
dependencies = [
"hostname",
"quick-error",
]
[[package]]
name = "resolver"
version = "0.1.0"
dependencies = [
"async-trait",
"futures-executor",
"futures-io",
"futures-util",
"libc",
"log",
"resolv-conf",
"trust-dns-proto",
"trust-dns-resolver",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "slab"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32"
[[package]]
name = "smallvec"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
[[package]]
name = "socket2"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "syn"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "thiserror"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tinyvec"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f48b6d60512a392e34dbf7fd456249fd2de3c83669ab642e021903f4015185b"
dependencies = [
"bytes",
"libc",
"memchr",
"mio",
"num_cpus",
"once_cell",
"pin-project-lite",
"socket2",
"winapi",
]
[[package]]
name = "trust-dns-proto"
version = "0.21.2"
source = "git+https://github.com/fantix/trust-dns?branch=0_21_2_patch#843c22f1d267660d816480d7168c17ee5467cda8"
dependencies = [
"async-trait",
"cfg-if",
"data-encoding",
"enum-as-inner",
"futures-channel",
"futures-io",
"futures-util",
"idna",
"ipnet",
"lazy_static",
"log",
"rand",
"smallvec",
"thiserror",
"tinyvec",
"tokio",
"url",
]
[[package]]
name = "trust-dns-resolver"
version = "0.21.2"
source = "git+https://github.com/fantix/trust-dns?branch=0_21_2_patch#843c22f1d267660d816480d7168c17ee5467cda8"
dependencies = [
"cfg-if",
"futures-util",
"ipconfig",
"lazy_static",
"log",
"lru-cache",
"parking_lot",
"resolv-conf",
"smallvec",
"thiserror",
"tokio",
"trust-dns-proto",
]
[[package]]
name = "unicode-bidi"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
[[package]]
name = "unicode-normalization"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "url"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
dependencies = [
"form_urlencoded",
"idna",
"matches",
"percent-encoding",
]
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "widestring"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825"
dependencies = [
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_msvc"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d"
[[package]]
name = "windows_i686_gnu"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed"
[[package]]
name = "windows_i686_msvc"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956"
[[package]]
name = "windows_x86_64_gnu"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4"
[[package]]
name = "windows_x86_64_msvc"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9"
[[package]]
name = "winreg"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69"
dependencies = [
"winapi",
]

19
resolver/Cargo.toml Normal file
View file

@ -0,0 +1,19 @@
[package]
name = "resolver"
version = "0.1.0"
edition = "2021"
[lib]
name = "kloop_resolver"
crate-type = ["staticlib"]
[dependencies]
libc = "0.2.124"
log = "0.4.16"
resolv-conf = { version = "0.7.0", features = ["system"] }
trust-dns-proto = { git = "https://github.com/fantix/trust-dns", branch = "0_21_2_patch", default-features = true }
trust-dns-resolver = { git = "https://github.com/fantix/trust-dns", branch = "0_21_2_patch", default-features = true }
futures-util = "0.3.21"
futures-io = "0.3.5"
futures-executor = "0.3.5"
async-trait = "0.1.43"

53
resolver/src/kloop.rs Normal file
View file

@ -0,0 +1,53 @@
/*
Copyright (c) 2022 Fantix King http://fantix.pro
kLoop is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
use core::marker;
use std::task::Waker;
use libc;
use crate::resolve::KLoopResolver;
#[repr(C)]
pub struct CResolver {
_data: [u8; 0],
_marker: marker::PhantomData<(*mut u8, marker::PhantomPinned)>,
}
#[repr(C)]
pub struct CResolve {
_data: [u8; 0],
_marker: marker::PhantomData<(*mut u8, marker::PhantomPinned)>,
}
#[repr(C)]
pub struct UDPSend {
_data: [u8; 0],
_marker: marker::PhantomData<(*mut u8, marker::PhantomPinned)>,
}
extern "C" {
pub fn resolver_set(c_resolver: *const CResolver, resolver: *mut KLoopResolver);
// pub fn resolve_set_poller(resolve: *const CResolve, poller: *mut Poller);
pub fn resolve_prep_addr(resolve: *const CResolve) -> *mut libc::sockaddr;
pub fn resolve_done_cb(resolve: *const CResolve) -> libc::c_int;
pub fn udp_bind(addr: *const libc::sockaddr, addrlen: libc::socklen_t) -> libc::c_int;
pub fn udp_send_init(fd: libc::c_int, resolver: *const CResolver) -> libc::c_ulong;
pub fn udp_send_poll(
send: libc::c_ulong,
data: *const u8,
datalen: libc::size_t,
addr: *const libc::sockaddr,
addrlen: libc::socklen_t,
waker: *mut Waker,
) -> libc::c_int;
}

18
resolver/src/lib.rs Normal file
View file

@ -0,0 +1,18 @@
/*
Copyright (c) 2022 Fantix King http://fantix.pro
kLoop is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
mod kloop;
mod resolve;
mod runtime;
pub use resolve::{resolver_init, resolver_lookup_ip};

57
resolver/src/poller.rs Normal file
View file

@ -0,0 +1,57 @@
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use futures_util::task::noop_waker_ref;
use libc;
pub type BoxFuture<'a, T> = Box<dyn Future<Output = T> + 'a>;
pub struct Poller<'a> {
ctx: Context<'a>,
fut: BoxFuture<'a, libc::c_int>,
}
impl<'a> Poller<'a> {
pub fn new(fut: impl Future<Output = libc::c_int> + 'a) -> Self {
let waker = noop_waker_ref();
Poller {
ctx: Context::from_waker(waker),
fut: Box::new(fut),
}
}
pub fn step(&mut self) -> Option<libc::c_int> {
let fut = unsafe { Pin::new_unchecked(self.fut.as_mut()) };
match fut.poll(&mut self.ctx) {
Poll::Ready(rv) => Some(rv),
Poll::Pending => None,
}
}
}
pub struct OnceFuture {
seen: bool,
}
impl OnceFuture {
pub fn new() -> Self {
Self { seen: false }
}
}
impl Future for OnceFuture {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.seen {
println!("poll ready");
Poll::Ready(())
} else {
println!("poll pending");
self.get_mut().seen = true;
Poll::Pending
}
}
}

185
resolver/src/resolve.rs Normal file
View file

@ -0,0 +1,185 @@
/*
Copyright (c) 2022 Fantix King http://fantix.pro
kLoop is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
use futures_executor::{LocalPool, LocalSpawner};
use futures_util::task::{LocalSpawnExt, SpawnError};
use std;
use std::cell::RefCell;
use std::future::Future;
use std::io;
use std::net::IpAddr;
use std::rc::Rc;
use libc;
use trust_dns_resolver::name_server::{GenericConnection, GenericConnectionProvider};
use trust_dns_resolver::system_conf::parse_resolv_conf;
use trust_dns_resolver::{AsyncResolver, Hosts};
use crate::kloop::{resolve_done_cb, resolve_prep_addr, resolver_set, CResolve, CResolver};
use crate::runtime::{KLoopHandle, KLoopRuntime};
const DEFAULT_PORT: u16 = 53;
type KLoopConnection = GenericConnection;
type KLoopConnectionProvider = GenericConnectionProvider<KLoopRuntime>;
thread_local! {
pub static CURRENT_RESOLVER: Rc<RefCell<Option<*mut KLoopResolver>>> = Rc::new(RefCell::new(None));
}
#[derive(Debug)]
pub struct KLoopResolver {
resolver: AsyncResolver<KLoopConnection, KLoopConnectionProvider>,
pub c_resolver: *const CResolver,
pool: LocalPool,
spawner: LocalSpawner,
}
impl KLoopResolver {
fn new(
resolv_conf: &[u8],
hosts_conf: &[u8],
c_resolver: *const CResolver,
) -> io::Result<Self> {
let (config, mut options) = parse_resolv_conf(resolv_conf)?;
options.use_hosts_file = false;
let conn_provider = GenericConnectionProvider::new(KLoopHandle);
let mut resolver = AsyncResolver::new_with_conn(config, options, conn_provider).unwrap();
resolver.set_hosts(Some(Hosts::default().read_hosts_conf(hosts_conf)));
let pool = LocalPool::new();
let spawner = pool.spawner();
Ok(Self {
resolver,
c_resolver,
pool,
spawner,
})
}
pub fn spawn<Fut>(&self, future: Fut) -> Result<(), SpawnError>
where
Fut: Future<Output = ()> + 'static,
{
self.spawner.spawn_local(future)
}
fn run_until_stalled(&mut self) {
loop {
self.pool.run_until_stalled();
if !self.pool.try_run_one() {
break;
}
}
}
async fn lookup_ip(&self, resolve: *mut CResolve, host: &str, port: libc::in_port_t) -> () {
match self.resolver.lookup_ip(host).await {
Ok(result) => {
for ip in result.into_iter() {
match ip {
IpAddr::V4(ip) => unsafe {
let out = resolve_prep_addr(resolve) as *mut libc::sockaddr_in;
if out.is_null() {
println!("resolve_prep_addr returned NULL");
break;
}
(*out).sin_family = libc::AF_INET as libc::sa_family_t;
(*out).sin_addr = libc::in_addr {
s_addr: u32::from_ne_bytes(ip.octets()),
};
(*out).sin_port = port.to_be();
(*out).sin_zero = [0; 8];
},
IpAddr::V6(ip) => unsafe {
let out = resolve_prep_addr(resolve) as *mut libc::sockaddr_in6;
if out.is_null() {
println!("resolve_prep_addr returned NULL");
break;
}
(*out).sin6_family = libc::AF_INET6 as libc::sa_family_t;
(*out).sin6_addr = libc::in6_addr {
s6_addr: ip.octets(),
};
(*out).sin6_port = port.to_be();
},
}
}
}
Err(e) => {
println!("lookup_ip error: {:?}", e);
}
}
unsafe {
resolve_done_cb(resolve);
}
}
}
#[no_mangle]
pub extern "C" fn resolver_init(
c_resolver: *const CResolver,
resolv_conf_data: *const u8,
resolv_conf_data_size: libc::size_t,
hosts_conf_data: *const u8,
hosts_conf_data_size: libc::size_t,
) -> libc::c_int {
let resolv_conf =
unsafe { std::slice::from_raw_parts(resolv_conf_data, resolv_conf_data_size) };
let hosts_conf = unsafe { std::slice::from_raw_parts(hosts_conf_data, hosts_conf_data_size) };
let mut resolver = match KLoopResolver::new(resolv_conf, hosts_conf, c_resolver) {
Ok(resolver) => resolver,
Err(e) => return 0,
};
let rv = Box::into_raw(Box::new(resolver));
unsafe {
resolver_set(c_resolver, rv);
}
1
}
#[no_mangle]
pub extern "C" fn resolver_lookup_ip(
resolver: *mut KLoopResolver,
resolve: *mut CResolve,
host_raw: *const u8,
length: libc::size_t,
port: libc::in_port_t,
) -> libc::c_int {
let host = match std::str::from_utf8(unsafe { std::slice::from_raw_parts(host_raw, length) }) {
Ok(host) => host,
_ => return 0,
};
let r = || unsafe { resolver.as_mut() }.unwrap();
let fut = r().lookup_ip(resolve, host, port);
if let Err(e) = r().spawn(fut) {
println!("spawn error: {:?}", e);
return 0;
}
CURRENT_RESOLVER.with(|current| {
*current.borrow_mut() = Some(resolver);
r().run_until_stalled();
*current.borrow_mut() = None;
});
1
}
#[no_mangle]
pub extern "C" fn resolver_run_until_stalled(resolver: *mut KLoopResolver) {
CURRENT_RESOLVER.with(|current| {
*current.borrow_mut() = Some(resolver);
unsafe { resolver.as_mut() }.unwrap().run_until_stalled();
*current.borrow_mut() = None;
});
}

209
resolver/src/runtime.rs Normal file
View file

@ -0,0 +1,209 @@
/*
Copyright (c) 2022 Fantix King http://fantix.pro
kLoop is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
use crate::kloop;
use crate::resolve::CURRENT_RESOLVER;
use async_trait::async_trait;
use futures_io::{AsyncRead, AsyncWrite};
use libc::{sockaddr, socklen_t};
use std::fmt::Debug;
use std::future::Future;
use std::net::SocketAddr;
use std::pin::Pin;
use std::task::{Context, Poll, Waker};
use std::time::Duration;
use std::{io, mem};
use trust_dns_proto::error::ProtoError;
use trust_dns_proto::tcp::{Connect, DnsTcpStream};
use trust_dns_proto::udp::UdpSocket;
use trust_dns_proto::Time;
use trust_dns_resolver::name_server::{RuntimeProvider, Spawn};
#[derive(Clone, Copy, Debug)]
pub struct KLoopTimer {}
#[async_trait]
impl Time for KLoopTimer {
async fn delay_for(duration: Duration) {
println!("TODO: delay_for: {:?}", duration);
}
async fn timeout<F: 'static + Future + Send>(
duration: Duration,
future: F,
) -> io::Result<F::Output> {
println!("TODO: timeout: {:?}", duration);
Ok(future.await)
}
}
pub struct KLoopTcp {}
#[async_trait]
impl Connect for KLoopTcp {
async fn connect_with_bind(
addr: SocketAddr,
bind_addr: Option<SocketAddr>,
) -> io::Result<Self> {
println!("TODO: connect_with_bind: {:?} {:?}", addr, bind_addr);
todo!()
}
}
impl AsyncRead for KLoopTcp {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
println!("TODO: poll_read");
todo!()
}
}
impl AsyncWrite for KLoopTcp {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
println!("TODO: poll_write");
todo!()
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
println!("TODO: poll_flush");
todo!()
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
println!("TODO: poll_close");
todo!()
}
}
impl DnsTcpStream for KLoopTcp {
type Time = KLoopTimer;
}
pub struct KLoopUdp {
fd: libc::c_int,
send: libc::c_ulong,
}
#[async_trait]
impl UdpSocket for KLoopUdp {
type Time = KLoopTimer;
async fn bind(addr: SocketAddr) -> io::Result<Self> {
let (addr_ptr, addr_len) = socket_addr_as_ptr(addr);
let fd = unsafe { kloop::udp_bind(addr_ptr, addr_len) };
CURRENT_RESOLVER.with(|resolver| {
let resolver = resolver.borrow().unwrap();
let resolver = unsafe { resolver.as_ref() }.unwrap();
let resolver = resolver.c_resolver;
let send = unsafe { kloop::udp_send_init(fd, resolver) };
Ok(KLoopUdp { fd, send })
})
}
fn poll_recv_from(
&self,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<(usize, SocketAddr)>> {
println!("TODO: poll_recv_from");
todo!()
}
fn poll_send_to(
&self,
cx: &mut Context<'_>,
buf: &[u8],
target: SocketAddr,
) -> Poll<io::Result<usize>> {
let waker = Box::new(cx.waker().clone());
let (addr, addrlen) = socket_addr_as_ptr(target);
match unsafe {
kloop::udp_send_poll(
self.send,
buf.as_ptr(),
buf.len(),
addr,
addrlen,
Box::into_raw(waker),
)
} {
res if res > 0 => {
Poll::Ready(Ok(res as usize))
}
res => {
Poll::Pending
}
}
}
}
fn socket_addr_as_ptr(addr: SocketAddr) -> (*const sockaddr, socklen_t) {
match addr {
SocketAddr::V4(ref a) => (
a as *const _ as *const _,
mem::size_of_val(a) as libc::socklen_t,
),
SocketAddr::V6(ref a) => (
a as *const _ as *const _,
mem::size_of_val(a) as libc::socklen_t,
),
}
}
#[derive(Clone, Copy)]
pub struct KLoopHandle;
impl Spawn for KLoopHandle {
fn spawn_bg<F>(&mut self, future: F)
where
F: Future<Output = Result<(), ProtoError>> + Send + 'static,
{
CURRENT_RESOLVER.with(|resolver| {
let r = resolver.borrow().unwrap();
let r = unsafe { r.as_mut() }.unwrap();
r.spawn(async {
future.await.unwrap_or_else(|e| {
println!("spawn_bg error: {:?}", e);
});
});
});
}
}
#[derive(Clone, Copy)]
pub struct KLoopRuntime;
impl RuntimeProvider for KLoopRuntime {
type Handle = KLoopHandle;
type Timer = KLoopTimer;
type Udp = KLoopUdp;
type Tcp = KLoopTcp;
}
#[no_mangle]
pub extern "C" fn waker_wake(waker: *mut Waker) {
let waker = unsafe { Box::from_raw(waker) };
waker.wake();
}
#[no_mangle]
pub extern "C" fn waker_forget(waker: *mut Waker) {
unsafe { Box::from_raw(waker) };
}

View file

@ -9,17 +9,42 @@
# See the Mulan PSL v2 for more details. # See the Mulan PSL v2 for more details.
import subprocess
import sysconfig import sysconfig
from setuptools import setup from setuptools import setup
from Cython.Build import cythonize from Cython.Build import cythonize
from Cython.Distutils import Extension from Cython.Distutils import Extension
from Cython.Distutils import build_ext
DEBUG = True
RESOLVER_LIB = (
f"resolver/target/{'debug' if DEBUG else 'release'}/libkloop_resolver.a"
)
class build_ext_with_resolver(build_ext):
def run(self):
subprocess.check_call(
["cargo", "build"] + [] if DEBUG else ["-r"],
cwd="resolver",
)
super().run()
setup( setup(
cmdclass={
"build_ext": build_ext_with_resolver,
},
ext_modules=cythonize( ext_modules=cythonize(
[ [
Extension("kloop.loop", ["src/kloop/loop.pyx"]), Extension(
"kloop.loop",
["src/kloop/loop.pyx"],
extra_link_args=[RESOLVER_LIB],
depends=[RESOLVER_LIB],
),
Extension( Extension(
"kloop.ktls", "kloop.ktls",
["src/kloop/ktls.pyx"], ["src/kloop/ktls.pyx"],
@ -53,5 +78,5 @@ setup(
), ),
], ],
language_level="3", language_level="3",
) ),
) )

19
src/kloop/fileio.pxd Normal file
View file

@ -0,0 +1,19 @@
# Copyright (c) 2022 Fantix King http://fantix.pro
# kLoop is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
cdef struct FileReader:
Loop* loop
const char* path
int fd, cancelled
char* data
size_t size, offset
RingCallback ring_cb
RingCallback done_cb

116
src/kloop/fileio.pyx Normal file
View file

@ -0,0 +1,116 @@
# Copyright (c) 2022 Fantix King http://fantix.pro
# kLoop is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
cdef size_t FILE_READ_BUF_SIZE = 4096
cdef int file_reader_openat_cb(RingCallback* cb) nogil except 0:
cdef:
int fd = cb.res
FileReader* fr = <FileReader*>cb.data
if fd < 0:
fr.done_cb.res = fd
return fr.done_cb.callback(&fr.done_cb)
if fr.cancelled:
fr.done_cb.res = -libc.ECANCELED
return fr.done_cb.callback(&fr.done_cb)
fr.fd = fd
fr.data = <char*>PyMem_RawMalloc(FILE_READ_BUF_SIZE)
if fr.data == NULL:
fr.done_cb.res = -errno.ENOMEM
return fr.done_cb.callback(&fr.done_cb)
fr.size = FILE_READ_BUF_SIZE
fr.offset = 0
fr.ring_cb.callback = file_reader_read_cb
if ring_sq_submit_read(
&fr.loop.ring.sq,
fd,
fr.data,
FILE_READ_BUF_SIZE,
0,
&fr.ring_cb,
):
return 1
else:
fr.done_cb.res = -errno.EAGAIN
return fr.done_cb.callback(&fr.done_cb)
cdef int file_reader_read_cb(RingCallback* cb) nogil except 0:
cdef:
int read = cb.res
FileReader* fr = <FileReader*>cb.data
size_t size = fr.size
size_t offset = fr.offset
if read < 0:
fr.done_cb.res = read
return fr.done_cb.callback(&fr.done_cb)
if fr.cancelled:
fr.done_cb.res = -libc.ECANCELED
return fr.done_cb.callback(&fr.done_cb)
offset += read
if read > 0 and offset == size:
size += FILE_READ_BUF_SIZE
if PyMem_RawRealloc(fr.data, size) == NULL:
fr.done_cb.res = -errno.ENOMEM
return fr.done_cb.callback(&fr.done_cb)
fr.size = size
fr.offset = offset
if ring_sq_submit_read(
&fr.loop.ring.sq,
fr.fd,
fr.data + offset,
FILE_READ_BUF_SIZE,
offset,
&fr.ring_cb,
):
return 1
else:
fr.done_cb.res = -errno.EAGAIN
return fr.done_cb.callback(&fr.done_cb)
else:
fr.done_cb.res = 1
fr.offset = offset
return fr.done_cb.callback(&fr.done_cb)
cdef int file_reader_start(
FileReader* fr, Loop* loop, const char* path
) nogil:
fr.loop = loop
fr.done_cb.res = 0
fr.fd = 0
fr.data = NULL
fr.cancelled = 0
fr.ring_cb.callback = file_reader_openat_cb
fr.ring_cb.data = <void*>fr
return ring_sq_submit_openat(
&loop.ring.sq,
0, # dfd
path, # path
0, # flags
0, # mode
&fr.ring_cb
)
cdef int file_reader_done(FileReader* fr) nogil:
cdef int fd = fr.fd
fr.done_cb.res = 0
if fr.data != NULL:
PyMem_RawFree(fr.data)
fr.data = NULL
if fd != 0:
fr.fd = 0
return ring_sq_submit_close(&fr.loop.ring.sq, fd, NULL)
return 1

View file

@ -21,18 +21,22 @@ cdef extern from "signal.h" nogil:
int _NSIG int _NSIG
cdef extern from "sys/socket.h" nogil: cdef extern from "sys/socket.h" nogil:
enum:
SOCK_DGRAM
SOCK_STREAM
ctypedef int socklen_t ctypedef int socklen_t
ctypedef int sa_family_t
ctypedef int in_port_t
int SOL_TLS int SOL_TLS
struct in_addr: struct sockaddr:
pass sa_family_t sa_family
struct sockaddr_in:
int sin_family
int sin_port
in_addr sin_addr
struct msghdr: struct msghdr:
void* msg_name # Optional address
socklen_t msg_namelen # Size of address
iovec* msg_iov # Scatter/gather array iovec* msg_iov # Scatter/gather array
size_t msg_iovlen # Number of elements in msg_iov size_t msg_iovlen # Number of elements in msg_iov
void* msg_control # ancillary data, see below void* msg_control # ancillary data, see below
@ -57,6 +61,7 @@ cdef extern from "sys/socket.h" nogil:
const void* option_value, const void* option_value,
socklen_t option_len, socklen_t option_len,
) )
int bind(int sockfd, const sockaddr* addr, socklen_t addrlen)
cdef extern from "arpa/inet.h" nogil: cdef extern from "arpa/inet.h" nogil:
@ -67,3 +72,8 @@ cdef extern from "sys/uio.h" nogil:
struct iovec: struct iovec:
void* iov_base void* iov_base
size_t iov_len size_t iov_len
cdef extern from "<errno.h>" nogil:
enum:
ECANCELED

View file

@ -80,6 +80,9 @@ cdef extern from "linux/io_uring.h" nogil:
IORING_OP_SENDMSG IORING_OP_SENDMSG
IORING_OP_RECV IORING_OP_RECV
IORING_OP_RECVMSG IORING_OP_RECVMSG
IORING_OP_OPENAT
IORING_OP_READ
IORING_OP_CLOSE
struct io_sqring_offsets: struct io_sqring_offsets:
__u32 head __u32 head
@ -120,6 +123,7 @@ cdef extern from "linux/io_uring.h" nogil:
__u32 len # buffer size or number of iovecs __u32 len # buffer size or number of iovecs
__u64 user_data # data to be passed back at completion time __u64 user_data # data to be passed back at completion time
__u8 flags # IOSQE_ flags __u8 flags # IOSQE_ flags
__u32 open_flags
struct io_uring_cqe: struct io_uring_cqe:
__u64 user_data # data to be passed back at completion time __u64 user_data # data to be passed back at completion time

View file

@ -14,6 +14,7 @@ from cpython cimport PyMem_RawMalloc, PyMem_RawFree, PyMem_RawRealloc
from cpython cimport PyObject, Py_INCREF, Py_DECREF from cpython cimport PyObject, Py_INCREF, Py_DECREF
from libc cimport errno, string from libc cimport errno, string
from posix cimport mman, unistd, time from posix cimport mman, unistd, time
from posix.types cimport mode_t
from .includes cimport libc, linux, barrier from .includes cimport libc, linux, barrier
@ -22,6 +23,9 @@ include "./queue.pxd"
include "./heapq.pxd" include "./heapq.pxd"
include "./uring.pxd" include "./uring.pxd"
include "./tcp.pxd" include "./tcp.pxd"
include "./udp.pxd"
include "./fileio.pxd"
include "./resolver.pxd"
cdef struct Loop: cdef struct Loop:
@ -31,6 +35,7 @@ cdef struct Loop:
Queue ready Queue ready
int timer_cancelled_count int timer_cancelled_count
PyObject* loop PyObject* loop
CResolver resolver
cdef class KLoopImpl: cdef class KLoopImpl:

View file

@ -16,7 +16,6 @@ import functools
import inspect import inspect
import os import os
import reprlib import reprlib
import socket
import threading import threading
import traceback import traceback
@ -39,11 +38,14 @@ cdef int MIN_SCHEDULED_TIMER_HANDLES = 100
# that are cancelled before cleanup # that are cancelled before cleanup
cdef int MAX_CANCELLED_TIMER_HANDLES_RATIO = 2 cdef int MAX_CANCELLED_TIMER_HANDLES_RATIO = 2
include "./handle.pyx" include "handle.pyx"
include "./queue.pyx" include "queue.pyx"
include "./heapq.pyx" include "heapq.pyx"
include "./uring.pyx" include "uring.pyx"
include "./tcp.pyx" include "tcp.pyx"
include "udp.pyx"
include "fileio.pyx"
include "resolver.pyx"
cdef long long monotonic_ns() nogil except -1: cdef long long monotonic_ns() nogil except -1:
@ -172,7 +174,7 @@ cdef inline int loop_run_once(
Callback* callback Callback* callback
long long timeout = -1, now long long timeout = -1, now
int nready int nready
RingCallback* cb RingCallback* cb = NULL
if scheduled.tail: if scheduled.tail:
if not filter_cancelled_calls(loop): if not filter_cancelled_calls(loop):
@ -248,6 +250,7 @@ cdef class KLoopImpl:
with nogil: with nogil:
loop_init(&self.loop, depth, &params) loop_init(&self.loop, depth, &params)
self.resolver = Resolver.new(self)
self.closed = False self.closed = False
self.thread_id = None self.thread_id = None
@ -510,11 +513,25 @@ cdef class KLoopImpl:
happy_eyeballs_delay=None, happy_eyeballs_delay=None,
interleave=None, interleave=None,
): ):
cdef TCPTransport transport = TCPTransport.new(protocol_factory, self) cdef:
r = socket.getaddrinfo(host, port)[0] TCPTransport transport
host, port = r[-1] Resolve resolve
waiter = transport.connect(host, port) object waiter
return transport, await waiter size_t i
resolve = await self.resolver.lookup_ip(host, port)
if not resolve.r.result_len:
raise RuntimeError(f"Cannot resolve host: {host!r}")
transport = TCPTransport.new(protocol_factory, self)
exceptions = []
for i in range(resolve.r.result_len):
try:
waiter = transport.connect(resolve.r.result + i)
return transport, await waiter
except OSError as e:
exceptions.append(e)
raise exceptions[0]
class KLoop(KLoopImpl, asyncio.AbstractEventLoop): class KLoop(KLoopImpl, asyncio.AbstractEventLoop):

75
src/kloop/resolver.pxd Normal file
View file

@ -0,0 +1,75 @@
# Copyright (c) 2022 Fantix King http://fantix.pro
# kLoop is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
cdef extern from * nogil:
int resolver_init(
CResolver* resolver,
char* resolv_conf_data,
size_t resolv_conf_data_size,
char* hosts_conf_data,
size_t hosts_conf_data_size,
)
int resolver_lookup_ip(
void* resolver,
void* resolve,
char* host,
size_t length,
libc.in_port_t port,
)
void resolver_run_until_stalled(void* rust_resolver)
void waker_wake(void* waker)
void waker_forget(void* waker)
cdef struct CResolver:
Loop* loop
Callback* cb
FileReader resolv_conf
FileReader hosts_conf
int res
void* rust_resolver
cdef class Resolver:
cdef:
CResolver resolver
KLoopImpl loop
Handle handle
object waiter
bint initialized
@staticmethod
cdef Resolver new(KLoopImpl loop)
cdef init_cb(self)
cdef err_cb(self, exc)
cdef struct CResolve:
CResolver* resolver
libc.sockaddr* result
size_t result_len, result_size
Callback* cb
int res
char* host
size_t host_len
libc.in_port_t port
cdef class Resolve:
cdef:
CResolve r
Handle handle
object waiter
object host
@staticmethod
cdef new(Resolver resolver, host, port)
cdef resolve_cb(self)

175
src/kloop/resolver.pyx Normal file
View file

@ -0,0 +1,175 @@
# Copyright (c) 2022 Fantix King http://fantix.pro
# kLoop is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
cdef const char* RESOLV_CONF = "/etc/resolv.conf"
cdef const char* HOSTS_CONF = "/etc/hosts"
cdef size_t SOCKADDR_CHUNK_SIZE = 4
cdef int resolve_cb(RingCallback* cb) nogil except 0:
cdef:
CResolver* r = <CResolver*>cb.data
int rv = 1
return rv
cdef int resolver_read_file_cb(RingCallback* cb) nogil except 0:
cdef:
CResolver* r = <CResolver*>cb.data
int rv = 1
void* ptr
if r.hosts_conf.done_cb.res == 0 or r.resolv_conf.done_cb.res == 0:
if cb.res < 0:
r.resolv_conf.cancelled = r.hosts_conf.cancelled = 1
else:
r.res = min(r.hosts_conf.done_cb.res, r.resolv_conf.done_cb.res)
if r.res > 0:
r.res = resolver_init(
r,
r.resolv_conf.data,
r.resolv_conf.offset,
r.hosts_conf.data,
r.hosts_conf.offset,
)
rv = queue_push(&r.loop.ready, r.cb)
if not file_reader_done(&r.resolv_conf):
# TODO: fd not closed?
pass
if not file_reader_done(&r.hosts_conf):
# TODO: fd not closed?
pass
return rv
cdef extern libc.sockaddr* resolve_prep_addr(CResolve* r) nogil:
cdef size_t l = r.result_len, size = r.result_size
if l == size:
size += SOCKADDR_CHUNK_SIZE
if PyMem_RawRealloc(r.result, sizeof(libc.sockaddr) * size) == NULL:
return NULL
r.result_size = size
r.result_len = l + 1
return r.result + l
cdef extern int resolve_done_cb(CResolve* r) nogil:
return queue_push(&r.resolver.loop.ready, r.cb)
cdef extern void resolver_set(CResolver* resolver, void* rust_resolver) nogil:
resolver.rust_resolver = rust_resolver
cdef class Resolver:
@staticmethod
cdef Resolver new(KLoopImpl loop):
cdef:
Resolver rv = Resolver.__new__(Resolver)
CResolver* r = &rv.resolver
rv.loop = loop
r.loop = &loop.loop
r.resolv_conf.done_cb.callback = resolver_read_file_cb
r.resolv_conf.done_cb.data = r
r.hosts_conf.done_cb.callback = resolver_read_file_cb
r.hosts_conf.done_cb.data = r
return rv
async def ensure_initialized(self):
cdef CResolver* r
if self.initialized:
return
waiter = self.waiter
if waiter is None:
r = &self.resolver
waiter = self.waiter = self.loop.create_future()
if not file_reader_start(&r.resolv_conf, r.loop, RESOLV_CONF):
self.err_cb(ValueError("Submission queue is full!"))
elif not file_reader_start(&r.hosts_conf, r.loop, HOSTS_CONF):
r.resolv_conf.cancelled = 1
self.err_cb(ValueError("Submission queue is full!"))
else:
self.handle = Handle(self.init_cb, (self,), self.loop, None)
r.cb = &self.handle.cb
await waiter
async def reload_config(self, *, force=False):
if self.initialized:
waiter = self.waiter
if waiter is None:
waiter = self.waiter = self.loop.create_future()
self.err_cb(NotImplementedError())
await waiter
else:
await self.ensure_initialized()
cdef init_cb(self):
cdef int res = self.resolver.res
if res < 0:
try:
errno.errno = -res
PyErr_SetFromErrno(IOError)
except IOError as e:
self.waiter.set_exception(e)
else:
self.waiter.set_result(None)
cdef err_cb(self, exc):
waiter, self.waiter = self.waiter, None
if waiter is not None:
waiter.set_exception(exc)
async def lookup_ip(self, host, port):
await self.ensure_initialized()
return await Resolve.new(self, host, port)
cdef class Resolve:
@staticmethod
cdef new(Resolver resolver, host, port):
cdef:
Resolve rv = Resolve.__new__(Resolve)
CResolve* r = &rv.r
rv.host = host.encode("utf-8")
rv.waiter = resolver.loop.create_future()
r.resolver = &resolver.resolver
r.host = <char*>rv.host
r.host_len = len(rv.host)
r.port = port
r.result = <libc.sockaddr*>PyMem_RawMalloc(
sizeof(libc.sockaddr) * SOCKADDR_CHUNK_SIZE
)
if r.result == NULL:
raise MemoryError
r.result_size = SOCKADDR_CHUNK_SIZE
rv.handle = Handle(rv.resolve_cb, (rv,), resolver.loop, None)
r.cb = &rv.handle.cb
return rv
def __await__(self):
cdef CResolve* r = &self.r
resolver_lookup_ip(r.resolver.rust_resolver, r, r.host, r.host_len, r.port)
return self.waiter.__await__()
def __dealloc__(self):
cdef CResolve* r = &self.r
r.host = NULL
r.host_len = 0
if r.result != NULL:
PyMem_RawFree(r.result)
r.result = NULL
r.result_size = 0
cdef resolve_cb(self):
self.waiter.set_result(self)

View file

@ -11,7 +11,7 @@
cdef struct TCPConnect: cdef struct TCPConnect:
int fd int fd
libc.sockaddr_in addr libc.sockaddr* addr
RingCallback ring_cb RingCallback ring_cb
Loop* loop Loop* loop
Callback* cb Callback* cb
@ -24,11 +24,10 @@ cdef class TCPTransport:
TCPConnect connector TCPConnect connector
object waiter object waiter
object protocol_factory object protocol_factory
object host_bytes
Handle handle Handle handle
@staticmethod @staticmethod
cdef TCPTransport new(object protocol_factory, KLoopImpl loop) cdef TCPTransport new(object protocol_factory, KLoopImpl loop)
cdef connect(self, host, port) cdef connect(self, libc.sockaddr* addr)
cdef connect_cb(self) cdef connect_cb(self)

View file

@ -13,7 +13,7 @@ cdef int tcp_connect(TCPConnect* connector) nogil:
return ring_sq_submit_connect( return ring_sq_submit_connect(
&connector.loop.ring.sq, &connector.loop.ring.sq,
connector.fd, connector.fd,
&connector.addr, connector.addr,
&connector.ring_cb, &connector.ring_cb,
) )
@ -29,29 +29,22 @@ cdef class TCPTransport:
cdef TCPTransport rv = TCPTransport.__new__(TCPTransport) cdef TCPTransport rv = TCPTransport.__new__(TCPTransport)
rv.protocol_factory = protocol_factory rv.protocol_factory = protocol_factory
rv.loop = loop rv.loop = loop
rv.connector.loop = &loop.loop
rv.connector.ring_cb.callback = tcp_connect_cb
rv.connector.ring_cb.data = &rv.connector
return rv return rv
cdef connect(self, host, port): cdef connect(self, libc.sockaddr* addr):
cdef: cdef:
int fd int fd
TCPConnect* c = &self.connector TCPConnect* c = &self.connector
fd = libc.socket(socket.AF_INET, socket.SOCK_STREAM, 0) fd = libc.socket(addr.sa_family, libc.SOCK_STREAM, 0)
if fd == -1: if fd == -1:
PyErr_SetFromErrno(IOError) PyErr_SetFromErrno(IOError)
return return
self.host_bytes = host.encode() c.addr = addr
if not libc.inet_pton(
socket.AF_INET, <char*>self.host_bytes, &c.addr.sin_addr
):
PyErr_SetFromErrno(IOError)
return
c.addr.sin_family = socket.AF_INET
c.addr.sin_port = libc.htons(port)
c.fd = self.fd = fd c.fd = self.fd = fd
c.loop = &self.loop.loop
c.ring_cb.callback = tcp_connect_cb
c.ring_cb.data = c
self.handle = Handle(self.connect_cb, (self,), self.loop, None) self.handle = Handle(self.connect_cb, (self,), self.loop, None)
c.cb = &self.handle.cb c.cb = &self.handle.cb
if not tcp_connect(c): if not tcp_connect(c):
@ -61,6 +54,11 @@ cdef class TCPTransport:
cdef connect_cb(self): cdef connect_cb(self):
if self.connector.ring_cb.res != 0: if self.connector.ring_cb.res != 0:
if not ring_sq_submit_close(
&self.loop.loop.ring.sq, self.fd, NULL
):
# TODO: fd not closed?
pass
try: try:
errno.errno = abs(self.connector.ring_cb.res) errno.errno = abs(self.connector.ring_cb.res)
PyErr_SetFromErrno(IOError) PyErr_SetFromErrno(IOError)

18
src/kloop/udp.pxd Normal file
View file

@ -0,0 +1,18 @@
# Copyright (c) 2022 Fantix King http://fantix.pro
# kLoop is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
cdef struct UDPSend:
int fd
libc.iovec vec
libc.msghdr msg
RingCallback callback
CResolver* resolver
void* rust_waker

69
src/kloop/udp.pyx Normal file
View file

@ -0,0 +1,69 @@
# Copyright (c) 2022 Fantix King http://fantix.pro
# kLoop is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
cdef extern int udp_bind(libc.sockaddr* addr, libc.socklen_t addrlen) nogil:
cdef int fd = libc.socket(addr.sa_family, libc.SOCK_DGRAM, 0)
if fd == -1:
return -1
if libc.bind(fd, addr, addrlen) == -1:
# TODO: close fd
return -1
return fd
cdef extern unsigned long udp_send_init(int fd, CResolver* resolver) nogil:
cdef UDPSend* rv
rv = <UDPSend*>PyMem_RawMalloc(sizeof(UDPSend))
if rv == NULL:
return 0
string.memset(rv, 0, sizeof(UDPSend))
rv.fd = fd
rv.resolver = resolver
rv.msg.msg_iov = &rv.vec
rv.msg.msg_iovlen = 1
rv.callback.data = <void*>rv
rv.callback.callback = udp_send_cb
return <unsigned long>rv
cdef int udp_send_cb(RingCallback* cb) nogil except 0:
cdef UDPSend* send = <UDPSend*>cb.data
waker_wake(send.rust_waker)
resolver_run_until_stalled(send.resolver.rust_resolver)
return 1
cdef extern int udp_send_poll(
unsigned long send_in,
char* data,
size_t datalen,
libc.sockaddr* addr,
libc.socklen_t addrlen,
void* waker,
) nogil:
cdef UDPSend* send = <UDPSend*>send_in
if send.vec.iov_base == NULL:
send.vec.iov_base = data
send.vec.iov_len = datalen
send.msg.msg_name = <void*>addr
send.msg.msg_namelen = addrlen
send.rust_waker = waker
return ring_sq_submit_sendmsg(
&send.resolver.loop.ring.sq,
send.fd,
&send.msg,
&send.callback,
) - 1
else:
waker_forget(waker)
if send.vec.iov_base != data or send.vec.iov_len != datalen:
return -1
return send.callback.res or -1

View file

@ -176,12 +176,13 @@ cdef inline void ring_cq_pop(CompletionQueue* cq, RingCallback** callback) nogil
head = cq.khead[0] head = cq.khead[0]
cqe = cq.cqes + (head & cq.kring_mask[0]) cqe = cq.cqes + (head & cq.kring_mask[0])
ret = <RingCallback*>cqe.user_data ret = <RingCallback*>cqe.user_data
ret.res = cqe.res if ret != NULL:
callback[0] = ret ret.res = cqe.res
callback[0] = ret
barrier.io_uring_smp_store_release(cq.khead, head + 1) barrier.io_uring_smp_store_release(cq.khead, head + 1)
cdef inline int ring_sq_submit( cdef inline linux.io_uring_sqe* ring_sq_submit(
SubmissionQueue* sq, SubmissionQueue* sq,
linux.__u8 op, linux.__u8 op,
int fd, int fd,
@ -209,15 +210,15 @@ cdef inline int ring_sq_submit(
if link: if link:
sqe.flags = linux.IOSQE_IO_LINK sqe.flags = linux.IOSQE_IO_LINK
sqe.user_data = <linux.__u64>callback sqe.user_data = <linux.__u64>callback
return 1 return sqe
else: else:
return 0 return NULL
cdef int ring_sq_submit_connect( cdef int ring_sq_submit_connect(
SubmissionQueue* sq, int fd, libc.sockaddr_in* addr, RingCallback* callback SubmissionQueue* sq, int fd, libc.sockaddr* addr, RingCallback* callback
) nogil: ) nogil:
return ring_sq_submit( return 1 if ring_sq_submit(
sq, sq,
linux.IORING_OP_CONNECT, linux.IORING_OP_CONNECT,
fd, fd,
@ -226,4 +227,83 @@ cdef int ring_sq_submit_connect(
sizeof(addr[0]), sizeof(addr[0]),
0, 0,
callback, callback,
) else 0
cdef int ring_sq_submit_openat(
SubmissionQueue* sq,
int dfd,
const char* path,
int flags,
mode_t mode,
RingCallback* callback,
) nogil:
cdef linux.io_uring_sqe* sqe = ring_sq_submit(
sq,
linux.IORING_OP_OPENAT,
dfd,
<unsigned long>path,
mode,
0,
0,
callback,
) )
if sqe == NULL:
return 0
else:
sqe.open_flags = flags
return 1
cdef int ring_sq_submit_read(
SubmissionQueue* sq,
int fd,
char* buf,
unsigned nbytes,
linux.__u64 offset,
RingCallback* callback,
) nogil:
return 1 if ring_sq_submit(
sq,
linux.IORING_OP_READ,
fd,
<unsigned long>buf,
nbytes,
offset,
0,
callback,
) else 0
cdef int ring_sq_submit_close(
SubmissionQueue* sq,
int fd,
RingCallback * callback,
) nogil:
return 1 if ring_sq_submit(
sq,
linux.IORING_OP_CLOSE,
fd,
0,
0,
0,
0,
callback,
) else 0
cdef int ring_sq_submit_sendmsg(
SubmissionQueue* sq,
int fd,
const libc.msghdr *msg,
RingCallback* callback,
) nogil:
return 1 if ring_sq_submit(
sq,
linux.IORING_OP_SENDMSG,
fd,
<unsigned long>msg,
1,
0,
0,
callback,
) else 0