├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md └── ustunet ├── Cargo.toml ├── examples ├── echo.rs ├── rend_.rs └── rendezvous.rs └── src ├── dispatch ├── mod.rs ├── mod1.rs ├── poll_queue.rs ├── sendbuf.rs └── shutdown.rs ├── lib.rs ├── listener.rs ├── sockets └── mod.rs ├── stream ├── internal.rs └── mod.rs ├── time.rs └── util.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | *.pcap 3 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "aho-corasick" 5 | version = "0.7.10" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" 8 | dependencies = [ 9 | "memchr", 10 | ] 11 | 12 | [[package]] 13 | name = "ansi_term" 14 | version = "0.11.0" 15 | source = "registry+https://github.com/rust-lang/crates.io-index" 16 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 17 | dependencies = [ 18 | "winapi", 19 | ] 20 | 21 | [[package]] 22 | name = "argh" 23 | version = "0.1.3" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | checksum = "ca1877e24cecacd700d469066e0160c4f8497cc5635367163f50c8beec820154" 26 | dependencies = [ 27 | "argh_derive", 28 | "argh_shared", 29 | ] 30 | 31 | [[package]] 32 | name = "argh_derive" 33 | version = "0.1.1" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "e742194e0f43fc932bcb801708c2b279d3ec8f527e3acda05a6a9f342c5ef764" 36 | dependencies = [ 37 | "argh_shared", 38 | "heck", 39 | "proc-macro2", 40 | "quote", 41 | "syn", 42 | ] 43 | 44 | [[package]] 45 | name = "argh_shared" 46 | version = "0.1.1" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "e1ba68f4276a778591e36a0c348a269888f3a177c8d2054969389e3b59611ff5" 49 | 50 | [[package]] 51 | name = "atty" 52 | version = "0.2.14" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 55 | dependencies = [ 56 | "hermit-abi", 57 | "libc", 58 | "winapi", 59 | ] 60 | 61 | [[package]] 62 | name = "autocfg" 63 | version = "1.0.0" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" 66 | 67 | [[package]] 68 | name = "backtrace" 69 | version = "0.3.46" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e" 72 | dependencies = [ 73 | "backtrace-sys", 74 | "cfg-if 0.1.10", 75 | "libc", 76 | "rustc-demangle", 77 | ] 78 | 79 | [[package]] 80 | name = "backtrace-sys" 81 | version = "0.1.36" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "78848718ee1255a2485d1309ad9cdecfc2e7d0362dd11c6829364c6b35ae1bc7" 84 | dependencies = [ 85 | "cc", 86 | "libc", 87 | ] 88 | 89 | [[package]] 90 | name = "bitflags" 91 | version = "1.2.1" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 94 | 95 | [[package]] 96 | name = "byteorder" 97 | version = "1.3.4" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" 100 | 101 | [[package]] 102 | name = "bytes" 103 | version = "1.0.1" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" 106 | 107 | [[package]] 108 | name = "cc" 109 | version = "1.0.52" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "c3d87b23d6a92cd03af510a5ade527033f6aa6fa92161e2d5863a907d4c5e31d" 112 | 113 | [[package]] 114 | name = "cfg-if" 115 | version = "0.1.10" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 118 | 119 | [[package]] 120 | name = "cfg-if" 121 | version = "1.0.0" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 124 | 125 | [[package]] 126 | name = "chrono" 127 | version = "0.4.11" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" 130 | dependencies = [ 131 | "num-integer", 132 | "num-traits", 133 | "time", 134 | ] 135 | 136 | [[package]] 137 | name = "doc-comment" 138 | version = "0.3.3" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" 141 | 142 | [[package]] 143 | name = "env_logger" 144 | version = "0.7.1" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" 147 | dependencies = [ 148 | "atty", 149 | "humantime", 150 | "log 0.4.8", 151 | "regex", 152 | "termcolor", 153 | ] 154 | 155 | [[package]] 156 | name = "error-chain" 157 | version = "0.11.0" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" 160 | dependencies = [ 161 | "backtrace", 162 | ] 163 | 164 | [[package]] 165 | name = "futures" 166 | version = "0.3.4" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780" 169 | dependencies = [ 170 | "futures-channel", 171 | "futures-core", 172 | "futures-executor", 173 | "futures-io", 174 | "futures-sink", 175 | "futures-task", 176 | "futures-util", 177 | ] 178 | 179 | [[package]] 180 | name = "futures-channel" 181 | version = "0.3.4" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8" 184 | dependencies = [ 185 | "futures-core", 186 | "futures-sink", 187 | ] 188 | 189 | [[package]] 190 | name = "futures-core" 191 | version = "0.3.4" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a" 194 | 195 | [[package]] 196 | name = "futures-executor" 197 | version = "0.3.4" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba" 200 | dependencies = [ 201 | "futures-core", 202 | "futures-task", 203 | "futures-util", 204 | ] 205 | 206 | [[package]] 207 | name = "futures-io" 208 | version = "0.3.4" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6" 211 | 212 | [[package]] 213 | name = "futures-macro" 214 | version = "0.3.4" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7" 217 | dependencies = [ 218 | "proc-macro-hack", 219 | "proc-macro2", 220 | "quote", 221 | "syn", 222 | ] 223 | 224 | [[package]] 225 | name = "futures-sink" 226 | version = "0.3.4" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6" 229 | 230 | [[package]] 231 | name = "futures-task" 232 | version = "0.3.4" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" 235 | 236 | [[package]] 237 | name = "futures-util" 238 | version = "0.3.4" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" 241 | dependencies = [ 242 | "futures-channel", 243 | "futures-core", 244 | "futures-io", 245 | "futures-macro", 246 | "futures-sink", 247 | "futures-task", 248 | "memchr", 249 | "pin-utils", 250 | "proc-macro-hack", 251 | "proc-macro-nested", 252 | "slab", 253 | ] 254 | 255 | [[package]] 256 | name = "heck" 257 | version = "0.3.1" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" 260 | dependencies = [ 261 | "unicode-segmentation", 262 | ] 263 | 264 | [[package]] 265 | name = "hermit-abi" 266 | version = "0.1.12" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4" 269 | dependencies = [ 270 | "libc", 271 | ] 272 | 273 | [[package]] 274 | name = "humantime" 275 | version = "1.3.0" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" 278 | dependencies = [ 279 | "quick-error", 280 | ] 281 | 282 | [[package]] 283 | name = "ioctl-sys" 284 | version = "0.5.2" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "5e2c4b26352496eaaa8ca7cfa9bd99e93419d3f7983dc6e99c2a35fe9e33504a" 287 | 288 | [[package]] 289 | name = "itoa" 290 | version = "0.4.5" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" 293 | 294 | [[package]] 295 | name = "lazy_static" 296 | version = "1.4.0" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 299 | 300 | [[package]] 301 | name = "libc" 302 | version = "0.2.84" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff" 305 | 306 | [[package]] 307 | name = "log" 308 | version = "0.3.9" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" 311 | dependencies = [ 312 | "log 0.4.8", 313 | ] 314 | 315 | [[package]] 316 | name = "log" 317 | version = "0.4.8" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 320 | dependencies = [ 321 | "cfg-if 0.1.10", 322 | ] 323 | 324 | [[package]] 325 | name = "managed" 326 | version = "0.7.1" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6" 329 | 330 | [[package]] 331 | name = "matchers" 332 | version = "0.0.1" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" 335 | dependencies = [ 336 | "regex-automata", 337 | ] 338 | 339 | [[package]] 340 | name = "memchr" 341 | version = "2.3.3" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" 344 | 345 | [[package]] 346 | name = "mio" 347 | version = "0.7.7" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7" 350 | dependencies = [ 351 | "libc", 352 | "log 0.4.8", 353 | "miow", 354 | "ntapi", 355 | "winapi", 356 | ] 357 | 358 | [[package]] 359 | name = "miow" 360 | version = "0.3.6" 361 | source = "registry+https://github.com/rust-lang/crates.io-index" 362 | checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" 363 | dependencies = [ 364 | "socket2", 365 | "winapi", 366 | ] 367 | 368 | [[package]] 369 | name = "ntapi" 370 | version = "0.3.6" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" 373 | dependencies = [ 374 | "winapi", 375 | ] 376 | 377 | [[package]] 378 | name = "num-integer" 379 | version = "0.1.42" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" 382 | dependencies = [ 383 | "autocfg", 384 | "num-traits", 385 | ] 386 | 387 | [[package]] 388 | name = "num-traits" 389 | version = "0.2.11" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" 392 | dependencies = [ 393 | "autocfg", 394 | ] 395 | 396 | [[package]] 397 | name = "num_cpus" 398 | version = "1.13.0" 399 | source = "registry+https://github.com/rust-lang/crates.io-index" 400 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 401 | dependencies = [ 402 | "hermit-abi", 403 | "libc", 404 | ] 405 | 406 | [[package]] 407 | name = "once_cell" 408 | version = "1.5.2" 409 | source = "registry+https://github.com/rust-lang/crates.io-index" 410 | checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" 411 | 412 | [[package]] 413 | name = "pin-project" 414 | version = "0.4.9" 415 | source = "registry+https://github.com/rust-lang/crates.io-index" 416 | checksum = "6f6a7f5eee6292c559c793430c55c00aea9d3b3d1905e855806ca4d7253426a2" 417 | dependencies = [ 418 | "pin-project-internal", 419 | ] 420 | 421 | [[package]] 422 | name = "pin-project-internal" 423 | version = "0.4.9" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "8988430ce790d8682672117bc06dda364c0be32d3abd738234f19f3240bad99a" 426 | dependencies = [ 427 | "proc-macro2", 428 | "quote", 429 | "syn", 430 | ] 431 | 432 | [[package]] 433 | name = "pin-project-lite" 434 | version = "0.2.4" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" 437 | 438 | [[package]] 439 | name = "pin-utils" 440 | version = "0.1.0" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 443 | 444 | [[package]] 445 | name = "pretty_env_logger" 446 | version = "0.4.0" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" 449 | dependencies = [ 450 | "env_logger", 451 | "log 0.4.8", 452 | ] 453 | 454 | [[package]] 455 | name = "proc-macro-hack" 456 | version = "0.5.15" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63" 459 | 460 | [[package]] 461 | name = "proc-macro-nested" 462 | version = "0.1.4" 463 | source = "registry+https://github.com/rust-lang/crates.io-index" 464 | checksum = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" 465 | 466 | [[package]] 467 | name = "proc-macro2" 468 | version = "1.0.10" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" 471 | dependencies = [ 472 | "unicode-xid", 473 | ] 474 | 475 | [[package]] 476 | name = "quick-error" 477 | version = "1.2.3" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 480 | 481 | [[package]] 482 | name = "quote" 483 | version = "1.0.3" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" 486 | dependencies = [ 487 | "proc-macro2", 488 | ] 489 | 490 | [[package]] 491 | name = "regex" 492 | version = "1.3.7" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | checksum = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692" 495 | dependencies = [ 496 | "aho-corasick", 497 | "memchr", 498 | "regex-syntax", 499 | "thread_local", 500 | ] 501 | 502 | [[package]] 503 | name = "regex-automata" 504 | version = "0.1.9" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" 507 | dependencies = [ 508 | "byteorder", 509 | "regex-syntax", 510 | ] 511 | 512 | [[package]] 513 | name = "regex-syntax" 514 | version = "0.6.17" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" 517 | 518 | [[package]] 519 | name = "rustc-demangle" 520 | version = "0.1.16" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" 523 | 524 | [[package]] 525 | name = "ryu" 526 | version = "1.0.4" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1" 529 | 530 | [[package]] 531 | name = "serde" 532 | version = "1.0.106" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" 535 | 536 | [[package]] 537 | name = "serde_json" 538 | version = "1.0.52" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "a7894c8ed05b7a3a279aeb79025fdec1d3158080b75b98a08faf2806bb799edd" 541 | dependencies = [ 542 | "itoa", 543 | "ryu", 544 | "serde", 545 | ] 546 | 547 | [[package]] 548 | name = "sharded-slab" 549 | version = "0.0.9" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "06d5a3f5166fb5b42a5439f2eee8b9de149e235961e3eb21c5808fc3ea17ff3e" 552 | dependencies = [ 553 | "lazy_static", 554 | ] 555 | 556 | [[package]] 557 | name = "signal-hook-registry" 558 | version = "1.3.0" 559 | source = "registry+https://github.com/rust-lang/crates.io-index" 560 | checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" 561 | dependencies = [ 562 | "libc", 563 | ] 564 | 565 | [[package]] 566 | name = "slab" 567 | version = "0.4.2" 568 | source = "registry+https://github.com/rust-lang/crates.io-index" 569 | checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 570 | 571 | [[package]] 572 | name = "smallvec" 573 | version = "1.4.0" 574 | source = "registry+https://github.com/rust-lang/crates.io-index" 575 | checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" 576 | 577 | [[package]] 578 | name = "smoltcp" 579 | version = "0.7.0" 580 | source = "git+https://github.com/wzhd/rstcp.git#4f8bb98c16c8f986d1e99b7aab40e86915ab4027" 581 | dependencies = [ 582 | "bitflags", 583 | "byteorder", 584 | "libc", 585 | "log 0.4.8", 586 | "managed", 587 | ] 588 | 589 | [[package]] 590 | name = "snafu" 591 | version = "0.6.6" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | checksum = "b1ec0ae2ed980f26e1ad62e717feb01df90731df56887b5391a2c79f9f6805be" 594 | dependencies = [ 595 | "doc-comment", 596 | "snafu-derive", 597 | ] 598 | 599 | [[package]] 600 | name = "snafu-derive" 601 | version = "0.6.6" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "0ec32ba84a7a86aeb0bc32fd0c46d31b0285599f68ea72e87eff6127889d99e1" 604 | dependencies = [ 605 | "proc-macro2", 606 | "quote", 607 | "syn", 608 | ] 609 | 610 | [[package]] 611 | name = "socket2" 612 | version = "0.3.19" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" 615 | dependencies = [ 616 | "cfg-if 1.0.0", 617 | "libc", 618 | "winapi", 619 | ] 620 | 621 | [[package]] 622 | name = "syn" 623 | version = "1.0.18" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "410a7488c0a728c7ceb4ad59b9567eb4053d02e8cc7f5c0e0eeeb39518369213" 626 | dependencies = [ 627 | "proc-macro2", 628 | "quote", 629 | "unicode-xid", 630 | ] 631 | 632 | [[package]] 633 | name = "termcolor" 634 | version = "1.1.0" 635 | source = "registry+https://github.com/rust-lang/crates.io-index" 636 | checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" 637 | dependencies = [ 638 | "winapi-util", 639 | ] 640 | 641 | [[package]] 642 | name = "thread_local" 643 | version = "1.0.1" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" 646 | dependencies = [ 647 | "lazy_static", 648 | ] 649 | 650 | [[package]] 651 | name = "time" 652 | version = "0.1.43" 653 | source = "registry+https://github.com/rust-lang/crates.io-index" 654 | checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" 655 | dependencies = [ 656 | "libc", 657 | "winapi", 658 | ] 659 | 660 | [[package]] 661 | name = "tokio" 662 | version = "1.1.0" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "8efab2086f17abcddb8f756117665c958feee6b2e39974c2f1600592ab3a4195" 665 | dependencies = [ 666 | "autocfg", 667 | "bytes", 668 | "libc", 669 | "memchr", 670 | "mio", 671 | "num_cpus", 672 | "once_cell", 673 | "pin-project-lite", 674 | "signal-hook-registry", 675 | "tokio-macros", 676 | "winapi", 677 | ] 678 | 679 | [[package]] 680 | name = "tokio-fd" 681 | version = "0.3.0" 682 | source = "registry+https://github.com/rust-lang/crates.io-index" 683 | checksum = "5cedf0b897610a4baff98bf6116c060c5cfe7574d4339c50e9d23fe09377641d" 684 | dependencies = [ 685 | "libc", 686 | "tokio", 687 | ] 688 | 689 | [[package]] 690 | name = "tokio-macros" 691 | version = "1.0.0" 692 | source = "registry+https://github.com/rust-lang/crates.io-index" 693 | checksum = "42517d2975ca3114b22a16192634e8241dc5cc1f130be194645970cc1c371494" 694 | dependencies = [ 695 | "proc-macro2", 696 | "quote", 697 | "syn", 698 | ] 699 | 700 | [[package]] 701 | name = "tokio-stream" 702 | version = "0.1.3" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "1981ad97df782ab506a1f43bf82c967326960d278acf3bf8279809648c3ff3ea" 705 | dependencies = [ 706 | "futures-core", 707 | "pin-project-lite", 708 | "tokio", 709 | ] 710 | 711 | [[package]] 712 | name = "tokio-util" 713 | version = "0.6.3" 714 | source = "registry+https://github.com/rust-lang/crates.io-index" 715 | checksum = "ebb7cb2f00c5ae8df755b252306272cd1790d39728363936e01827e11f0b017b" 716 | dependencies = [ 717 | "bytes", 718 | "futures-core", 719 | "futures-sink", 720 | "log 0.4.8", 721 | "pin-project-lite", 722 | "slab", 723 | "tokio", 724 | ] 725 | 726 | [[package]] 727 | name = "tracing" 728 | version = "0.1.13" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "1721cc8cf7d770cc4257872507180f35a4797272f5962f24c806af9e7faf52ab" 731 | dependencies = [ 732 | "cfg-if 0.1.10", 733 | "tracing-attributes", 734 | "tracing-core", 735 | ] 736 | 737 | [[package]] 738 | name = "tracing-attributes" 739 | version = "0.1.7" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "7fbad39da2f9af1cae3016339ad7f2c7a9e870f12e8fd04c4fd7ef35b30c0d2b" 742 | dependencies = [ 743 | "quote", 744 | "syn", 745 | ] 746 | 747 | [[package]] 748 | name = "tracing-core" 749 | version = "0.1.10" 750 | source = "registry+https://github.com/rust-lang/crates.io-index" 751 | checksum = "0aa83a9a47081cd522c09c81b31aec2c9273424976f922ad61c053b58350b715" 752 | dependencies = [ 753 | "lazy_static", 754 | ] 755 | 756 | [[package]] 757 | name = "tracing-futures" 758 | version = "0.2.4" 759 | source = "registry+https://github.com/rust-lang/crates.io-index" 760 | checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c" 761 | dependencies = [ 762 | "pin-project", 763 | "tracing", 764 | ] 765 | 766 | [[package]] 767 | name = "tracing-log" 768 | version = "0.1.1" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "5e0f8c7178e13481ff6765bd169b33e8d554c5d2bbede5e32c356194be02b9b9" 771 | dependencies = [ 772 | "lazy_static", 773 | "log 0.4.8", 774 | "tracing-core", 775 | ] 776 | 777 | [[package]] 778 | name = "tracing-serde" 779 | version = "0.1.1" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | checksum = "b6ccba2f8f16e0ed268fc765d9b7ff22e965e7185d32f8f1ec8294fe17d86e79" 782 | dependencies = [ 783 | "serde", 784 | "tracing-core", 785 | ] 786 | 787 | [[package]] 788 | name = "tracing-subscriber" 789 | version = "0.2.5" 790 | source = "registry+https://github.com/rust-lang/crates.io-index" 791 | checksum = "1d53c40489aa69c9aed21ff483f26886ca8403df33bdc2d2f87c60c1617826d2" 792 | dependencies = [ 793 | "ansi_term", 794 | "chrono", 795 | "lazy_static", 796 | "matchers", 797 | "regex", 798 | "serde", 799 | "serde_json", 800 | "sharded-slab", 801 | "smallvec", 802 | "tracing-core", 803 | "tracing-log", 804 | "tracing-serde", 805 | ] 806 | 807 | [[package]] 808 | name = "trilock" 809 | version = "0.1.0" 810 | source = "git+https://github.com/wzhd/trilock.git#dc5b657f8042061847f6f7c03354479ea95a545b" 811 | 812 | [[package]] 813 | name = "tun" 814 | version = "0.4.4" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "9c381483a1daa36ccc3452223bdcb3dbea7ad407d1ede80496b87707368ba755" 817 | dependencies = [ 818 | "error-chain", 819 | "ioctl-sys", 820 | "libc", 821 | ] 822 | 823 | [[package]] 824 | name = "unicode-segmentation" 825 | version = "1.6.0" 826 | source = "registry+https://github.com/rust-lang/crates.io-index" 827 | checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" 828 | 829 | [[package]] 830 | name = "unicode-xid" 831 | version = "0.2.0" 832 | source = "registry+https://github.com/rust-lang/crates.io-index" 833 | checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" 834 | 835 | [[package]] 836 | name = "ustunet" 837 | version = "0.2.0" 838 | dependencies = [ 839 | "argh", 840 | "futures", 841 | "log 0.3.9", 842 | "managed", 843 | "pretty_env_logger", 844 | "smoltcp", 845 | "snafu", 846 | "tokio", 847 | "tokio-fd", 848 | "tokio-stream", 849 | "tokio-util", 850 | "tracing", 851 | "tracing-futures", 852 | "tracing-subscriber", 853 | "trilock", 854 | "tun", 855 | ] 856 | 857 | [[package]] 858 | name = "winapi" 859 | version = "0.3.9" 860 | source = "registry+https://github.com/rust-lang/crates.io-index" 861 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 862 | dependencies = [ 863 | "winapi-i686-pc-windows-gnu", 864 | "winapi-x86_64-pc-windows-gnu", 865 | ] 866 | 867 | [[package]] 868 | name = "winapi-i686-pc-windows-gnu" 869 | version = "0.4.0" 870 | source = "registry+https://github.com/rust-lang/crates.io-index" 871 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 872 | 873 | [[package]] 874 | name = "winapi-util" 875 | version = "0.1.5" 876 | source = "registry+https://github.com/rust-lang/crates.io-index" 877 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 878 | dependencies = [ 879 | "winapi", 880 | ] 881 | 882 | [[package]] 883 | name = "winapi-x86_64-pc-windows-gnu" 884 | version = "0.4.0" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 887 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "ustunet", 5 | ] 6 | 7 | [profile.release] 8 | debug = true 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ustunet 2 | 3 | A pure Rust TCP library that can be simply used in place of TCP implementations provided by operating systems, 4 | enabling services to be built with uncommon flexibility. 5 | 6 | ## Usage 7 | 8 | At a high level, 9 | it provides APIs similar to any asynchronous TCP socket library. 10 | 11 | To start listening, use `TcpListener`. 12 | But instead of binding to a single `SocketAddr`, 13 | give it the name of a TUN network interface: 14 | 15 | use ustunet::TcpListener; 16 | 17 | let mut listener = TcpListener::bind("tuna").unwrap(); 18 | 19 | And it will process all IP packets going to the interface, 20 | accepting incoming TCP connections destined to any `SocketAddr`. 21 | It's like binding to all possible IP and ports. 22 | (But without the complexity or the cost. 23 | Only one file descriptor is used.) 24 | 25 | Accept `TcpStream`s: 26 | 27 | while let Some(tcp_stream) = listener.next().await { 28 | } 29 | 30 | Use `tokio::io::AsyncRead` and `AsyncWrite` implementations: 31 | 32 | let mut buf = [0u8; 1024]; 33 | let n = tcp_stream.read(&mut buf).await.unwrap(); 34 | 35 | tcp_stream.write("Aloha!".as_bytes()).await.unwrap(); 36 | 37 | Since the listener is not bound to an address, 38 | the `SocketAddr` actually used by a connection can be of more interest. 39 | 40 | let server_addr = socket.local_addr(); 41 | println!("Provided service on port {}, IP: {}.", server_addr.port(), server_addr.ip()); 42 | 43 | Similarly, call `peer_addr` to get the address of the host that initiated the connection. 44 | 45 | ### Adding the dependency 46 | 47 | Add to `Cargo.toml` 48 | 49 | [dependencies.ustunet] 50 | git = "https://github.com/ustcp/ustcp.git" 51 | 52 | ## Setting up a TUN network interface 53 | 54 | TUN allows a user to send and receive IP packets on the interface with no permission requirements at runtime. 55 | 56 | Create a TUN interface with name set to `tuna`, and ownership given to user `yuki`. 57 | And bring it up. 58 | 59 | sudo ip tuntap add dev tuna mode tun user yuki 60 | sudo ip link set up dev tuna 61 | 62 | Give it an IP address (and a subnet mask) that's not currently in use: 63 | 64 | sudo ip addr add 192.168.9.100/24 dev tuna 65 | 66 | With the subnet mask `/24`, 67 | ustunet will be able to respond on any address in the range from `192.168.9.1` to `192.168.9.254`. 68 | 69 | The command can be repeated to add more addresses, 70 | but adding routes can be more flexible. 71 | Configure any address in the subnet as a gateway for a different range of IPs 72 | to instruct the operating systems to contact those addresses also via `tuna`. 73 | 74 | sudo ip route add 10.33.0.0/16 via 192.168.9.4 dev tuna 75 | 76 | -------------------------------------------------------------------------------- /ustunet/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ustunet" 3 | version = "0.2.0" 4 | authors = ["wzhd"] 5 | edition="2018" 6 | 7 | [dependencies] 8 | managed = { version = "0.7", default-features = false, features = ["map"] } 9 | log = "0.3" 10 | tun = { version = "0.4.4" } 11 | tokio-fd = "0.3.0" 12 | tokio-stream = "0.1" 13 | tokio-util = {version = "0.6.2", features = ["time"]} 14 | snafu = "0.6.3" 15 | futures = "0.3" 16 | tracing = "0.1" 17 | tracing-futures = "0.2.4" 18 | 19 | [dependencies.trilock] 20 | git = "https://github.com/wzhd/trilock.git" 21 | 22 | [dependencies.smoltcp] 23 | git = "https://github.com/wzhd/rstcp.git" 24 | 25 | [dependencies.tokio] 26 | version = "1" 27 | features = [ 28 | "sync", 29 | "time", 30 | "signal", 31 | "rt-multi-thread", 32 | "io-util", 33 | "io-std", 34 | "macros", 35 | ] 36 | 37 | [dev-dependencies] 38 | tracing-subscriber = "0.2.4" 39 | pretty_env_logger = "0.4" 40 | argh = "0.1" 41 | -------------------------------------------------------------------------------- /ustunet/examples/echo.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate log; 3 | use argh::FromArgs; 4 | use futures::StreamExt; 5 | use tokio::io::{AsyncReadExt, AsyncWriteExt}; 6 | use ustunet; 7 | use ustunet::TcpListener; 8 | 9 | #[derive(FromArgs)] 10 | /// Echoing server on every address. 11 | struct EchoUp { 12 | /// tun device owned by current user 13 | #[argh(option)] 14 | tun: String, 15 | } 16 | 17 | #[tokio::main] 18 | async fn main() { 19 | pretty_env_logger::init(); 20 | let up: EchoUp = argh::from_env(); 21 | let mut echo_server = TcpListener::bind(up.tun).unwrap(); 22 | 23 | while let Some(mut socket) = echo_server.next().await { 24 | debug!("accepted new tcp stream"); 25 | let mut buf = vec![0u8; 1024]; 26 | tokio::spawn(async move { 27 | loop { 28 | let n = socket.read(&mut buf).await.expect("read"); 29 | if n == 0 { 30 | info!("stream closed"); 31 | break; 32 | } 33 | let content = &buf[..n]; 34 | eprintln!("read {:?} bytes: {:?}", n, content); 35 | let n = socket.write(content).await.expect("write failed"); 36 | println!("Written {} bytes", n); 37 | } 38 | eprintln!("connection ended"); 39 | }); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ustunet/examples/rend_.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate log; 3 | use argh::FromArgs; 4 | use futures::StreamExt; 5 | use std::io; 6 | use std::net::SocketAddr; 7 | use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; 8 | use tokio::net::TcpStream; 9 | use tokio::time::{timeout, Duration}; 10 | use tracing_subscriber; 11 | use tracing_subscriber::EnvFilter; 12 | use ustunet; 13 | use ustunet::TcpListener; 14 | 15 | #[derive(FromArgs)] 16 | /// Reach one server with arbitrary socket addresses. 17 | struct ConnectUp { 18 | /// address of server to connect to 19 | #[argh(positional)] 20 | server: SocketAddr, 21 | 22 | /// tun device owned by current user 23 | #[argh(option)] 24 | tun: String, 25 | } 26 | 27 | #[tokio::main] 28 | async fn main() { 29 | let _subscriber = tracing_subscriber::fmt() 30 | .with_env_filter(EnvFilter::from_default_env()) 31 | .init(); 32 | let up: ConnectUp = argh::from_env(); 33 | let server = up.server; 34 | let mut listener = TcpListener::bind(&up.tun).unwrap(); 35 | println!("Listening on {}", up.tun); 36 | while let Some(socket) = listener.next().await { 37 | tokio::spawn(async move { 38 | match copy_to_server(server, socket).await { 39 | Ok((s, r)) => info!("Received {} bytes, sent {}", r, s), 40 | Err(error) => error!("Error while copying: {:?}", error), 41 | } 42 | }); 43 | } 44 | } 45 | 46 | async fn copy_to_server( 47 | remote: SocketAddr, 48 | socket: ustunet::stream::TcpStream, 49 | ) -> io::Result<(u64, u64)> { 50 | let peer = socket.peer_addr(); 51 | info!( 52 | "Accepted new tcp stream from {:?} to {:?}", 53 | socket.peer_addr(), 54 | socket.local_addr() 55 | ); 56 | let server = TcpStream::connect(&remote).await?; 57 | info!("Connected to {:?}", remote); 58 | let (mut s_reader, mut s_writer) = server.into_split(); 59 | let (mut client_reader, mut client_writer) = socket.split(); 60 | let sent = tokio::spawn(async move { 61 | let n = copy(&mut s_reader, &mut client_writer, "srv", peer).await; 62 | info!("Served bytes: {:?}", n); 63 | n 64 | }); 65 | let recv = tokio::spawn(async move { 66 | let n = copy(&mut client_reader, &mut s_writer, "req", peer).await; 67 | info!("Request bytes: {:?}", n); 68 | n 69 | }); 70 | let (sent, recv) = tokio::join!(sent, recv); 71 | let sent = sent??; 72 | let recv = recv??; 73 | Ok((sent as u64, recv as u64)) 74 | } 75 | 76 | async fn copy<'a, R, W>( 77 | reader: &'a mut R, 78 | writer: &'a mut W, 79 | des: &str, 80 | addr: SocketAddr, 81 | ) -> io::Result 82 | where 83 | R: AsyncRead + Unpin + ?Sized, 84 | W: AsyncWrite + Unpin + ?Sized, 85 | { 86 | let mut n = 0; 87 | let mut nr = 0; 88 | let mut buf = [0; 2048]; 89 | let d = Duration::from_secs(60); 90 | loop { 91 | let r = match timeout(d, reader.read(&mut buf)).await { 92 | Ok(f) => { 93 | let i = f?; 94 | nr += i; 95 | if i == 0 { 96 | break; 97 | } 98 | i 99 | } 100 | Err(_t) => { 101 | error!("timeout {} at reading {}, {}", des, nr, addr); 102 | break; 103 | } 104 | }; 105 | match timeout(d, writer.write_all(&buf[..r])).await { 106 | Ok(_f) => { 107 | n += r; 108 | } 109 | Err(_t) => { 110 | error!("timeout {} at writing {}, {}", des, n, addr); 111 | break; 112 | } 113 | }; 114 | } 115 | Ok(n) 116 | } 117 | -------------------------------------------------------------------------------- /ustunet/examples/rendezvous.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate log; 3 | use argh::FromArgs; 4 | use futures::StreamExt; 5 | use std::io; 6 | use std::net::SocketAddr; 7 | use tokio::net::TcpStream; 8 | use tracing_subscriber; 9 | use tracing_subscriber::EnvFilter; 10 | use ustunet; 11 | use ustunet::TcpListener; 12 | 13 | #[derive(FromArgs)] 14 | /// Reach one server with arbitrary socket addresses. 15 | struct ConnectUp { 16 | /// address of server to connect to 17 | #[argh(positional)] 18 | server: SocketAddr, 19 | 20 | /// tun device owned by current user 21 | #[argh(option)] 22 | tun: String, 23 | } 24 | 25 | #[tokio::main] 26 | async fn main() { 27 | let _subscriber = tracing_subscriber::fmt() 28 | .with_env_filter(EnvFilter::from_default_env()) 29 | .init(); 30 | let up: ConnectUp = argh::from_env(); 31 | let server = up.server; 32 | let mut listener = TcpListener::bind(&up.tun).unwrap(); 33 | println!("Listening on {}", up.tun); 34 | while let Some(socket) = listener.next().await { 35 | tokio::spawn(async move { 36 | match copy_to_server(server, socket).await { 37 | Ok((s, r)) => info!("Received {} bytes, sent {}", r, s), 38 | Err(error) => error!("Error while copying: {:?}", error), 39 | } 40 | }); 41 | } 42 | } 43 | 44 | async fn copy_to_server( 45 | remote: SocketAddr, 46 | socket: ustunet::stream::TcpStream, 47 | ) -> io::Result<(u64, u64)> { 48 | info!( 49 | "Accepted new tcp stream from {:?} to {:?}", 50 | socket.peer_addr(), 51 | socket.local_addr() 52 | ); 53 | let server = TcpStream::connect(&remote).await?; 54 | info!("Connected to {:?}", remote); 55 | let (mut reader, mut writer) = server.into_split(); 56 | let (mut client_reader, mut client_writer) = socket.split(); 57 | let sent = tokio::spawn(async move { 58 | let n = tokio::io::copy(&mut reader, &mut client_writer).await; 59 | info!("Sent bytes: {:?}", n); 60 | n 61 | }); 62 | let recv = tokio::spawn(async move { 63 | let n = tokio::io::copy(&mut client_reader, &mut writer).await; 64 | info!("Received bytes: {:?}", n); 65 | n 66 | }); 67 | let (sent, recv) = tokio::join!(sent, recv); 68 | let sent = sent??; 69 | let recv = recv??; 70 | Ok((sent, recv)) 71 | } 72 | -------------------------------------------------------------------------------- /ustunet/src/dispatch/mod.rs: -------------------------------------------------------------------------------- 1 | use super::mpsc::{self}; 2 | use crate::sockets::{AddrPair, SocketPool}; 3 | use crate::stream::TcpStream; 4 | use crate::time::Clock; 5 | use smoltcp::iface::IpPacket as Packet; 6 | use smoltcp::phy::{ChecksumCapabilities, DeviceCapabilities}; 7 | use smoltcp::wire::{IpProtocol, Ipv6Packet, Ipv6Repr}; 8 | use smoltcp::wire::{IpRepr, Ipv4Packet, Ipv4Repr, TcpPacket, TcpRepr}; 9 | use smoltcp::Error; 10 | use std::io; 11 | use tokio::io::{AsyncReadExt, AsyncWriteExt, ReadHalf, WriteHalf}; 12 | use tokio_fd::AsyncFd; 13 | 14 | pub(crate) mod poll_queue; 15 | mod shutdown; 16 | 17 | use crate::dispatch::poll_queue::PollReceiver; 18 | use crate::dispatch::shutdown::shutdown_channel; 19 | use crate::util::{Selected, Selector}; 20 | use futures::future::Either; 21 | use futures::pin_mut; 22 | use poll_queue::DispatchQueue; 23 | pub(crate) use shutdown::{Close, CloseSender, HalfCloseSender}; 24 | use smoltcp::socket::PollAt; 25 | use tokio::sync::mpsc::Sender; 26 | use tokio::task::JoinHandle; 27 | 28 | type SMResult = Result; 29 | type ProcessingReply = Option<(IpRepr, TcpRepr<'static>)>; 30 | 31 | /// Used to locate a socket in the storage. 32 | /// The address pair can be used but there are other options. 33 | pub(crate) type SocketHandle = AddrPair; 34 | 35 | pub struct Interface { 36 | sockets: SocketPool, 37 | checksum_caps: ChecksumCapabilities, 38 | } 39 | 40 | type ReadBuf = Box<[u8]>; 41 | async fn read_future( 42 | mut reader: ReadHalf, 43 | mut buf: ReadBuf, 44 | ) -> (io::Result, ReadHalf, ReadBuf) { 45 | let n = reader.read(&mut buf).await; 46 | (n, reader, buf) 47 | } 48 | 49 | async fn write_future( 50 | mut writer: WriteHalf, 51 | buf: Vec, 52 | ) -> (io::Result, WriteHalf, Vec) { 53 | let n = writer.write(&buf).await; 54 | (n, writer, buf) 55 | } 56 | 57 | type CloseReceiver = mpsc::UnboundedReceiver<(SocketHandle, Close)>; 58 | 59 | async fn recv_close(mut chan: CloseReceiver) -> (SocketHandle, Close, CloseReceiver) { 60 | let (s, c) = chan.recv().await.expect("Channel closed."); 61 | (s, c, chan) 62 | } 63 | async fn recv_poll(mut chan: PollReceiver) -> (SocketHandle, PollAt, PollReceiver) { 64 | let (s, c) = chan.recv().await.unwrap(); 65 | (s, c, chan) 66 | } 67 | 68 | pub(crate) fn start_io( 69 | dev_caps: DeviceCapabilities, 70 | reader: ReadHalf, 71 | writer: WriteHalf, 72 | ) -> (JoinHandle>, mpsc::Receiver) { 73 | let (tx, incoming) = mpsc::channel(1); 74 | let t = tokio::spawn(async move { io_loop(dev_caps, reader, writer, tx).await }); 75 | (t, incoming) 76 | } 77 | 78 | async fn io_loop( 79 | dev_caps: DeviceCapabilities, 80 | reader: ReadHalf, 81 | writer: WriteHalf, 82 | tx: Sender, 83 | ) -> io::Result<()> { 84 | let clock = Clock::new(); 85 | let (shutdown_builder, closing) = shutdown_channel(); 86 | let (queue, queue_sender, poll_recv) = DispatchQueue::new(clock); 87 | let sockets = SocketPool::new( 88 | queue_sender, 89 | shutdown_builder, 90 | dev_caps.clone(), 91 | tx, 92 | queue, 93 | clock, 94 | ); 95 | let mut ingress_replies = vec![]; 96 | let mut writing = Some((writer, Vec::with_capacity(2048))); 97 | let mut selector = Selector::new(); 98 | selector.insert_b(read_future(reader, vec![0u8; 2048].into_boxed_slice())); 99 | selector.insert_c(recv_close(closing)); 100 | selector.insert_d(recv_poll(poll_recv)); 101 | let mut next_poll = None; 102 | let capabilities = dev_caps.clone(); 103 | let mut interface = Interface { 104 | sockets, 105 | checksum_caps: dev_caps.checksum.clone(), 106 | }; 107 | loop { 108 | assert!(selector.b().is_some()); 109 | if let Some((writer, mut write_buf)) = writing.take() { 110 | if write_buf.is_empty() { 111 | while let Some(r) = ingress_replies.pop() { 112 | packet_to_bytes(r, &mut write_buf, &capabilities.checksum).unwrap(); 113 | if !write_buf.is_empty() { 114 | break; 115 | } 116 | } 117 | } 118 | if write_buf.is_empty() { 119 | if let Some(addr) = next_poll.take() { 120 | interface.dispatch(&mut write_buf, addr).await; 121 | } 122 | } 123 | if !write_buf.is_empty() { 124 | let f = write_future(writer, write_buf); 125 | selector.insert_a(f); 126 | } else { 127 | info!("nothing to write"); 128 | writing = Some((writer, write_buf)); 129 | } 130 | }; 131 | let se = selector.select(); 132 | let s = { 133 | let nopoll = next_poll.is_none(); 134 | if nopoll { 135 | let wp = interface.sockets.queue.poll(); 136 | pin_mut!(se); 137 | pin_mut!(wp); 138 | match futures::future::select(se, wp).await { 139 | Either::Left((s, _w)) => s, 140 | Either::Right((expired, _se)) => { 141 | let addr = expired.into_inner(); 142 | next_poll = Some(addr); 143 | continue; 144 | } 145 | } 146 | } else { 147 | se.await 148 | } 149 | }; 150 | match s { 151 | Selected::A((n, w, mut b)) => { 152 | let n = n?; 153 | info!("Written {} bytes", n); 154 | b.clear(); 155 | writing = Some((w, b)); 156 | } 157 | Selected::B((n, r, read_buf)) => { 158 | let n = n?; 159 | info!("ingress packet size: {}", n); 160 | if n > 0 { 161 | match interface.process(&read_buf[..n]).await { 162 | Ok(reply) => { 163 | if let Some(repr) = reply { 164 | debug!("ingress reply: {:?}", repr); 165 | let packet = Packet::Tcp(repr); 166 | ingress_replies.push(packet); 167 | } 168 | } 169 | Err(e) => { 170 | if e != smoltcp::Error::Dropped { 171 | warn!("process error {:?}", e); 172 | } 173 | } 174 | } 175 | } 176 | selector.insert_b(read_future(r, read_buf)); 177 | } 178 | Selected::C((s, c, r)) => { 179 | info!("Closing {:?}'s {:?}", s, c); 180 | interface.sockets.drop_tcp_half(&s, c).await; 181 | selector.insert_c(recv_close(r)); 182 | } 183 | Selected::D((s, t, p)) => { 184 | interface.sockets.queue.send(s, t); 185 | selector.insert_d(recv_poll(p)); 186 | } 187 | } 188 | tokio::task::yield_now().await; 189 | } 190 | } 191 | impl Interface { 192 | pub(crate) async fn dispatch(&mut self, write_buf: &mut Vec, addr: AddrPair) { 193 | self.sockets.dispatch(write_buf, addr).await; 194 | } 195 | /// Process incoming packet. 196 | pub(crate) async fn process + ?Sized>( 197 | &mut self, 198 | packet: &T, 199 | ) -> Result { 200 | let packet = packet.as_ref(); 201 | let v = packet[0] / 16; 202 | if v == 4 { 203 | self.process_ipv4(packet).await 204 | } else if v == 6 { 205 | self.process_ipv6(packet).await 206 | } else { 207 | Err(smoltcp::Error::Dropped) 208 | } 209 | } 210 | 211 | /// Process incoming ipv4 packet. 212 | async fn process_ipv4(&mut self, payload: &[u8]) -> SMResult { 213 | let ipv4_packet = Ipv4Packet::new_checked(payload)?; 214 | let ipv4_repr = Ipv4Repr::parse(&ipv4_packet, &self.checksum_caps)?; 215 | 216 | if !ipv4_repr.src_addr.is_unicast() { 217 | // Discard packets with non-unicast source addresses. 218 | debug!("non-unicast source address"); 219 | return Err(Error::Malformed); 220 | } 221 | 222 | let ip_repr = IpRepr::Ipv4(ipv4_repr); 223 | let ip_payload = ipv4_packet.payload(); 224 | 225 | trace!("processing ip4 to {:?}", ipv4_repr.dst_addr); 226 | 227 | match ipv4_repr.protocol { 228 | IpProtocol::Tcp => self.process_tcp(ip_repr, ip_payload).await, 229 | _ => { 230 | debug!("ipv4 not tcp"); 231 | Ok(None) 232 | } 233 | } 234 | } 235 | 236 | async fn process_ipv6(&mut self, payload: &[u8]) -> SMResult { 237 | let ipv6_packet = Ipv6Packet::new_checked(payload)?; 238 | let ipv6_repr = Ipv6Repr::parse(&ipv6_packet)?; 239 | 240 | if !ipv6_repr.src_addr.is_unicast() { 241 | // Discard packets with non-unicast source addresses. 242 | debug!("non-unicast source address"); 243 | return Err(Error::Malformed); 244 | } 245 | 246 | let ip_repr = IpRepr::Ipv6(ipv6_repr); 247 | let ip_payload = ipv6_packet.payload(); 248 | 249 | trace!("processing ip6 to {:?}", ipv6_repr.dst_addr); 250 | 251 | match ipv6_repr.next_header { 252 | IpProtocol::Tcp => self.process_tcp(ip_repr, ip_payload).await, 253 | _ => { 254 | debug!("ipv6 not tcp"); 255 | Ok(None) 256 | } 257 | } 258 | } 259 | /// Process incoming tcp packet. 260 | async fn process_tcp( 261 | &mut self, 262 | ip_repr: IpRepr, 263 | ip_payload: &[u8], 264 | ) -> Result)>, smoltcp::Error> { 265 | trace!("processing tcp to {:?}", ip_repr); 266 | let tcp_packet = TcpPacket::new_checked(ip_payload)?; 267 | let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr()); 268 | let tcp_repr = TcpRepr::parse(&tcp_packet, &src_addr, &dst_addr, &self.checksum_caps)?; 269 | let reply = self.sockets.process(ip_repr, tcp_repr).await?; 270 | Ok(reply) 271 | } 272 | } 273 | 274 | pub(crate) fn packet_to_bytes( 275 | packet: Packet<'_>, 276 | mut buffer: &mut Vec, 277 | checksum_caps: &ChecksumCapabilities, 278 | ) -> Result<(), smoltcp::Error> { 279 | assert_eq!(0, buffer.len(), "Given buffer should be empty."); 280 | trace!("serialising packet {:?}", packet); 281 | match packet { 282 | Packet::Tcp((ip_repr, tcp_repr)) => { 283 | let ip_repr = ip_repr.lower(&[])?; 284 | let l = ip_repr.total_len(); 285 | buffer.resize(l, 0); 286 | ip_repr.emit(&mut buffer, checksum_caps); 287 | let payload = &mut buffer[ip_repr.buffer_len()..]; 288 | tcp_repr.emit( 289 | &mut TcpPacket::new_unchecked(payload), 290 | &ip_repr.src_addr(), 291 | &ip_repr.dst_addr(), 292 | &checksum_caps, 293 | ); 294 | } 295 | p => { 296 | trace!("other packet {:?}", p); 297 | } 298 | } 299 | Ok(()) 300 | } 301 | -------------------------------------------------------------------------------- /ustunet/src/dispatch/mod1.rs: -------------------------------------------------------------------------------- 1 | use super::mpsc::{self}; 2 | use crate::sockets::{AddrPair, SocketPool}; 3 | use crate::stream::TcpStream; 4 | use crate::time::Clock; 5 | use futures::future::{Fuse, FusedFuture}; 6 | use futures::{future::FutureExt, pin_mut, select}; 7 | use futures::TryFutureExt; 8 | use smoltcp::iface::IpPacket as Packet; 9 | use smoltcp::phy::{ChecksumCapabilities, DeviceCapabilities}; 10 | use smoltcp::time::Instant; 11 | use smoltcp::wire::IpProtocol; 12 | use smoltcp::wire::{IpRepr, Ipv4Packet, Ipv4Repr, TcpPacket, TcpRepr}; 13 | use smoltcp::Error; 14 | use std::fmt; 15 | use std::fmt::Formatter; 16 | use std::io; 17 | use tokio::io::{AsyncReadExt, AsyncWriteExt, ReadHalf, WriteHalf}; 18 | use tokio_fd::AsyncFd; 19 | 20 | pub(crate) mod poll_queue; 21 | 22 | type SMResult = Result; 23 | type ProcessingReply = Option<(IpRepr, TcpRepr<'static>)>; 24 | 25 | /// Used to locate a socket in the storage. 26 | /// The address pair can be used but there are other options. 27 | pub(crate) type SocketHandle = AddrPair; 28 | type ReadResult = (io::Result, ReadHalf, Vec); 29 | 30 | pub struct Interface { 31 | sockets: SocketPool, 32 | capabilities: DeviceCapabilities, 33 | clock: Clock, 34 | /// Receive next socket to be polled for dispatch 35 | poll_recv: Option>, 36 | } 37 | 38 | enum SelectValue { 39 | Read(ReadResult), 40 | Written((io::Result, Writer)), 41 | NextPoll((SocketHandle, mpsc::Receiver)), 42 | } 43 | 44 | impl Interface { 45 | pub fn new(capabilities: DeviceCapabilities) -> (Interface, mpsc::Receiver) { 46 | let clock = Clock::new(); 47 | let (send_poll, receive_poll) = poll_queue::poll_queue(clock); 48 | let (pool, incoming) = SocketPool::new(send_poll); 49 | let interface = Interface { 50 | sockets: pool, 51 | capabilities, 52 | clock: Clock::new(), 53 | poll_recv: Some(receive_poll), 54 | }; 55 | (interface, incoming) 56 | } 57 | 58 | async fn read(mut reader: ReadHalf, mut buf: Vec) -> ReadResult { 59 | let n = reader.read(&mut buf).fuse().await; 60 | (n, reader, buf) 61 | } 62 | /// Keeps reading, processing, and writing 63 | pub async fn poll( 64 | &mut self, 65 | read_half: ReadHalf, 66 | write_half: WriteHalf, 67 | ) -> io::Result<()> { 68 | let mut ingress_replies = vec![]; 69 | let mut next_poll = None; 70 | let read = Self::read(read_half, vec![0u8; 2048]).fuse(); 71 | let write_fut = Fuse::terminated(); 72 | let next_poll_future = Fuse::terminated(); 73 | let mut writer = Some(Writer::new(write_half)); 74 | pin_mut!(read, write_fut, next_poll_future); 75 | let mut timestamp = self.clock.timestamp(); 76 | loop { 77 | if next_poll.is_none() { 78 | if let Some(mut receiver) = self.poll_recv.take() { 79 | assert!(next_poll_future.is_terminated(), "Receiving in progress."); 80 | let future = async move { 81 | let o = receiver.recv().await.expect("No more sockets to poll."); 82 | (o, receiver) 83 | }; 84 | next_poll_future.set(future.fuse()); 85 | } 86 | } 87 | if write_fut.is_terminated() { 88 | let mut w = writer.take().unwrap(); 89 | if w.buf.is_empty() { 90 | while let Some(r) = ingress_replies.pop() { 91 | packet_to_bytes(r, &mut w.buf, &self.capabilities.checksum).unwrap(); 92 | if !w.buf.is_empty() { 93 | break; 94 | } 95 | } 96 | } 97 | if w.buf.is_empty() { 98 | if let Some(addr) = next_poll.take() { 99 | if let Err(e) = self 100 | .sockets 101 | .dispatch(&mut w.buf, timestamp, addr, &self.capabilities) 102 | .await 103 | { 104 | error!("Tcp dispatch error {:?}", e); 105 | } 106 | } 107 | } 108 | if w.buf.is_empty() { 109 | debug!("nothing to dispatch"); 110 | writer = Some(w); 111 | } else { 112 | write_fut.set(w.write().fuse()); 113 | } 114 | } 115 | let v = select! { 116 | n = read => SelectValue::Read((n)), 117 | n = write_fut => SelectValue::Written(n), 118 | p = next_poll_future => SelectValue::NextPoll(p), 119 | }; 120 | debug!("selected value {:?}", v); 121 | timestamp = self.clock.timestamp(); 122 | match v { 123 | SelectValue::Read((n, read_half, buf)) => { 124 | let n = n?; 125 | trace!("ingress packet size: {}", n); 126 | match self.process(&buf[..n], timestamp).await { 127 | Ok(reply) => { 128 | if let Some(repr) = reply { 129 | debug!("ingress reply: {:?}", repr); 130 | let packet = Packet::Tcp(repr); 131 | ingress_replies.push(packet); 132 | } 133 | } 134 | Err(e) => { 135 | println!("process error {:?}", e); 136 | } 137 | } 138 | read.set(Self::read(read_half, buf).fuse()); 139 | } 140 | SelectValue::Written((n, wr)) => { 141 | let _n = n?; 142 | writer = Some(wr); 143 | } 144 | SelectValue::NextPoll((s, r)) => { 145 | assert!(self.poll_recv.is_none()); 146 | self.poll_recv = Some(r); 147 | assert!(next_poll.is_none()); 148 | next_poll = Some(s); 149 | } 150 | } 151 | tokio::task::yield_now().await; 152 | } 153 | } 154 | /// Process incoming packet. 155 | pub async fn process + ?Sized>( 156 | &mut self, 157 | packet: &T, 158 | timestamp: Instant, 159 | ) -> Result { 160 | self.process_ipv4(packet, timestamp).await 161 | } 162 | 163 | /// Process incoming ipv4 packet. 164 | async fn process_ipv4 + ?Sized>( 165 | &mut self, 166 | payload: &T, 167 | timestamp: Instant, 168 | ) -> SMResult { 169 | let ipv4_packet = Ipv4Packet::new_checked(payload)?; 170 | let checksum_caps = self.capabilities.checksum.clone(); 171 | let ipv4_repr = Ipv4Repr::parse(&ipv4_packet, &checksum_caps)?; 172 | 173 | if !ipv4_repr.src_addr.is_unicast() { 174 | // Discard packets with non-unicast source addresses. 175 | debug!("non-unicast source address"); 176 | return Err(Error::Malformed); 177 | } 178 | 179 | let ip_repr = IpRepr::Ipv4(ipv4_repr); 180 | let ip_payload = ipv4_packet.payload(); 181 | 182 | trace!("processing ip4 to {:?}", ipv4_repr.dst_addr); 183 | 184 | match ipv4_repr.protocol { 185 | IpProtocol::Tcp => self.process_tcp(timestamp, ip_repr, ip_payload).await, 186 | _ => { 187 | debug!("ipv4 not tcp"); 188 | Ok(None) 189 | } 190 | } 191 | } 192 | 193 | /// Process incoming tcp packet. 194 | async fn process_tcp( 195 | &mut self, 196 | timestamp: Instant, 197 | ip_repr: IpRepr, 198 | ip_payload: &[u8], 199 | ) -> Result)>, smoltcp::Error> { 200 | trace!("processing tcp to {:?}", ip_repr); 201 | let tcp_packet = TcpPacket::new_checked(ip_payload)?; 202 | let checksum_caps = &self.capabilities.checksum; 203 | let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr()); 204 | let tcp_repr = TcpRepr::parse(&tcp_packet, &src_addr, &dst_addr, checksum_caps)?; 205 | let reply = self.sockets.process(ip_repr, tcp_repr, timestamp).await?; 206 | Ok(reply) 207 | } 208 | } 209 | 210 | pub(crate) fn packet_to_bytes( 211 | packet: Packet<'_>, 212 | mut buffer: &mut Vec, 213 | checksum_caps: &ChecksumCapabilities, 214 | ) -> Result<(), smoltcp::Error> { 215 | assert_eq!(0, buffer.len(), "Given buffer should be empty."); 216 | trace!("serialising packet {:?}", packet); 217 | match packet { 218 | Packet::Tcp((ip_repr, tcp_repr)) => { 219 | let ip_repr = ip_repr.lower(&[])?; 220 | let l = ip_repr.total_len(); 221 | buffer.resize(l, 0); 222 | ip_repr.emit(&mut buffer, checksum_caps); 223 | let payload = &mut buffer[ip_repr.buffer_len()..]; 224 | tcp_repr.emit( 225 | &mut TcpPacket::new_unchecked(payload), 226 | &ip_repr.src_addr(), 227 | &ip_repr.dst_addr(), 228 | &checksum_caps, 229 | ); 230 | } 231 | p => { 232 | trace!("other packet {:?}", p); 233 | } 234 | } 235 | Ok(()) 236 | } 237 | 238 | struct Writer { 239 | fd: WriteHalf, 240 | pub buf: Vec, 241 | } 242 | 243 | impl Writer { 244 | fn new(fd: WriteHalf) -> Writer { 245 | Writer { 246 | fd, 247 | buf: Vec::with_capacity(2048), 248 | } 249 | } 250 | async fn write(mut self) -> (io::Result, Self) { 251 | let n = self.fd.write(&self.buf).await; 252 | self.buf.clear(); 253 | (n, self) 254 | } 255 | } 256 | 257 | impl fmt::Debug for SelectValue { 258 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 259 | use SelectValue::*; 260 | match self { 261 | Read((n, _, _)) => write!(f, "Read({:?} bytes)", n), 262 | Written((n, _)) => write!(f, "Written({:?} bytes)", n), 263 | NextPoll((s, _)) => write!(f, "Polling({:?})", s), 264 | } 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /ustunet/src/dispatch/poll_queue.rs: -------------------------------------------------------------------------------- 1 | use super::super::mpsc; 2 | use super::SocketHandle; 3 | use crate::sockets::AddrPair; 4 | use crate::time::Clock; 5 | use futures::future::poll_fn; 6 | 7 | use smoltcp::socket::PollAt; 8 | use std::collections::HashMap; 9 | 10 | use std::time::Instant; 11 | use tokio_util::time::delay_queue::{Expired, Key}; 12 | use tokio_util::time::DelayQueue; 13 | 14 | pub(super) type PollReceiver = mpsc::UnboundedReceiver; 15 | /// Update the timing for polling a socket for retransmission. 16 | pub(crate) type PollUpdate = (SocketHandle, PollAt); 17 | 18 | /// Used to send updated polling delay to the queue. 19 | #[derive(Clone, Debug)] 20 | pub(crate) struct QueueUpdater { 21 | sender: mpsc::UnboundedSender, 22 | } 23 | 24 | pub(crate) struct DispatchQueue { 25 | clock: Clock, 26 | delayed: Delays, 27 | } 28 | 29 | impl QueueUpdater { 30 | pub fn send(&mut self, socket: SocketHandle, poll_at: PollAt) { 31 | self.sender.send((socket, poll_at)).unwrap(); 32 | } 33 | } 34 | 35 | impl DispatchQueue { 36 | pub fn new(clock: Clock) -> (Self, QueueUpdater, PollReceiver) { 37 | let (sender, receiver) = mpsc::unbounded_channel(); 38 | let queue = Self { 39 | clock, 40 | delayed: Delays::new(), 41 | }; 42 | let updater = QueueUpdater { sender }; 43 | (queue, updater, receiver) 44 | } 45 | pub fn send(&mut self, socket: SocketHandle, poll_at: PollAt) { 46 | let instant = match poll_at { 47 | PollAt::Now => self.clock.origin(), 48 | PollAt::Time(millis) => self.clock.resolve(millis), 49 | PollAt::Ingress => return, 50 | }; 51 | self.delayed.insert(socket, instant); 52 | } 53 | pub(crate) async fn poll(&mut self) -> Expired { 54 | let n = self.delayed.next().await; 55 | if let Some(e) = n { 56 | return e; 57 | } 58 | futures::future::pending().await 59 | } 60 | pub(crate) fn remove(&mut self, socket: &SocketHandle) { 61 | self.delayed.remove(socket); 62 | } 63 | pub(crate) fn contains(&mut self, socket: &SocketHandle) -> bool { 64 | self.delayed.contains_key(socket) 65 | } 66 | } 67 | 68 | struct Delays { 69 | queue: DelayQueue, 70 | keys: HashMap, 71 | } 72 | 73 | impl Delays { 74 | fn new() -> Delays { 75 | Delays { 76 | queue: DelayQueue::new(), 77 | keys: HashMap::new(), 78 | } 79 | } 80 | async fn next(&mut self) -> Option> { 81 | let n = poll_fn(|c| self.queue.poll_expired(c)).await?; 82 | let expired = n.unwrap(); 83 | let s = expired.get_ref(); 84 | self.keys.remove(s).unwrap(); 85 | Some(expired) 86 | } 87 | fn insert(&mut self, socket: SocketHandle, instant: Instant) { 88 | if let Some(k) = self.keys.get(&socket) { 89 | self.queue.reset_at(k, instant.into()); 90 | } else { 91 | let k = self.queue.insert_at(socket.clone(), instant.into()); 92 | self.keys.insert(socket, k); 93 | } 94 | } 95 | fn contains_key(&self, socket: &SocketHandle) -> bool { 96 | self.keys.contains_key(socket) 97 | } 98 | fn remove(&mut self, socket: &SocketHandle) { 99 | if let Some(key) = self.keys.remove(socket) { 100 | self.queue.remove(&key); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /ustunet/src/dispatch/sendbuf.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | use std::iter::FromIterator; 3 | 4 | const BUFSIZE: usize = 2048; 5 | const NUM_BUFFS: usize =4; 6 | /// Buffer packets to be written to device 7 | pub(crate) struct SendingBuffer { 8 | /// with data 9 | packets: VecDeque>, 10 | bufs: Vec>, 11 | } 12 | 13 | impl SendingBuffer { 14 | pub(crate) fn new() -> Self { 15 | SendingBuffer { 16 | packets: VecDeque::new(), 17 | bufs: Vec::from_iter(std::iter::repeat(vec![]).take(NUM_BUFFS)), 18 | } 19 | } 20 | pub(crate) fn pop_packet(&mut self) -> Option> { 21 | self.packets.pop_front() 22 | } 23 | pub(crate) fn first(&self) -> Option<&[u8]> { 24 | self.packets.front().map(|v| &v[..]) 25 | } 26 | pub(crate) fn pop_front(&mut self) { 27 | let f = self.packets.pop_front().unwrap(); 28 | self.bufs.push(f); 29 | // error!("num bufs {}", self.bufs.len()); 30 | } 31 | pub(crate) fn get_buf(&mut self) -> Option> { 32 | if self.bufs.is_empty() { return None} 33 | let mut b = self.bufs.remove(self.bufs.len()-1); 34 | b.clear(); 35 | Some(b) 36 | } 37 | pub(crate) fn get_mut(&mut self) -> Option<&mut Vec> { 38 | if self.bufs.is_empty() { 39 | // error!("no bufs"); 40 | } 41 | let b = self.bufs.last_mut()?; 42 | b.clear(); 43 | Some(b) 44 | } 45 | pub(crate) fn queue_buf(&mut self, b: Vec) { 46 | if b.is_empty() 47 | { 48 | self.bufs.push(b) 49 | } else { 50 | self.packets.push_back(b); 51 | } 52 | } 53 | pub(crate) fn queue_written(&mut self) { 54 | let b = self.bufs.remove(self.bufs.len()-1); 55 | if b.is_empty() 56 | { 57 | self.bufs.push(b) 58 | } else { 59 | self.packets.push_back(b); 60 | } 61 | 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /ustunet/src/dispatch/shutdown.rs: -------------------------------------------------------------------------------- 1 | use crate::dispatch::SocketHandle; 2 | use core::fmt; 3 | use tokio::sync::mpsc; 4 | 5 | #[derive(Clone, Copy, Debug)] 6 | pub(crate) enum Close { 7 | Read, 8 | Write, 9 | } 10 | 11 | pub(crate) struct HalfCloseSender { 12 | socket: SocketHandle, 13 | rw: Close, 14 | sender: CloseSender, 15 | } 16 | 17 | #[derive(Clone)] 18 | pub(crate) struct CloseSender { 19 | tx: mpsc::UnboundedSender<(SocketHandle, Close)>, 20 | } 21 | 22 | pub(crate) fn shutdown_channel() -> (CloseSender, mpsc::UnboundedReceiver<(SocketHandle, Close)>) { 23 | let (end_sender, end_receiver) = mpsc::unbounded_channel(); 24 | let shutdown_builder = CloseSender { tx: end_sender }; 25 | (shutdown_builder, end_receiver) 26 | } 27 | 28 | impl HalfCloseSender { 29 | pub fn notify(&mut self) { 30 | self.sender.notify(self.socket.clone(), self.rw); 31 | } 32 | } 33 | 34 | impl CloseSender { 35 | pub fn notify(&mut self, socket: SocketHandle, rw: Close) { 36 | self.tx.send((socket, rw)).unwrap(); 37 | } 38 | pub fn build(&self, socket: SocketHandle, rw: Close) -> HalfCloseSender { 39 | HalfCloseSender { 40 | sender: self.clone(), 41 | rw, 42 | socket, 43 | } 44 | } 45 | } 46 | 47 | impl fmt::Debug for HalfCloseSender { 48 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 49 | write!(f, "ShutdownNotifier({:?})", self.socket) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ustunet/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate log; 3 | mod dispatch; 4 | mod listener; 5 | mod sockets; 6 | pub mod stream; 7 | mod time; 8 | pub(crate) mod util; 9 | use snafu::Snafu; 10 | 11 | pub use listener::TcpListener; 12 | pub(crate) use tokio::sync::mpsc; 13 | pub(crate) use trilock::TriLock as SocketLock; 14 | 15 | #[derive(Debug, Snafu)] 16 | pub enum Error { 17 | #[snafu(display("IO error {}", source))] 18 | Io { source: std::io::Error }, 19 | } 20 | 21 | #[cfg(test)] 22 | mod tests { 23 | #[test] 24 | fn it_works() { 25 | assert_eq!(2 + 2, 4); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ustunet/src/listener.rs: -------------------------------------------------------------------------------- 1 | use super::stream::TcpStream; 2 | use smoltcp::phy::DeviceCapabilities; 3 | use snafu::{ResultExt, Snafu}; 4 | use std::convert::TryFrom; 5 | use std::os::unix::io::IntoRawFd; 6 | 7 | use super::mpsc::Receiver; 8 | use crate::dispatch::start_io; 9 | use futures::task::Poll; 10 | use std::task::Context; 11 | use tokio::io::split; 12 | use tokio_fd::AsyncFd; 13 | use tun::Device as TunDevice; 14 | 15 | #[derive(Debug, Snafu)] 16 | pub enum TunError { 17 | #[snafu(display("Unable to open tun device {}: {}", name, source))] 18 | Tun { source: tun::Error, name: String }, 19 | } 20 | 21 | type Result = std::result::Result; 22 | 23 | pub struct TcpListener { 24 | receiver: Receiver, 25 | } 26 | 27 | impl TcpListener { 28 | pub fn bind>(name: S) -> Result { 29 | let mut conf = tun::configure(); 30 | let name = name.as_ref(); 31 | conf.name(name); 32 | let d = tun::create(&conf).context(Tun { name })?; 33 | let mtu = d.mtu().context(Tun { name })? as usize; 34 | let mut capabilities = DeviceCapabilities::default(); 35 | capabilities.max_transmission_unit = mtu; 36 | let fd = d.into_raw_fd(); 37 | let fd = AsyncFd::try_from(fd).unwrap(); 38 | let (rd, wr) = split(fd); 39 | let (_interface, connections) = start_io(capabilities, rd, wr); 40 | let listener = TcpListener { 41 | receiver: connections, 42 | }; 43 | Ok(listener) 44 | } 45 | pub async fn accept(&mut self) -> Option { 46 | self.receiver.recv().await 47 | } 48 | } 49 | 50 | impl tokio_stream::Stream for TcpListener { 51 | type Item = TcpStream; 52 | 53 | fn poll_next( 54 | mut self: std::pin::Pin<&mut Self>, 55 | cx: &mut Context<'_>, 56 | ) -> Poll> { 57 | self.receiver.poll_recv(cx) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ustunet/src/sockets/mod.rs: -------------------------------------------------------------------------------- 1 | //! Store TcpSockets and deliver packets by source and destination SocketAddr for processing. 2 | use std::collections::HashMap; 3 | use std::net::SocketAddr; 4 | 5 | pub use super::util::convert_to_socket_address; 6 | use smoltcp::socket::TcpSocketBuffer; 7 | use smoltcp::socket::{TcpSocket, TcpState}; 8 | 9 | use crate::stream::TcpStream; 10 | use log::{error, info}; 11 | 12 | use super::mpsc::{self}; 13 | 14 | use crate::dispatch::poll_queue::{DispatchQueue, QueueUpdater}; 15 | use crate::stream::internal::Connection; 16 | 17 | use crate::dispatch::{Close, CloseSender, SocketHandle}; 18 | use crate::time::Clock; 19 | use smoltcp::phy::DeviceCapabilities; 20 | use smoltcp::time::Duration; 21 | use smoltcp::wire::{IpRepr, TcpControl, TcpRepr}; 22 | use std::fmt; 23 | use std::fmt::Formatter; 24 | use tokio::sync::mpsc::Sender; 25 | 26 | /// An extensible set of sockets. 27 | pub(crate) struct SocketPool { 28 | pub(crate) queue: DispatchQueue, 29 | sockets: HashMap, 30 | /// Received tcp connections. 31 | new_conns: mpsc::Sender, 32 | /// Queue a socket to be polled for egress after a period. 33 | send_poll: QueueUpdater, 34 | shutdown_builder: CloseSender, 35 | capabilities: DeviceCapabilities, 36 | clock: Clock, 37 | } 38 | 39 | #[derive(Clone, Debug, Eq, PartialEq, Hash)] 40 | /// Client and server. Peer and local. 41 | pub struct AddrPair { 42 | pub peer: SocketAddr, 43 | pub local: SocketAddr, 44 | } 45 | 46 | impl SocketPool { 47 | /// Create a socket set using the provided storage. 48 | pub fn new( 49 | send_poll: QueueUpdater, 50 | shutdown_builder: CloseSender, 51 | capabilities: DeviceCapabilities, 52 | tx: Sender, 53 | queue: DispatchQueue, 54 | clock: Clock, 55 | ) -> SocketPool { 56 | let sockets = HashMap::new(); 57 | SocketPool { 58 | sockets, 59 | new_conns: tx, 60 | send_poll, 61 | shutdown_builder, 62 | capabilities, 63 | clock, 64 | queue, 65 | } 66 | } 67 | 68 | /// Find or create socket and process the incoming packet. 69 | pub(crate) async fn process( 70 | &mut self, 71 | ip_repr: IpRepr, 72 | tcp_repr: TcpRepr<'_>, 73 | ) -> Result)>, smoltcp::Error> { 74 | let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr()); 75 | let src = convert_to_socket_address(src_addr, tcp_repr.src_port)?; 76 | let dst = convert_to_socket_address(dst_addr, tcp_repr.dst_port)?; 77 | let pair = AddrPair { 78 | peer: src, 79 | local: dst, 80 | }; 81 | if tcp_repr.control == TcpControl::Syn && tcp_repr.ack_number.is_some() { 82 | warn!( 83 | "Syn with ack number {:?} is not expected.", 84 | tcp_repr.ack_number 85 | ); 86 | return Err(smoltcp::Error::Dropped); 87 | } 88 | let ts = self.clock.timestamp(); 89 | self.create_syn(&pair, tcp_repr).await?; 90 | let socket = self.sockets.get_mut(&pair).unwrap(); 91 | let reply = socket 92 | .process(ts, &ip_repr, &tcp_repr, &mut self.queue) 93 | .await?; 94 | Ok(reply) 95 | } 96 | pub(crate) async fn dispatch(&mut self, buf: &mut Vec, addr: AddrPair) { 97 | assert_eq!(0, buf.len(), "Given buffer should be empty."); 98 | let timestamp = self.clock.timestamp(); 99 | let socket = self 100 | .sockets 101 | .get_mut(&addr) 102 | .expect("Dispatching should not happen after dropping."); 103 | let drop = socket 104 | .dispatch(buf, timestamp, &self.capabilities, &mut self.queue) 105 | .await; 106 | if drop { 107 | debug!("Removing socket {:?} from collection.", addr); 108 | self.sockets.remove(&addr).unwrap(); 109 | self.queue.remove(&addr); 110 | } 111 | } 112 | /// Mark reader or writer as dropped. 113 | pub(crate) async fn drop_tcp_half(&mut self, socket: &SocketHandle, rw: Close) { 114 | debug!("Dropping {:?} of {:?}", rw, socket); 115 | let connection = self 116 | .sockets 117 | .get_mut(&socket) 118 | .expect("Socket only gets removed after dropping both reader and writer."); 119 | connection.drop_half(rw, &mut self.queue).await; 120 | } 121 | 122 | async fn create_syn( 123 | &mut self, 124 | pair: &AddrPair, 125 | tcp_repr: TcpRepr<'_>, 126 | ) -> Result<(), smoltcp::Error> { 127 | if let Some(s) = self.sockets.get_mut(pair) { 128 | if tcp_repr.control == TcpControl::Syn { 129 | { 130 | let k = s.socket.lock().await; 131 | let s = k.tcp.state(); 132 | if s != TcpState::SynReceived { 133 | warn!("Received syn in state {:?} on {:?}", s, pair); 134 | } 135 | } 136 | } 137 | } else if tcp_repr.control == TcpControl::Syn { 138 | debug!("creating socket {:?}", pair); 139 | let socket = open_socket(pair.local)?; 140 | let (tcp, connection) = TcpStream::new( 141 | socket, 142 | self.send_poll.clone(), 143 | pair.clone(), 144 | &self.shutdown_builder, 145 | ); 146 | self.new_conns.send(tcp).await.unwrap_or_else(|error| { 147 | error!("tcp source {:?}", error); 148 | }); 149 | let prev = self.sockets.insert(pair.clone(), connection); 150 | assert!(prev.is_none()); 151 | } else { 152 | debug!("No known socket for {:?}.", pair); 153 | return Err(smoltcp::Error::Dropped); 154 | } 155 | Ok(()) 156 | } 157 | } 158 | 159 | fn open_socket(local: SocketAddr) -> Result, smoltcp::Error> { 160 | let mut socket = create_tcp_socket(); 161 | if !socket.is_open() { 162 | info!("opening tcp listener for {:?}", local); 163 | socket.listen(local).map_err(|e| { 164 | error!("tcp can't listen {:?}", e); 165 | e 166 | })?; 167 | } 168 | socket.set_ack_delay(Some(Duration::from_millis(0))); 169 | Ok(socket) 170 | } 171 | 172 | const RX_BUF_SIZE: usize = 32768; 173 | const TX_BUF_SIZE: usize = RX_BUF_SIZE; 174 | fn create_tcp_socket<'a>() -> TcpSocket<'a> { 175 | let tcp1_rx_buffer = TcpSocketBuffer::new(vec![0; RX_BUF_SIZE]); 176 | let tcp1_tx_buffer = TcpSocketBuffer::new(vec![0; TX_BUF_SIZE]); 177 | TcpSocket::new(tcp1_rx_buffer, tcp1_tx_buffer) 178 | } 179 | 180 | impl fmt::Debug for SocketPool { 181 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 182 | write!(f, "SocketPool")?; 183 | Ok(()) 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /ustunet/src/stream/internal.rs: -------------------------------------------------------------------------------- 1 | use crate::dispatch::poll_queue::DispatchQueue; 2 | use crate::dispatch::{packet_to_bytes, Close, SocketHandle}; 3 | use crate::stream::{Inner, ReadinessState, Tcp, TcpLock, WriteReadiness}; 4 | use smoltcp::iface::IpPacket as Packet; 5 | use smoltcp::phy::DeviceCapabilities; 6 | use smoltcp::socket::PollAt; 7 | use smoltcp::time::Instant; 8 | use smoltcp::wire::IpRepr; 9 | use smoltcp::wire::TcpRepr; 10 | use smoltcp::Error; 11 | use std::fmt; 12 | use std::fmt::Formatter; 13 | use std::ops::DerefMut; 14 | 15 | /// Reference to TcpSocket. 16 | /// Notify readers and writers after IO activities. 17 | pub(crate) struct Connection { 18 | pub(crate) socket: TcpLock, 19 | inner: RwStatus, 20 | } 21 | 22 | struct RwStatus { 23 | /// Can be used as a key in key-value storage. 24 | handle: SocketHandle, 25 | /// Contains an optional Waker which would be set by the reader 26 | /// after exhausting the rx buffer. 27 | read_readiness: ReadinessState, 28 | /// Use to wake the writer when a full tx buffer has newly freed up space 29 | /// and can be written to again. 30 | write_readiness: WriteReadiness, 31 | reader_dropped: bool, 32 | writer_dropped: bool, 33 | } 34 | 35 | impl fmt::Debug for Connection { 36 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 37 | write!(f, "Connection") 38 | } 39 | } 40 | 41 | impl Connection { 42 | pub(super) fn new( 43 | socket: TcpLock, 44 | addr: SocketHandle, 45 | read_readiness: ReadinessState, 46 | write_readiness: WriteReadiness, 47 | ) -> Connection { 48 | let inner = RwStatus { 49 | handle: addr, 50 | read_readiness, 51 | write_readiness, 52 | writer_dropped: false, 53 | reader_dropped: false, 54 | }; 55 | Connection { socket, inner } 56 | } 57 | /// Process incoming packet and queue for polling. 58 | pub async fn process( 59 | &mut self, 60 | timestamp: Instant, 61 | ip_repr: &IpRepr, 62 | tcp_repr: &TcpRepr<'_>, 63 | send_poll: &mut DispatchQueue, 64 | ) -> Result)>, Error> { 65 | let handle = self.handle().clone(); 66 | let mut socket = self.socket.lock().await; 67 | let socket = &mut socket.deref_mut().tcp; 68 | check_acceptability(socket, ip_repr, tcp_repr)?; 69 | let reply = socket.process(timestamp, &ip_repr, &tcp_repr); 70 | if socket.can_recv() { 71 | self.inner.wake_reader(); 72 | } 73 | self.inner.wake_to_close(socket); 74 | let mut poll_at = socket.poll_at(); 75 | if self.inner.both_dropped() && poll_at == PollAt::Ingress && !send_poll.contains(&handle) { 76 | poll_at = PollAt::Now; 77 | } 78 | send_poll.send(handle.clone(), poll_at); 79 | trace!("connection reply {:?}", reply); 80 | reply 81 | } 82 | /// Serialise outgoing packet and queue for next dispatch. 83 | /// Assumes the packet will be written to network device immediately. 84 | pub(crate) async fn dispatch( 85 | &mut self, 86 | mut buf: &mut Vec, 87 | timestamp: Instant, 88 | capabilities: &DeviceCapabilities, 89 | send_poll: &mut DispatchQueue, 90 | ) -> bool { 91 | assert_eq!(0, buf.len(), "Given buffer should be empty."); 92 | let handle = self.handle(); 93 | let mut guard = self.socket.lock().await; 94 | let tcp = &mut guard.tcp; 95 | let r = tcp.dispatch(timestamp, capabilities, |(i, t)| { 96 | let p = Packet::Tcp((i, t)); 97 | packet_to_bytes(p, &mut buf, &capabilities.checksum)?; 98 | let ns = buf.len(); 99 | if ns > 0 { 100 | debug!("Filled tcp dispatch packet {} bytes.", ns); 101 | } else { 102 | error!("Dispatched empty tcp packet.") 103 | } 104 | Ok(()) 105 | }); 106 | if let Err(error) = r { 107 | if error != smoltcp::Error::Exhausted { 108 | error!("Error in dispatch {:?}.", error); 109 | } 110 | } 111 | self.inner.wake_to_close(tcp); 112 | if tcp.can_send() { 113 | self.inner.wake_writer(); 114 | } 115 | let poll_at = tcp.poll_at(); 116 | if self.inner.both_dropped() { 117 | if !tcp.remote_endpoint().is_specified() { 118 | debug!( 119 | "Disassociated from remote endpoint, dropping connection {:?}", 120 | handle 121 | ); 122 | return true; 123 | } 124 | if let Err(smoltcp::Error::Exhausted) = r { 125 | debug!("Finished dispatching, dropping connection {:?}", handle); 126 | return true; 127 | } 128 | if poll_at == PollAt::Ingress { 129 | debug!( 130 | "Dropping connection {:?} to avoid waiting indefinitely.", 131 | handle 132 | ); 133 | return true; 134 | } 135 | } 136 | guard.polling_active = poll_at == PollAt::Now; 137 | send_poll.send(handle, poll_at); 138 | false 139 | } 140 | /// Mark reader or writer as dropped. 141 | /// Returns whether the connection should be dropped. 142 | pub(crate) async fn drop_half(&mut self, rw: Close, dispatch_queue: &mut DispatchQueue) { 143 | let handle = self.handle(); 144 | let Self { socket, inner } = self; 145 | match rw { 146 | Close::Read => inner.reader_dropped = true, 147 | Close::Write => inner.writer_dropped = true, 148 | } 149 | if !inner.writer_dropped { 150 | return; 151 | } 152 | let mut guard = socket.lock().await; 153 | let Inner { tcp, .. } = guard.deref_mut(); 154 | tcp.close(); 155 | let mut poll_at = tcp.poll_at(); 156 | if inner.both_dropped() && poll_at == PollAt::Ingress { 157 | poll_at = PollAt::Now; 158 | } 159 | dispatch_queue.send(handle, poll_at); 160 | } 161 | fn handle(&self) -> SocketHandle { 162 | self.inner.handle.clone() 163 | } 164 | } 165 | 166 | impl RwStatus { 167 | /// Notify reader or writer after reaching the end. 168 | /// TcpSocket state may change after either processing or dispatching. 169 | fn wake_to_close(&mut self, socket: &mut Tcp) { 170 | if !socket.may_recv() { 171 | self.wake_reader(); 172 | } 173 | if !socket.may_send() { 174 | self.wake_writer(); 175 | } 176 | } 177 | fn wake_reader(&mut self) { 178 | if !self.reader_dropped { 179 | self.read_readiness.lock().unwrap().wake_once(); 180 | } 181 | } 182 | fn wake_writer(&mut self) { 183 | if !self.writer_dropped { 184 | self.write_readiness.lock().unwrap().wake_once(); 185 | } 186 | } 187 | fn both_dropped(&self) -> bool { 188 | self.writer_dropped && self.reader_dropped 189 | } 190 | } 191 | 192 | fn check_acceptability(tcp: &Tcp, ip_repr: &IpRepr, repr: &TcpRepr) -> Result<(), smoltcp::Error> { 193 | use smoltcp::socket::TcpState as State; 194 | use smoltcp::Error::Dropped; 195 | use std::borrow::Borrow; 196 | let error = Err(Dropped); 197 | 198 | let tcp = tcp.borrow(); 199 | let state = tcp.state(); 200 | let local_endpoint = tcp.local_endpoint(); 201 | let remote_endpoint = tcp.remote_endpoint(); 202 | if state == State::Closed { 203 | warn!( 204 | "Socket closed, could not accept packet with source {:?}:{} and destination {:?}:{}.", 205 | ip_repr.src_addr(), 206 | repr.src_port, 207 | ip_repr.dst_addr(), 208 | repr.dst_port, 209 | ); 210 | return Err(Dropped); 211 | } 212 | 213 | // If we're still listening for SYNs and the packet has an ACK, it cannot 214 | // be destined to this socket, but another one may well listen on the same 215 | // local endpoint. 216 | if state == State::Listen && repr.ack_number.is_some() { 217 | warn!( 218 | "Socket listening for SYN could not accept ACK, from {:?} to {:?}", 219 | remote_endpoint, local_endpoint 220 | ); 221 | return Err(Dropped); 222 | } 223 | 224 | // Reject packets with a wrong destination. 225 | if local_endpoint.port != repr.dst_port { 226 | warn!( 227 | "Destination {:?} does not match local_endpoint {:?}", 228 | repr.dst_port, local_endpoint 229 | ); 230 | return error; 231 | } 232 | if !local_endpoint.addr.is_unspecified() && local_endpoint.addr != ip_repr.dst_addr() { 233 | warn!( 234 | "Destination address {:?} does not match local endpoint {:?}", 235 | ip_repr.dst_addr(), 236 | local_endpoint.addr 237 | ); 238 | return error; 239 | } 240 | 241 | // Reject packets from a source to which we aren't connected. 242 | if remote_endpoint.port != 0 && remote_endpoint.port != repr.src_port { 243 | warn!( 244 | "Packet source port {} does not match remote endpoint {:?}", 245 | repr.src_port, remote_endpoint 246 | ); 247 | return error; 248 | } 249 | if !remote_endpoint.addr.is_unspecified() && remote_endpoint.addr != ip_repr.src_addr() { 250 | warn!( 251 | "Packet source address {:?} does not match remote address {:?}", 252 | ip_repr.src_addr(), 253 | remote_endpoint.addr 254 | ); 255 | return error; 256 | } 257 | 258 | Ok(()) 259 | } 260 | -------------------------------------------------------------------------------- /ustunet/src/stream/mod.rs: -------------------------------------------------------------------------------- 1 | //! TcpStream and private structures. 2 | use super::SocketLock; 3 | use crate::dispatch::poll_queue::QueueUpdater; 4 | use crate::dispatch::{Close, CloseSender, HalfCloseSender, SocketHandle}; 5 | use crate::sockets::AddrPair; 6 | use crate::stream::internal::Connection; 7 | use futures::future::poll_fn; 8 | use futures::io::Error; 9 | use futures::ready; 10 | use futures::task::Poll; 11 | use smoltcp::socket::TcpSocket; 12 | use smoltcp::socket::TcpState; 13 | use std::borrow::BorrowMut; 14 | use std::fmt; 15 | use std::fmt::Formatter; 16 | use std::io; 17 | use std::net::SocketAddr; 18 | use std::ops::DerefMut; 19 | use std::pin::Pin; 20 | use std::sync as std_sync; 21 | use std::sync::Arc; 22 | use std::task; 23 | use std::task::{Context, Waker}; 24 | use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; 25 | 26 | pub(crate) type ReadinessState = Arc>; 27 | pub(crate) type WriteReadiness = Arc>; 28 | 29 | pub(crate) mod internal; 30 | 31 | type Tcp = TcpSocket<'static>; 32 | type TcpLock = SocketLock; 33 | 34 | pub(crate) struct Inner { 35 | pub(crate) tcp: Tcp, 36 | /// Whether the connection is in queue to be dispatched. 37 | /// If true, data in the tx buffer will be sent out. 38 | /// If false, the dispatch queue should be notified 39 | /// after writing to the tx buffer. 40 | polling_active: bool, 41 | } 42 | 43 | pub struct TcpStream { 44 | writer: WriteHalf, 45 | reader: ReadHalf, 46 | /// Local and peer address. 47 | // Immutable. 48 | addr: AddrPair, 49 | } 50 | 51 | pub struct ReadHalf { 52 | mutex: TcpLock, 53 | shared_state: ReadinessState, 54 | eof_reached: bool, 55 | /// Send a message when getting dropped. 56 | shutdown_notifier: HalfCloseSender, 57 | } 58 | 59 | pub struct WriteHalf { 60 | mutex: TcpLock, 61 | shared_state: ReadinessState, 62 | handle: SocketHandle, 63 | notifier: QueueUpdater, 64 | shutdown_notifier: HalfCloseSender, 65 | } 66 | 67 | #[derive(Debug)] 68 | pub(crate) struct SharedState { 69 | pub waker: Option, 70 | } 71 | 72 | impl SharedState { 73 | pub(crate) fn wake_once(&mut self) { 74 | if let Some(waker) = self.waker.take() { 75 | waker.wake(); 76 | } 77 | } 78 | } 79 | 80 | impl TcpStream { 81 | /// Returns a TcpStream and a struct containing references used 82 | /// internally to move data between buffers and network interfaces. 83 | pub(crate) fn new( 84 | tcp: Tcp, 85 | poll_queue: QueueUpdater, 86 | addr: AddrPair, 87 | shutdown_builder: &CloseSender, 88 | ) -> (TcpStream, Connection) { 89 | let inner = Inner { 90 | tcp, 91 | polling_active: false, 92 | }; 93 | let tcp_locks = SocketLock::new(inner); 94 | let (reader, set_ready) = ReadHalf::new( 95 | tcp_locks.0, 96 | shutdown_builder.build(addr.clone(), Close::Read), 97 | ); 98 | let (writer, write_readiness) = WriteHalf::new( 99 | tcp_locks.1, 100 | poll_queue, 101 | addr.clone(), 102 | shutdown_builder.build(addr.clone(), Close::Write), 103 | ); 104 | let tcp = TcpStream { 105 | reader, 106 | writer, 107 | addr: addr.clone(), 108 | }; 109 | let connection = Connection::new(tcp_locks.2, addr, set_ready, write_readiness); 110 | (tcp, connection) 111 | } 112 | 113 | pub fn reader(&mut self) -> &mut ReadHalf { 114 | &mut self.reader 115 | } 116 | pub fn writer(&mut self) -> &mut WriteHalf { 117 | &mut self.writer 118 | } 119 | /// Returns the local address that this TcpStream is bound to. 120 | pub fn local_addr(&self) -> SocketAddr { 121 | self.addr.local 122 | } 123 | 124 | /// Returns the remote address that this stream is connected to. 125 | pub fn peer_addr(&self) -> SocketAddr { 126 | self.addr.peer 127 | } 128 | 129 | pub fn split(self) -> (ReadHalf, WriteHalf) { 130 | (self.reader, self.writer) 131 | } 132 | 133 | /// Close the transmit half of the full-duplex connection. 134 | pub async fn close(&mut self) { 135 | self.writer.close().await; 136 | } 137 | } 138 | 139 | impl AsyncRead for TcpStream { 140 | fn poll_read( 141 | mut self: Pin<&mut Self>, 142 | cx: &mut Context<'_>, 143 | buf: &mut ReadBuf<'_>, 144 | ) -> Poll> { 145 | let b = buf.initialize_unfilled(); 146 | self.reader 147 | .poll_read_inner(cx, b) 148 | .map(|o| o.map(|n| buf.advance(n))) 149 | } 150 | } 151 | 152 | impl futures::io::AsyncRead for TcpStream { 153 | fn poll_read( 154 | mut self: Pin<&mut Self>, 155 | cx: &mut Context<'_>, 156 | buf: &mut [u8], 157 | ) -> Poll> { 158 | self.reader.poll_read_inner(cx, buf) 159 | } 160 | } 161 | 162 | impl AsyncWrite for TcpStream { 163 | fn poll_write( 164 | mut self: Pin<&mut Self>, 165 | cx: &mut Context<'_>, 166 | buf: &[u8], 167 | ) -> Poll> { 168 | self.writer.poll_write_inner(cx, buf) 169 | } 170 | 171 | fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { 172 | Poll::Ready(Ok(())) 173 | } 174 | 175 | fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 176 | self.writer.poll_close_inner(cx).map(|_| Ok(())) 177 | } 178 | } 179 | 180 | impl futures::io::AsyncWrite for TcpStream { 181 | fn poll_write( 182 | mut self: Pin<&mut Self>, 183 | cx: &mut Context<'_>, 184 | buf: &[u8], 185 | ) -> Poll> { 186 | self.writer.poll_write_inner(cx, buf) 187 | } 188 | 189 | fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { 190 | Poll::Ready(Ok(())) 191 | } 192 | 193 | fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 194 | self.writer.poll_close_inner(cx).map(|_| Ok(())) 195 | } 196 | } 197 | 198 | impl ReadHalf { 199 | fn new(socket: TcpLock, shutdown_notifier: HalfCloseSender) -> (Self, ReadinessState) { 200 | let state = SharedState { waker: None }; 201 | let shared_state = Arc::new(std_sync::Mutex::new(state)); 202 | let s = ReadHalf { 203 | mutex: socket, 204 | shared_state: shared_state.clone(), 205 | eof_reached: false, 206 | shutdown_notifier, 207 | }; 208 | (s, shared_state) 209 | } 210 | } 211 | 212 | impl WriteHalf { 213 | fn new( 214 | socket: TcpLock, 215 | notifier: QueueUpdater, 216 | handle: SocketHandle, 217 | shutdown_notifier: HalfCloseSender, 218 | ) -> (Self, WriteReadiness) { 219 | let shared_state = Arc::new(std_sync::Mutex::new(SharedState { waker: None })); 220 | let s = Self { 221 | mutex: socket, 222 | shared_state: shared_state.clone(), 223 | notifier, 224 | handle, 225 | shutdown_notifier, 226 | }; 227 | (s, shared_state) 228 | } 229 | 230 | /// Close the transmit half of the full-duplex connection. 231 | pub async fn close(&mut self) { 232 | poll_fn(|cx| self.poll_close_inner(cx)).await 233 | } 234 | fn poll_close_inner(&mut self, cx: &mut Context<'_>) -> Poll<()> { 235 | let mut guard = ready!(self.mutex.poll_lock(cx)); 236 | let Inner { 237 | tcp, 238 | polling_active, 239 | } = guard.deref_mut(); 240 | tcp.close(); 241 | if !*polling_active { 242 | self.notifier.send(self.handle.clone(), tcp.poll_at()); 243 | }; 244 | Poll::Ready(()) 245 | } 246 | } 247 | 248 | impl AsyncRead for ReadHalf { 249 | fn poll_read( 250 | mut self: Pin<&mut Self>, 251 | cx: &mut Context<'_>, 252 | buf: &mut ReadBuf<'_>, 253 | ) -> Poll> { 254 | let b = buf.initialize_unfilled(); 255 | self.as_mut() 256 | .poll_read_inner(cx, b) 257 | .map(|o| o.map(|n| buf.advance(n))) 258 | } 259 | } 260 | 261 | impl futures::io::AsyncRead for ReadHalf { 262 | fn poll_read( 263 | mut self: Pin<&mut Self>, 264 | cx: &mut Context<'_>, 265 | buf: &mut [u8], 266 | ) -> Poll> { 267 | self.as_mut().poll_read_inner(cx, buf) 268 | } 269 | } 270 | 271 | impl ReadHalf { 272 | fn poll_read_inner(&mut self, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll> { 273 | let Self { 274 | ref mut mutex, 275 | ref mut shared_state, 276 | ref mut eof_reached, 277 | .. 278 | } = self; 279 | let l = mutex.poll_lock(cx); 280 | let mut guard = ready!(l); 281 | let tcp = &mut guard.borrow_mut().tcp; 282 | if tcp.can_recv() { 283 | // Actually there should not be any error when can_recv is true. 284 | let n = tcp 285 | .recv_slice(buf) 286 | .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?; 287 | if n > 0 { 288 | trace!("recv_slice {}", n); 289 | return Poll::Ready(Ok(n)); 290 | } else { 291 | error!("Read zero when can_recv is true."); 292 | } 293 | } 294 | let state = tcp.state(); 295 | if tcp.may_recv() || 296 | // Reader could be used before the handshake is finished. 297 | state == TcpState::SynReceived 298 | { 299 | shared_state.lock().unwrap().waker = Some(cx.waker().clone()); 300 | return task::Poll::Pending; 301 | } else { 302 | debug!("Socket may not receive in state {:?}", state); 303 | } 304 | if *eof_reached { 305 | return Poll::Ready(Err(io::ErrorKind::ConnectionAborted.into())); 306 | } 307 | *eof_reached = true; 308 | Poll::Ready(Ok(0)) 309 | } 310 | } 311 | 312 | impl AsyncWrite for WriteHalf { 313 | fn poll_write( 314 | mut self: Pin<&mut Self>, 315 | cx: &mut Context<'_>, 316 | buf: &[u8], 317 | ) -> task::Poll> { 318 | self.as_mut().poll_write_inner(cx, buf) 319 | } 320 | fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { 321 | Poll::Ready(Ok(())) 322 | } 323 | fn poll_shutdown( 324 | mut self: Pin<&mut Self>, 325 | cx: &mut Context<'_>, 326 | ) -> Poll> { 327 | ready!(self.poll_close_inner(cx)); 328 | Poll::Ready(Ok(())) 329 | } 330 | } 331 | impl futures::io::AsyncWrite for WriteHalf { 332 | fn poll_write( 333 | mut self: Pin<&mut Self>, 334 | cx: &mut Context<'_>, 335 | buf: &[u8], 336 | ) -> task::Poll> { 337 | self.as_mut().poll_write_inner(cx, buf) 338 | } 339 | fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { 340 | Poll::Ready(Ok(())) 341 | } 342 | fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 343 | ready!(self.poll_close_inner(cx)); 344 | Poll::Ready(Ok(())) 345 | } 346 | } 347 | 348 | impl WriteHalf { 349 | fn poll_write_inner( 350 | &mut self, 351 | cx: &mut Context<'_>, 352 | buf: &[u8], 353 | ) -> task::Poll> { 354 | let Self { 355 | ref mut mutex, 356 | ref mut shared_state, 357 | ref mut notifier, 358 | handle, 359 | .. 360 | } = self; 361 | let p = mutex.poll_lock(cx); 362 | let mut guard = ready!(p); 363 | let inactive = !guard.polling_active; 364 | let s = &mut guard.tcp; 365 | let n = if s.can_send() { 366 | let s = s 367 | .send_slice(buf) 368 | .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?; 369 | trace!("Written {} bytes.", s); 370 | s 371 | } else { 372 | 0 373 | }; 374 | if inactive { 375 | notifier.send(handle.clone(), s.poll_at()); 376 | } 377 | if n > 0 { 378 | return Poll::Ready(Ok(n)); 379 | } 380 | if !s.may_send() { 381 | return Poll::Ready(Err(io::ErrorKind::ConnectionAborted.into())); 382 | } 383 | trace!("Setting waker for writer."); 384 | shared_state.lock().unwrap().waker = Some(cx.waker().clone()); 385 | Poll::Pending 386 | } 387 | } 388 | 389 | impl Drop for ReadHalf { 390 | fn drop(&mut self) { 391 | debug!("Drop ReadHalf {:?}", self.shutdown_notifier); 392 | self.shutdown_notifier.notify(); 393 | } 394 | } 395 | 396 | impl Drop for WriteHalf { 397 | fn drop(&mut self) { 398 | debug!("Drop WriteHalf {:?}", self.shutdown_notifier); 399 | self.shutdown_notifier.notify(); 400 | } 401 | } 402 | 403 | impl fmt::Debug for TcpStream { 404 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 405 | write!(f, "UsTcpStream({:?})", self.addr)?; 406 | Ok(()) 407 | } 408 | } 409 | 410 | #[cfg(test)] 411 | mod tests { 412 | 413 | #[test] 414 | fn t1() {} 415 | } 416 | -------------------------------------------------------------------------------- /ustunet/src/time.rs: -------------------------------------------------------------------------------- 1 | use smoltcp::time::Instant as SmolInstant; 2 | use std::ops::Add; 3 | use std::time::{Duration, Instant}; 4 | 5 | #[derive(Clone, Copy, Debug)] 6 | pub(crate) struct Clock { 7 | start_time: Instant, 8 | } 9 | 10 | impl Clock { 11 | pub fn new() -> Clock { 12 | Clock { 13 | start_time: Instant::now(), 14 | } 15 | } 16 | pub fn origin(&self) -> Instant { 17 | self.start_time 18 | } 19 | /// Returns a wrapper around a `i64` value that 20 | /// represents the number of milliseconds since start_time. 21 | pub fn timestamp(&self) -> SmolInstant { 22 | let elapsed = self.start_time.elapsed(); 23 | SmolInstant::from_millis( 24 | (elapsed.as_secs() * 1_000) as i64 + (elapsed.subsec_millis()) as i64, 25 | ) 26 | } 27 | /// Convert the number of milliseconds that smoltcp uses 28 | /// back to std::time::Instant. 29 | pub fn resolve(&self, timestamp: SmolInstant) -> Instant { 30 | self.start_time 31 | .add(Duration::from_millis(timestamp.millis as u64)) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ustunet/src/util.rs: -------------------------------------------------------------------------------- 1 | use smoltcp::wire::IpAddress as Address; 2 | use std::future::Future; 3 | use std::net::SocketAddr; 4 | use std::pin::Pin; 5 | use std::task::{Context, Poll}; 6 | 7 | pub fn convert_to_socket_address( 8 | address: Address, 9 | port: u16, 10 | ) -> Result { 11 | let socket_address = match address { 12 | Address::Ipv4(v4) => SocketAddr::from((v4.0, port)), 13 | Address::Ipv6(v6) => { 14 | let mut b = [0u16; 8]; 15 | v6.write_parts(&mut b); 16 | SocketAddr::from((b, port)) 17 | } 18 | _ => return Err(smoltcp::Error::Unrecognized), 19 | }; 20 | Ok(socket_address) 21 | } 22 | 23 | pub(crate) struct Selector { 24 | a: Pin>>, 25 | b: Pin>>, 26 | c: Pin>>, 27 | d: Pin>>, 28 | } 29 | 30 | impl Selector { 31 | pub fn new() -> Self { 32 | Selector { 33 | a: Box::pin(None), 34 | b: Box::pin(None), 35 | c: Box::pin(None), 36 | d: Box::pin(None), 37 | } 38 | } 39 | pub fn b(&self) -> &Option { 40 | self.b.as_ref().get_ref() 41 | } 42 | pub fn insert_a(&mut self, a: A) { 43 | assert!(self.a.is_none()); 44 | self.a.set(Some(a)); 45 | } 46 | pub fn insert_b(&mut self, b: B) { 47 | assert!(self.b.is_none()); 48 | self.b.set(Some(b)); 49 | } 50 | pub fn insert_c(&mut self, c: C) { 51 | assert!(self.c.is_none()); 52 | self.c.set(Some(c)); 53 | } 54 | pub fn insert_d(&mut self, d: D) { 55 | assert!(self.d.is_none()); 56 | self.d.set(Some(d)); 57 | } 58 | } 59 | 60 | pub(crate) struct SelectorFuture<'a, A, B, C, D> { 61 | select: &'a mut Selector, 62 | } 63 | 64 | impl Selector 65 | where 66 | A: Future, 67 | B: Future, 68 | C: Future, 69 | D: Future, 70 | { 71 | pub(crate) fn select(&mut self) -> SelectorFuture { 72 | SelectorFuture { select: self } 73 | } 74 | } 75 | 76 | impl Future for SelectorFuture<'_, A, B, C, D> 77 | where 78 | A: Future, 79 | B: Future, 80 | C: Future, 81 | D: Future, 82 | { 83 | type Output = Selected; 84 | 85 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 86 | let sel = &mut self.select; 87 | let a = &mut sel.a; 88 | let m = a.as_mut(); 89 | let p = m.as_pin_mut(); 90 | if let Some(b) = p { 91 | if let Poll::Ready(x) = b.poll(cx) { 92 | sel.a.set(None); 93 | return Poll::Ready(Selected::A(x)); 94 | } 95 | } 96 | if let Some(b) = sel.b.as_mut().as_pin_mut() { 97 | if let Poll::Ready(x) = b.poll(cx) { 98 | sel.b.set(None); 99 | return Poll::Ready(Selected::B(x)); 100 | } 101 | } 102 | let c = &mut sel.c; 103 | if let Some(b) = c.as_mut().as_pin_mut() { 104 | if let Poll::Ready(x) = b.poll(cx) { 105 | c.set(None); 106 | return Poll::Ready(Selected::C(x)); 107 | } 108 | } 109 | let c = &mut sel.d; 110 | if let Some(b) = c.as_mut().as_pin_mut() { 111 | if let Poll::Ready(x) = b.poll(cx) { 112 | c.set(None); 113 | return Poll::Ready(Selected::D(x)); 114 | } 115 | } 116 | Poll::Pending 117 | } 118 | } 119 | 120 | #[derive(Debug)] 121 | pub(crate) enum Selected { 122 | A(A), 123 | B(B), 124 | C(C), 125 | D(D), 126 | } 127 | 128 | #[cfg(test)] 129 | mod tests { 130 | use crate::util::{Selected, Selector}; 131 | use tokio::time::{sleep, Duration}; 132 | 133 | async fn fut2(u: u8) -> String { 134 | sleep(Duration::from_millis(1)).await; 135 | format!("u{}", u + 1) 136 | } 137 | #[tokio::test] 138 | async fn testss() { 139 | let future1 = async { 140 | sleep(Duration::from_millis(3)).await; 141 | "a" 142 | }; 143 | let future2 = fut2(34); 144 | let future3 = async { 145 | sleep(Duration::from_millis(3)).await; 146 | "a" 147 | }; 148 | let mut s = Selector::new(); 149 | s.insert_a(future1); 150 | s.insert_b(future2); 151 | s.insert_c(future3); 152 | s.insert_d(async { 153 | sleep(Duration::from_millis(9)).await; 154 | 1 155 | }); 156 | { 157 | let f = s.select(); 158 | let o = f.await; 159 | match o { 160 | Selected::A(x) => panic!("Output is {:?}", x), 161 | Selected::B(n) => assert_eq!("u35", n), 162 | Selected::C(_) => {} 163 | Selected::D(_) => {} 164 | } 165 | } 166 | { 167 | let f = s.select(); 168 | let o = f.await; 169 | match o { 170 | Selected::A(x) => assert_eq!("a", x), 171 | Selected::B(n) => panic!("Output is {:?}", n), 172 | Selected::C(_) => {} 173 | _ => {} 174 | } 175 | } 176 | let future3 = fut2(75); 177 | s.insert_b(future3); 178 | let _o = s.select().await; 179 | let _o = s.select().await; 180 | } 181 | } 182 | --------------------------------------------------------------------------------