mirror of
https://github.com/DragonOS-Community/dragonos-berkeley-socket.git
synced 2025-06-08 15:36:47 +00:00
first init
This commit is contained in:
commit
a34468c6c1
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
496
Cargo.lock
generated
Normal file
496
Cargo.lock
generated
Normal file
@ -0,0 +1,496 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "allocator-api2"
|
||||||
|
version = "0.2.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.98"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "berkeley-socket"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.9.0",
|
||||||
|
"hashbrown",
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
"linux-errnos",
|
||||||
|
"log",
|
||||||
|
"netsock",
|
||||||
|
"num-derive",
|
||||||
|
"num-traits",
|
||||||
|
"smoltcp",
|
||||||
|
"spin",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "defmt"
|
||||||
|
version = "0.3.100"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad"
|
||||||
|
dependencies = [
|
||||||
|
"defmt 1.0.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "defmt"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"defmt-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "defmt-macros"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e"
|
||||||
|
dependencies = [
|
||||||
|
"defmt-parser",
|
||||||
|
"proc-macro-error2",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "defmt-parser"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror 2.0.12",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foldhash"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hash32"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.15.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||||
|
dependencies = [
|
||||||
|
"allocator-api2",
|
||||||
|
"equivalent",
|
||||||
|
"foldhash",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heapless"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
|
||||||
|
dependencies = [
|
||||||
|
"hash32",
|
||||||
|
"stable_deref_trait",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.172"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-errnos"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "de9df90411fa4fbcb0177a4d342f93fd59aa81382dc74bd568a820903bf28ef7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "managed"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "netlink-packet-core"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72724faf704479d67b388da142b186f916188505e7e0b26719019c525882eda4"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"byteorder",
|
||||||
|
"netlink-packet-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "netlink-packet-sock-diag"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a495cb1de50560a7cd12fdcf023db70eec00e340df81be31cedbbfd4aadd6b76"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"byteorder",
|
||||||
|
"libc",
|
||||||
|
"netlink-packet-core",
|
||||||
|
"netlink-packet-utils",
|
||||||
|
"smallvec",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "netlink-packet-utils"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"byteorder",
|
||||||
|
"paste",
|
||||||
|
"thiserror 1.0.69",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "netlink-sys"
|
||||||
|
version = "0.8.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "16c903aa70590cb93691bf97a767c8d1d6122d2cc9070433deb3bbf36ce8bd23"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "netsock"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e0619d68669a4107fe8be0e76d4e7557304c83d7e6a23d50e3111b5dab888741"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.9.0",
|
||||||
|
"byteorder",
|
||||||
|
"netlink-packet-core",
|
||||||
|
"netlink-packet-sock-diag",
|
||||||
|
"netlink-packet-utils",
|
||||||
|
"netlink-sys",
|
||||||
|
"num-derive",
|
||||||
|
"num-traits",
|
||||||
|
"thiserror 2.0.12",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-derive"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr2"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error2"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr2",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.95"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smoltcp"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dad095989c1533c1c266d9b1e8d70a1329dd3723c3edac6d03bbd67e7bf6f4bb"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"byteorder",
|
||||||
|
"cfg-if",
|
||||||
|
"defmt 0.3.100",
|
||||||
|
"heapless",
|
||||||
|
"log",
|
||||||
|
"managed",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stable_deref_trait"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.100"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "1.0.69"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl 1.0.69",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl 2.0.12",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "1.0.69"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.59.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_gnullvm",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
28
Cargo.toml
Normal file
28
Cargo.toml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
[package]
|
||||||
|
name = "berkeley-socket"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
smoltcp = { version = "0.12.0", default-features = false, features = [
|
||||||
|
"std",
|
||||||
|
"alloc",
|
||||||
|
"log",
|
||||||
|
"medium-ethernet",
|
||||||
|
"medium-ip",
|
||||||
|
"proto-ipv4",
|
||||||
|
"socket-udp",
|
||||||
|
"socket-tcp",
|
||||||
|
]}
|
||||||
|
|
||||||
|
spin = "0.9.4"
|
||||||
|
|
||||||
|
linux-errnos = "*"
|
||||||
|
hashbrown = "0.15.2"
|
||||||
|
bitflags = "2.9.0"
|
||||||
|
num-derive = "0.4.2"
|
||||||
|
num-traits = "0.2.15"
|
||||||
|
log = "*"
|
||||||
|
netsock = "0.3.0"
|
||||||
|
libc = "0.2.172"
|
||||||
|
lazy_static = "1.5.0"
|
129
src/driver/irq.rs
Normal file
129
src/driver/irq.rs
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
use std::os::unix::io::RawFd;
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::{io, thread};
|
||||||
|
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
|
use crate::socket::inet::common::NET_DEVICES;
|
||||||
|
|
||||||
|
const EPOLL_TIMEOUT_MS: i32 = 100;
|
||||||
|
|
||||||
|
/// Start a thread that polls network devices when their tap interfaces are readable
|
||||||
|
pub fn start_network_polling_thread() -> io::Result<thread::JoinHandle<()>> {
|
||||||
|
// Create an epoll instance
|
||||||
|
let epoll_fd = unsafe { libc::epoll_create1(0) };
|
||||||
|
if epoll_fd < 0 {
|
||||||
|
return Err(io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
let handle = thread::spawn(move || {
|
||||||
|
let mut events = Vec::with_capacity(32);
|
||||||
|
events.resize(32, libc::epoll_event { events: 0, u64: 0 });
|
||||||
|
let mut fd_to_device_id = HashMap::new();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// Update the list of devices to watch
|
||||||
|
update_watched_devices(epoll_fd, &mut fd_to_device_id);
|
||||||
|
|
||||||
|
// Wait for events
|
||||||
|
let num_events = unsafe {
|
||||||
|
libc::epoll_wait(
|
||||||
|
epoll_fd,
|
||||||
|
events.as_mut_ptr(),
|
||||||
|
events.len() as i32,
|
||||||
|
EPOLL_TIMEOUT_MS,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if num_events < 0 {
|
||||||
|
let err = io::Error::last_os_error();
|
||||||
|
// Ignore EINTR, which happens when the thread receives a signal
|
||||||
|
if err.kind() != io::ErrorKind::Interrupted {
|
||||||
|
log::error!("epoll_wait failed: {:?}", err);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process events
|
||||||
|
for event in events.iter().take(num_events as usize) {
|
||||||
|
let fd = event.u64 as RawFd;
|
||||||
|
|
||||||
|
if let Some(&device_id) = fd_to_device_id.get(&fd) {
|
||||||
|
if let Some(device) = NET_DEVICES.read().get(&device_id) {
|
||||||
|
// Poll the device that has data available
|
||||||
|
device.poll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also poll all devices periodically regardless of events
|
||||||
|
// This ensures timers and other internal state are updated
|
||||||
|
for device in NET_DEVICES.read().values() {
|
||||||
|
device.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Small sleep to prevent CPU hogging
|
||||||
|
thread::sleep(Duration::from_millis(1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update the list of devices being watched by epoll
|
||||||
|
fn update_watched_devices(epoll_fd: RawFd, fd_to_device_id: &mut HashMap<RawFd, usize>) {
|
||||||
|
let devices = NET_DEVICES.read();
|
||||||
|
|
||||||
|
// Find new devices to add
|
||||||
|
for (&id, device) in devices.iter() {
|
||||||
|
// Try to downcast to get TAP device
|
||||||
|
if let Some(tap_fd) = device.raw_fd() {
|
||||||
|
if !fd_to_device_id.contains_key(&tap_fd) {
|
||||||
|
// Add new device to epoll
|
||||||
|
let mut event = libc::epoll_event {
|
||||||
|
events: (libc::EPOLLIN | libc::EPOLLET) as u32,
|
||||||
|
u64: tap_fd as u64,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result =
|
||||||
|
unsafe { libc::epoll_ctl(epoll_fd, libc::EPOLL_CTL_ADD, tap_fd, &mut event) };
|
||||||
|
|
||||||
|
if result == 0 {
|
||||||
|
fd_to_device_id.insert(tap_fd, id);
|
||||||
|
} else {
|
||||||
|
log::error!(
|
||||||
|
"Failed to add device fd {} to epoll: {:?}",
|
||||||
|
tap_fd,
|
||||||
|
io::Error::last_os_error()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find devices to remove
|
||||||
|
let mut to_remove = Vec::new();
|
||||||
|
for &fd in fd_to_device_id.keys() {
|
||||||
|
let id = fd_to_device_id[&fd];
|
||||||
|
if !devices.contains_key(&id) {
|
||||||
|
to_remove.push(fd);
|
||||||
|
|
||||||
|
// Remove from epoll
|
||||||
|
let result =
|
||||||
|
unsafe { libc::epoll_ctl(epoll_fd, libc::EPOLL_CTL_DEL, fd, std::ptr::null_mut()) };
|
||||||
|
|
||||||
|
if result != 0 {
|
||||||
|
log::error!(
|
||||||
|
"Failed to remove device fd {} from epoll: {:?}",
|
||||||
|
fd,
|
||||||
|
io::Error::last_os_error()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually remove the entries
|
||||||
|
for fd in to_remove {
|
||||||
|
fd_to_device_id.remove(&fd);
|
||||||
|
}
|
||||||
|
}
|
38
src/driver/mod.rs
Normal file
38
src/driver/mod.rs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
use std::io;
|
||||||
|
|
||||||
|
pub mod tap;
|
||||||
|
pub use tap::TapDesc;
|
||||||
|
pub mod irq;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct ifreq {
|
||||||
|
ifr_name: [libc::c_char; libc::IF_NAMESIZE],
|
||||||
|
ifr_data: libc::c_int, /* ifr_ifindex or ifr_mtu */
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ifreq_for(name: &str) -> ifreq {
|
||||||
|
let mut ifreq = ifreq {
|
||||||
|
ifr_name: [0; libc::IF_NAMESIZE],
|
||||||
|
ifr_data: 0,
|
||||||
|
};
|
||||||
|
for (i, byte) in name.as_bytes().iter().enumerate() {
|
||||||
|
ifreq.ifr_name[i] = *byte as libc::c_char
|
||||||
|
}
|
||||||
|
ifreq
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ifreq_ioctl(
|
||||||
|
lower: libc::c_int,
|
||||||
|
ifreq: &mut ifreq,
|
||||||
|
cmd: libc::c_ulong,
|
||||||
|
) -> io::Result<libc::c_int> {
|
||||||
|
unsafe {
|
||||||
|
let res = libc::ioctl(lower, cmd as _, ifreq as *mut ifreq);
|
||||||
|
if res == -1 {
|
||||||
|
return Err(io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ifreq.ifr_data)
|
||||||
|
}
|
270
src/driver/tap.rs
Normal file
270
src/driver/tap.rs
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
use super::*;
|
||||||
|
use smoltcp::{phy::Medium, wire::EthernetFrame};
|
||||||
|
use std::io;
|
||||||
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TapDesc {
|
||||||
|
lower: libc::c_int,
|
||||||
|
mtu: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRawFd for TapDesc {
|
||||||
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
|
self.lower
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TapDesc {
|
||||||
|
pub fn new(name: &str, medium: Medium) -> io::Result<TapDesc> {
|
||||||
|
let lower = unsafe {
|
||||||
|
let lower = libc::open(
|
||||||
|
c"/dev/net/tun".as_ptr() as *const libc::c_char,
|
||||||
|
libc::O_RDWR | libc::O_NONBLOCK,
|
||||||
|
);
|
||||||
|
if lower == -1 {
|
||||||
|
return Err(io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
lower
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut ifreq = ifreq_for(name);
|
||||||
|
Self::attach_interface_ifreq(lower, medium, &mut ifreq)?;
|
||||||
|
let mtu = Self::mtu_ifreq(medium, &mut ifreq)?;
|
||||||
|
|
||||||
|
Ok(TapDesc { lower, mtu })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_fd(fd: RawFd, mtu: usize) -> io::Result<TapDesc> {
|
||||||
|
Ok(TapDesc { lower: fd, mtu })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attach_interface_ifreq(
|
||||||
|
lower: libc::c_int,
|
||||||
|
medium: Medium,
|
||||||
|
ifr: &mut ifreq,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
let mode = match medium {
|
||||||
|
Medium::Ip => libc::IFF_TUN,
|
||||||
|
Medium::Ethernet => libc::IFF_TAP,
|
||||||
|
};
|
||||||
|
ifr.ifr_data = mode | libc::IFF_NO_PI;
|
||||||
|
ifreq_ioctl(lower, ifr, libc::TUNSETIFF).map(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mtu_ifreq(medium: Medium, ifr: &mut ifreq) -> io::Result<usize> {
|
||||||
|
let lower = unsafe {
|
||||||
|
let lower = libc::socket(libc::AF_INET, libc::SOCK_DGRAM, libc::IPPROTO_IP);
|
||||||
|
if lower == -1 {
|
||||||
|
return Err(io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
lower
|
||||||
|
};
|
||||||
|
|
||||||
|
let ip_mtu = ifreq_ioctl(lower, ifr, libc::SIOCGIFMTU).map(|mtu| mtu as usize);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
libc::close(lower);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Propagate error after close, to ensure we always close.
|
||||||
|
let ip_mtu = ip_mtu?;
|
||||||
|
|
||||||
|
// SIOCGIFMTU returns the IP MTU (typically 1500 bytes.)
|
||||||
|
// smoltcp counts the entire Ethernet packet in the MTU, so add the Ethernet header size to it.
|
||||||
|
let mtu = match medium {
|
||||||
|
Medium::Ip => ip_mtu,
|
||||||
|
Medium::Ethernet => ip_mtu + EthernetFrame::<&[u8]>::header_len(),
|
||||||
|
// Medium::Ieee802154 => todo!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(mtu)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interface_mtu(&self) -> io::Result<usize> {
|
||||||
|
Ok(self.mtu)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recv(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
|
||||||
|
unsafe {
|
||||||
|
let len = libc::read(
|
||||||
|
self.lower,
|
||||||
|
buffer.as_mut_ptr() as *mut libc::c_void,
|
||||||
|
buffer.len(),
|
||||||
|
);
|
||||||
|
if len == -1 {
|
||||||
|
return Err(io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
Ok(len as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send(&mut self, buffer: &[u8]) -> io::Result<usize> {
|
||||||
|
unsafe {
|
||||||
|
let len = libc::write(
|
||||||
|
self.lower,
|
||||||
|
buffer.as_ptr() as *const libc::c_void,
|
||||||
|
buffer.len(),
|
||||||
|
);
|
||||||
|
if len == -1 {
|
||||||
|
return Err(io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
Ok(len as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TapDesc {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
libc::close(self.lower);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
use smoltcp::phy::{self, Device, DeviceCapabilities};
|
||||||
|
use smoltcp::time::Instant;
|
||||||
|
|
||||||
|
/// A virtual TUN (IP) or TAP (Ethernet) interface.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TapDevice {
|
||||||
|
lower: Rc<RefCell<crate::driver::TapDesc>>,
|
||||||
|
mtu: usize,
|
||||||
|
medium: Medium,
|
||||||
|
mac: smoltcp::wire::EthernetAddress,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRawFd for TapDevice {
|
||||||
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
|
self.lower.borrow().as_raw_fd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TapDevice {
|
||||||
|
/// Attaches to a TUN/TAP interface called `name`, or creates it if it does not exist.
|
||||||
|
///
|
||||||
|
/// If `name` is a persistent interface configured with UID of the current user,
|
||||||
|
/// no special privileges are needed. Otherwise, this requires superuser privileges
|
||||||
|
/// or a corresponding capability set on the executable.
|
||||||
|
pub fn new(name: &str, medium: Medium) -> io::Result<TapDevice> {
|
||||||
|
let lower = crate::driver::TapDesc::new(name, medium)?;
|
||||||
|
let mtu = lower.interface_mtu()?;
|
||||||
|
let mac = smoltcp::wire::EthernetAddress::from_bytes(&[
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
std::random::random::<u8>(),
|
||||||
|
std::random::random::<u8>(),
|
||||||
|
std::random::random::<u8>(),
|
||||||
|
]);
|
||||||
|
Ok(TapDevice {
|
||||||
|
lower: Rc::new(RefCell::new(lower)),
|
||||||
|
mtu,
|
||||||
|
medium,
|
||||||
|
mac,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attaches to a TUN/TAP interface specified by file descriptor `fd`.
|
||||||
|
///
|
||||||
|
/// On platforms like Android, a file descriptor to a tun interface is exposed.
|
||||||
|
/// On these platforms, a TunTapInterface cannot be instantiated with a name.
|
||||||
|
pub fn from_fd(fd: RawFd, medium: Medium, mtu: usize) -> io::Result<TapDevice> {
|
||||||
|
let lower = crate::driver::TapDesc::from_fd(fd, mtu)?;
|
||||||
|
let mac = smoltcp::wire::EthernetAddress::from_bytes(&[
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
std::random::random::<u8>(),
|
||||||
|
std::random::random::<u8>(),
|
||||||
|
std::random::random::<u8>(),
|
||||||
|
]);
|
||||||
|
Ok(TapDevice {
|
||||||
|
lower: Rc::new(RefCell::new(lower)),
|
||||||
|
mtu,
|
||||||
|
medium,
|
||||||
|
mac,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mac(&self) -> smoltcp::wire::EthernetAddress {
|
||||||
|
self.mac
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for TapDevice {
|
||||||
|
type RxToken<'a> = RxToken;
|
||||||
|
type TxToken<'a> = TxToken;
|
||||||
|
|
||||||
|
fn capabilities(&self) -> DeviceCapabilities {
|
||||||
|
let mut caps = DeviceCapabilities::default();
|
||||||
|
caps.max_transmission_unit = self.mtu;
|
||||||
|
caps.medium = self.medium;
|
||||||
|
caps
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
||||||
|
let mut lower = self.lower.borrow_mut();
|
||||||
|
let mut buffer = vec![0; self.mtu];
|
||||||
|
match lower.recv(&mut buffer[..]) {
|
||||||
|
Ok(size) => {
|
||||||
|
buffer.resize(size, 0);
|
||||||
|
let rx = RxToken { buffer };
|
||||||
|
let tx = TxToken {
|
||||||
|
lower: self.lower.clone(),
|
||||||
|
};
|
||||||
|
Some((rx, tx))
|
||||||
|
}
|
||||||
|
Err(err) if err.kind() == io::ErrorKind::WouldBlock => None,
|
||||||
|
Err(err) => panic!("{}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
|
||||||
|
Some(TxToken {
|
||||||
|
lower: self.lower.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub struct RxToken {
|
||||||
|
buffer: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl phy::RxToken for RxToken {
|
||||||
|
fn consume<R, F>(self, f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&[u8]) -> R,
|
||||||
|
{
|
||||||
|
f(&self.buffer[..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub struct TxToken {
|
||||||
|
lower: Rc<RefCell<crate::driver::TapDesc>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl phy::TxToken for TxToken {
|
||||||
|
fn consume<R, F>(self, len: usize, f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut [u8]) -> R,
|
||||||
|
{
|
||||||
|
let mut lower = self.lower.borrow_mut();
|
||||||
|
let mut buffer = vec![0; len];
|
||||||
|
let result = f(&mut buffer);
|
||||||
|
match lower.send(&buffer[..]) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) if err.kind() == io::ErrorKind::WouldBlock => {
|
||||||
|
log::debug!("phy: tx failed due to WouldBlock")
|
||||||
|
}
|
||||||
|
Err(err) => panic!("{}", err),
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
65
src/event_poll.rs
Normal file
65
src/event_poll.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
bitflags::bitflags! {
|
||||||
|
pub struct EPollEventType: u32 {
|
||||||
|
/// 对应的描述符有新的数据可读时会触发
|
||||||
|
const EPOLLIN = 0x00000001;
|
||||||
|
/// 对应的描述符有紧急数据可读时会触发
|
||||||
|
const EPOLLPRI = 0x00000002;
|
||||||
|
/// 对应的描述符可以写入数据时会触发
|
||||||
|
const EPOLLOUT = 0x00000004;
|
||||||
|
/// 对应的描述符发生错误时会触发
|
||||||
|
const EPOLLERR = 0x00000008;
|
||||||
|
/// 对应的描述符被挂断(连接关闭)时会触发
|
||||||
|
const EPOLLHUP = 0x00000010;
|
||||||
|
/// 对应的描述符不是一个有效的文件描述符时会触发
|
||||||
|
const EPOLLNVAL = 0x00000020;
|
||||||
|
/// 普通数据可读,类似于`EPOLLIN`
|
||||||
|
const EPOLLRDNORM = 0x00000040;
|
||||||
|
/// 优先级带外数据可读
|
||||||
|
const EPOLLRDBAND = 0x00000080;
|
||||||
|
/// 普通数据可写,类似于'EPOLLOUT'
|
||||||
|
const EPOLLWRNORM = 0x00000100;
|
||||||
|
/// 优先级带外数据可写
|
||||||
|
const EPOLLWRBAND = 0x00000200;
|
||||||
|
/// 通过消息队列收到消息时会触
|
||||||
|
const EPOLLMSG = 0x00000400;
|
||||||
|
/// 对应的描述符被挂断(连接关闭)的一端发送了 FIN 时会触发(读关闭)
|
||||||
|
const EPOLLRDHUP = 0x00002000;
|
||||||
|
|
||||||
|
/// 以下为额外选项
|
||||||
|
///
|
||||||
|
/// 特定选项,用于异步 I/O,目前未实现
|
||||||
|
const EPOLL_URING_WAKE = 1u32 << 27;
|
||||||
|
/// 设置epoll为独占模式
|
||||||
|
const EPOLLEXCLUSIVE = 1u32 << 28;
|
||||||
|
/// 允许在系统挂起时唤醒 epoll,通常用于通过 eventfd 或 timerfd 唤醒 epoll,(通常与电源管理相关,未实现)
|
||||||
|
const EPOLLWAKEUP = 1u32 << 29;
|
||||||
|
/// 表示只监听一次事件,之后需要重新添加
|
||||||
|
const EPOLLONESHOT = 1u32 << 30;
|
||||||
|
|
||||||
|
/// 启用边缘触发模式(即只有下次触发事件时才会通过epoll_wait返回),
|
||||||
|
/// 对应为水平触发(默认),水平触发模式下若这次未处理完数据,那epoll还会将其加入自己的就绪队列
|
||||||
|
const EPOLLET = 1u32 << 31;
|
||||||
|
|
||||||
|
/// 以下为组合码
|
||||||
|
const EPOLLINOUT_BITS = Self::EPOLLIN.bits() | Self::EPOLLOUT.bits();
|
||||||
|
const EPOLLEXCLUSIVE_OK_BITS =
|
||||||
|
Self::EPOLLINOUT_BITS.bits()
|
||||||
|
| Self::EPOLLERR.bits()
|
||||||
|
| Self::EPOLLHUP.bits()
|
||||||
|
| Self::EPOLLWAKEUP.bits()
|
||||||
|
| Self::EPOLLET.bits()
|
||||||
|
| Self::EPOLLEXCLUSIVE.bits();
|
||||||
|
|
||||||
|
const EP_PRIVATE_BITS =
|
||||||
|
Self::EPOLLWAKEUP.bits()
|
||||||
|
| Self::EPOLLONESHOT.bits()
|
||||||
|
| Self::EPOLLET.bits()
|
||||||
|
| Self::EPOLLEXCLUSIVE.bits();
|
||||||
|
|
||||||
|
/// 表示epoll已经被释放,但是在目前的设计中未用到
|
||||||
|
const POLLFREE = 0x4000;
|
||||||
|
|
||||||
|
/// listen状态的socket可以接受连接
|
||||||
|
const EPOLL_LISTEN_CAN_ACCEPT = Self::EPOLLIN.bits() | Self::EPOLLRDNORM.bits();
|
||||||
|
}
|
||||||
|
}
|
262
src/interface/mod.rs
Normal file
262
src/interface/mod.rs
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
use linux_errnos::Errno;
|
||||||
|
use spin::Mutex;
|
||||||
|
use spin::RwLock;
|
||||||
|
use std::any::Any;
|
||||||
|
use std::fmt;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::socket::inet::common::PortManager;
|
||||||
|
use crate::socket::inet::InetSocket;
|
||||||
|
|
||||||
|
pub mod tap;
|
||||||
|
|
||||||
|
pub trait Iface: Sync + Send + Debug + Any {
|
||||||
|
/// # `common`
|
||||||
|
/// 获取网卡的公共信息
|
||||||
|
fn common(&self) -> &IfaceCommon;
|
||||||
|
|
||||||
|
/// # `mac`
|
||||||
|
/// 获取网卡的MAC地址
|
||||||
|
fn mac(&self) -> smoltcp::wire::EthernetAddress;
|
||||||
|
|
||||||
|
// /// # `name`
|
||||||
|
// /// 获取网卡名
|
||||||
|
// fn iface_name(&self) -> String;
|
||||||
|
|
||||||
|
// /// # `nic_id`
|
||||||
|
// /// 获取网卡id
|
||||||
|
// fn nic_id(&self) -> usize {
|
||||||
|
// self.common().iface_id
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// # `poll`
|
||||||
|
/// 用于轮询接口的状态。
|
||||||
|
/// ## 参数
|
||||||
|
/// - `sockets` :一个可变引用到 `smoltcp::iface::SocketSet`,表示要轮询的套接字集
|
||||||
|
/// ## 返回值
|
||||||
|
/// - 成功返回 `Ok(())`
|
||||||
|
/// - 如果轮询失败,返回 `Err(Errno::EAGAIN_OR_EWOULDBLOCK)`,表示需要再次尝试或者操作会阻塞
|
||||||
|
fn poll(&self);
|
||||||
|
|
||||||
|
/// # `update_ip_addrs`
|
||||||
|
/// 用于更新接口的 IP 地址
|
||||||
|
/// ## 参数
|
||||||
|
/// - `ip_addrs` :一个包含 `smoltcp::wire::IpCidr` 的切片,表示要设置的 IP 地址和子网掩码
|
||||||
|
/// ## 返回值
|
||||||
|
/// - 如果 `ip_addrs` 的长度不为 1,返回 `Err(Errno::EINVAL)`,表示输入参数无效
|
||||||
|
fn update_ip_addrs(&self, ip_addrs: &[smoltcp::wire::IpCidr]) -> Result<(), Errno> {
|
||||||
|
self.common().update_ip_addrs(ip_addrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 获取smoltcp的网卡接口类型
|
||||||
|
#[inline(always)]
|
||||||
|
fn smol_iface(&self) -> &Mutex<smoltcp::iface::Interface> {
|
||||||
|
&self.common().smol_iface
|
||||||
|
}
|
||||||
|
// fn as_any_ref(&'static self) -> &'static dyn core::any::Any;
|
||||||
|
|
||||||
|
/// # `sockets`
|
||||||
|
/// 获取网卡的套接字集
|
||||||
|
fn sockets(&self) -> &Mutex<smoltcp::iface::SocketSet<'static>> {
|
||||||
|
&self.common().sockets
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # `port_manager`
|
||||||
|
/// 用于管理网卡的端口
|
||||||
|
fn port_manager(&self) -> &PortManager {
|
||||||
|
&self.common().port_manager
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the raw file descriptor if this interface has one
|
||||||
|
/// Returns None if this interface doesn't have a file descriptor
|
||||||
|
fn raw_fd(&self) -> Option<std::os::unix::io::RawFd> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// fn addr_assign_type(&self) -> u8;
|
||||||
|
|
||||||
|
// fn net_device_type(&self) -> u16;
|
||||||
|
|
||||||
|
// fn net_state(&self) -> NetDeivceState;
|
||||||
|
|
||||||
|
// fn set_net_state(&self, state: NetDeivceState);
|
||||||
|
|
||||||
|
// fn operstate(&self) -> Operstate;
|
||||||
|
|
||||||
|
// fn set_operstate(&self, state: Operstate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 网络设备的公共数据
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NetDeviceCommonData {
|
||||||
|
/// 表示网络接口的地址分配类型
|
||||||
|
pub addr_assign_type: u8,
|
||||||
|
/// 表示网络接口的类型
|
||||||
|
pub net_device_type: u16,
|
||||||
|
// /// 表示网络接口的状态
|
||||||
|
// pub state: NetDeivceState,
|
||||||
|
// /// 表示网络接口的操作状态
|
||||||
|
// pub operstate: Operstate,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for NetDeviceCommonData {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
addr_assign_type: 0,
|
||||||
|
net_device_type: 1,
|
||||||
|
// state: NetDeivceState::empty(),
|
||||||
|
// operstate: Operstate::IF_OPER_UNKNOWN,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// /// 将网络设备注册到sysfs中
|
||||||
|
// /// 参考:https://code.dragonos.org.cn/xref/linux-2.6.39/net/core/dev.c?fi=register_netdev#5373
|
||||||
|
// fn register_netdevice(dev: Arc<dyn Iface>) -> Result<(), Errno> {
|
||||||
|
// // 在sysfs中注册设备
|
||||||
|
// netdev_register_kobject(dev.clone())?;
|
||||||
|
|
||||||
|
// // 标识网络设备在系统中存在
|
||||||
|
// dev.set_net_state(NetDeivceState::__LINK_STATE_PRESENT);
|
||||||
|
|
||||||
|
// return Ok(());
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub struct IfaceCommon {
|
||||||
|
iface_id: usize,
|
||||||
|
smol_iface: Mutex<smoltcp::iface::Interface>,
|
||||||
|
/// 存smoltcp网卡的套接字集
|
||||||
|
sockets: Mutex<smoltcp::iface::SocketSet<'static>>,
|
||||||
|
/// 存 kernel wrap smoltcp socket 的集合
|
||||||
|
bounds: RwLock<Vec<Arc<dyn InetSocket>>>,
|
||||||
|
/// 端口管理器
|
||||||
|
port_manager: PortManager,
|
||||||
|
/// 下次轮询的时间
|
||||||
|
poll_at_ms: core::sync::atomic::AtomicU64,
|
||||||
|
/// 默认网卡标识
|
||||||
|
/// TODO: 此字段设置目的是解决对bind unspecified地址的分包问题,需要在inet实现多网卡监听或路由子系统实现后移除
|
||||||
|
default_iface: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for IfaceCommon {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("IfaceCommon")
|
||||||
|
.field("iface_id", &self.iface_id)
|
||||||
|
.field("sockets", &self.sockets)
|
||||||
|
// .field("bounds", &self.bounds)
|
||||||
|
.field("port_manager", &self.port_manager)
|
||||||
|
.field("poll_at_ms", &self.poll_at_ms)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IfaceCommon {
|
||||||
|
pub fn new(iface_id: usize, default_iface: bool, iface: smoltcp::iface::Interface) -> Self {
|
||||||
|
IfaceCommon {
|
||||||
|
iface_id,
|
||||||
|
smol_iface: Mutex::new(iface),
|
||||||
|
sockets: Mutex::new(smoltcp::iface::SocketSet::new(Vec::new())),
|
||||||
|
bounds: RwLock::new(Vec::new()),
|
||||||
|
port_manager: PortManager::new(),
|
||||||
|
poll_at_ms: core::sync::atomic::AtomicU64::new(0),
|
||||||
|
default_iface,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn poll<D>(&self, device: &mut D)
|
||||||
|
where
|
||||||
|
D: smoltcp::phy::Device + ?Sized,
|
||||||
|
{
|
||||||
|
let timestamp = std::time::Instant::now().into();
|
||||||
|
let mut sockets = self.sockets.lock();
|
||||||
|
let mut interface = self.smol_iface.lock();
|
||||||
|
|
||||||
|
let (has_events, poll_at) = {
|
||||||
|
(
|
||||||
|
matches!(
|
||||||
|
interface.poll(timestamp, device, &mut sockets),
|
||||||
|
smoltcp::iface::PollResult::SocketStateChanged
|
||||||
|
),
|
||||||
|
loop {
|
||||||
|
let poll_at = interface.poll_at(timestamp, &sockets);
|
||||||
|
let Some(instant) = poll_at else {
|
||||||
|
break poll_at;
|
||||||
|
};
|
||||||
|
if instant > timestamp {
|
||||||
|
break poll_at;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
// drop sockets here to avoid deadlock
|
||||||
|
drop(interface);
|
||||||
|
drop(sockets);
|
||||||
|
|
||||||
|
use core::sync::atomic::Ordering;
|
||||||
|
if let Some(instant) = poll_at {
|
||||||
|
let _old_instant = self.poll_at_ms.load(Ordering::Relaxed);
|
||||||
|
let new_instant = instant.total_millis() as u64;
|
||||||
|
self.poll_at_ms.store(new_instant, Ordering::Relaxed);
|
||||||
|
|
||||||
|
// TODO: poll at
|
||||||
|
// if old_instant == 0 || new_instant < old_instant {
|
||||||
|
// self.polling_wait_queue.wake_all();
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
self.poll_at_ms.store(0, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.bounds.read().iter().for_each(|bound_socket| {
|
||||||
|
// incase our inet socket missed the event, we manually notify it each time we poll
|
||||||
|
if has_events {
|
||||||
|
bound_socket.on_iface_events();
|
||||||
|
bound_socket.wait_queue().wakeup();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: remove closed sockets
|
||||||
|
// let closed_sockets = self
|
||||||
|
// .closing_sockets
|
||||||
|
// .lock_irq_disabled()
|
||||||
|
// .extract_if(|closing_socket| closing_socket.is_closed())
|
||||||
|
// .collect::<Vec<_>>();
|
||||||
|
// drop(closed_sockets);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_ip_addrs(&self, ip_addrs: &[smoltcp::wire::IpCidr]) -> Result<(), Errno> {
|
||||||
|
if ip_addrs.len() != 1 {
|
||||||
|
return Err(Errno::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.smol_iface.lock().update_ip_addrs(|addrs| {
|
||||||
|
let dest = addrs.iter_mut().next();
|
||||||
|
|
||||||
|
if let Some(dest) = dest {
|
||||||
|
*dest = ip_addrs[0];
|
||||||
|
} else {
|
||||||
|
addrs.push(ip_addrs[0]).expect("Push ipCidr failed: full");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 需要bounds储存具体的Inet Socket信息,以提供不同种类inet socket的事件分发
|
||||||
|
pub fn bind_socket(&self, socket: Arc<dyn InetSocket>) {
|
||||||
|
self.bounds.write().push(socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unbind_socket(&self, socket: Arc<dyn InetSocket>) {
|
||||||
|
let mut bounds = self.bounds.write();
|
||||||
|
if let Some(index) = bounds.iter().position(|s| Arc::ptr_eq(s, &socket)) {
|
||||||
|
bounds.remove(index);
|
||||||
|
log::debug!("unbind socket success");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: 需要在inet实现多网卡监听或路由子系统实现后移除
|
||||||
|
pub fn is_default_iface(&self) -> bool {
|
||||||
|
self.default_iface
|
||||||
|
}
|
||||||
|
}
|
62
src/interface/tap.rs
Normal file
62
src/interface/tap.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
use std::{ops::DerefMut, sync::Arc, time::Instant};
|
||||||
|
|
||||||
|
use smoltcp::{
|
||||||
|
iface::{Config, Interface},
|
||||||
|
wire::HardwareAddress,
|
||||||
|
};
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
use crate::driver::tap::TapDevice;
|
||||||
|
|
||||||
|
use super::{Iface, IfaceCommon};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TapIface {
|
||||||
|
pub inner: Arc<Mutex<TapDevice>>,
|
||||||
|
pub common: IfaceCommon,
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[derive(Debug)]
|
||||||
|
// pub struct TapIface (Arc<Mutex<TapIfaceInner>>);
|
||||||
|
|
||||||
|
impl TapIface {
|
||||||
|
pub fn new(inner: Arc<Mutex<TapDevice>>) -> Self {
|
||||||
|
let mut iface_config = Config::new(HardwareAddress::Ethernet(inner.lock().mac()));
|
||||||
|
iface_config.random_seed = std::random::random();
|
||||||
|
|
||||||
|
let iface = Interface::new(
|
||||||
|
iface_config,
|
||||||
|
inner.lock().deref_mut(),
|
||||||
|
Instant::now().into(),
|
||||||
|
);
|
||||||
|
let common = IfaceCommon::new(1, true, iface);
|
||||||
|
TapIface { inner, common }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for TapIface {}
|
||||||
|
unsafe impl Sync for TapIface {}
|
||||||
|
|
||||||
|
impl Iface for TapIface {
|
||||||
|
fn common(&self) -> &IfaceCommon {
|
||||||
|
&self.common
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mac(&self) -> smoltcp::wire::EthernetAddress {
|
||||||
|
self.inner.lock().mac()
|
||||||
|
}
|
||||||
|
|
||||||
|
// fn iface_name(&self) -> String {
|
||||||
|
// "tap0".to_string()
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn nic_id(&self) -> usize {
|
||||||
|
// self.inner.nic_id()
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn poll(&self) {
|
||||||
|
let mut guard = self.inner.lock();
|
||||||
|
let reference = guard.deref_mut();
|
||||||
|
self.common.poll(reference);
|
||||||
|
}
|
||||||
|
}
|
15
src/lib.rs
Normal file
15
src/lib.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#![feature(thread_id_value)]
|
||||||
|
#![feature(random)]
|
||||||
|
pub mod driver;
|
||||||
|
pub mod event_poll;
|
||||||
|
pub mod interface;
|
||||||
|
pub mod libs;
|
||||||
|
pub mod posix;
|
||||||
|
pub mod process;
|
||||||
|
pub mod socket;
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
extern crate bitflags;
|
||||||
|
extern crate num_derive;
|
||||||
|
extern crate num_traits;
|
||||||
|
extern crate smoltcp;
|
3
src/libs/mod.rs
Normal file
3
src/libs/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod rwlock;
|
||||||
|
pub mod spinlock;
|
||||||
|
pub mod wait_queue;
|
1
src/libs/rwlock.rs
Normal file
1
src/libs/rwlock.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub use spin::RwLock;
|
24
src/libs/spinlock.rs
Normal file
24
src/libs/spinlock.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
pub use spin::{Mutex as SpinLock, MutexGuard};
|
||||||
|
|
||||||
|
// pub struct SpinLock<T: ?Sized> {
|
||||||
|
// inner: Mutex<T>,
|
||||||
|
// }
|
||||||
|
// impl<T> SpinLock<T> {
|
||||||
|
// pub fn new(data: T) -> Self {
|
||||||
|
// Self {
|
||||||
|
// inner: Mutex::new(data),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn lock(&self) -> MutexGuard<'_, T> {
|
||||||
|
// self.inner.lock()
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn lock_irq_disabled(&self) -> MutexGuard<'_, T> {
|
||||||
|
// self.inner.lock()
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn lock_irqsave(&self) -> MutexGuard<'_, T> {
|
||||||
|
// self.inner.lock()
|
||||||
|
// }
|
||||||
|
// }
|
58
src/libs/wait_queue.rs
Normal file
58
src/libs/wait_queue.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
use std::{
|
||||||
|
sync::atomic::AtomicBool,
|
||||||
|
thread::sleep,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use linux_errnos::Errno;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WaitQueue {
|
||||||
|
// events: AtomicUsize,
|
||||||
|
is_scheduled: AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wq_wait_event_interruptible<T: Fn() -> bool>(
|
||||||
|
wait_queue: &WaitQueue,
|
||||||
|
should_wake: T,
|
||||||
|
_: Option<usize>,
|
||||||
|
) -> Result<(), Errno> {
|
||||||
|
// Simulate waiting for an event
|
||||||
|
if should_wake() {
|
||||||
|
wait_queue
|
||||||
|
.is_scheduled
|
||||||
|
.store(false, std::sync::atomic::Ordering::SeqCst);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
wait_queue
|
||||||
|
.is_scheduled
|
||||||
|
.store(false, std::sync::atomic::Ordering::SeqCst);
|
||||||
|
loop {
|
||||||
|
if wait_queue
|
||||||
|
.is_scheduled
|
||||||
|
.load(std::sync::atomic::Ordering::SeqCst)
|
||||||
|
&& should_wake()
|
||||||
|
{
|
||||||
|
return Ok(());
|
||||||
|
} else {
|
||||||
|
// simulate never schedule to this process
|
||||||
|
sleep(Duration::from_millis(10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WaitQueue {
|
||||||
|
pub fn wakeup(&self) {
|
||||||
|
self.is_scheduled
|
||||||
|
.store(true, std::sync::atomic::Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for WaitQueue {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
// events: AtomicUsize::new(0),
|
||||||
|
is_scheduled: AtomicBool::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/main.rs
Normal file
16
src/main.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use berkeley_socket::{
|
||||||
|
driver::{irq::start_network_polling_thread, tap::TapDevice},
|
||||||
|
interface::tap::TapIface,
|
||||||
|
socket::inet::common::NET_DEVICES,
|
||||||
|
};
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let device = TapDevice::new("tap0", smoltcp::phy::Medium::Ethernet).unwrap();
|
||||||
|
let iface = Arc::new(TapIface::new(Arc::new(Mutex::new(device))));
|
||||||
|
NET_DEVICES.write().insert(0, iface);
|
||||||
|
let _ = start_network_polling_thread();
|
||||||
|
// TODO: add socket tests
|
||||||
|
}
|
113
src/posix/family.rs
Normal file
113
src/posix/family.rs
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
|
/// # AddressFamily
|
||||||
|
/// Socket address families.
|
||||||
|
/// ## Reference
|
||||||
|
/// https://code.dragonos.org.cn/xref/linux-5.19.10/include/linux/socket.h#180
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
||||||
|
pub enum AddressFamily {
|
||||||
|
/// AF_UNSPEC 表示地址族未指定
|
||||||
|
Unspecified = 0,
|
||||||
|
/// AF_UNIX 表示Unix域的socket (与AF_LOCAL相同)
|
||||||
|
Unix = 1,
|
||||||
|
/// AF_INET 表示IPv4的socket
|
||||||
|
INet = 2,
|
||||||
|
/// AF_AX25 表示AMPR AX.25的socket
|
||||||
|
AX25 = 3,
|
||||||
|
/// AF_IPX 表示IPX的socket
|
||||||
|
IPX = 4,
|
||||||
|
/// AF_APPLETALK 表示Appletalk的socket
|
||||||
|
Appletalk = 5,
|
||||||
|
/// AF_NETROM 表示AMPR NET/ROM的socket
|
||||||
|
Netrom = 6,
|
||||||
|
/// AF_BRIDGE 表示多协议桥接的socket
|
||||||
|
Bridge = 7,
|
||||||
|
/// AF_ATMPVC 表示ATM PVCs的socket
|
||||||
|
Atmpvc = 8,
|
||||||
|
/// AF_X25 表示X.25的socket
|
||||||
|
X25 = 9,
|
||||||
|
/// AF_INET6 表示IPv6的socket
|
||||||
|
INet6 = 10,
|
||||||
|
/// AF_ROSE 表示AMPR ROSE的socket
|
||||||
|
Rose = 11,
|
||||||
|
/// AF_DECnet Reserved for DECnet project
|
||||||
|
Decnet = 12,
|
||||||
|
/// AF_NETBEUI Reserved for 802.2LLC project
|
||||||
|
Netbeui = 13,
|
||||||
|
/// AF_SECURITY 表示Security callback的伪AF
|
||||||
|
Security = 14,
|
||||||
|
/// AF_KEY 表示Key management API
|
||||||
|
Key = 15,
|
||||||
|
/// AF_NETLINK 表示Netlink的socket
|
||||||
|
Netlink = 16,
|
||||||
|
/// AF_PACKET 表示Low level packet interface
|
||||||
|
Packet = 17,
|
||||||
|
/// AF_ASH 表示Ash
|
||||||
|
Ash = 18,
|
||||||
|
/// AF_ECONET 表示Acorn Econet
|
||||||
|
Econet = 19,
|
||||||
|
/// AF_ATMSVC 表示ATM SVCs
|
||||||
|
Atmsvc = 20,
|
||||||
|
/// AF_RDS 表示Reliable Datagram Sockets
|
||||||
|
Rds = 21,
|
||||||
|
/// AF_SNA 表示Linux SNA Project
|
||||||
|
Sna = 22,
|
||||||
|
/// AF_IRDA 表示IRDA sockets
|
||||||
|
Irda = 23,
|
||||||
|
/// AF_PPPOX 表示PPPoX sockets
|
||||||
|
Pppox = 24,
|
||||||
|
/// AF_WANPIPE 表示WANPIPE API sockets
|
||||||
|
WanPipe = 25,
|
||||||
|
/// AF_LLC 表示Linux LLC
|
||||||
|
Llc = 26,
|
||||||
|
/// AF_IB 表示Native InfiniBand address
|
||||||
|
/// 介绍:https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html-single/configuring_infiniband_and_rdma_networks/index#understanding-infiniband-and-rdma_configuring-infiniband-and-rdma-networks
|
||||||
|
Ib = 27,
|
||||||
|
/// AF_MPLS 表示MPLS
|
||||||
|
Mpls = 28,
|
||||||
|
/// AF_CAN 表示Controller Area Network
|
||||||
|
Can = 29,
|
||||||
|
/// AF_TIPC 表示TIPC sockets
|
||||||
|
Tipc = 30,
|
||||||
|
/// AF_BLUETOOTH 表示Bluetooth sockets
|
||||||
|
Bluetooth = 31,
|
||||||
|
/// AF_IUCV 表示IUCV sockets
|
||||||
|
Iucv = 32,
|
||||||
|
/// AF_RXRPC 表示RxRPC sockets
|
||||||
|
Rxrpc = 33,
|
||||||
|
/// AF_ISDN 表示mISDN sockets
|
||||||
|
Isdn = 34,
|
||||||
|
/// AF_PHONET 表示Phonet sockets
|
||||||
|
Phonet = 35,
|
||||||
|
/// AF_IEEE802154 表示IEEE 802.15.4 sockets
|
||||||
|
Ieee802154 = 36,
|
||||||
|
/// AF_CAIF 表示CAIF sockets
|
||||||
|
Caif = 37,
|
||||||
|
/// AF_ALG 表示Algorithm sockets
|
||||||
|
Alg = 38,
|
||||||
|
/// AF_NFC 表示NFC sockets
|
||||||
|
Nfc = 39,
|
||||||
|
/// AF_VSOCK 表示vSockets
|
||||||
|
Vsock = 40,
|
||||||
|
/// AF_KCM 表示Kernel Connection Multiplexor
|
||||||
|
Kcm = 41,
|
||||||
|
/// AF_QIPCRTR 表示Qualcomm IPC Router
|
||||||
|
Qipcrtr = 42,
|
||||||
|
/// AF_SMC 表示SMC-R sockets.
|
||||||
|
/// reserve number for PF_SMC protocol family that reuses AF_INET address family
|
||||||
|
Smc = 43,
|
||||||
|
/// AF_XDP 表示XDP sockets
|
||||||
|
Xdp = 44,
|
||||||
|
/// AF_MCTP 表示Management Component Transport Protocol
|
||||||
|
Mctp = 45,
|
||||||
|
/// AF_MAX 表示最大的地址族
|
||||||
|
Max = 46,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::convert::TryFrom<u16> for AddressFamily {
|
||||||
|
type Error = linux_errnos::Errno;
|
||||||
|
fn try_from(x: u16) -> Result<Self, Self::Error> {
|
||||||
|
use num_traits::FromPrimitive;
|
||||||
|
// this will return EINVAL but still works, idk why
|
||||||
|
<Self as FromPrimitive>::from_u16(x).ok_or(Self::Error::EINVAL)
|
||||||
|
}
|
||||||
|
}
|
14
src/posix/mod.rs
Normal file
14
src/posix/mod.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// posix socket and arguments definitions
|
||||||
|
// now all posix definitions are with P front like MSG -> PMSG,
|
||||||
|
// for better understanding and avoiding conflicts with other definitions
|
||||||
|
pub mod family;
|
||||||
|
mod msg_flag;
|
||||||
|
mod option;
|
||||||
|
mod option_level;
|
||||||
|
pub mod posix;
|
||||||
|
mod types;
|
||||||
|
|
||||||
|
pub use msg_flag::MessageFlag as PMSG; // Socket message flags MSG_*
|
||||||
|
pub use option::Options as PSO; // Socket options SO_*
|
||||||
|
pub use option_level::OptionLevel as PSOL; // Socket options level SOL_*
|
||||||
|
pub use types::SOCK; // Socket types SOCK_*
|
110
src/posix/msg_flag.rs
Normal file
110
src/posix/msg_flag.rs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
bitflags::bitflags! {
|
||||||
|
/// # Message Flags
|
||||||
|
/// Flags we can use with send/ and recv. \
|
||||||
|
/// Added those for 1003.1g not all are supported yet
|
||||||
|
/// ## Reference
|
||||||
|
/// - [Linux Socket Flags](https://code.dragonos.org.cn/xref/linux-6.6.21/include/linux/socket.h#299)
|
||||||
|
pub struct MessageFlag: u32 {
|
||||||
|
/// `MSG_OOB`
|
||||||
|
/// `0b0000_0001`\
|
||||||
|
/// Process out-of-band data.
|
||||||
|
const OOB = 1;
|
||||||
|
/// `MSG_PEEK`
|
||||||
|
/// `0b0000_0010`\
|
||||||
|
/// Peek at an incoming message.
|
||||||
|
const PEEK = 2;
|
||||||
|
/// `MSG_DONTROUTE`
|
||||||
|
/// `0b0000_0100`\
|
||||||
|
/// Don't use routing tables.
|
||||||
|
const DONTROUTE = 4;
|
||||||
|
/// `MSG_TRYHARD`
|
||||||
|
/// `0b0000_0100`\
|
||||||
|
/// `MSG_TRYHARD` is not defined in the standard, but it is used in Linux.
|
||||||
|
const TRYHARD = 4;
|
||||||
|
/// `MSG_CTRUNC`
|
||||||
|
/// `0b0000_1000`\
|
||||||
|
/// Control data lost before delivery.
|
||||||
|
const CTRUNC = 8;
|
||||||
|
/// `MSG_PROBE`
|
||||||
|
/// `0b0001_0000`\
|
||||||
|
const PROBE = 0x10;
|
||||||
|
/// `MSG_TRUNC`
|
||||||
|
/// `0b0010_0000`\
|
||||||
|
/// Data truncated before delivery.
|
||||||
|
const TRUNC = 0x20;
|
||||||
|
/// `MSG_DONTWAIT`
|
||||||
|
/// `0b0100_0000`\
|
||||||
|
/// This flag is used to make the socket non-blocking.
|
||||||
|
const DONTWAIT = 0x40;
|
||||||
|
/// `MSG_EOR`
|
||||||
|
/// `0b1000_0000`\
|
||||||
|
/// End of record.
|
||||||
|
const EOR = 0x80;
|
||||||
|
/// `MSG_WAITALL`
|
||||||
|
/// `0b0001_0000_0000`\
|
||||||
|
/// Wait for full request or error.
|
||||||
|
const WAITALL = 0x100;
|
||||||
|
/// `MSG_FIN`
|
||||||
|
/// `0b0010_0000_0000`\
|
||||||
|
/// Terminate the connection.
|
||||||
|
const FIN = 0x200;
|
||||||
|
/// `MSG_SYN`
|
||||||
|
/// `0b0100_0000_0000`\
|
||||||
|
/// Synchronize sequence numbers.
|
||||||
|
const SYN = 0x400;
|
||||||
|
/// `MSG_CONFIRM`
|
||||||
|
/// `0b1000_0000_0000`\
|
||||||
|
/// Confirm path validity.
|
||||||
|
const CONFIRM = 0x800;
|
||||||
|
/// `MSG_RST`
|
||||||
|
/// `0b0001_0000_0000_0000`\
|
||||||
|
/// Reset the connection.
|
||||||
|
const RST = 0x1000;
|
||||||
|
/// `MSG_ERRQUEUE`
|
||||||
|
/// `0b0010_0000_0000_0000`\
|
||||||
|
/// Fetch message from error queue.
|
||||||
|
const ERRQUEUE = 0x2000;
|
||||||
|
/// `MSG_NOSIGNAL`
|
||||||
|
/// `0b0100_0000_0000_0000`\
|
||||||
|
/// Do not generate a signal.
|
||||||
|
const NOSIGNAL = 0x4000;
|
||||||
|
/// `MSG_MORE`
|
||||||
|
/// `0b1000_0000_0000_0000`\
|
||||||
|
/// Sender will send more.
|
||||||
|
const MORE = 0x8000;
|
||||||
|
/// `MSG_WAITFORONE`
|
||||||
|
/// `0b0001_0000_0000_0000_0000`\
|
||||||
|
/// For nonblocking operation.
|
||||||
|
const WAITFORONE = 0x10000;
|
||||||
|
/// `MSG_SENDPAGE_NOPOLICY`
|
||||||
|
/// `0b0010_0000_0000_0000_0000`\
|
||||||
|
/// Sendpage: do not apply policy.
|
||||||
|
const SENDPAGE_NOPOLICY = 0x10000;
|
||||||
|
/// `MSG_BATCH`
|
||||||
|
/// `0b0100_0000_0000_0000_0000`\
|
||||||
|
/// Sendpage: next message is batch.
|
||||||
|
const BATCH = 0x40000;
|
||||||
|
/// `MSG_EOF`
|
||||||
|
const EOF = Self::FIN.bits();
|
||||||
|
/// `MSG_NO_SHARED_FRAGS`
|
||||||
|
const NO_SHARED_FRAGS = 0x80000;
|
||||||
|
/// `MSG_SENDPAGE_DECRYPTED`
|
||||||
|
const SENDPAGE_DECRYPTED = 0x10_0000;
|
||||||
|
|
||||||
|
/// `MSG_ZEROCOPY`
|
||||||
|
const ZEROCOPY = 0x400_0000;
|
||||||
|
/// `MSG_SPLICE_PAGES`
|
||||||
|
const SPLICE_PAGES = 0x800_0000;
|
||||||
|
/// `MSG_FASTOPEN`
|
||||||
|
const FASTOPEN = 0x2000_0000;
|
||||||
|
/// `MSG_CMSG_CLOEXEC`
|
||||||
|
const CMSG_CLOEXEC = 0x4000_0000;
|
||||||
|
/// `MSG_CMSG_COMPAT`
|
||||||
|
// if define CONFIG_COMPAT
|
||||||
|
// const CMSG_COMPAT = 0x8000_0000;
|
||||||
|
const CMSG_COMPAT = 0;
|
||||||
|
/// `MSG_INTERNAL_SENDMSG_FLAGS`
|
||||||
|
const INTERNAL_SENDMSG_FLAGS
|
||||||
|
= Self::SPLICE_PAGES.bits() | Self::SENDPAGE_NOPOLICY.bits() | Self::SENDPAGE_DECRYPTED.bits();
|
||||||
|
}
|
||||||
|
}
|
94
src/posix/option.rs
Normal file
94
src/posix/option.rs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub enum Options {
|
||||||
|
DEBUG = 1,
|
||||||
|
REUSEADDR = 2,
|
||||||
|
TYPE = 3,
|
||||||
|
ERROR = 4,
|
||||||
|
DONTROUTE = 5,
|
||||||
|
BROADCAST = 6,
|
||||||
|
SNDBUF = 7,
|
||||||
|
RCVBUF = 8,
|
||||||
|
SNDBUFFORCE = 32,
|
||||||
|
RCVBUFFORCE = 33,
|
||||||
|
KEEPALIVE = 9,
|
||||||
|
OOBINLINE = 10,
|
||||||
|
NO_CHECK = 11,
|
||||||
|
PRIORITY = 12,
|
||||||
|
LINGER = 13,
|
||||||
|
BSDCOMPAT = 14,
|
||||||
|
REUSEPORT = 15,
|
||||||
|
PASSCRED = 16,
|
||||||
|
PEERCRED = 17,
|
||||||
|
RCVLOWAT = 18,
|
||||||
|
SNDLOWAT = 19,
|
||||||
|
RCVTIMEO_OLD = 20,
|
||||||
|
SNDTIMEO_OLD = 21,
|
||||||
|
SECURITY_AUTHENTICATION = 22,
|
||||||
|
SECURITY_ENCRYPTION_TRANSPORT = 23,
|
||||||
|
SECURITY_ENCRYPTION_NETWORK = 24,
|
||||||
|
BINDTODEVICE = 25,
|
||||||
|
/// 与GET_FILTER相同
|
||||||
|
ATTACH_FILTER = 26,
|
||||||
|
DETACH_FILTER = 27,
|
||||||
|
PEERNAME = 28,
|
||||||
|
ACCEPTCONN = 30,
|
||||||
|
PEERSEC = 31,
|
||||||
|
PASSSEC = 34,
|
||||||
|
MARK = 36,
|
||||||
|
PROTOCOL = 38,
|
||||||
|
DOMAIN = 39,
|
||||||
|
RXQ_OVFL = 40,
|
||||||
|
/// 与SCM_WIFI_STATUS相同
|
||||||
|
WIFI_STATUS = 41,
|
||||||
|
PEEK_OFF = 42,
|
||||||
|
/* Instruct lower device to use last 4-bytes of skb data as FCS */
|
||||||
|
NOFCS = 43,
|
||||||
|
LOCK_FILTER = 44,
|
||||||
|
SELECT_ERR_QUEUE = 45,
|
||||||
|
BUSY_POLL = 46,
|
||||||
|
MAX_PACING_RATE = 47,
|
||||||
|
BPF_EXTENSIONS = 48,
|
||||||
|
INCOMING_CPU = 49,
|
||||||
|
ATTACH_BPF = 50,
|
||||||
|
// DETACH_BPF = DETACH_FILTER,
|
||||||
|
ATTACH_REUSEPORT_CBPF = 51,
|
||||||
|
ATTACH_REUSEPORT_EBPF = 52,
|
||||||
|
CNX_ADVICE = 53,
|
||||||
|
SCM_TIMESTAMPING_OPT_STATS = 54,
|
||||||
|
MEMINFO = 55,
|
||||||
|
INCOMING_NAPI_ID = 56,
|
||||||
|
COOKIE = 57,
|
||||||
|
SCM_TIMESTAMPING_PKTINFO = 58,
|
||||||
|
PEERGROUPS = 59,
|
||||||
|
ZEROCOPY = 60,
|
||||||
|
/// 与SCM_TXTIME相同
|
||||||
|
TXTIME = 61,
|
||||||
|
BINDTOIFINDEX = 62,
|
||||||
|
TIMESTAMP_OLD = 29,
|
||||||
|
TIMESTAMPNS_OLD = 35,
|
||||||
|
TIMESTAMPING_OLD = 37,
|
||||||
|
TIMESTAMP_NEW = 63,
|
||||||
|
TIMESTAMPNS_NEW = 64,
|
||||||
|
TIMESTAMPING_NEW = 65,
|
||||||
|
RCVTIMEO_NEW = 66,
|
||||||
|
SNDTIMEO_NEW = 67,
|
||||||
|
DETACH_REUSEPORT_BPF = 68,
|
||||||
|
PREFER_BUSY_POLL = 69,
|
||||||
|
BUSY_POLL_BUDGET = 70,
|
||||||
|
NETNS_COOKIE = 71,
|
||||||
|
BUF_LOCK = 72,
|
||||||
|
RESERVE_MEM = 73,
|
||||||
|
TXREHASH = 74,
|
||||||
|
RCVMARK = 75,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u32> for Options {
|
||||||
|
type Error = linux_errnos::Errno;
|
||||||
|
fn try_from(x: u32) -> Result<Self, Self::Error> {
|
||||||
|
use num_traits::FromPrimitive;
|
||||||
|
<Self as FromPrimitive>::from_u32(x).ok_or(Self::Error::EINVAL)
|
||||||
|
}
|
||||||
|
}
|
69
src/posix/option_level.rs
Normal file
69
src/posix/option_level.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
|
|
||||||
|
/// # SOL (Socket Option Level)
|
||||||
|
/// Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx
|
||||||
|
/// ## Reference
|
||||||
|
/// - [Setsockoptions(2) level](https://code.dragonos.org.cn/xref/linux-6.6.21/include/linux/socket.h#345)
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub enum OptionLevel {
|
||||||
|
IP = 0,
|
||||||
|
SOCKET = 1,
|
||||||
|
// ICMP = 1, No-no-no! Due to Linux :-) we cannot
|
||||||
|
TCP = 6,
|
||||||
|
UDP = 17,
|
||||||
|
IPV6 = 41,
|
||||||
|
ICMPV6 = 58,
|
||||||
|
SCTP = 132,
|
||||||
|
UDPLITE = 136, // UDP-Lite (RFC 3828)
|
||||||
|
RAW = 255,
|
||||||
|
IPX = 256,
|
||||||
|
AX25 = 257,
|
||||||
|
ATALK = 258,
|
||||||
|
NETROM = 259,
|
||||||
|
ROSE = 260,
|
||||||
|
DECNET = 261,
|
||||||
|
X25 = 262,
|
||||||
|
PACKET = 263,
|
||||||
|
ATM = 264, // ATM layer (cell level)
|
||||||
|
AAL = 265, // ATM Adaption Layer (packet level)
|
||||||
|
IRDA = 266,
|
||||||
|
NETBEUI = 267,
|
||||||
|
LLC = 268,
|
||||||
|
DCCP = 269,
|
||||||
|
NETLINK = 270,
|
||||||
|
TIPC = 271,
|
||||||
|
RXRPC = 272,
|
||||||
|
PPPOL2TP = 273,
|
||||||
|
BLUETOOTH = 274,
|
||||||
|
PNPIPE = 275,
|
||||||
|
RDS = 276,
|
||||||
|
IUCV = 277,
|
||||||
|
CAIF = 278,
|
||||||
|
ALG = 279,
|
||||||
|
NFC = 280,
|
||||||
|
KCM = 281,
|
||||||
|
TLS = 282,
|
||||||
|
XDP = 283,
|
||||||
|
MPTCP = 284,
|
||||||
|
MCTP = 285,
|
||||||
|
SMC = 286,
|
||||||
|
VSOCK = 287,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u32> for OptionLevel {
|
||||||
|
type Error = linux_errnos::Errno;
|
||||||
|
|
||||||
|
fn try_from(value: u32) -> Result<Self, Self::Error> {
|
||||||
|
match <Self as num_traits::FromPrimitive>::from_u32(value) {
|
||||||
|
Some(p) => Ok(p),
|
||||||
|
None => Err(linux_errnos::Errno::EPROTONOSUPPORT),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<OptionLevel> for u32 {
|
||||||
|
fn from(value: OptionLevel) -> Self {
|
||||||
|
<OptionLevel as num_traits::ToPrimitive>::to_u32(&value).unwrap()
|
||||||
|
}
|
||||||
|
}
|
84
src/posix/posix.rs
Normal file
84
src/posix/posix.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
//
|
||||||
|
// posix.rs 记录了系统调用时用到的结构
|
||||||
|
//
|
||||||
|
bitflags::bitflags! {
|
||||||
|
// #[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||||
|
pub struct PosixArgsSocketType: u32 {
|
||||||
|
const DGRAM = 1; // 0b0000_0001
|
||||||
|
const STREAM = 2; // 0b0000_0010
|
||||||
|
const RAW = 3; // 0b0000_0011
|
||||||
|
const RDM = 4; // 0b0000_0100
|
||||||
|
const SEQPACKET = 5; // 0b0000_0101
|
||||||
|
const DCCP = 6; // 0b0000_0110
|
||||||
|
const PACKET = 10; // 0b0000_1010
|
||||||
|
|
||||||
|
const NONBLOCK = 0b0000_1000; // 0x8000_0000
|
||||||
|
const CLOEXEC = 0b0000_0100; // 0x4000_0000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PosixArgsSocketType {
|
||||||
|
#[inline(always)]
|
||||||
|
pub(super) fn types(&self) -> PosixArgsSocketType {
|
||||||
|
PosixArgsSocketType::from_bits(self.bits() & 0b_1111).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn is_nonblock(&self) -> bool {
|
||||||
|
self.contains(PosixArgsSocketType::NONBLOCK)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn is_cloexec(&self) -> bool {
|
||||||
|
self.contains(PosixArgsSocketType::CLOEXEC)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use super::family::AddressFamily;
|
||||||
|
|
||||||
|
// use super::socket::{endpoint::Endpoint, AddressFamily};
|
||||||
|
|
||||||
|
// 参考资料: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html#tag_13_32
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct SockAddrIn {
|
||||||
|
pub sin_family: u16,
|
||||||
|
pub sin_port: u16,
|
||||||
|
pub sin_addr: u32,
|
||||||
|
pub sin_zero: [u8; 8],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct SockAddrUn {
|
||||||
|
pub sun_family: u16,
|
||||||
|
pub sun_path: [u8; 108],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct SockAddrLl {
|
||||||
|
pub sll_family: u16,
|
||||||
|
pub sll_protocol: u16,
|
||||||
|
pub sll_ifindex: u32,
|
||||||
|
pub sll_hatype: u16,
|
||||||
|
pub sll_pkttype: u8,
|
||||||
|
pub sll_halen: u8,
|
||||||
|
pub sll_addr: [u8; 8],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct SockAddrNl {
|
||||||
|
pub nl_family: AddressFamily,
|
||||||
|
pub nl_pad: u16,
|
||||||
|
pub nl_pid: u32,
|
||||||
|
pub nl_groups: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct SockAddrPlaceholder {
|
||||||
|
pub family: u16,
|
||||||
|
pub data: [u8; 14],
|
||||||
|
}
|
21
src/posix/types.rs
Normal file
21
src/posix/types.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use linux_errnos::Errno;
|
||||||
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
||||||
|
pub enum SOCK {
|
||||||
|
Stream = 1,
|
||||||
|
Datagram = 2,
|
||||||
|
Raw = 3,
|
||||||
|
RDM = 4,
|
||||||
|
SeqPacket = 5,
|
||||||
|
DCCP = 6,
|
||||||
|
Packet = 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
use super::posix::PosixArgsSocketType;
|
||||||
|
impl TryFrom<PosixArgsSocketType> for SOCK {
|
||||||
|
type Error = Errno;
|
||||||
|
fn try_from(x: PosixArgsSocketType) -> Result<Self, Self::Error> {
|
||||||
|
use num_traits::FromPrimitive;
|
||||||
|
<Self as FromPrimitive>::from_u32(x.types().bits()).ok_or(Self::Error::EINVAL)
|
||||||
|
}
|
||||||
|
}
|
11
src/process/mod.rs
Normal file
11
src/process/mod.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// To make compatible
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub struct Pid(usize);
|
||||||
|
|
||||||
|
pub struct ProcessManager {}
|
||||||
|
|
||||||
|
impl ProcessManager {
|
||||||
|
pub fn current_pid() -> Pid {
|
||||||
|
Pid(std::thread::current().id().as_u64().get() as usize)
|
||||||
|
}
|
||||||
|
}
|
18
src/socket/common/mod.rs
Normal file
18
src/socket/common/mod.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// pub mod poll_unit;
|
||||||
|
// mod epoll_items;
|
||||||
|
|
||||||
|
pub mod shutdown;
|
||||||
|
// pub use epoll_items::EPollItems;
|
||||||
|
|
||||||
|
// /// @brief 在trait Socket的metadata函数中返回该结构体供外部使用
|
||||||
|
// #[derive(Debug, Clone)]
|
||||||
|
// pub struct Metadata {
|
||||||
|
// /// 接收缓冲区的大小
|
||||||
|
// pub rx_buf_size: usize,
|
||||||
|
// /// 发送缓冲区的大小
|
||||||
|
// pub tx_buf_size: usize,
|
||||||
|
// /// 元数据的缓冲区的大小
|
||||||
|
// pub metadata_buf_size: usize,
|
||||||
|
// /// socket的选项
|
||||||
|
// pub options: SocketOptions,
|
||||||
|
// }
|
136
src/socket/common/shutdown.rs
Normal file
136
src/socket/common/shutdown.rs
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
// TODO: 其他模块需要实现shutdown的具体逻辑
|
||||||
|
#![allow(dead_code)]
|
||||||
|
use core::sync::atomic::AtomicU8;
|
||||||
|
|
||||||
|
use linux_errnos::Errno;
|
||||||
|
|
||||||
|
bitflags::bitflags! {
|
||||||
|
/// @brief 用于指定socket的关闭类型
|
||||||
|
/// 参考:https://code.dragonos.org.cn/xref/linux-6.1.9/include/net/sock.h?fi=SHUTDOWN_MASK#1573
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct ShutdownBit: u8 {
|
||||||
|
const SHUT_RD = 0;
|
||||||
|
const SHUT_WR = 1;
|
||||||
|
const SHUT_RDWR = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const RCV_SHUTDOWN: u8 = 0x01;
|
||||||
|
const SEND_SHUTDOWN: u8 = 0x02;
|
||||||
|
const SHUTDOWN_MASK: u8 = 0x03;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Shutdown {
|
||||||
|
bit: AtomicU8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ShutdownBit> for Shutdown {
|
||||||
|
fn from(shutdown_bit: ShutdownBit) -> Self {
|
||||||
|
match shutdown_bit {
|
||||||
|
ShutdownBit::SHUT_RD => Shutdown {
|
||||||
|
bit: AtomicU8::new(RCV_SHUTDOWN),
|
||||||
|
},
|
||||||
|
ShutdownBit::SHUT_WR => Shutdown {
|
||||||
|
bit: AtomicU8::new(SEND_SHUTDOWN),
|
||||||
|
},
|
||||||
|
ShutdownBit::SHUT_RDWR => Shutdown {
|
||||||
|
bit: AtomicU8::new(SHUTDOWN_MASK),
|
||||||
|
},
|
||||||
|
_ => Shutdown::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shutdown {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
bit: AtomicU8::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recv_shutdown(&self) {
|
||||||
|
self.bit
|
||||||
|
.fetch_or(RCV_SHUTDOWN, core::sync::atomic::Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_shutdown(&self) {
|
||||||
|
self.bit
|
||||||
|
.fetch_or(SEND_SHUTDOWN, core::sync::atomic::Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_recv_shutdown(&self) -> bool {
|
||||||
|
self.bit.load(core::sync::atomic::Ordering::SeqCst) & RCV_SHUTDOWN != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_send_shutdown(&self) -> bool {
|
||||||
|
self.bit.load(core::sync::atomic::Ordering::SeqCst) & SEND_SHUTDOWN != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_both_shutdown(&self) -> bool {
|
||||||
|
self.bit.load(core::sync::atomic::Ordering::SeqCst) & SHUTDOWN_MASK == SHUTDOWN_MASK
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.bit.load(core::sync::atomic::Ordering::SeqCst) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_how(how: usize) -> Self {
|
||||||
|
Self::from(ShutdownBit::from_bits_truncate(how as u8))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self) -> ShutdownTemp {
|
||||||
|
ShutdownTemp {
|
||||||
|
bit: self.bit.load(core::sync::atomic::Ordering::SeqCst),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ShutdownTemp {
|
||||||
|
bit: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShutdownTemp {
|
||||||
|
pub fn is_recv_shutdown(&self) -> bool {
|
||||||
|
self.bit & RCV_SHUTDOWN != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_send_shutdown(&self) -> bool {
|
||||||
|
self.bit & SEND_SHUTDOWN != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_both_shutdown(&self) -> bool {
|
||||||
|
self.bit & SHUTDOWN_MASK == SHUTDOWN_MASK
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.bit == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bits(&self) -> ShutdownBit {
|
||||||
|
ShutdownBit::from_bits_truncate(self.bit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ShutdownBit> for ShutdownTemp {
|
||||||
|
fn from(shutdown_bit: ShutdownBit) -> Self {
|
||||||
|
match shutdown_bit {
|
||||||
|
ShutdownBit::SHUT_RD => Self { bit: RCV_SHUTDOWN },
|
||||||
|
ShutdownBit::SHUT_WR => Self { bit: SEND_SHUTDOWN },
|
||||||
|
ShutdownBit::SHUT_RDWR => Self { bit: SHUTDOWN_MASK },
|
||||||
|
_ => Self { bit: 0 },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<usize> for ShutdownTemp {
|
||||||
|
type Error = Errno;
|
||||||
|
|
||||||
|
fn try_from(value: usize) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
0..2 => Ok(ShutdownTemp {
|
||||||
|
bit: value as u8 + 1,
|
||||||
|
}),
|
||||||
|
_ => Err(Errno::EINVAL),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
src/socket/endpoint.rs
Normal file
44
src/socket/endpoint.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// use crate::{filesystem::vfs::InodeId, net::socket};
|
||||||
|
// use alloc::{string::String, sync::Arc};
|
||||||
|
|
||||||
|
pub use smoltcp::wire::IpEndpoint;
|
||||||
|
|
||||||
|
// use super::unix::ns::abs::AbsHandle;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Endpoint {
|
||||||
|
// /// 链路层端点
|
||||||
|
// LinkLayer(LinkLayerEndpoint),
|
||||||
|
/// 网络层端点
|
||||||
|
Ip(IpEndpoint),
|
||||||
|
// /// inode端点,Unix实际保存的端点
|
||||||
|
// Inode((Arc<socket::SocketInode>, String)),
|
||||||
|
// /// Unix传递id索引和path所用的端点
|
||||||
|
// Unixpath((InodeId, String)),
|
||||||
|
// /// Unix抽象端点
|
||||||
|
// Abspath((AbsHandle, String)),
|
||||||
|
}
|
||||||
|
|
||||||
|
// /// @brief 链路层端点
|
||||||
|
// #[derive(Debug, Clone)]
|
||||||
|
// pub struct LinkLayerEndpoint {
|
||||||
|
// /// 网卡的接口号
|
||||||
|
// pub interface: usize,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl LinkLayerEndpoint {
|
||||||
|
// /// @brief 创建一个链路层端点
|
||||||
|
// ///
|
||||||
|
// /// @param interface 网卡的接口号
|
||||||
|
// ///
|
||||||
|
// /// @return 返回创建的链路层端点
|
||||||
|
// pub fn new(interface: usize) -> Self {
|
||||||
|
// Self { interface }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
impl From<IpEndpoint> for Endpoint {
|
||||||
|
fn from(endpoint: IpEndpoint) -> Self {
|
||||||
|
Self::Ip(endpoint)
|
||||||
|
}
|
||||||
|
}
|
157
src/socket/inet/common/mod.rs
Normal file
157
src/socket/inet/common/mod.rs
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
// use crate::net::{Iface, NET_DEVICES};
|
||||||
|
use crate::interface::Iface;
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
|
pub mod port;
|
||||||
|
use linux_errnos::Errno as SystemError;
|
||||||
|
pub use port::PortManager;
|
||||||
|
use spin::RwLock;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub enum Types {
|
||||||
|
Raw,
|
||||||
|
Icmp,
|
||||||
|
Udp,
|
||||||
|
Tcp,
|
||||||
|
Dhcpv4,
|
||||||
|
Dns,
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
/// # 所有网络接口的列表
|
||||||
|
/// 这个列表在中断上下文会使用到,因此需要irqsave
|
||||||
|
pub static ref NET_DEVICES: RwLock<BTreeMap<usize, Arc<dyn Iface>>> = RwLock::new(BTreeMap::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 目前,以下设计仍然没有考虑多网卡的listen问题,仅只解决了socket在绑定单网卡下的问题。
|
||||||
|
*/
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BoundInner {
|
||||||
|
handle: smoltcp::iface::SocketHandle,
|
||||||
|
iface: Arc<dyn Iface>,
|
||||||
|
// inner: Vec<(smoltcp::iface::SocketHandle, Arc<dyn Iface>)>
|
||||||
|
// address: smoltcp::wire::IpAddress,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BoundInner {
|
||||||
|
/// # `bind`
|
||||||
|
/// 将socket绑定到指定的地址上,置入指定的网络接口中
|
||||||
|
pub fn bind<T>(
|
||||||
|
socket: T,
|
||||||
|
// socket_type: Types,
|
||||||
|
address: &smoltcp::wire::IpAddress,
|
||||||
|
) -> Result<Self, SystemError>
|
||||||
|
where
|
||||||
|
T: smoltcp::socket::AnySocket<'static>,
|
||||||
|
{
|
||||||
|
if address.is_unspecified() {
|
||||||
|
// 强绑VirtualIO
|
||||||
|
let iface = NET_DEVICES
|
||||||
|
.read()
|
||||||
|
.iter()
|
||||||
|
.find_map(|(_, v)| {
|
||||||
|
if v.common().is_default_iface() {
|
||||||
|
Some(v.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.expect("No default interface");
|
||||||
|
|
||||||
|
let handle = iface.sockets().lock().add(socket);
|
||||||
|
Ok(Self { handle, iface })
|
||||||
|
} else {
|
||||||
|
let iface = get_iface_to_bind(address).ok_or(SystemError::ENODEV)?;
|
||||||
|
let handle = iface.sockets().lock().add(socket);
|
||||||
|
Ok(Self { handle, iface })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind_ephemeral<T>(
|
||||||
|
socket: T,
|
||||||
|
// socket_type: Types,
|
||||||
|
remote: smoltcp::wire::IpAddress,
|
||||||
|
) -> Result<(Self, smoltcp::wire::IpAddress), SystemError>
|
||||||
|
where
|
||||||
|
T: smoltcp::socket::AnySocket<'static>,
|
||||||
|
{
|
||||||
|
let (iface, address) = get_ephemeral_iface(&remote);
|
||||||
|
// let bound_port = iface.port_manager().bind_ephemeral_port(socket_type)?;
|
||||||
|
let handle = iface.sockets().lock().add(socket);
|
||||||
|
// let endpoint = smoltcp::wire::IpEndpoint::new(local_addr, bound_port);
|
||||||
|
Ok((Self { handle, iface }, address))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn port_manager(&self) -> &PortManager {
|
||||||
|
self.iface.port_manager()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_mut<T: smoltcp::socket::AnySocket<'static>, R, F: FnMut(&mut T) -> R>(
|
||||||
|
&self,
|
||||||
|
mut f: F,
|
||||||
|
) -> R {
|
||||||
|
f(self.iface.sockets().lock().get_mut::<T>(self.handle))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with<T: smoltcp::socket::AnySocket<'static>, R, F: Fn(&T) -> R>(&self, f: F) -> R {
|
||||||
|
f(self.iface.sockets().lock().get::<T>(self.handle))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iface(&self) -> &Arc<dyn Iface> {
|
||||||
|
&self.iface
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release(&self) {
|
||||||
|
self.iface.sockets().lock().remove(self.handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_iface_to_bind(ip_addr: &smoltcp::wire::IpAddress) -> Option<Arc<dyn Iface>> {
|
||||||
|
// log::debug!("get_iface_to_bind: {:?}", ip_addr);
|
||||||
|
// if ip_addr.is_unspecified()
|
||||||
|
NET_DEVICES
|
||||||
|
.read()
|
||||||
|
.iter()
|
||||||
|
.find(|(_, iface)| {
|
||||||
|
let guard = iface.smol_iface().lock();
|
||||||
|
// log::debug!("iface name: {}, ip: {:?}", iface.iface_name(), guard.ip_addrs());
|
||||||
|
guard.has_ip_addr(*ip_addr)
|
||||||
|
})
|
||||||
|
.map(|(_, iface)| iface.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a suitable iface to deal with sendto/connect request if the socket is not bound to an iface.
|
||||||
|
/// If the remote address is the same as that of some iface, we will use the iface.
|
||||||
|
/// Otherwise, we will use a default interface.
|
||||||
|
fn get_ephemeral_iface(
|
||||||
|
remote_ip_addr: &smoltcp::wire::IpAddress,
|
||||||
|
) -> (Arc<dyn Iface>, smoltcp::wire::IpAddress) {
|
||||||
|
get_iface_to_bind(remote_ip_addr)
|
||||||
|
.map(|iface| (iface, *remote_ip_addr))
|
||||||
|
.or({
|
||||||
|
let ifaces = NET_DEVICES.read();
|
||||||
|
ifaces.iter().find_map(|(_, iface)| {
|
||||||
|
iface
|
||||||
|
.smol_iface()
|
||||||
|
.lock()
|
||||||
|
.ip_addrs()
|
||||||
|
.iter()
|
||||||
|
.find(|cidr| cidr.contains_addr(remote_ip_addr))
|
||||||
|
.map(|cidr| (iface.clone(), cidr.address()))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.or({
|
||||||
|
NET_DEVICES.read().values().next().map(|iface| {
|
||||||
|
(
|
||||||
|
iface.clone(),
|
||||||
|
iface.smol_iface().lock().ip_addrs()[0].address(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.expect("No network interface")
|
||||||
|
}
|
121
src/socket/inet/common/port.rs
Normal file
121
src/socket/inet/common/port.rs
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
use hashbrown::HashMap;
|
||||||
|
use libc::rand;
|
||||||
|
use linux_errnos::Errno as SystemError;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
// arch::rand::rand,
|
||||||
|
libs::spinlock::SpinLock,
|
||||||
|
process::{Pid, ProcessManager},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::Types::{self, *};
|
||||||
|
|
||||||
|
/// # TCP 和 UDP 的端口管理器。
|
||||||
|
/// 如果 TCP/UDP 的 socket 绑定了某个端口,它会在对应的表中记录,以检测端口冲突。
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PortManager {
|
||||||
|
// TCP 端口记录表
|
||||||
|
tcp_port_table: SpinLock<HashMap<u16, Pid>>,
|
||||||
|
// UDP 端口记录表
|
||||||
|
udp_port_table: SpinLock<HashMap<u16, Pid>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PortManager {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PortManager {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
tcp_port_table: SpinLock::new(HashMap::new()),
|
||||||
|
udp_port_table: SpinLock::new(HashMap::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 自动分配一个相对应协议中未被使用的PORT,如果动态端口均已被占用,返回错误码 EADDRINUSE
|
||||||
|
pub fn get_ephemeral_port(&self, socket_type: Types) -> Result<u16, SystemError> {
|
||||||
|
// TODO: selects non-conflict high port
|
||||||
|
|
||||||
|
static mut EPHEMERAL_PORT: u16 = 0;
|
||||||
|
unsafe {
|
||||||
|
if EPHEMERAL_PORT == 0 {
|
||||||
|
EPHEMERAL_PORT = (49152 + rand() % (65536 - 49152)) as u16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut remaining = 65536 - 49152; // 剩余尝试分配端口次数
|
||||||
|
let mut port: u16;
|
||||||
|
while remaining > 0 {
|
||||||
|
unsafe {
|
||||||
|
if EPHEMERAL_PORT == 65535 {
|
||||||
|
EPHEMERAL_PORT = 49152;
|
||||||
|
} else {
|
||||||
|
EPHEMERAL_PORT += 1;
|
||||||
|
}
|
||||||
|
port = EPHEMERAL_PORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 ListenTable 检查端口是否被占用
|
||||||
|
let listen_table_guard = match socket_type {
|
||||||
|
Udp => self.udp_port_table.lock(),
|
||||||
|
Tcp => self.tcp_port_table.lock(),
|
||||||
|
_ => panic!("{:?} cann't get a port", socket_type),
|
||||||
|
};
|
||||||
|
if listen_table_guard.get(&port).is_none() {
|
||||||
|
drop(listen_table_guard);
|
||||||
|
return Ok(port);
|
||||||
|
}
|
||||||
|
remaining -= 1;
|
||||||
|
}
|
||||||
|
Err(SystemError::EADDRINUSE)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn bind_ephemeral_port(&self, socket_type: Types) -> Result<u16, SystemError> {
|
||||||
|
let port = self.get_ephemeral_port(socket_type)?;
|
||||||
|
self.bind_port(socket_type, port)?;
|
||||||
|
Ok(port)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 检测给定端口是否已被占用,如果未被占用则在 TCP/UDP 对应的表中记录
|
||||||
|
///
|
||||||
|
/// TODO: 增加支持端口复用的逻辑
|
||||||
|
pub fn bind_port(&self, socket_type: Types, port: u16) -> Result<(), SystemError> {
|
||||||
|
if port > 0 {
|
||||||
|
match socket_type {
|
||||||
|
Udp => {
|
||||||
|
let mut guard = self.udp_port_table.lock();
|
||||||
|
if guard.get(&port).is_some() {
|
||||||
|
return Err(SystemError::EADDRINUSE);
|
||||||
|
}
|
||||||
|
guard.insert(port, ProcessManager::current_pid());
|
||||||
|
}
|
||||||
|
Tcp => {
|
||||||
|
let mut guard = self.tcp_port_table.lock();
|
||||||
|
if guard.get(&port).is_some() {
|
||||||
|
return Err(SystemError::EADDRINUSE);
|
||||||
|
}
|
||||||
|
guard.insert(port, ProcessManager::current_pid());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 在对应的端口记录表中将端口和 socket 解绑
|
||||||
|
/// should call this function when socket is closed or aborted
|
||||||
|
pub fn unbind_port(&self, socket_type: Types, port: u16) {
|
||||||
|
match socket_type {
|
||||||
|
Udp => {
|
||||||
|
self.udp_port_table.lock().remove(&port);
|
||||||
|
}
|
||||||
|
Tcp => {
|
||||||
|
self.tcp_port_table.lock().remove(&port);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
167
src/socket/inet/datagram/inner.rs
Normal file
167
src/socket/inet/datagram/inner.rs
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
use linux_errnos::Errno as SystemError;
|
||||||
|
use smoltcp;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
libs::spinlock::SpinLock,
|
||||||
|
socket::inet::common::{BoundInner, Types as InetTypes},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub type SmolUdpSocket = smoltcp::socket::udp::Socket<'static>;
|
||||||
|
|
||||||
|
pub const DEFAULT_METADATA_BUF_SIZE: usize = 1024;
|
||||||
|
pub const DEFAULT_RX_BUF_SIZE: usize = 64 * 1024;
|
||||||
|
pub const DEFAULT_TX_BUF_SIZE: usize = 64 * 1024;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct UnboundUdp {
|
||||||
|
socket: SmolUdpSocket,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for UnboundUdp {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnboundUdp {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let rx_buffer = smoltcp::socket::udp::PacketBuffer::new(
|
||||||
|
vec![smoltcp::socket::udp::PacketMetadata::EMPTY; DEFAULT_METADATA_BUF_SIZE],
|
||||||
|
vec![0; DEFAULT_RX_BUF_SIZE],
|
||||||
|
);
|
||||||
|
let tx_buffer = smoltcp::socket::udp::PacketBuffer::new(
|
||||||
|
vec![smoltcp::socket::udp::PacketMetadata::EMPTY; DEFAULT_METADATA_BUF_SIZE],
|
||||||
|
vec![0; DEFAULT_TX_BUF_SIZE],
|
||||||
|
);
|
||||||
|
let socket = SmolUdpSocket::new(rx_buffer, tx_buffer);
|
||||||
|
|
||||||
|
Self { socket }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind(self, local_endpoint: smoltcp::wire::IpEndpoint) -> Result<BoundUdp, SystemError> {
|
||||||
|
let inner = BoundInner::bind(self.socket, &local_endpoint.addr)?;
|
||||||
|
let bind_addr = local_endpoint.addr;
|
||||||
|
let bind_port = if local_endpoint.port == 0 {
|
||||||
|
inner.port_manager().bind_ephemeral_port(InetTypes::Udp)?
|
||||||
|
} else {
|
||||||
|
inner
|
||||||
|
.port_manager()
|
||||||
|
.bind_port(InetTypes::Udp, local_endpoint.port)?;
|
||||||
|
local_endpoint.port
|
||||||
|
};
|
||||||
|
|
||||||
|
if bind_addr.is_unspecified() {
|
||||||
|
if inner
|
||||||
|
.with_mut::<smoltcp::socket::udp::Socket, _, _>(|socket| socket.bind(bind_port))
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
} else if inner
|
||||||
|
.with_mut::<smoltcp::socket::udp::Socket, _, _>(|socket| {
|
||||||
|
socket.bind(smoltcp::wire::IpEndpoint::new(bind_addr, bind_port))
|
||||||
|
})
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
Ok(BoundUdp {
|
||||||
|
inner,
|
||||||
|
remote: SpinLock::new(None),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind_ephemeral(self, remote: smoltcp::wire::IpAddress) -> Result<BoundUdp, SystemError> {
|
||||||
|
// let (addr, port) = (remote.addr, remote.port);
|
||||||
|
let (inner, address) = BoundInner::bind_ephemeral(self.socket, remote)?;
|
||||||
|
let bound_port = inner.port_manager().bind_ephemeral_port(InetTypes::Udp)?;
|
||||||
|
let endpoint = smoltcp::wire::IpEndpoint::new(address, bound_port);
|
||||||
|
Ok(BoundUdp {
|
||||||
|
inner,
|
||||||
|
remote: SpinLock::new(Some(endpoint)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BoundUdp {
|
||||||
|
inner: BoundInner,
|
||||||
|
remote: SpinLock<Option<smoltcp::wire::IpEndpoint>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BoundUdp {
|
||||||
|
pub fn with_mut_socket<F, T>(&self, f: F) -> T
|
||||||
|
where
|
||||||
|
F: FnMut(&mut SmolUdpSocket) -> T,
|
||||||
|
{
|
||||||
|
self.inner.with_mut(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_socket<F, T>(&self, f: F) -> T
|
||||||
|
where
|
||||||
|
F: Fn(&SmolUdpSocket) -> T,
|
||||||
|
{
|
||||||
|
self.inner.with(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn endpoint(&self) -> smoltcp::wire::IpListenEndpoint {
|
||||||
|
self.inner
|
||||||
|
.with::<SmolUdpSocket, _, _>(|socket| socket.endpoint())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn connect(&self, remote: smoltcp::wire::IpEndpoint) {
|
||||||
|
self.remote.lock().replace(remote);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn try_recv(
|
||||||
|
&self,
|
||||||
|
buf: &mut [u8],
|
||||||
|
) -> Result<(usize, smoltcp::wire::IpEndpoint), SystemError> {
|
||||||
|
self.with_mut_socket(|socket| {
|
||||||
|
if socket.can_recv() {
|
||||||
|
if let Ok((size, metadata)) = socket.recv_slice(buf) {
|
||||||
|
return Ok((size, metadata.endpoint));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(SystemError::EAGAIN)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_send(
|
||||||
|
&self,
|
||||||
|
buf: &[u8],
|
||||||
|
to: Option<smoltcp::wire::IpEndpoint>,
|
||||||
|
) -> Result<usize, SystemError> {
|
||||||
|
let remote = to.or(*self.remote.lock()).ok_or(SystemError::ENOTCONN)?;
|
||||||
|
|
||||||
|
self.with_mut_socket(|socket| {
|
||||||
|
if socket.can_send() && socket.send_slice(buf, remote).is_ok() {
|
||||||
|
log::debug!("send {} bytes", buf.len());
|
||||||
|
return Ok(buf.len());
|
||||||
|
}
|
||||||
|
Err(SystemError::ENOBUFS)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inner(&self) -> &BoundInner {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close(&self) {
|
||||||
|
self.inner
|
||||||
|
.iface()
|
||||||
|
.port_manager()
|
||||||
|
.unbind_port(InetTypes::Udp, self.endpoint().port);
|
||||||
|
self.with_mut_socket(|socket| {
|
||||||
|
socket.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Udp Inner 负责其内部资源管理
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum UdpInner {
|
||||||
|
Unbound(UnboundUdp),
|
||||||
|
Bound(BoundUdp),
|
||||||
|
}
|
306
src/socket/inet/datagram/mod.rs
Normal file
306
src/socket/inet/datagram/mod.rs
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
use inner::{UdpInner, UnboundUdp};
|
||||||
|
use linux_errnos::Errno as SystemError;
|
||||||
|
use smoltcp;
|
||||||
|
|
||||||
|
use crate::event_poll::EPollEventType;
|
||||||
|
use crate::libs::wait_queue::{wq_wait_event_interruptible, WaitQueue};
|
||||||
|
use crate::socket::{Socket, PMSG};
|
||||||
|
use crate::{libs::rwlock::RwLock, socket::endpoint::Endpoint};
|
||||||
|
use alloc::sync::{Arc, Weak};
|
||||||
|
use core::sync::atomic::AtomicBool;
|
||||||
|
|
||||||
|
use super::InetSocket;
|
||||||
|
|
||||||
|
pub mod inner;
|
||||||
|
|
||||||
|
type EP = EPollEventType;
|
||||||
|
|
||||||
|
// Udp Socket 负责提供状态切换接口、执行状态切换
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct UdpSocket {
|
||||||
|
inner: RwLock<Option<UdpInner>>,
|
||||||
|
nonblock: AtomicBool,
|
||||||
|
wait_queue: WaitQueue,
|
||||||
|
self_ref: Weak<UdpSocket>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UdpSocket {
|
||||||
|
pub fn new(nonblock: bool) -> Arc<Self> {
|
||||||
|
Arc::new_cyclic(|me| Self {
|
||||||
|
inner: RwLock::new(Some(UdpInner::Unbound(UnboundUdp::new()))),
|
||||||
|
nonblock: AtomicBool::new(nonblock),
|
||||||
|
wait_queue: WaitQueue::default(),
|
||||||
|
self_ref: me.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_nonblock(&self) -> bool {
|
||||||
|
self.nonblock.load(core::sync::atomic::Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_bind(&self, local_endpoint: smoltcp::wire::IpEndpoint) -> Result<(), SystemError> {
|
||||||
|
let mut inner = self.inner.write();
|
||||||
|
if let Some(UdpInner::Unbound(unbound)) = inner.take() {
|
||||||
|
let bound = unbound.bind(local_endpoint)?;
|
||||||
|
|
||||||
|
bound
|
||||||
|
.inner()
|
||||||
|
.iface()
|
||||||
|
.common()
|
||||||
|
.bind_socket(self.self_ref.upgrade().unwrap());
|
||||||
|
*inner = Some(UdpInner::Bound(bound));
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Err(SystemError::EINVAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind_emphemeral(&self, remote: smoltcp::wire::IpAddress) -> Result<(), SystemError> {
|
||||||
|
let mut inner_guard = self.inner.write();
|
||||||
|
let bound = match inner_guard.take().expect("Udp inner is None") {
|
||||||
|
UdpInner::Bound(inner) => inner,
|
||||||
|
UdpInner::Unbound(inner) => inner.bind_ephemeral(remote)?,
|
||||||
|
};
|
||||||
|
inner_guard.replace(UdpInner::Bound(bound));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_bound(&self) -> bool {
|
||||||
|
let inner = self.inner.read();
|
||||||
|
if let Some(UdpInner::Bound(_)) = &*inner {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close(&self) {
|
||||||
|
let mut inner = self.inner.write();
|
||||||
|
if let Some(UdpInner::Bound(bound)) = &mut *inner {
|
||||||
|
bound.close();
|
||||||
|
inner.take();
|
||||||
|
}
|
||||||
|
// unbound socket just drop (only need to free memory)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_recv(
|
||||||
|
&self,
|
||||||
|
buf: &mut [u8],
|
||||||
|
) -> Result<(usize, smoltcp::wire::IpEndpoint), SystemError> {
|
||||||
|
match self.inner.read().as_ref().expect("Udp Inner is None") {
|
||||||
|
UdpInner::Bound(bound) => {
|
||||||
|
let ret = bound.try_recv(buf);
|
||||||
|
bound.inner().iface().poll();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
_ => Err(SystemError::ENOTCONN),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn can_recv(&self) -> bool {
|
||||||
|
self.event().contains(EP::EPOLLIN)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn can_send(&self) -> bool {
|
||||||
|
self.event().contains(EP::EPOLLOUT)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_send(
|
||||||
|
&self,
|
||||||
|
buf: &[u8],
|
||||||
|
to: Option<smoltcp::wire::IpEndpoint>,
|
||||||
|
) -> Result<usize, SystemError> {
|
||||||
|
{
|
||||||
|
let mut inner_guard = self.inner.write();
|
||||||
|
let inner = match inner_guard.take().expect("Udp Inner is None") {
|
||||||
|
UdpInner::Bound(bound) => bound,
|
||||||
|
UdpInner::Unbound(unbound) => {
|
||||||
|
unbound.bind_ephemeral(to.ok_or(SystemError::EADDRNOTAVAIL)?.addr)?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// size = inner.try_send(buf, to)?;
|
||||||
|
inner_guard.replace(UdpInner::Bound(inner));
|
||||||
|
};
|
||||||
|
// Optimize: 拿两次锁的平均效率是否比一次长时间的读锁效率要高?
|
||||||
|
let result = match self.inner.read().as_ref().expect("Udp Inner is None") {
|
||||||
|
UdpInner::Bound(bound) => {
|
||||||
|
let ret = bound.try_send(buf, to);
|
||||||
|
bound.inner().iface().poll();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
_ => Err(SystemError::ENOTCONN),
|
||||||
|
};
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn event(&self) -> EPollEventType {
|
||||||
|
let mut event = EPollEventType::empty();
|
||||||
|
match self.inner.read().as_ref().unwrap() {
|
||||||
|
UdpInner::Unbound(_) => {
|
||||||
|
event.insert(EP::EPOLLOUT | EP::EPOLLWRNORM | EP::EPOLLWRBAND);
|
||||||
|
}
|
||||||
|
UdpInner::Bound(bound) => {
|
||||||
|
let (can_recv, can_send) =
|
||||||
|
bound.with_socket(|socket| (socket.can_recv(), socket.can_send()));
|
||||||
|
|
||||||
|
if can_recv {
|
||||||
|
event.insert(EP::EPOLLIN | EP::EPOLLRDNORM);
|
||||||
|
}
|
||||||
|
|
||||||
|
if can_send {
|
||||||
|
event.insert(EP::EPOLLOUT | EP::EPOLLWRNORM | EP::EPOLLWRBAND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Socket for UdpSocket {
|
||||||
|
fn wait_queue(&self) -> &WaitQueue {
|
||||||
|
&self.wait_queue
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll(&self) -> usize {
|
||||||
|
self.event().bits() as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind(&self, local_endpoint: Endpoint) -> Result<(), SystemError> {
|
||||||
|
if let Endpoint::Ip(local_endpoint) = local_endpoint {
|
||||||
|
return self.do_bind(local_endpoint);
|
||||||
|
}
|
||||||
|
Err(SystemError::EAFNOSUPPORT)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_buffer_size(&self) -> usize {
|
||||||
|
match self.inner.read().as_ref().unwrap() {
|
||||||
|
UdpInner::Bound(bound) => bound.with_socket(|socket| socket.payload_send_capacity()),
|
||||||
|
_ => inner::DEFAULT_TX_BUF_SIZE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recv_buffer_size(&self) -> usize {
|
||||||
|
match self.inner.read().as_ref().unwrap() {
|
||||||
|
UdpInner::Bound(bound) => bound.with_socket(|socket| socket.payload_recv_capacity()),
|
||||||
|
_ => inner::DEFAULT_RX_BUF_SIZE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn connect(&self, endpoint: Endpoint) -> Result<(), SystemError> {
|
||||||
|
if let Endpoint::Ip(remote) = endpoint {
|
||||||
|
if !self.is_bound() {
|
||||||
|
self.bind_emphemeral(remote.addr)?;
|
||||||
|
}
|
||||||
|
if let UdpInner::Bound(inner) = self.inner.read().as_ref().expect("UDP Inner disappear")
|
||||||
|
{
|
||||||
|
inner.connect(remote);
|
||||||
|
return Ok(());
|
||||||
|
} else {
|
||||||
|
panic!("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(SystemError::EAFNOSUPPORT)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send(&self, buffer: &[u8], flags: PMSG) -> Result<usize, SystemError> {
|
||||||
|
if flags.contains(PMSG::DONTWAIT) {
|
||||||
|
log::warn!("Nonblock send is not implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.try_send(buffer, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_to(&self, buffer: &[u8], flags: PMSG, address: Endpoint) -> Result<usize, SystemError> {
|
||||||
|
if flags.contains(PMSG::DONTWAIT) {
|
||||||
|
log::warn!("Nonblock send is not implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Endpoint::Ip(remote) = address {
|
||||||
|
return self.try_send(buffer, Some(remote));
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(SystemError::EINVAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recv(&self, buffer: &mut [u8], flags: PMSG) -> Result<usize, SystemError> {
|
||||||
|
if self.is_nonblock() || flags.contains(PMSG::DONTWAIT) {
|
||||||
|
self.try_recv(buffer)
|
||||||
|
} else {
|
||||||
|
loop {
|
||||||
|
match self.try_recv(buffer) {
|
||||||
|
Err(SystemError::EAGAIN) => {
|
||||||
|
wq_wait_event_interruptible(&self.wait_queue, || self.can_recv(), None)?;
|
||||||
|
}
|
||||||
|
result => break result,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.map(|(len, _)| len)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recv_from(
|
||||||
|
&self,
|
||||||
|
buffer: &mut [u8],
|
||||||
|
flags: PMSG,
|
||||||
|
address: Option<Endpoint>,
|
||||||
|
) -> Result<(usize, Endpoint), SystemError> {
|
||||||
|
// could block io
|
||||||
|
if let Some(endpoint) = address {
|
||||||
|
self.connect(endpoint)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.is_nonblock() || flags.contains(PMSG::DONTWAIT) {
|
||||||
|
self.try_recv(buffer)
|
||||||
|
} else {
|
||||||
|
loop {
|
||||||
|
match self.try_recv(buffer) {
|
||||||
|
Err(SystemError::EAGAIN) => {
|
||||||
|
wq_wait_event_interruptible(&self.wait_queue, || self.can_recv(), None)?;
|
||||||
|
log::debug!("UdpSocket::recv_from: wake up");
|
||||||
|
}
|
||||||
|
result => break result,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.map(|(len, remote)| (len, Endpoint::Ip(remote)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn close(&self) -> Result<(), SystemError> {
|
||||||
|
self.close();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InetSocket for UdpSocket {
|
||||||
|
fn on_iface_events(&self) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags::bitflags! {
|
||||||
|
pub struct UdpSocketOptions: u32 {
|
||||||
|
const ZERO = 0; /* No UDP options */
|
||||||
|
const UDP_CORK = 1; /* Never send partially complete segments */
|
||||||
|
const UDP_ENCAP = 100; /* Set the socket to accept encapsulated packets */
|
||||||
|
const UDP_NO_CHECK6_TX = 101; /* Disable sending checksum for UDP6X */
|
||||||
|
const UDP_NO_CHECK6_RX = 102; /* Disable accepting checksum for UDP6 */
|
||||||
|
const UDP_SEGMENT = 103; /* Set GSO segmentation size */
|
||||||
|
const UDP_GRO = 104; /* This socket can receive UDP GRO packets */
|
||||||
|
|
||||||
|
const UDPLITE_SEND_CSCOV = 10; /* sender partial coverage (as sent) */
|
||||||
|
const UDPLITE_RECV_CSCOV = 11; /* receiver partial coverage (threshold ) */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags::bitflags! {
|
||||||
|
pub struct UdpEncapTypes: u8 {
|
||||||
|
const ZERO = 0;
|
||||||
|
const ESPINUDP_NON_IKE = 1; // draft-ietf-ipsec-nat-t-ike-00/01
|
||||||
|
const ESPINUDP = 2; // draft-ietf-ipsec-udp-encaps-06
|
||||||
|
const L2TPINUDP = 3; // rfc2661
|
||||||
|
const GTP0 = 4; // GSM TS 09.60
|
||||||
|
const GTP1U = 5; // 3GPP TS 29.060
|
||||||
|
const RXRPC = 6;
|
||||||
|
const ESPINTCP = 7; // Yikes, this is really xfrm encap types.
|
||||||
|
}
|
||||||
|
}
|
40
src/socket/inet/mod.rs
Normal file
40
src/socket/inet/mod.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
use smoltcp;
|
||||||
|
|
||||||
|
// pub mod raw;
|
||||||
|
// pub mod icmp;
|
||||||
|
pub mod common;
|
||||||
|
pub mod datagram;
|
||||||
|
// pub mod stream;
|
||||||
|
pub mod posix;
|
||||||
|
pub mod syscall;
|
||||||
|
|
||||||
|
pub use common::BoundInner;
|
||||||
|
pub use common::Types;
|
||||||
|
// pub use raw::RawSocket;
|
||||||
|
pub use datagram::UdpSocket;
|
||||||
|
|
||||||
|
use smoltcp::wire::IpAddress;
|
||||||
|
use smoltcp::wire::IpEndpoint;
|
||||||
|
use smoltcp::wire::Ipv4Address;
|
||||||
|
// use smoltcp::wire::Ipv6Address;
|
||||||
|
|
||||||
|
// pub use stream::TcpSocket;
|
||||||
|
// pub use syscall::Inet;
|
||||||
|
|
||||||
|
use super::Socket;
|
||||||
|
|
||||||
|
/// A local endpoint, which indicates that the local endpoint is unspecified.
|
||||||
|
///
|
||||||
|
/// According to the Linux man pages and the Linux implementation, `getsockname()` will _not_ fail
|
||||||
|
/// even if the socket is unbound. Instead, it will return an unspecified socket address. This
|
||||||
|
/// unspecified endpoint helps with that.
|
||||||
|
const UNSPECIFIED_LOCAL_ENDPOINT_V4: IpEndpoint =
|
||||||
|
IpEndpoint::new(IpAddress::Ipv4(Ipv4Address::UNSPECIFIED), 0);
|
||||||
|
// const UNSPECIFIED_LOCAL_ENDPOINT_V6: IpEndpoint =
|
||||||
|
// IpEndpoint::new(IpAddress::Ipv6(Ipv6Address::UNSPECIFIED), 0);
|
||||||
|
|
||||||
|
pub trait InetSocket: Socket {
|
||||||
|
/// `on_iface_events`
|
||||||
|
/// 通知socket发生的事件
|
||||||
|
fn on_iface_events(&self);
|
||||||
|
}
|
2
src/socket/inet/posix/mod.rs
Normal file
2
src/socket/inet/posix/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod option;
|
||||||
|
pub mod proto;
|
67
src/socket/inet/posix/option.rs
Normal file
67
src/socket/inet/posix/option.rs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
bitflags::bitflags! {
|
||||||
|
pub struct IpOptions: u32 {
|
||||||
|
const IP_TOS = 1; // Type of service
|
||||||
|
const IP_TTL = 2; // Time to live
|
||||||
|
const IP_HDRINCL = 3; // Header compression
|
||||||
|
const IP_OPTIONS = 4; // IP options
|
||||||
|
const IP_ROUTER_ALERT = 5; // Router alert
|
||||||
|
const IP_RECVOPTS = 6; // Receive options
|
||||||
|
const IP_RETOPTS = 7; // Return options
|
||||||
|
const IP_PKTINFO = 8; // Packet information
|
||||||
|
const IP_PKTOPTIONS = 9; // Packet options
|
||||||
|
const IP_MTU_DISCOVER = 10; // MTU discovery
|
||||||
|
const IP_RECVERR = 11; // Receive errors
|
||||||
|
const IP_RECVTTL = 12; // Receive time to live
|
||||||
|
const IP_RECVTOS = 13; // Receive type of service
|
||||||
|
const IP_MTU = 14; // MTU
|
||||||
|
const IP_FREEBIND = 15; // Freebind
|
||||||
|
const IP_IPSEC_POLICY = 16; // IPsec policy
|
||||||
|
const IP_XFRM_POLICY = 17; // IPipsec transform policy
|
||||||
|
const IP_PASSSEC = 18; // Pass security
|
||||||
|
const IP_TRANSPARENT = 19; // Transparent
|
||||||
|
|
||||||
|
const IP_RECVRETOPTS = 20; // Receive return options (deprecated)
|
||||||
|
|
||||||
|
const IP_ORIGDSTADDR = 21; // Originate destination address (used by TProxy)
|
||||||
|
const IP_RECVORIGDSTADDR = 21; // Receive originate destination address
|
||||||
|
|
||||||
|
const IP_MINTTL = 22; // Minimum time to live
|
||||||
|
const IP_NODEFRAG = 23; // Don't fragment (used by TProxy)
|
||||||
|
const IP_CHECKSUM = 24; // Checksum offload (used by TProxy)
|
||||||
|
const IP_BIND_ADDRESS_NO_PORT = 25; // Bind to address without port (used by TProxy)
|
||||||
|
const IP_RECVFRAGSIZE = 26; // Receive fragment size
|
||||||
|
const IP_RECVERR_RFC4884 = 27; // Receive ICMPv6 error notifications
|
||||||
|
|
||||||
|
const IP_PMTUDISC_DONT = 28; // Don't send DF frames
|
||||||
|
const IP_PMTUDISC_DO = 29; // Always DF
|
||||||
|
const IP_PMTUDISC_PROBE = 30; // Ignore dst pmtu
|
||||||
|
const IP_PMTUDISC_INTERFACE = 31; // Always use interface mtu (ignores dst pmtu)
|
||||||
|
const IP_PMTUDISC_OMIT = 32; // Weaker version of IP_PMTUDISC_INTERFACE
|
||||||
|
|
||||||
|
const IP_MULTICAST_IF = 33; // Multicast interface
|
||||||
|
const IP_MULTICAST_TTL = 34; // Multicast time to live
|
||||||
|
const IP_MULTICAST_LOOP = 35; // Multicast loopback
|
||||||
|
const IP_ADD_MEMBERSHIP = 36; // Add multicast group membership
|
||||||
|
const IP_DROP_MEMBERSHIP = 37; // Drop multicast group membership
|
||||||
|
const IP_UNBLOCK_SOURCE = 38; // Unblock source
|
||||||
|
const IP_BLOCK_SOURCE = 39; // Block source
|
||||||
|
const IP_ADD_SOURCE_MEMBERSHIP = 40; // Add source multicast group membership
|
||||||
|
const IP_DROP_SOURCE_MEMBERSHIP = 41; // Drop source multicast group membership
|
||||||
|
const IP_MSFILTER = 42; // Multicast source filter
|
||||||
|
|
||||||
|
const MCAST_JOIN_GROUP = 43; // Join a multicast group
|
||||||
|
const MCAST_BLOCK_SOURCE = 44; // Block a multicast source
|
||||||
|
const MCAST_UNBLOCK_SOURCE = 45; // Unblock a multicast source
|
||||||
|
const MCAST_LEAVE_GROUP = 46; // Leave a multicast group
|
||||||
|
const MCAST_JOIN_SOURCE_GROUP = 47; // Join a multicast source group
|
||||||
|
const MCAST_LEAVE_SOURCE_GROUP = 48; // Leave a multicast source group
|
||||||
|
const MCAST_MSFILTER = 49; // Multicast source filter
|
||||||
|
|
||||||
|
const IP_MULTICAST_ALL = 50; // Multicast all
|
||||||
|
const IP_UNICAST_IF = 51; // Unicast interface
|
||||||
|
const IP_LOCAL_PORT_RANGE = 52; // Local port range
|
||||||
|
const IP_PROTOCOL = 53; // Protocol
|
||||||
|
|
||||||
|
// ... other flags ...
|
||||||
|
}
|
||||||
|
}
|
78
src/socket/inet/posix/proto.rs
Normal file
78
src/socket/inet/posix/proto.rs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
|
|
||||||
|
pub const SOL_SOCKET: u16 = 1;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, FromPrimitive, ToPrimitive, PartialEq, Eq)]
|
||||||
|
pub enum IPProtocol {
|
||||||
|
/// Dummy protocol for TCP.
|
||||||
|
IP = 0,
|
||||||
|
/// Internet Control Message Protocol.
|
||||||
|
ICMP = 1,
|
||||||
|
/// Internet Group Management Protocol.
|
||||||
|
IGMP = 2,
|
||||||
|
/// IPIP tunnels (older KA9Q tunnels use 94).
|
||||||
|
IPIP = 4,
|
||||||
|
/// Transmission Control Protocol.
|
||||||
|
TCP = 6,
|
||||||
|
/// Exterior Gateway Protocol.
|
||||||
|
EGP = 8,
|
||||||
|
/// PUP protocol.
|
||||||
|
PUP = 12,
|
||||||
|
/// User Datagram Protocol.
|
||||||
|
UDP = 17,
|
||||||
|
/// XNS IDP protocol.
|
||||||
|
IDP = 22,
|
||||||
|
/// SO Transport Protocol Class 4.
|
||||||
|
TP = 29,
|
||||||
|
/// Datagram Congestion Control Protocol.
|
||||||
|
DCCP = 33,
|
||||||
|
/// IPv6-in-IPv4 tunnelling.
|
||||||
|
IPv6 = 41,
|
||||||
|
/// RSVP Protocol.
|
||||||
|
RSVP = 46,
|
||||||
|
/// Generic Routing Encapsulation. (Cisco GRE) (rfc 1701, 1702)
|
||||||
|
GRE = 47,
|
||||||
|
/// Encapsulation Security Payload protocol
|
||||||
|
ESP = 50,
|
||||||
|
/// Authentication Header protocol
|
||||||
|
AH = 51,
|
||||||
|
/// Multicast Transport Protocol.
|
||||||
|
MTP = 92,
|
||||||
|
/// IP option pseudo header for BEET
|
||||||
|
BEETPH = 94,
|
||||||
|
/// Encapsulation Header.
|
||||||
|
ENCAP = 98,
|
||||||
|
/// Protocol Independent Multicast.
|
||||||
|
PIM = 103,
|
||||||
|
/// Compression Header Protocol.
|
||||||
|
COMP = 108,
|
||||||
|
/// Stream Control Transport Protocol
|
||||||
|
SCTP = 132,
|
||||||
|
/// UDP-Lite protocol (RFC 3828)
|
||||||
|
UDPLITE = 136,
|
||||||
|
/// MPLS in IP (RFC 4023)
|
||||||
|
MPLSINIP = 137,
|
||||||
|
/// Ethernet-within-IPv6 Encapsulation
|
||||||
|
ETHERNET = 143,
|
||||||
|
/// Raw IP packets
|
||||||
|
RAW = 255,
|
||||||
|
/// Multipath TCP connection
|
||||||
|
MPTCP = 262,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u16> for IPProtocol {
|
||||||
|
type Error = linux_errnos::Errno;
|
||||||
|
|
||||||
|
fn try_from(value: u16) -> Result<Self, Self::Error> {
|
||||||
|
match <Self as num_traits::FromPrimitive>::from_u16(value) {
|
||||||
|
Some(p) => Ok(p),
|
||||||
|
None => Err(Self::Error::EPROTONOSUPPORT),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<IPProtocol> for u16 {
|
||||||
|
fn from(value: IPProtocol) -> Self {
|
||||||
|
<IPProtocol as num_traits::ToPrimitive>::to_u16(&value).unwrap()
|
||||||
|
}
|
||||||
|
}
|
517
src/socket/inet/stream/inner.rs
Normal file
517
src/socket/inet/stream/inner.rs
Normal file
@ -0,0 +1,517 @@
|
|||||||
|
use core::sync::atomic::AtomicUsize;
|
||||||
|
|
||||||
|
use crate::libs::rwlock::RwLock;
|
||||||
|
// use crate::net::socket::EPollEventType;
|
||||||
|
use crate::socket::{self, inet::Types};
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use smoltcp;
|
||||||
|
use smoltcp::socket::tcp;
|
||||||
|
use linux_errnos::Errno as SystemError;
|
||||||
|
|
||||||
|
// pub const DEFAULT_METADATA_BUF_SIZE: usize = 1024;
|
||||||
|
pub const DEFAULT_RX_BUF_SIZE: usize = 512 * 1024;
|
||||||
|
pub const DEFAULT_TX_BUF_SIZE: usize = 512 * 1024;
|
||||||
|
|
||||||
|
fn new_smoltcp_socket() -> smoltcp::socket::tcp::Socket<'static> {
|
||||||
|
let rx_buffer = smoltcp::socket::tcp::SocketBuffer::new(vec![0; DEFAULT_RX_BUF_SIZE]);
|
||||||
|
let tx_buffer = smoltcp::socket::tcp::SocketBuffer::new(vec![0; DEFAULT_TX_BUF_SIZE]);
|
||||||
|
smoltcp::socket::tcp::Socket::new(rx_buffer, tx_buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_listen_smoltcp_socket<T>(local_endpoint: T) -> smoltcp::socket::tcp::Socket<'static>
|
||||||
|
where
|
||||||
|
T: Into<smoltcp::wire::IpListenEndpoint>,
|
||||||
|
{
|
||||||
|
let mut socket = new_smoltcp_socket();
|
||||||
|
socket.listen(local_endpoint).unwrap();
|
||||||
|
socket
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Init {
|
||||||
|
Unbound(
|
||||||
|
(
|
||||||
|
Box<smoltcp::socket::tcp::Socket<'static>>,
|
||||||
|
smoltcp::wire::IpVersion,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Bound((socket::inet::BoundInner, smoltcp::wire::IpEndpoint)),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Init {
|
||||||
|
pub(super) fn new(ver: smoltcp::wire::IpVersion) -> Self {
|
||||||
|
Init::Unbound((Box::new(new_smoltcp_socket()), ver))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 传入一个已经绑定的socket
|
||||||
|
pub(super) fn new_bound(inner: socket::inet::BoundInner) -> Self {
|
||||||
|
let endpoint = inner.with::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
|
||||||
|
socket
|
||||||
|
.local_endpoint()
|
||||||
|
.expect("A Bound Socket Must Have A Local Endpoint")
|
||||||
|
});
|
||||||
|
Init::Bound((inner, endpoint))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn bind(
|
||||||
|
self,
|
||||||
|
local_endpoint: smoltcp::wire::IpEndpoint,
|
||||||
|
) -> Result<Self, SystemError> {
|
||||||
|
match self {
|
||||||
|
Init::Unbound((socket, _)) => {
|
||||||
|
let bound = socket::inet::BoundInner::bind(*socket, &local_endpoint.addr)?;
|
||||||
|
bound
|
||||||
|
.port_manager()
|
||||||
|
.bind_port(Types::Tcp, local_endpoint.port)?;
|
||||||
|
// bound.iface().common().bind_socket()
|
||||||
|
Ok(Init::Bound((bound, local_endpoint)))
|
||||||
|
}
|
||||||
|
Init::Bound(_) => {
|
||||||
|
log::debug!("Already Bound");
|
||||||
|
Err(SystemError::EINVAL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn bind_to_ephemeral(
|
||||||
|
self,
|
||||||
|
remote_endpoint: smoltcp::wire::IpEndpoint,
|
||||||
|
) -> Result<(socket::inet::BoundInner, smoltcp::wire::IpEndpoint), (Self, SystemError)> {
|
||||||
|
match self {
|
||||||
|
Init::Unbound((socket, ver)) => {
|
||||||
|
let (bound, address) =
|
||||||
|
socket::inet::BoundInner::bind_ephemeral(*socket, remote_endpoint.addr)
|
||||||
|
.map_err(|err| (Self::new(ver), err))?;
|
||||||
|
let bound_port = bound
|
||||||
|
.port_manager()
|
||||||
|
.bind_ephemeral_port(Types::Tcp)
|
||||||
|
.map_err(|err| (Self::new(ver), err))?;
|
||||||
|
let endpoint = smoltcp::wire::IpEndpoint::new(address, bound_port);
|
||||||
|
Ok((bound, endpoint))
|
||||||
|
}
|
||||||
|
Init::Bound(_) => Err((self, SystemError::EINVAL)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn connect(
|
||||||
|
self,
|
||||||
|
remote_endpoint: smoltcp::wire::IpEndpoint,
|
||||||
|
) -> Result<Connecting, (Self, SystemError)> {
|
||||||
|
let (inner, local) = match self {
|
||||||
|
Init::Unbound(_) => self.bind_to_ephemeral(remote_endpoint)?,
|
||||||
|
Init::Bound(inner) => inner,
|
||||||
|
};
|
||||||
|
if local.addr.is_unspecified() {
|
||||||
|
return Err((Init::Bound((inner, local)), SystemError::EINVAL));
|
||||||
|
}
|
||||||
|
let result = inner.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
|
||||||
|
socket
|
||||||
|
.connect(
|
||||||
|
inner.iface().smol_iface().lock().context(),
|
||||||
|
remote_endpoint,
|
||||||
|
local,
|
||||||
|
)
|
||||||
|
.map_err(|_| SystemError::ECONNREFUSED)
|
||||||
|
});
|
||||||
|
match result {
|
||||||
|
Ok(_) => Ok(Connecting::new(inner)),
|
||||||
|
Err(err) => Err((Init::Bound((inner, local)), err)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # `listen`
|
||||||
|
pub(super) fn listen(self, backlog: usize) -> Result<Listening, (Self, SystemError)> {
|
||||||
|
let (inner, local) = match self {
|
||||||
|
Init::Unbound(_) => {
|
||||||
|
return Err((self, SystemError::EINVAL));
|
||||||
|
}
|
||||||
|
Init::Bound(inner) => inner,
|
||||||
|
};
|
||||||
|
let listen_addr = if local.addr.is_unspecified() {
|
||||||
|
smoltcp::wire::IpListenEndpoint::from(local.port)
|
||||||
|
} else {
|
||||||
|
smoltcp::wire::IpListenEndpoint::from(local)
|
||||||
|
};
|
||||||
|
log::debug!("listen at {:?}", listen_addr);
|
||||||
|
let mut inners = Vec::new();
|
||||||
|
if let Err(err) = || -> Result<(), SystemError> {
|
||||||
|
for _ in 0..(backlog - 1) {
|
||||||
|
// -1 because the first one is already bound
|
||||||
|
let new_listen = socket::inet::BoundInner::bind(
|
||||||
|
new_listen_smoltcp_socket(listen_addr),
|
||||||
|
listen_addr
|
||||||
|
.addr
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&smoltcp::wire::IpAddress::from(
|
||||||
|
smoltcp::wire::Ipv4Address::UNSPECIFIED,
|
||||||
|
)),
|
||||||
|
)?;
|
||||||
|
inners.push(new_listen);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}() {
|
||||||
|
return Err((Init::Bound((inner, local)), err));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(err) = inner.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
|
||||||
|
socket
|
||||||
|
.listen(listen_addr)
|
||||||
|
.map_err(|_| SystemError::ECONNREFUSED)
|
||||||
|
}) {
|
||||||
|
return Err((Init::Bound((inner, local)), err));
|
||||||
|
}
|
||||||
|
|
||||||
|
inners.push(inner);
|
||||||
|
return Ok(Listening {
|
||||||
|
inners,
|
||||||
|
connect: AtomicUsize::new(0),
|
||||||
|
listen_addr,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn close(&self) {
|
||||||
|
match self {
|
||||||
|
Init::Unbound(_) => {}
|
||||||
|
Init::Bound((inner, endpoint)) => {
|
||||||
|
inner.port_manager().unbind_port(Types::Tcp, endpoint.port);
|
||||||
|
inner.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| socket.close());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
|
enum ConnectResult {
|
||||||
|
Connected,
|
||||||
|
#[default]
|
||||||
|
Connecting,
|
||||||
|
Refused,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Connecting {
|
||||||
|
inner: socket::inet::BoundInner,
|
||||||
|
result: RwLock<ConnectResult>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Connecting {
|
||||||
|
fn new(inner: socket::inet::BoundInner) -> Self {
|
||||||
|
Connecting {
|
||||||
|
inner,
|
||||||
|
result: RwLock::new(ConnectResult::Connecting),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_mut<R, F: FnMut(&mut smoltcp::socket::tcp::Socket<'static>) -> R>(
|
||||||
|
&self,
|
||||||
|
f: F,
|
||||||
|
) -> R {
|
||||||
|
self.inner.with_mut(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_result(self) -> (Inner, Result<(), SystemError>) {
|
||||||
|
let result = *self.result.read();
|
||||||
|
match result {
|
||||||
|
ConnectResult::Connecting => (
|
||||||
|
Inner::Connecting(self),
|
||||||
|
Err(SystemError::EAGAIN_OR_EWOULDBLOCK),
|
||||||
|
),
|
||||||
|
ConnectResult::Connected => (
|
||||||
|
Inner::Established(Established { inner: self.inner }),
|
||||||
|
Ok(()),
|
||||||
|
),
|
||||||
|
ConnectResult::Refused => (
|
||||||
|
Inner::Init(Init::new_bound(self.inner)),
|
||||||
|
Err(SystemError::ECONNREFUSED),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn into_established(self) -> Established {
|
||||||
|
Established { inner: self.inner }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` when `conn_result` becomes ready, which indicates that the caller should
|
||||||
|
/// invoke the `into_result()` method as soon as possible.
|
||||||
|
///
|
||||||
|
/// Since `into_result()` needs to be called only once, this method will return `true`
|
||||||
|
/// _exactly_ once. The caller is responsible for not missing this event.
|
||||||
|
#[must_use]
|
||||||
|
pub(super) fn update_io_events(&self) -> bool {
|
||||||
|
// if matches!(*self.result.read_irqsave(), ConnectResult::Connecting) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
self.inner
|
||||||
|
.with_mut(|socket: &mut smoltcp::socket::tcp::Socket| {
|
||||||
|
let mut result = self.result.write();
|
||||||
|
if matches!(*result, ConnectResult::Refused | ConnectResult::Connected) {
|
||||||
|
return false; // Already connected or refused
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connected
|
||||||
|
if socket.can_send() {
|
||||||
|
log::debug!("can send");
|
||||||
|
*result = ConnectResult::Connected;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Connecting
|
||||||
|
if socket.is_open() {
|
||||||
|
log::debug!("connecting");
|
||||||
|
*result = ConnectResult::Connecting;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Refused
|
||||||
|
*result = ConnectResult::Refused;
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_name(&self) -> smoltcp::wire::IpEndpoint {
|
||||||
|
self.inner
|
||||||
|
.with::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
|
||||||
|
socket
|
||||||
|
.local_endpoint()
|
||||||
|
.expect("A Connecting Tcp With No Local Endpoint")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_peer_name(&self) -> smoltcp::wire::IpEndpoint {
|
||||||
|
self.inner
|
||||||
|
.with::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
|
||||||
|
socket
|
||||||
|
.remote_endpoint()
|
||||||
|
.expect("A Connecting Tcp With No Remote Endpoint")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Listening {
|
||||||
|
inners: Vec<socket::inet::BoundInner>,
|
||||||
|
connect: AtomicUsize,
|
||||||
|
listen_addr: smoltcp::wire::IpListenEndpoint,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Listening {
|
||||||
|
pub fn accept(&mut self) -> Result<(Established, smoltcp::wire::IpEndpoint), SystemError> {
|
||||||
|
let connected: &mut socket::inet::BoundInner = self
|
||||||
|
.inners
|
||||||
|
.get_mut(self.connect.load(core::sync::atomic::Ordering::Relaxed))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if connected.with::<smoltcp::socket::tcp::Socket, _, _>(|socket| !socket.is_active()) {
|
||||||
|
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
let remote_endpoint = connected.with::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
|
||||||
|
socket
|
||||||
|
.remote_endpoint()
|
||||||
|
.expect("A Connected Tcp With No Remote Endpoint")
|
||||||
|
});
|
||||||
|
|
||||||
|
// log::debug!("local at {:?}", local_endpoint);
|
||||||
|
|
||||||
|
let mut new_listen = socket::inet::BoundInner::bind(
|
||||||
|
new_listen_smoltcp_socket(self.listen_addr),
|
||||||
|
self.listen_addr
|
||||||
|
.addr
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&smoltcp::wire::IpAddress::from(
|
||||||
|
smoltcp::wire::Ipv4Address::UNSPECIFIED,
|
||||||
|
)),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// swap the connected socket with the new_listen socket
|
||||||
|
// TODO is smoltcp socket swappable?
|
||||||
|
core::mem::swap(&mut new_listen, connected);
|
||||||
|
|
||||||
|
return Ok((Established { inner: new_listen }, remote_endpoint));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_io_events(&self, pollee: &AtomicUsize) {
|
||||||
|
let position = self.inners.iter().position(|inner| {
|
||||||
|
inner.with::<smoltcp::socket::tcp::Socket, _, _>(|socket| socket.is_active())
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(position) = position {
|
||||||
|
self.connect
|
||||||
|
.store(position, core::sync::atomic::Ordering::Relaxed);
|
||||||
|
pollee.fetch_or(
|
||||||
|
EPollEventType::EPOLLIN.bits() as usize,
|
||||||
|
core::sync::atomic::Ordering::Relaxed,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
pollee.fetch_and(
|
||||||
|
!EPollEventType::EPOLLIN.bits() as usize,
|
||||||
|
core::sync::atomic::Ordering::Relaxed,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_name(&self) -> smoltcp::wire::IpEndpoint {
|
||||||
|
smoltcp::wire::IpEndpoint::new(
|
||||||
|
self.listen_addr
|
||||||
|
.addr
|
||||||
|
.unwrap_or(smoltcp::wire::IpAddress::from(
|
||||||
|
smoltcp::wire::Ipv4Address::UNSPECIFIED,
|
||||||
|
)),
|
||||||
|
self.listen_addr.port,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close(&self) {
|
||||||
|
// log::debug!("Close Listening Socket");
|
||||||
|
let port = self.get_name().port;
|
||||||
|
for inner in self.inners.iter() {
|
||||||
|
inner.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| socket.close());
|
||||||
|
}
|
||||||
|
self.inners[0]
|
||||||
|
.iface()
|
||||||
|
.port_manager()
|
||||||
|
.unbind_port(Types::Tcp, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release(&self) {
|
||||||
|
// log::debug!("Release Listening Socket");
|
||||||
|
for inner in self.inners.iter() {
|
||||||
|
inner.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Established {
|
||||||
|
inner: socket::inet::BoundInner,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Established {
|
||||||
|
pub fn with_mut<R, F: FnMut(&mut smoltcp::socket::tcp::Socket<'static>) -> R>(
|
||||||
|
&self,
|
||||||
|
f: F,
|
||||||
|
) -> R {
|
||||||
|
self.inner.with_mut(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close(&self) {
|
||||||
|
self.inner
|
||||||
|
.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| socket.close());
|
||||||
|
self.inner.iface().poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release(&self) {
|
||||||
|
self.inner.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_name(&self) -> smoltcp::wire::IpEndpoint {
|
||||||
|
self.inner
|
||||||
|
.with::<smoltcp::socket::tcp::Socket, _, _>(|socket| socket.local_endpoint())
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_peer_name(&self) -> smoltcp::wire::IpEndpoint {
|
||||||
|
self.inner
|
||||||
|
.with::<smoltcp::socket::tcp::Socket, _, _>(|socket| socket.remote_endpoint().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recv_slice(&self, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||||
|
self.inner
|
||||||
|
.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
|
||||||
|
if socket.can_send() {
|
||||||
|
match socket.recv_slice(buf) {
|
||||||
|
Ok(size) => Ok(size),
|
||||||
|
Err(tcp::RecvError::InvalidState) => {
|
||||||
|
log::error!("TcpSocket::try_recv: InvalidState");
|
||||||
|
Err(SystemError::ENOTCONN)
|
||||||
|
}
|
||||||
|
Err(tcp::RecvError::Finished) => Ok(0),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(SystemError::ENOBUFS)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_slice(&self, buf: &[u8]) -> Result<usize, SystemError> {
|
||||||
|
self.inner
|
||||||
|
.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
|
||||||
|
if socket.can_send() {
|
||||||
|
socket
|
||||||
|
.send_slice(buf)
|
||||||
|
.map_err(|_| SystemError::ECONNABORTED)
|
||||||
|
} else {
|
||||||
|
Err(SystemError::ENOBUFS)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_io_events(&self, pollee: &AtomicUsize) {
|
||||||
|
self.inner
|
||||||
|
.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
|
||||||
|
if socket.can_send() {
|
||||||
|
pollee.fetch_or(
|
||||||
|
EPollEventType::EPOLLOUT.bits() as usize,
|
||||||
|
core::sync::atomic::Ordering::Relaxed,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
pollee.fetch_and(
|
||||||
|
!EPollEventType::EPOLLOUT.bits() as usize,
|
||||||
|
core::sync::atomic::Ordering::Relaxed,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if socket.can_recv() {
|
||||||
|
pollee.fetch_or(
|
||||||
|
EPollEventType::EPOLLIN.bits() as usize,
|
||||||
|
core::sync::atomic::Ordering::Relaxed,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
pollee.fetch_and(
|
||||||
|
!EPollEventType::EPOLLIN.bits() as usize,
|
||||||
|
core::sync::atomic::Ordering::Relaxed,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Inner {
|
||||||
|
Init(Init),
|
||||||
|
Connecting(Connecting),
|
||||||
|
Listening(Listening),
|
||||||
|
Established(Established),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Inner {
|
||||||
|
pub fn send_buffer_size(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
Inner::Init(_) => DEFAULT_TX_BUF_SIZE,
|
||||||
|
Inner::Connecting(conn) => conn.with_mut(|socket| socket.send_capacity()),
|
||||||
|
// only the first socket in the list is used for sending
|
||||||
|
Inner::Listening(listen) => listen.inners[0]
|
||||||
|
.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| socket.send_capacity()),
|
||||||
|
Inner::Established(est) => est.with_mut(|socket| socket.send_capacity()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recv_buffer_size(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
Inner::Init(_) => DEFAULT_RX_BUF_SIZE,
|
||||||
|
Inner::Connecting(conn) => conn.with_mut(|socket| socket.recv_capacity()),
|
||||||
|
// only the first socket in the list is used for receiving
|
||||||
|
Inner::Listening(listen) => listen.inners[0]
|
||||||
|
.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| socket.recv_capacity()),
|
||||||
|
Inner::Established(est) => est.with_mut(|socket| socket.recv_capacity()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iface(&self) -> Option<&alloc::sync::Arc<dyn crate::interface::Iface>> {
|
||||||
|
match self {
|
||||||
|
Inner::Init(_) => None,
|
||||||
|
Inner::Connecting(conn) => Some(conn.inner.iface()),
|
||||||
|
Inner::Listening(listen) => Some(listen.inners[0].iface()),
|
||||||
|
Inner::Established(est) => Some(est.inner.iface()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
507
src/socket/inet/stream/mod.rs
Normal file
507
src/socket/inet/stream/mod.rs
Normal file
@ -0,0 +1,507 @@
|
|||||||
|
use alloc::sync::{Arc, Weak};
|
||||||
|
use core::sync::atomic::{AtomicBool, AtomicUsize};
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
|
use crate::libs::wait_queue::WaitQueue;
|
||||||
|
// use crate::event_poll::EPollEventType;
|
||||||
|
use crate::socket::common::shutdown::{ShutdownBit, ShutdownTemp};
|
||||||
|
use crate::socket::endpoint::Endpoint;
|
||||||
|
use crate::socket::{Socket, PMSG, PSOL};
|
||||||
|
// use crate::sched::SchedMode;
|
||||||
|
use crate::{libs::rwlock::RwLock, net::socket::common::shutdown::Shutdown};
|
||||||
|
use smoltcp;
|
||||||
|
|
||||||
|
mod inner;
|
||||||
|
|
||||||
|
mod option;
|
||||||
|
pub use option::Options as TcpOption;
|
||||||
|
|
||||||
|
use super::{InetSocket, UNSPECIFIED_LOCAL_ENDPOINT_V4};
|
||||||
|
|
||||||
|
type EP = EPollEventType;
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TcpSocket {
|
||||||
|
inner: RwLock<Option<inner::Inner>>,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
shutdown: Shutdown, // TODO set shutdown status
|
||||||
|
nonblock: AtomicBool,
|
||||||
|
wait_queue: WaitQueue,
|
||||||
|
self_ref: Weak<Self>,
|
||||||
|
pollee: AtomicUsize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TcpSocket {
|
||||||
|
pub fn new(_nonblock: bool, ver: smoltcp::wire::IpVersion) -> Arc<Self> {
|
||||||
|
Arc::new_cyclic(|me| Self {
|
||||||
|
inner: RwLock::new(Some(inner::Inner::Init(inner::Init::new(ver)))),
|
||||||
|
shutdown: Shutdown::new(),
|
||||||
|
nonblock: AtomicBool::new(false),
|
||||||
|
wait_queue: WaitQueue::default(),
|
||||||
|
self_ref: me.clone(),
|
||||||
|
pollee: AtomicUsize::new(0_usize),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_established(inner: inner::Established, nonblock: bool) -> Arc<Self> {
|
||||||
|
Arc::new_cyclic(|me| Self {
|
||||||
|
inner: RwLock::new(Some(inner::Inner::Established(inner))),
|
||||||
|
shutdown: Shutdown::new(),
|
||||||
|
nonblock: AtomicBool::new(nonblock),
|
||||||
|
wait_queue: WaitQueue::default(),
|
||||||
|
self_ref: me.clone(),
|
||||||
|
pollee: AtomicUsize::new((EP::EPOLLIN.bits() | EP::EPOLLOUT.bits()) as usize),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_nonblock(&self) -> bool {
|
||||||
|
self.nonblock.load(core::sync::atomic::Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_bind(&self, local_endpoint: smoltcp::wire::IpEndpoint) -> Result<(), SystemError> {
|
||||||
|
let mut writer = self.inner.write();
|
||||||
|
match writer.take().expect("Tcp inner::Inner is None") {
|
||||||
|
inner::Inner::Init(inner) => {
|
||||||
|
let bound = inner.bind(local_endpoint)?;
|
||||||
|
if let inner::Init::Bound((ref bound, _)) = bound {
|
||||||
|
bound
|
||||||
|
.iface()
|
||||||
|
.common()
|
||||||
|
.bind_socket(self.self_ref.upgrade().unwrap());
|
||||||
|
}
|
||||||
|
writer.replace(inner::Inner::Init(bound));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
any => {
|
||||||
|
writer.replace(any);
|
||||||
|
log::error!("TcpSocket::do_bind: not Init");
|
||||||
|
Err(SystemError::EINVAL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_listen(&self, backlog: usize) -> Result<(), SystemError> {
|
||||||
|
let mut writer = self.inner.write();
|
||||||
|
let inner = writer.take().expect("Tcp inner::Inner is None");
|
||||||
|
let (listening, err) = match inner {
|
||||||
|
inner::Inner::Init(init) => {
|
||||||
|
let listen_result = init.listen(backlog);
|
||||||
|
match listen_result {
|
||||||
|
Ok(listening) => (inner::Inner::Listening(listening), None),
|
||||||
|
Err((init, err)) => (inner::Inner::Init(init), Some(err)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (inner, Some(SystemError::EINVAL)),
|
||||||
|
};
|
||||||
|
writer.replace(listening);
|
||||||
|
drop(writer);
|
||||||
|
|
||||||
|
if let Some(err) = err {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_accept(&self) -> Result<(Arc<TcpSocket>, smoltcp::wire::IpEndpoint), SystemError> {
|
||||||
|
match self
|
||||||
|
.inner
|
||||||
|
.write()
|
||||||
|
.as_mut()
|
||||||
|
.expect("Tcp inner::Inner is None")
|
||||||
|
{
|
||||||
|
inner::Inner::Listening(listening) => listening.accept().map(|(stream, remote)| {
|
||||||
|
(
|
||||||
|
TcpSocket::new_established(stream, self.is_nonblock()),
|
||||||
|
remote,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
_ => Err(SystemError::EINVAL),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHOULD refactor
|
||||||
|
pub fn start_connect(
|
||||||
|
&self,
|
||||||
|
remote_endpoint: smoltcp::wire::IpEndpoint,
|
||||||
|
) -> Result<(), SystemError> {
|
||||||
|
let mut writer = self.inner.write();
|
||||||
|
let inner = writer.take().expect("Tcp inner::Inner is None");
|
||||||
|
let (init, result) = match inner {
|
||||||
|
inner::Inner::Init(init) => {
|
||||||
|
let conn_result = init.connect(remote_endpoint);
|
||||||
|
match conn_result {
|
||||||
|
Ok(connecting) => (
|
||||||
|
inner::Inner::Connecting(connecting),
|
||||||
|
if !self.is_nonblock() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(SystemError::EINPROGRESS)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Err((init, err)) => (inner::Inner::Init(init), Err(err)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inner::Inner::Connecting(connecting) if self.is_nonblock() => (
|
||||||
|
inner::Inner::Connecting(connecting),
|
||||||
|
Err(SystemError::EALREADY),
|
||||||
|
),
|
||||||
|
inner::Inner::Connecting(connecting) => (inner::Inner::Connecting(connecting), Ok(())),
|
||||||
|
inner::Inner::Listening(inner) => {
|
||||||
|
(inner::Inner::Listening(inner), Err(SystemError::EISCONN))
|
||||||
|
}
|
||||||
|
inner::Inner::Established(inner) => {
|
||||||
|
(inner::Inner::Established(inner), Err(SystemError::EISCONN))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(()) | Err(SystemError::EINPROGRESS) => {
|
||||||
|
init.iface().unwrap().poll();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.replace(init);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for irq use
|
||||||
|
pub fn finish_connect(&self) -> Result<(), SystemError> {
|
||||||
|
let mut writer = self.inner.write();
|
||||||
|
let inner::Inner::Connecting(conn) = writer.take().expect("Tcp inner::Inner is None")
|
||||||
|
else {
|
||||||
|
log::error!("TcpSocket::finish_connect: not Connecting");
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
};
|
||||||
|
|
||||||
|
let (inner, result) = conn.into_result();
|
||||||
|
writer.replace(inner);
|
||||||
|
drop(writer);
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_connect(&self) -> Result<(), SystemError> {
|
||||||
|
self.update_events();
|
||||||
|
let mut write_state = self.inner.write();
|
||||||
|
let inner = write_state.take().expect("Tcp inner::Inner is None");
|
||||||
|
let (replace, result) = match inner {
|
||||||
|
inner::Inner::Connecting(conn) => conn.into_result(),
|
||||||
|
inner::Inner::Established(es) => {
|
||||||
|
log::warn!("TODO: check new established");
|
||||||
|
(inner::Inner::Established(es), Ok(()))
|
||||||
|
} // TODO check established
|
||||||
|
_ => {
|
||||||
|
log::warn!("TODO: connecting socket error options");
|
||||||
|
(inner, Err(SystemError::EINVAL))
|
||||||
|
} // TODO socket error options
|
||||||
|
};
|
||||||
|
write_state.replace(replace);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_recv(&self, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||||
|
self.inner
|
||||||
|
.read()
|
||||||
|
.as_ref()
|
||||||
|
.map(|inner| {
|
||||||
|
inner.iface().unwrap().poll();
|
||||||
|
let result = match inner {
|
||||||
|
inner::Inner::Established(inner) => inner.recv_slice(buf),
|
||||||
|
_ => Err(SystemError::EINVAL),
|
||||||
|
};
|
||||||
|
inner.iface().unwrap().poll();
|
||||||
|
result
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_send(&self, buf: &[u8]) -> Result<usize, SystemError> {
|
||||||
|
// TODO: add nonblock check of connecting socket
|
||||||
|
let sent = match self
|
||||||
|
.inner
|
||||||
|
.read()
|
||||||
|
.as_ref()
|
||||||
|
.expect("Tcp inner::Inner is None")
|
||||||
|
{
|
||||||
|
inner::Inner::Established(inner) => inner.send_slice(buf),
|
||||||
|
_ => Err(SystemError::EINVAL),
|
||||||
|
};
|
||||||
|
self.inner.read().as_ref().unwrap().iface().unwrap().poll();
|
||||||
|
sent
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_events(&self) -> bool {
|
||||||
|
match self
|
||||||
|
.inner
|
||||||
|
.read()
|
||||||
|
.as_ref()
|
||||||
|
.expect("Tcp inner::Inner is None")
|
||||||
|
{
|
||||||
|
inner::Inner::Init(_) => false,
|
||||||
|
inner::Inner::Connecting(connecting) => connecting.update_io_events(),
|
||||||
|
inner::Inner::Established(established) => {
|
||||||
|
established.update_io_events(&self.pollee);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
inner::Inner::Listening(listening) => {
|
||||||
|
listening.update_io_events(&self.pollee);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn incoming(&self) -> bool {
|
||||||
|
EP::from_bits_truncate(self.poll() as u32).contains(EP::EPOLLIN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Socket for TcpSocket {
|
||||||
|
fn wait_queue(&self) -> &WaitQueue {
|
||||||
|
&self.wait_queue
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_name(&self) -> Result<Endpoint, SystemError> {
|
||||||
|
match self
|
||||||
|
.inner
|
||||||
|
.read()
|
||||||
|
.as_ref()
|
||||||
|
.expect("Tcp inner::Inner is None")
|
||||||
|
{
|
||||||
|
inner::Inner::Init(inner::Init::Unbound((_, ver))) => Ok(Endpoint::Ip(match ver {
|
||||||
|
smoltcp::wire::IpVersion::Ipv4 => UNSPECIFIED_LOCAL_ENDPOINT_V4,
|
||||||
|
// smoltcp::wire::IpVersion::Ipv6 => UNSPECIFIED_LOCAL_ENDPOINT_V6,
|
||||||
|
})),
|
||||||
|
inner::Inner::Init(inner::Init::Bound((_, local))) => Ok(Endpoint::Ip(*local)),
|
||||||
|
inner::Inner::Connecting(connecting) => Ok(Endpoint::Ip(connecting.get_name())),
|
||||||
|
inner::Inner::Established(established) => Ok(Endpoint::Ip(established.get_name())),
|
||||||
|
inner::Inner::Listening(listening) => Ok(Endpoint::Ip(listening.get_name())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_peer_name(&self) -> Result<Endpoint, SystemError> {
|
||||||
|
match self
|
||||||
|
.inner
|
||||||
|
.read()
|
||||||
|
.as_ref()
|
||||||
|
.expect("Tcp inner::Inner is None")
|
||||||
|
{
|
||||||
|
inner::Inner::Init(_) => Err(SystemError::ENOTCONN),
|
||||||
|
inner::Inner::Connecting(connecting) => Ok(Endpoint::Ip(connecting.get_peer_name())),
|
||||||
|
inner::Inner::Established(established) => Ok(Endpoint::Ip(established.get_peer_name())),
|
||||||
|
inner::Inner::Listening(_) => Err(SystemError::ENOTCONN),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind(&self, endpoint: Endpoint) -> Result<(), SystemError> {
|
||||||
|
if let Endpoint::Ip(addr) = endpoint {
|
||||||
|
return self.do_bind(addr);
|
||||||
|
}
|
||||||
|
log::debug!("TcpSocket::bind: invalid endpoint");
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn connect(&self, endpoint: Endpoint) -> Result<(), SystemError> {
|
||||||
|
let Endpoint::Ip(endpoint) = endpoint else {
|
||||||
|
log::debug!("TcpSocket::connect: invalid endpoint");
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
};
|
||||||
|
self.start_connect(endpoint)?; // Only Nonblock or error will return error.
|
||||||
|
|
||||||
|
return loop {
|
||||||
|
match self.check_connect() {
|
||||||
|
Err(SystemError::EAGAIN_OR_EWOULDBLOCK) => {}
|
||||||
|
result => break result,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll(&self) -> usize {
|
||||||
|
self.pollee.load(core::sync::atomic::Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn listen(&self, backlog: usize) -> Result<(), SystemError> {
|
||||||
|
self.do_listen(backlog)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accept(&self) -> Result<(Arc<SocketInode>, Endpoint), SystemError> {
|
||||||
|
if self.is_nonblock() {
|
||||||
|
self.try_accept()
|
||||||
|
} else {
|
||||||
|
loop {
|
||||||
|
match self.try_accept() {
|
||||||
|
Err(SystemError::EAGAIN_OR_EWOULDBLOCK) => {
|
||||||
|
wq_wait_event_interruptible!(self.wait_queue, self.incoming(), {})?;
|
||||||
|
}
|
||||||
|
result => break result,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.map(|(inner, endpoint)| (SocketInode::new(inner), Endpoint::Ip(endpoint)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recv(&self, buffer: &mut [u8], _flags: PMSG) -> Result<usize, SystemError> {
|
||||||
|
self.try_recv(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send(&self, buffer: &[u8], _flags: PMSG) -> Result<usize, SystemError> {
|
||||||
|
self.try_send(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_buffer_size(&self) -> usize {
|
||||||
|
self.inner
|
||||||
|
.read()
|
||||||
|
.as_ref()
|
||||||
|
.expect("Tcp inner::Inner is None")
|
||||||
|
.send_buffer_size()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recv_buffer_size(&self) -> usize {
|
||||||
|
self.inner
|
||||||
|
.read()
|
||||||
|
.as_ref()
|
||||||
|
.expect("Tcp inner::Inner is None")
|
||||||
|
.recv_buffer_size()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shutdown(&self, how: ShutdownTemp) -> Result<(), SystemError> {
|
||||||
|
let self_shutdown = self.shutdown.get().bits();
|
||||||
|
let diff = how.bits().difference(self_shutdown);
|
||||||
|
match diff.is_empty() {
|
||||||
|
true => return Ok(()),
|
||||||
|
false => {
|
||||||
|
if diff.contains(ShutdownBit::SHUT_RD) {
|
||||||
|
self.shutdown.recv_shutdown();
|
||||||
|
// TODO 协议栈处理
|
||||||
|
}
|
||||||
|
if diff.contains(ShutdownBit::SHUT_WR) {
|
||||||
|
self.shutdown.send_shutdown();
|
||||||
|
// TODO 协议栈处理
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn close(&self) -> Result<(), SystemError> {
|
||||||
|
let Some(inner) = self.inner.write().take() else {
|
||||||
|
log::warn!("TcpSocket::close: already closed, unexpected");
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
if let Some(iface) = inner.iface() {
|
||||||
|
iface
|
||||||
|
.common()
|
||||||
|
.unbind_socket(self.self_ref.upgrade().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
match inner {
|
||||||
|
// complete connecting socket close logic
|
||||||
|
inner::Inner::Connecting(conn) => {
|
||||||
|
let conn = unsafe { conn.into_established() };
|
||||||
|
conn.close();
|
||||||
|
conn.release();
|
||||||
|
}
|
||||||
|
inner::Inner::Established(es) => {
|
||||||
|
es.close();
|
||||||
|
es.release();
|
||||||
|
}
|
||||||
|
inner::Inner::Listening(ls) => {
|
||||||
|
ls.close();
|
||||||
|
ls.release();
|
||||||
|
}
|
||||||
|
inner::Inner::Init(init) => {
|
||||||
|
init.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_option(&self, level: PSOL, name: usize, val: &[u8]) -> Result<(), SystemError> {
|
||||||
|
if level != PSOL::TCP {
|
||||||
|
// return Err(SystemError::EINVAL);
|
||||||
|
log::debug!("TcpSocket::set_option: not TCP");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
use option::Options::{self, *};
|
||||||
|
let option_name = Options::try_from(name as i32)?;
|
||||||
|
log::debug!("TCP Option: {:?}, value = {:?}", option_name, val);
|
||||||
|
match option_name {
|
||||||
|
NoDelay => {
|
||||||
|
let nagle_enabled = val[0] != 0;
|
||||||
|
let mut writer = self.inner.write();
|
||||||
|
let inner = writer.take().expect("Tcp inner::Inner is None");
|
||||||
|
match inner {
|
||||||
|
inner::Inner::Established(established) => {
|
||||||
|
established.with_mut(|socket| {
|
||||||
|
socket.set_nagle_enabled(nagle_enabled);
|
||||||
|
});
|
||||||
|
writer.replace(inner::Inner::Established(established));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
writer.replace(inner);
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeepIntvl => {
|
||||||
|
if val.len() == 4 {
|
||||||
|
let mut writer = self.inner.write();
|
||||||
|
let inner = writer.take().expect("Tcp inner::Inner is None");
|
||||||
|
match inner {
|
||||||
|
inner::Inner::Established(established) => {
|
||||||
|
let interval = u32::from_ne_bytes([val[0], val[1], val[2], val[3]]);
|
||||||
|
established.with_mut(|socket| {
|
||||||
|
socket.set_keep_alive(Some(smoltcp::time::Duration::from_secs(
|
||||||
|
interval as u64,
|
||||||
|
)));
|
||||||
|
});
|
||||||
|
writer.replace(inner::Inner::Established(established));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
writer.replace(inner);
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeepCnt => {
|
||||||
|
// if val.len() == 4 {
|
||||||
|
// let mut writer = self.inner.write();
|
||||||
|
// let inner = writer.take().expect("Tcp inner::Inner is None");
|
||||||
|
// match inner {
|
||||||
|
// inner::Inner::Established(established) => {
|
||||||
|
// let count = u32::from_ne_bytes([val[0], val[1], val[2], val[3]]);
|
||||||
|
// established.with_mut(|socket| {
|
||||||
|
// socket.set_keep_alive_count(count);
|
||||||
|
// });
|
||||||
|
// writer.replace(inner::Inner::Established(established));
|
||||||
|
// }
|
||||||
|
// _ => {
|
||||||
|
// writer.replace(inner);
|
||||||
|
// return Err(SystemError::EINVAL);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// return Err(SystemError::EINVAL);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
KeepIdle => {}
|
||||||
|
_ => {
|
||||||
|
log::debug!("TcpSocket::set_option: not supported");
|
||||||
|
// return Err(ENOPROTOOPT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InetSocket for TcpSocket {
|
||||||
|
fn on_iface_events(&self) {
|
||||||
|
if self.update_events() {
|
||||||
|
let _result = self.finish_connect();
|
||||||
|
// set error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
94
src/socket/inet/stream/option.rs
Normal file
94
src/socket/inet/stream/option.rs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
use linux_errnos::Errno;
|
||||||
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
||||||
|
pub enum Options {
|
||||||
|
/// Turn off Nagle's algorithm.
|
||||||
|
NoDelay = 1,
|
||||||
|
/// Limit MSS.
|
||||||
|
MaxSegment = 2,
|
||||||
|
/// Never send partially complete segments.
|
||||||
|
Cork = 3,
|
||||||
|
/// Start keeplives after this period.
|
||||||
|
KeepIdle = 4,
|
||||||
|
/// Interval between keepalives.
|
||||||
|
KeepIntvl = 5,
|
||||||
|
/// Number of keepalives before death.
|
||||||
|
KeepCnt = 6,
|
||||||
|
/// Number of SYN retransmits.
|
||||||
|
Syncnt = 7,
|
||||||
|
/// Lifetime for orphaned FIN-WAIT-2 state.
|
||||||
|
Linger2 = 8,
|
||||||
|
/// Wake up listener only when data arrive.
|
||||||
|
DeferAccept = 9,
|
||||||
|
/// Bound advertised window
|
||||||
|
WindowClamp = 10,
|
||||||
|
/// Information about this connection.
|
||||||
|
Info = 11,
|
||||||
|
/// Block/reenable quick acks.
|
||||||
|
QuickAck = 12,
|
||||||
|
/// Congestion control algorithm.
|
||||||
|
Congestion = 13,
|
||||||
|
/// TCP MD5 Signature (RFC2385).
|
||||||
|
Md5Sig = 14,
|
||||||
|
/// Use linear timeouts for thin streams
|
||||||
|
ThinLinearTimeouts = 16,
|
||||||
|
/// Fast retrans. after 1 dupack.
|
||||||
|
ThinDupack = 17,
|
||||||
|
/// How long for loss retry before timeout.
|
||||||
|
UserTimeout = 18,
|
||||||
|
/// TCP sock is under repair right now.
|
||||||
|
Repair = 19,
|
||||||
|
RepairQueue = 20,
|
||||||
|
QueueSeq = 21,
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
|
RepairOptions = 22,
|
||||||
|
/// Enable FastOpen on listeners
|
||||||
|
FastOpen = 23,
|
||||||
|
Timestamp = 24,
|
||||||
|
/// Limit number of unsent bytes in write queue.
|
||||||
|
NotSentLowat = 25,
|
||||||
|
/// Get Congestion Control (optional) info.
|
||||||
|
CCInfo = 26,
|
||||||
|
/// Record SYN headers for new connections.
|
||||||
|
SaveSyn = 27,
|
||||||
|
/// Get SYN headers recorded for connection.
|
||||||
|
SavedSyn = 28,
|
||||||
|
/// Get/set window parameters.
|
||||||
|
RepairWindow = 29,
|
||||||
|
/// Attempt FastOpen with connect.
|
||||||
|
FastOpenConnect = 30,
|
||||||
|
/// Attach a ULP to a TCP connection.
|
||||||
|
ULP = 31,
|
||||||
|
/// TCP MD5 Signature with extensions.
|
||||||
|
Md5SigExt = 32,
|
||||||
|
/// Set the key for Fast Open(cookie).
|
||||||
|
FastOpenKey = 33,
|
||||||
|
/// Enable TFO without a TFO cookie.
|
||||||
|
FastOpenNoCookie = 34,
|
||||||
|
ZeroCopyReceive = 35,
|
||||||
|
/// Notify bytes available to read as a cmsg on read.
|
||||||
|
/// 与TCP_CM_INQ相同
|
||||||
|
INQ = 36,
|
||||||
|
/// delay outgoing packets by XX usec
|
||||||
|
TxDelay = 37,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<i32> for Options {
|
||||||
|
type Error = Errno;
|
||||||
|
|
||||||
|
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||||||
|
use num_traits::FromPrimitive;
|
||||||
|
match <Self as FromPrimitive>::from_i32(value) {
|
||||||
|
Some(p) => Ok(p),
|
||||||
|
None => Err(Self::Error::EINVAL),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Options> for i32 {
|
||||||
|
fn from(val: Options) -> Self {
|
||||||
|
use num_traits::ToPrimitive;
|
||||||
|
<Options as ToPrimitive>::to_i32(&val).unwrap()
|
||||||
|
}
|
||||||
|
}
|
67
src/socket/inet/syscall.rs
Normal file
67
src/socket/inet/syscall.rs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
use alloc::sync::Arc;
|
||||||
|
use linux_errnos::Errno as SystemError;
|
||||||
|
use smoltcp::{self, wire::IpProtocol};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
posix::SOCK,
|
||||||
|
socket::{
|
||||||
|
inet::UdpSocket,
|
||||||
|
Family,
|
||||||
|
Socket, // SocketInode,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
fn create_inet_socket(
|
||||||
|
version: smoltcp::wire::IpVersion,
|
||||||
|
socket_type: SOCK,
|
||||||
|
protocol: smoltcp::wire::IpProtocol,
|
||||||
|
) -> Result<Arc<dyn Socket>, SystemError> {
|
||||||
|
// log::debug!("type: {:?}, protocol: {:?}", socket_type, protocol);
|
||||||
|
match socket_type {
|
||||||
|
SOCK::Datagram => match protocol {
|
||||||
|
IpProtocol::HopByHop | IpProtocol::Udp => {
|
||||||
|
Ok(UdpSocket::new(false))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Err(SystemError::EPROTONOSUPPORT)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// SOCK::Stream => match protocol {
|
||||||
|
// IpProtocol::HopByHop | IpProtocol::Tcp => {
|
||||||
|
// log::debug!("create tcp socket");
|
||||||
|
// return Ok(TcpSocket::new(false, version));
|
||||||
|
// }
|
||||||
|
// _ => {
|
||||||
|
// return Err(SystemError::EPROTONOSUPPORT);
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
SOCK::Raw => {
|
||||||
|
todo!("raw")
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Err(SystemError::EPROTONOSUPPORT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Inet;
|
||||||
|
impl Family for Inet {
|
||||||
|
fn socket(stype: SOCK, protocol: u32) -> Result<Arc<dyn Socket>, SystemError> {
|
||||||
|
create_inet_socket(
|
||||||
|
smoltcp::wire::IpVersion::Ipv4,
|
||||||
|
stype,
|
||||||
|
smoltcp::wire::IpProtocol::from(protocol as u8),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub struct Inet6;
|
||||||
|
// impl Family for Inet6 {
|
||||||
|
// fn socket(stype: PSOCK, protocol: u32) -> Result<Arc<dyn Socket>, SystemError> {
|
||||||
|
// create_inet_socket(
|
||||||
|
// smoltcp::wire::IpVersion::Ipv6,
|
||||||
|
// stype,
|
||||||
|
// smoltcp::wire::IpProtocol::from(protocol as u8),
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
148
src/socket/mod.rs
Normal file
148
src/socket/mod.rs
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
pub mod common;
|
||||||
|
pub mod endpoint;
|
||||||
|
pub mod inet;
|
||||||
|
|
||||||
|
use crate::{libs::wait_queue::WaitQueue, posix::SOCK};
|
||||||
|
use core::any::Any;
|
||||||
|
use core::fmt::Debug;
|
||||||
|
use linux_errnos::Errno as SystemError;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
posix::{PMSG, PSOL},
|
||||||
|
// SocketInode,
|
||||||
|
};
|
||||||
|
use common::shutdown::ShutdownTemp;
|
||||||
|
use endpoint::Endpoint;
|
||||||
|
|
||||||
|
/// # `Socket` methods
|
||||||
|
/// ## Reference
|
||||||
|
/// - [Posix standard](https://pubs.opengroup.org/onlinepubs/9699919799/)
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
pub trait Socket: Sync + Send + Debug + Any {
|
||||||
|
/// # `wait_queue`
|
||||||
|
/// 获取socket的wait queue
|
||||||
|
fn wait_queue(&self) -> &WaitQueue;
|
||||||
|
/// # `socket_poll`
|
||||||
|
/// 获取socket的事件。
|
||||||
|
fn poll(&self) -> usize;
|
||||||
|
|
||||||
|
fn send_buffer_size(&self) -> usize;
|
||||||
|
fn recv_buffer_size(&self) -> usize;
|
||||||
|
// /// # `accept`
|
||||||
|
// /// 接受连接,仅用于listening stream socket
|
||||||
|
// /// ## Block
|
||||||
|
// /// 如果没有连接到来,会阻塞
|
||||||
|
// fn accept(&self) -> Result<(Arc<SocketInode>, Endpoint), SystemError> {
|
||||||
|
// Err(SystemError::ENOSYS)
|
||||||
|
// }
|
||||||
|
/// # `bind`
|
||||||
|
/// 对应于POSIX的bind函数,用于绑定到本机指定的端点
|
||||||
|
fn bind(&self, endpoint: Endpoint) -> Result<(), SystemError> {
|
||||||
|
Err(SystemError::ENOSYS)
|
||||||
|
}
|
||||||
|
/// # `close`
|
||||||
|
/// 关闭socket
|
||||||
|
fn close(&self) -> Result<(), SystemError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
/// # `connect`
|
||||||
|
/// 对应于POSIX的connect函数,用于连接到指定的远程服务器端点
|
||||||
|
fn connect(&self, endpoint: Endpoint) -> Result<(), SystemError> {
|
||||||
|
Err(SystemError::ENOSYS)
|
||||||
|
}
|
||||||
|
// fnctl
|
||||||
|
// freeaddrinfo
|
||||||
|
// getaddrinfo
|
||||||
|
// getnameinfo
|
||||||
|
/// # `get_peer_name`
|
||||||
|
/// 获取对端的地址
|
||||||
|
fn get_peer_name(&self) -> Result<Endpoint, SystemError> {
|
||||||
|
Err(SystemError::ENOSYS)
|
||||||
|
}
|
||||||
|
/// # `get_name`
|
||||||
|
/// 获取socket的地址
|
||||||
|
fn get_name(&self) -> Result<Endpoint, SystemError> {
|
||||||
|
Err(SystemError::ENOSYS)
|
||||||
|
}
|
||||||
|
/// # `get_option`
|
||||||
|
/// 对应于 Posix `getsockopt` ,获取socket选项
|
||||||
|
fn get_option(&self, level: PSOL, name: usize, value: &mut [u8]) -> Result<usize, SystemError> {
|
||||||
|
log::warn!("getsockopt is not implemented");
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
/// # `listen`
|
||||||
|
/// 监听socket,仅用于stream socket
|
||||||
|
fn listen(&self, backlog: usize) -> Result<(), SystemError> {
|
||||||
|
Err(SystemError::ENOSYS)
|
||||||
|
}
|
||||||
|
// poll
|
||||||
|
// pselect
|
||||||
|
/// # `read`
|
||||||
|
fn read(&self, buffer: &mut [u8]) -> Result<usize, SystemError> {
|
||||||
|
self.recv(buffer, PMSG::empty())
|
||||||
|
}
|
||||||
|
/// # `recv`
|
||||||
|
/// 接收数据,`read` = `recv` with flags = 0
|
||||||
|
fn recv(&self, buffer: &mut [u8], flags: PMSG) -> Result<usize, SystemError> {
|
||||||
|
Err(SystemError::ENOSYS)
|
||||||
|
}
|
||||||
|
/// # `recv_from`
|
||||||
|
fn recv_from(
|
||||||
|
&self,
|
||||||
|
buffer: &mut [u8],
|
||||||
|
flags: PMSG,
|
||||||
|
address: Option<Endpoint>,
|
||||||
|
) -> Result<(usize, Endpoint), SystemError> {
|
||||||
|
Err(SystemError::ENOSYS)
|
||||||
|
}
|
||||||
|
// /// # `recv_msg`
|
||||||
|
// fn recv_msg(&self, msg: &mut MsgHdr, flags: PMSG) -> Result<usize, SystemError> {
|
||||||
|
// Err(SystemError::ENOSYS)
|
||||||
|
// }
|
||||||
|
// select
|
||||||
|
/// # `send`
|
||||||
|
fn send(&self, buffer: &[u8], flags: PMSG) -> Result<usize, SystemError> {
|
||||||
|
Err(SystemError::ENOSYS)
|
||||||
|
}
|
||||||
|
// /// # `send_msg`
|
||||||
|
// fn send_msg(&self, msg: &MsgHdr, flags: PMSG) -> Result<usize, SystemError> {
|
||||||
|
// Err(SystemError::ENOSYS)
|
||||||
|
// }
|
||||||
|
/// # `send_to`
|
||||||
|
fn send_to(&self, buffer: &[u8], flags: PMSG, address: Endpoint) -> Result<usize, SystemError> {
|
||||||
|
Err(SystemError::ENOSYS)
|
||||||
|
}
|
||||||
|
/// # `set_option`
|
||||||
|
/// Posix `setsockopt` ,设置socket选项
|
||||||
|
/// ## Parameters
|
||||||
|
/// - level 选项的层次
|
||||||
|
/// - name 选项的名称
|
||||||
|
/// - value 选项的值
|
||||||
|
/// ## Reference
|
||||||
|
/// https://code.dragonos.org.cn/s?refs=sk_setsockopt&project=linux-6.6.21
|
||||||
|
fn set_option(&self, level: PSOL, name: usize, val: &[u8]) -> Result<(), SystemError> {
|
||||||
|
log::warn!("setsockopt is not implemented");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
/// # `shutdown`
|
||||||
|
fn shutdown(&self, how: ShutdownTemp) -> Result<(), SystemError> {
|
||||||
|
// TODO 构建shutdown系统调用
|
||||||
|
// set shutdown bit
|
||||||
|
Err(SystemError::ENOSYS)
|
||||||
|
}
|
||||||
|
// sockatmark
|
||||||
|
// socket
|
||||||
|
// socketpair
|
||||||
|
/// # `write`
|
||||||
|
fn write(&self, buffer: &[u8]) -> Result<usize, SystemError> {
|
||||||
|
self.send(buffer, PMSG::empty())
|
||||||
|
}
|
||||||
|
// fn write_buffer(&self, _buf: &[u8]) -> Result<usize, SystemError> {
|
||||||
|
// todo!()
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Family {
|
||||||
|
fn socket(stype: SOCK, protocol: u32) -> Result<Arc<dyn Socket>, SystemError>;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user