Add Rust bindings (WIP)

This commit is contained in:
Joseph Henry
2021-05-24 21:29:57 -07:00
parent b13746871f
commit 2a41301e33
13 changed files with 9547 additions and 0 deletions

336
pkg/crate/libzt/Cargo.lock generated Normal file
View File

@@ -0,0 +1,336 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
"winapi",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "bindgen"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd4865004a46a0aafb2a0a5eb19d3c9fc46ee5f063a6cfc605c69ac9ecf5263d"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
"clap",
"env_logger",
"lazy_static",
"lazycell",
"log",
"peeking_take_while",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"which",
]
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "cexpr"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clang-sys"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "853eda514c284c2287f4bf20ae614f8781f40a81d32ecda6e91449304dfe077c"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "clap"
version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"unicode-width",
"vec_map",
]
[[package]]
name = "env_logger"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "hermit-abi"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
dependencies = [
"libc",
]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
[[package]]
name = "libloading"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a"
dependencies = [
"cfg-if",
"winapi",
]
[[package]]
name = "libzt"
version = "0.1.0"
dependencies = [
"bindgen",
"libc",
]
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "nom"
version = "5.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
dependencies = [
"memchr",
"version_check",
]
[[package]]
name = "peeking_take_while"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "proc-macro2"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce5f1ceb7f74abbce32601642fcf8e8508a8a8991e0621c7d750295b9095702b"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "shlex"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "termcolor"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]]
name = "unicode-width"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "which"
version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
dependencies = [
"libc",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@@ -0,0 +1,27 @@
[package]
name = "libzt"
version = "0.1.0"
authors = ["Joseph Henry <joseph.henry@zerotier.com>"]
edition = "2018"
description = "Encrypted P2P SD-WAN library by ZeroTier"
documentation = "https://github.com/zerotier/libzt"
readme = "README.md"
homepage = "https://www.zerotier.com"
license-file = "LICENSE.txt"
keywords = ["zerotier", "p2p", "vpn", "socket", "network"]
categories = ["network-programming", "cryptography"]
[dependencies]
[build-dependencies]
bindgen = "0.57"
libc = "0.2"
[lib]
name = "libzt"
path = "src/lib.rs"
[[bin]]
name = "libzt-test-app"
path = "src/bin/libzt-test-app.rs"

631
pkg/crate/libzt/LICENSE.txt Normal file
View File

@@ -0,0 +1,631 @@
-----------------------------------------------------------------------------
Business Source License 1.1
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
"Business Source License" is a trademark of MariaDB Corporation Ab.
-----------------------------------------------------------------------------
Parameters
Licensor: ZeroTier, Inc.
Licensed Work: ZeroTier Network Virtualization Engine 1.4.4
The Licensed Work is (c)2019 ZeroTier, Inc.
Additional Use Grant: You may make use of the Licensed Work, provided you
do not use it in any of the following ways:
* Sell hosted ZeroTier services as a "SaaS" Product
(1) Operate or sell access to ZeroTier root servers,
network controllers, or authorization key or certificate
generation components of the Licensed Work as a
for-profit service, regardless of whether the use of
these components is sold alone or is bundled with other
services. Note that this does not apply to the use of
ZeroTier behind the scenes to operate a service not
related to ZeroTier network administration.
* Create Non-Open-Source Commercial Derviative Works
(2) Link or directly include the Licensed Work in a
commercial or for-profit application or other product
not distributed under an Open Source Initiative (OSI)
compliant license. See: https://opensource.org/licenses
(3) Remove the name, logo, copyright, or other branding
material from the Licensed Work to create a "rebranded"
or "white labeled" version to distribute as part of
any commercial or for-profit product or service.
* Certain Government Uses
(4) Use or deploy the Licensed Work in a government
setting in support of any active government function
or operation with the exception of the following:
physical or mental health care, family and social
services, social welfare, senior care, child care, and
the care of persons with disabilities.
Change Date: 2023-01-01
Change License: Apache License version 2.0 as published by the Apache
Software Foundation
https://www.apache.org/licenses/
Alternative Licensing
If you would like to use the Licensed Work in any way that conflicts with
the stipulations of the Additional Use Grant, contact ZeroTier, Inc. to
obtain an alternative commercial license.
Visit us on the web at: https://www.zerotier.com/
Notice
The Business Source License (this document, or the "License") is not an Open
Source license. However, the Licensed Work will eventually be made available
under an Open Source License, as stated in this License.
For more information on the use of the Business Source License for ZeroTier
products, please visit our pricing page which contains license details and
and license FAQ: https://zerotier.com/pricing
For more information on the use of the Business Source License generally,
please visit the Adopting and Developing Business Source License FAQ at
https://mariadb.com/bsl-faq-adopting.
-----------------------------------------------------------------------------
Business Source License 1.1
Terms
The Licensor hereby grants you the right to copy, modify, create derivative
works, redistribute, and make non-production use of the Licensed Work. The
Licensor may make an Additional Use Grant, above, permitting limited
production use.
Effective on the Change Date, or the fourth anniversary of the first publicly
available distribution of a specific version of the Licensed Work under this
License, whichever comes first, the Licensor hereby grants you rights under
the terms of the Change License, and the rights granted in the paragraph
above terminate.
If your use of the Licensed Work does not comply with the requirements
currently in effect as described in this License, you must purchase a
commercial license from the Licensor, its affiliated entities, or authorized
resellers, or you must refrain from using the Licensed Work.
All copies of the original and modified Licensed Work, and derivative works
of the Licensed Work, are subject to this License. This License applies
separately for each version of the Licensed Work and the Change Date may vary
for each version of the Licensed Work released by Licensor.
You must conspicuously display this License on each original or modified copy
of the Licensed Work. If you receive the Licensed Work in original or
modified form from a third party, the terms and conditions set forth in this
License apply to your use of that work.
Any use of the Licensed Work in violation of this License will automatically
terminate your rights under this License for the current and all other
versions of the Licensed Work.
This License does not grant you any right in any trademark or logo of
Licensor or its affiliates (provided that you may use a trademark or logo of
Licensor as expressly required by this License).
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
TITLE.
-----------------------------------------------------------------------------
MariaDB hereby grants you permission to use this Licenses text to license
your works, and to refer to it using the trademark "Business Source License",
as long as you comply with the Covenants of Licensor below.
Covenants of Licensor
In consideration of the right to use this Licenses text and the "Business
Source License" name and trademark, Licensor covenants to MariaDB, and to all
other recipients of the licensed work to be provided by Licensor:
1. To specify as the Change License the GPL Version 2.0 or any later version,
or a license that is compatible with GPL Version 2.0 or a later version,
where "compatible" means that software provided under the Change License can
be included in a program with software provided under GPL Version 2.0 or a
later version. Licensor may specify additional Change Licenses without
limitation.
2. To either: (a) specify an additional grant of rights to use that does not
impose any additional restriction on the right granted in this License, as
the Additional Use Grant; or (b) insert the text "None".
3. To specify a Change Date.
4. Not to modify this License in any other way.
END OF Business Source License 1.1
--------------------------------------------------------------------------------
Portions of the Rust crate that wraps the functionality of libzt into an
idiomatic interface are derived from the Rust standard library. The standard
library's copyright and associated licenses are reproduced below. The copyright
and its licenses only apply to the code derived from the Rust standard library
and not libzt or ZeroTier. libzt and ZeroTier are subject to the BUSL-1.1
license reproduced above.
--------------------------------------------------------------------------------
Short version for non-lawyers:
The Rust Project is dual-licensed under Apache 2.0 and MIT
terms.
Longer version:
Copyrights in the Rust project are retained by their contributors. No
copyright assignment is required to contribute to the Rust project.
Some files include explicit copyright notices and/or license notices.
For full authorship information, see the version control history or
https://thanks.rust-lang.org
Except as otherwise noted (below and/or in individual files), Rust is
licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or
<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option.
The Rust Project includes packages written by third parties.
The following third party packages are included, and carry
their own copyright notices and license terms:
* LLVM. Code for this package is found in src/llvm-project.
Copyright (c) 2003-2013 University of Illinois at
Urbana-Champaign. All rights reserved.
Developed by:
LLVM Team
University of Illinois at Urbana-Champaign
http://llvm.org
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal with the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
* Redistributions of source code must retain the
above copyright notice, this list of conditions
and the following disclaimers.
* Redistributions in binary form must reproduce the
above copyright notice, this list of conditions
and the following disclaimers in the documentation
and/or other materials provided with the
distribution.
* Neither the names of the LLVM Team, University of
Illinois at Urbana-Champaign, nor the names of its
contributors may be used to endorse or promote
products derived from this Software without
specific prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS WITH THE SOFTWARE.
* Additional libraries included in LLVM carry separate
BSD-compatible licenses. See src/llvm-project/llvm/LICENSE.TXT
for details.
* compiler-rt, in src/compiler-rt is dual licensed under
LLVM's license and MIT:
Copyright (c) 2009-2014 by the contributors listed in
CREDITS.TXT
All rights reserved.
Developed by:
LLVM Team
University of Illinois at Urbana-Champaign
http://llvm.org
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal with the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
* Redistributions of source code must retain the
above copyright notice, this list of conditions
and the following disclaimers.
* Redistributions in binary form must reproduce the
above copyright notice, this list of conditions
and the following disclaimers in the documentation
and/or other materials provided with the
distribution.
* Neither the names of the LLVM Team, University of
Illinois at Urbana-Champaign, nor the names of its
contributors may be used to endorse or promote
products derived from this Software without
specific prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS WITH THE SOFTWARE.
========================================================
Copyright (c) 2009-2014 by the contributors listed in
CREDITS.TXT
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
* Portions of the FFI code for interacting with the native ABI
is derived from the Clay programming language, which carries
the following license.
Copyright (C) 2008-2010 Tachyon Technologies.
All rights reserved.
Redistribution and use in source and binary forms, with
or without modification, are permitted provided that the
following conditions are met:
1. Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
2. Redistributions in binary form must reproduce the
above copyright notice, this list of conditions and
the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
* libbacktrace, under src/libbacktrace:
Copyright (C) 2012-2014 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with
or without modification, are permitted provided that the
following conditions are met:
(1) Redistributions of source code must retain the
above copyright notice, this list of conditions and
the following disclaimer.
(2) Redistributions in binary form must reproduce
the above copyright notice, this list of conditions
and the following disclaimer in the documentation
and/or other materials provided with the
distribution.
(3) The name of the author may not be used to
endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE. */
--------------------------------------------------------------------------------
MIT License
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@@ -0,0 +1,3 @@
# Unsafe bindings for ZeroTier SDK
This crate is a pre-Alpha work in progress intended as a placeholder as development continues. Currently only basic creation and management of a node and unsafe BSD-style socket operations are supported. An idiomatic wrapper will eventually replace this.

19
pkg/crate/libzt/build.rs Normal file
View File

@@ -0,0 +1,19 @@
extern crate bindgen;
fn main() {
println!("cargo:rustc-link-lib=zt");
println!("cargo:rustc-env=LLVM_CONFIG_PATH=/usr/local/opt/llvm/bin/llvm-config");
//println!("cargo:rerun-if-changed=../../../include/ZeroTierSockets.h");
//println!("cargo:include=/usr/local/include");
let bindings = bindgen::Builder::default()
.header("../../../include/ZeroTierSockets.h")
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.generate()
.expect("Unable to generate bindings");
bindings
.write_to_file("./src/libzt.rs")
.expect("Couldn't write bindings!");
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
include!(concat!("./libzt.rs"));
pub mod node;
pub mod socket;
pub mod tcp;
pub mod udp;
pub mod utils;

6872
pkg/crate/libzt/src/libzt.rs Normal file

File diff suppressed because it is too large Load Diff

115
pkg/crate/libzt/src/node.rs Normal file
View File

@@ -0,0 +1,115 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
include!(concat!("./libzt.rs"));
use std::ffi::{c_void, CStr, CString};
extern "C" fn native_event_handler(msg: *mut c_void) {
let event: &mut zts_event_msg_t = unsafe { &mut *(msg as *mut zts_event_msg_t) };
println!("event: {}", event.event_code);
//user_event_handler(event.event_code);
}
pub struct ZeroTierNode {
// TODO
}
impl ZeroTierNode {
pub fn init_set_event_handler(&self, user_event_handler: impl Fn(i16) -> ()) -> i32 {
unsafe {
return zts_init_set_event_handler(Some(native_event_handler));
}
}
pub fn init_set_port(&self, port: u16) -> i32 {
unsafe {
return zts_init_set_port(port);
}
}
pub fn init_from_storage(&self, storage_path: &str) -> i32 {
unsafe {
// This is a false-positive by the linter
// See: https://github.com/rust-lang/rust/issues/78691
#[allow(temporary_cstring_as_ptr)]
return zts_init_from_storage(CString::new(storage_path).unwrap().as_ptr());
}
}
pub fn start(&self) -> i32 {
unsafe {
return zts_node_start();
}
}
pub fn stop(&self) -> i32 {
unsafe {
return zts_node_stop();
}
}
pub fn free(&self) -> i32 {
unsafe {
return zts_node_free();
}
}
pub fn net_join(&self, net_id: u64) -> i32 {
unsafe {
return zts_net_join(net_id);
}
}
pub fn net_leave(&self, net_id: u64) -> i32 {
unsafe {
return zts_net_leave(net_id);
}
}
pub fn net_transport_is_ready(&self, net_id: u64) -> bool {
unsafe {
return zts_net_transport_is_ready(net_id) == 1;
}
}
pub fn is_online(&self) -> bool {
unsafe {
return zts_node_is_online() == 1;
}
}
pub fn id(&self) -> u64 {
unsafe {
return zts_node_get_id();
}
}
pub fn delay(&self, interval_ms: u64) -> () {
unsafe { zts_util_delay(interval_ms) }
}
pub fn addr_get(&self, net_id: u64) -> String {
unsafe {
let mut v = vec![0; (ZTS_INET6_ADDRSTRLEN as usize) + 1];
let ptr = v.as_mut_ptr() as *mut i8;
zts_addr_get_str(net_id, ZTS_AF_INET, ptr, ZTS_INET6_ADDRSTRLEN);
let c_str = CStr::from_ptr(ptr);
return c_str.to_string_lossy().into_owned();
}
}
}

View File

@@ -0,0 +1,329 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
use std::convert::TryInto;
use std::ffi::c_void;
use std::io::{Error, ErrorKind};
use std::net::{Shutdown, SocketAddr};
use std::os::raw::c_int;
use std::time::Duration;
use std::{io, mem};
use crate::utils::*;
// Note: FileDesc and c_int in libc are private so we can't use that. Use i32 instead
pub struct Socket(c_int);
impl Socket {
pub fn new(addr: &SocketAddr, sock_type: c_int) -> io::Result<Socket> {
let family = match *addr {
SocketAddr::V4(..) => ZTS_AF_INET,
SocketAddr::V6(..) => ZTS_AF_INET6,
};
Socket::new_raw(family as i32, sock_type)
}
pub fn new_raw(family: c_int, sock_type: c_int) -> io::Result<Socket> {
unsafe {
// TODO: Set O_CLOEXEC (this is done in the Rust netc implementation)
let fd = zts_bsd_socket(family, sock_type, 0);
Ok(Socket(fd))
}
}
pub fn accept(
&self,
storage: *mut zts_sockaddr,
len: *mut zts_socklen_t,
) -> io::Result<Socket> {
let fd = unsafe { zts_bsd_accept(self.0, storage, len) };
Ok(Socket(fd))
}
pub fn as_inner(&self) -> &c_int {
&self.0
//.as_inner()
}
/*
pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
self.set_nonblocking(true)?;
let r = unsafe {
let (addrp, len) = addr.into_inner();
cvt(zts_bsd_connect(self.0, addrp, len))
};
self.set_nonblocking(false)?;
match r {
Ok(_) => return Ok(()),
// there's no ErrorKind for EINPROGRESS :(
Err(ref e) if e.raw_os_error() == Some(ZTS_EINPROGRESS) => {}
Err(e) => return Err(e),
}
let mut pollfd = zts_pollfd { fd: self.0, events: ZTS_POLLOUT, revents: 0 };
if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
return Err(io::Error::new_const(
io::ErrorKind::InvalidInput,
&"cannot set a 0 duration timeout",
));
}
let start = Instant::now();
loop {
let elapsed = start.elapsed();
if elapsed >= timeout {
return Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out"));
}
let timeout = timeout - elapsed;
let mut timeout = timeout
.as_secs()
.saturating_mul(1_000)
.saturating_add(timeout.subsec_nanos() as u64 / 1_000_000);
if timeout == 0 {
timeout = 1;
}
let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int;
match unsafe { zts_bsd_poll(&mut pollfd, 1, timeout) } {
-1 => {
let err = io::Error::last_os_error();
if err.kind() != io::ErrorKind::Interrupted {
return Err(err);
}
}
0 => {}
_ => {
// linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
// for POLLHUP rather than read readiness
if pollfd.revents & ZTS_POLLHUP != 0 {
let e = self.take_error()?.unwrap_or_else(|| {
io::Error::new_const(
io::ErrorKind::Other,
&"no error set after POLLHUP",
)
});
return Err(e);
}
return Ok(());
}
}
}
}
*/
fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
unsafe {
let raw = zts_bsd_recv(
self.0,
buf.as_mut_ptr() as *mut c_void,
(buf.len() as usize).try_into().unwrap(),
flags,
);
Ok(raw as usize)
}
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.recv_with_flags(buf, 0)
}
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.recv_with_flags(buf, ZTS_MSG_PEEK as i32)
}
/*
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.0.read_vectored(bufs)
}
*/
#[inline]
pub fn is_read_vectored(&self) -> bool {
// TODO: In principle this is possible but is not hooked up yet
return false;
}
fn recv_from_with_flags(
&self,
buf: &mut [u8],
flags: c_int,
) -> io::Result<(usize, SocketAddr)> {
let mut storage: zts_sockaddr_storage = unsafe { mem::zeroed() };
let mut addrlen = mem::size_of_val(&storage) as zts_socklen_t;
unsafe {
let n = zts_bsd_recvfrom(
self.0,
buf.as_mut_ptr() as *mut c_void,
buf.len().try_into().unwrap(),
flags,
&mut storage as *mut _ as *mut _,
&mut addrlen,
);
Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
}
}
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.recv_from_with_flags(buf, 0)
}
pub fn recv_msg(&self, msg: &mut zts_msghdr) -> io::Result<usize> {
unsafe {
let n = zts_bsd_recvmsg(self.0, msg, 0 /*ZTS_MSG_CMSG_CLOEXEC*/);
Ok(n as usize)
}
}
pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.recv_from_with_flags(buf, ZTS_MSG_PEEK as i32)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
unsafe {
let raw = zts_bsd_write(
self.0,
buf.as_ptr() as *const c_void,
buf.len().try_into().unwrap(),
);
if raw >= 0 {
Ok(raw.try_into().unwrap())
} else {
Err(io::Error::from_raw_os_error(raw as i32))
}
}
}
/*
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.0.write_vectored(bufs)
}
*/
#[inline]
pub fn is_write_vectored(&self) -> bool {
// TODO: In principle this is possible but is not hooked up yet
return false;
}
pub fn send_msg(&self, msg: &mut zts_msghdr) -> io::Result<usize> {
unsafe {
let n = zts_bsd_sendmsg(self.0, msg, 0);
Ok(n as usize)
}
}
pub fn set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()> {
let timeout = match dur {
Some(dur) => {
if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
// TODO: Use new_const to avoid allocations
return Err(Error::new(
ErrorKind::InvalidInput,
"Cannot set a 0 duration timeout",
));
}
let secs = if dur.as_secs() > time_t::MAX as u64 {
time_t::MAX
} else {
dur.as_secs() as time_t
};
let mut timeout = zts_timeval {
tv_sec: secs,
tv_usec: dur.subsec_micros() as std::os::raw::c_long,
};
if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
timeout.tv_usec = 1;
}
timeout
}
None => zts_timeval {
tv_sec: 0,
tv_usec: 0,
},
};
setsockopt(self, ZTS_SOL_SOCKET as i32, kind, timeout)
}
pub fn timeout(&self, kind: c_int) -> io::Result<Option<Duration>> {
let raw: zts_timeval = getsockopt(self, ZTS_SOL_SOCKET as i32, kind)?;
if raw.tv_sec == 0 && raw.tv_usec == 0 {
Ok(None)
} else {
let sec = raw.tv_sec as u64;
let nsec = (raw.tv_usec as u32) * 1000;
Ok(Some(Duration::new(sec, nsec)))
}
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
let how = match how {
Shutdown::Write => ZTS_SHUT_WR as i32,
Shutdown::Read => ZTS_SHUT_RD as i32,
Shutdown::Both => ZTS_SHUT_RDWR as i32,
};
unsafe {
let raw: c_int = zts_bsd_shutdown(self.0, how);
if raw == 0 {
Ok(())
} else {
Err(io::Error::from_raw_os_error(raw as i32))
}
}
}
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
let nodelay = nodelay as c_int;
unsafe {
let raw: c_int = zts_set_no_delay(self.0, nodelay);
if raw == 0 {
Ok(())
} else {
Err(io::Error::from_raw_os_error(raw as i32))
}
}
}
pub fn nodelay(&self) -> io::Result<bool> {
unsafe {
let raw: c_int = zts_get_no_delay(self.0);
Ok(raw != 0)
}
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
let nonblocking = nonblocking as c_int;
unsafe {
let raw: c_int = zts_set_blocking(self.0, !nonblocking);
if raw == 0 {
Ok(())
} else {
Err(io::Error::from_raw_os_error(raw as i32))
}
}
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
unsafe {
let raw: c_int = zts_get_last_socket_error(self.0);
if raw == 0 {
Ok(None)
} else {
Err(io::Error::from_raw_os_error(raw as i32))
}
}
}
}

518
pkg/crate/libzt/src/tcp.rs Normal file
View File

@@ -0,0 +1,518 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
use std::ffi::{c_void, CString};
use std::io;
use std::io::{Read, Write};
use std::net::{Shutdown, SocketAddr, ToSocketAddrs};
use std::os::raw::c_int;
use std::time::Duration;
use std::{cmp, mem};
use crate::socket::Socket;
use crate::utils::*;
//----------------------------------------------------------------------------//
// TcpStream //
//----------------------------------------------------------------------------//
pub struct TcpStreamImpl {
inner: Socket,
}
impl TcpStreamImpl {
pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStreamImpl> {
let addr = addr?;
let socket = Socket::new(addr, ZTS_SOCK_STREAM as i32)?;
//let (addrp, len) = addr.into_inner();
unsafe {
// TODO: Find a better way to split this address string
let full_str = addr.to_string();
let full_vec = full_str.split(":");
let lvec: Vec<&str> = full_vec.collect();
let addr_str = lvec[0];
let port = addr.port();
let timeout_ms = 0;
// TODO: Handle native error code, consider cvt?
// This is a false-positive by the linter
// See: https://github.com/rust-lang/rust/issues/78691
#[allow(temporary_cstring_as_ptr)]
zts_connect(
*socket.as_inner(),
CString::new(addr_str).unwrap().as_ptr(),
port,
timeout_ms,
);
}
Ok(TcpStreamImpl { inner: socket })
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let len = cmp::min(buf.len(), <size_t>::MAX as usize) as size_t;
// TODO: Handle native error code, consider cvt?
let ret =
unsafe { zts_bsd_write(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len) };
Ok(ret as usize)
}
/*
pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
init();
let sock = Socket::new(addr, c::SOCK_STREAM)?;
sock.connect_timeout(addr, timeout)?;
Ok(TcpStream { inner: sock })
}
*/
pub fn socket(&self) -> &Socket {
&self.inner
}
pub fn into_socket(self) -> Socket {
self.inner
}
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
self.inner.set_timeout(dur, ZTS_SO_RCVTIMEO as i32)
}
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
self.inner.set_timeout(dur, ZTS_SO_SNDTIMEO as i32)
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
self.inner.timeout(ZTS_SO_RCVTIMEO as i32)
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
self.inner.timeout(ZTS_SO_SNDTIMEO as i32)
}
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.peek(buf)
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
/*
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.inner.read_vectored(bufs)
}
#[inline]
pub fn is_read_vectored(&self) -> bool {
self.inner.is_read_vectored()
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
let ret = cvt(unsafe {
zts_bsd_send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, ZTS_MSG_NOSIGNAL)
})?;
Ok(ret as usize)
}
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.inner.write_vectored(bufs)
}
#[inline]
pub fn is_write_vectored(&self) -> bool {
self.inner.is_write_vectored()
}
*/
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
sockname(|buf, len| unsafe { zts_bsd_getpeername(*self.inner.as_inner(), buf, len) })
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
sockname(|buf, len| unsafe { zts_bsd_getsockname(*self.inner.as_inner(), buf, len) })
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
self.inner.shutdown(how)
}
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
self.inner.set_nodelay(nodelay)
}
pub fn nodelay(&self) -> io::Result<bool> {
self.inner.nodelay()
}
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
setsockopt(
&self.inner,
ZTS_IPPROTO_IP as i32,
ZTS_IP_TTL as i32,
ttl as c_int,
)
}
pub fn ttl(&self) -> io::Result<u32> {
let raw: c_int = getsockopt(&self.inner, ZTS_IPPROTO_IP as i32, ZTS_IP_TTL as i32)?;
Ok(raw as u32)
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.inner.take_error()
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
self.inner.set_nonblocking(nonblocking)
}
}
pub struct TcpStream(TcpStreamImpl);
impl TcpStream {
pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
each_addr(addr, TcpStreamImpl::connect).map(TcpStream)
}
/*
pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
TcpStreamImpl::connect_timeout(addr, timeout).map(TcpStream)
}
*/
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.0.peer_addr()
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.0.socket_addr()
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
self.0.shutdown(how)
}
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
self.0.set_read_timeout(dur)
}
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
self.0.set_write_timeout(dur)
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
self.0.read_timeout()
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
self.0.write_timeout()
}
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.0.peek(buf)
}
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
self.0.set_nodelay(nodelay)
}
pub fn nodelay(&self) -> io::Result<bool> {
self.0.nodelay()
}
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
self.0.set_ttl(ttl)
}
pub fn ttl(&self) -> io::Result<u32> {
self.0.ttl()
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.0.take_error()
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
self.0.set_nonblocking(nonblocking)
}
}
impl Read for TcpStream {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
/*
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.0.read_vectored(bufs)
}
#[inline]
fn is_read_vectored(&self) -> bool {
self.0.is_read_vectored()
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
// SAFETY: Read is guaranteed to work on uninitialized memory
unsafe { Initializer::nop() }
}
*/
}
impl Write for TcpStream {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
/*
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.0.write_vectored(bufs)
}
#[inline]
fn is_write_vectored(&self) -> bool {
self.0.is_write_vectored()
}
*/
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl Read for &TcpStream {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
/*
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.0.read_vectored(bufs)
}
#[inline]
fn is_read_vectored(&self) -> bool {
self.0.is_read_vectored()
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
// SAFETY: Read is guaranteed to work on uninitialized memory
unsafe { Initializer::nop() }
}
*/
}
impl Write for &TcpStream {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
/*
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.0.write_vectored(bufs)
}
#[inline]
fn is_write_vectored(&self) -> bool {
self.0.is_write_vectored()
}
*/
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl AsInner<TcpStreamImpl> for TcpStream {
fn as_inner(&self) -> &TcpStreamImpl {
&self.0
}
}
impl FromInner<TcpStreamImpl> for TcpStream {
fn from_inner(inner: TcpStreamImpl) -> TcpStream {
TcpStream(inner)
}
}
impl IntoInner<TcpStreamImpl> for TcpStream {
fn into_inner(self) -> TcpStreamImpl {
self.0
}
}
/*
impl fmt::Debug for TcpStream {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
*/
//----------------------------------------------------------------------------//
// TcpListener //
//----------------------------------------------------------------------------//
pub struct TcpListenerImpl {
inner: Socket,
}
impl TcpListenerImpl {
pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListenerImpl> {
let addr = addr?;
let socket = Socket::new(addr, ZTS_SOCK_STREAM as i32)?;
// TODO: Possibly set SO_REUSEADDR
//let (addrp, len) = addr.into_inner();
unsafe {
//zts_bsd_bind(*socket.as_inner(), addrp, len as _);
// TODO: Find a better way to split this address string
let full_str = addr.to_string();
let full_vec = full_str.split(":");
let lvec: Vec<&str> = full_vec.collect();
let addr_str = lvec[0];
let port = addr.port();
// TODO: Handle native error code, consider cvt?
// This is a false-positive by the linter
// See: https://github.com/rust-lang/rust/issues/78691
#[allow(temporary_cstring_as_ptr)]
zts_bind(
*socket.as_inner(),
CString::new(addr_str).unwrap().as_ptr(),
port,
);
// TODO: Handle native error code, consider cvt?
zts_bsd_listen(*socket.as_inner(), 128);
}
Ok(TcpListenerImpl { inner: socket })
}
pub fn accept(&self) -> io::Result<(TcpStreamImpl, SocketAddr)> {
let mut storage: zts_sockaddr_storage = unsafe { mem::zeroed() };
let mut len = mem::size_of_val(&storage) as zts_socklen_t;
// TODO: Handle native error code, consider cvt?
let socket = self
.inner
.accept(&mut storage as *mut _ as *mut _, &mut len)?;
let addr = sockaddr_to_addr(&storage, len as usize)?;
Ok((TcpStreamImpl { inner: socket }, addr))
}
pub fn socket(&self) -> &Socket {
&self.inner
}
pub fn into_socket(self) -> Socket {
self.inner
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
sockname(|buf, len| unsafe { zts_bsd_getsockname(*self.inner.as_inner(), buf, len) })
}
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
setsockopt(
&self.inner,
ZTS_IPPROTO_IP as i32,
ZTS_IP_TTL as i32,
ttl as c_int,
)
}
pub fn ttl(&self) -> io::Result<u32> {
let raw: c_int = getsockopt(&self.inner, ZTS_IPPROTO_IP as i32, ZTS_IP_TTL as i32)?;
Ok(raw as u32)
}
pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
setsockopt(
&self.inner,
ZTS_IPPROTO_IPV6 as i32,
ZTS_IPV6_V6ONLY as i32,
only_v6 as c_int,
)
}
pub fn only_v6(&self) -> io::Result<bool> {
let raw: c_int = getsockopt(&self.inner, ZTS_IPPROTO_IPV6 as i32, ZTS_IPV6_V6ONLY as i32)?;
Ok(raw != 0)
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.inner.take_error()
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
self.inner.set_nonblocking(nonblocking)
}
}
pub struct TcpListener(TcpListenerImpl);
pub struct Incoming<'a> {
listener: &'a TcpListener,
}
impl<'a> Iterator for Incoming<'a> {
type Item = io::Result<TcpStream>;
fn next(&mut self) -> Option<io::Result<TcpStream>> {
Some(self.listener.accept().map(|p| p.0))
}
}
impl TcpListener {
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
each_addr(addr, TcpListenerImpl::bind).map(TcpListener)
}
pub fn incoming(&self) -> Incoming<'_> {
Incoming { listener: self }
}
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
self.0.accept().map(|(a, b)| (TcpStream(a), b))
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.0.socket_addr()
}
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
self.0.set_ttl(ttl)
}
pub fn ttl(&self) -> io::Result<u32> {
self.0.ttl()
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.0.take_error()
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
self.0.set_nonblocking(nonblocking)
}
}
impl AsInner<TcpListenerImpl> for TcpListener {
fn as_inner(&self) -> &TcpListenerImpl {
&self.0
}
}
impl FromInner<TcpListenerImpl> for TcpListener {
fn from_inner(inner: TcpListenerImpl) -> TcpListener {
TcpListener(inner)
}
}
impl IntoInner<TcpListenerImpl> for TcpListener {
fn into_inner(self) -> TcpListenerImpl {
self.0
}
}
/*
impl fmt::Debug for TcpListener {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
*/

459
pkg/crate/libzt/src/udp.rs Normal file
View File

@@ -0,0 +1,459 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
use std::convert::TryInto;
use std::ffi::{c_void, CString};
use std::io::{self, Error, ErrorKind};
use std::net::{/*Ipv4Addr, Ipv6Addr,*/ SocketAddr, ToSocketAddrs};
use std::os::raw::c_int;
use std::time::Duration;
//use std::cmp;
use crate::socket::Socket;
use crate::utils::*;
//----------------------------------------------------------------------------//
// UdpSocketImpl //
//----------------------------------------------------------------------------//
pub struct UdpSocketImpl {
inner: Socket,
}
impl UdpSocketImpl {
pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<UdpSocketImpl> {
let addr = addr?;
let socket = Socket::new(addr, ZTS_SOCK_DGRAM as i32)?;
// TODO: Possibly set SO_REUSEADDR
//let (addrp, len) = addr.into_inner();
unsafe {
//zts_bsd_bind(*socket.as_inner(), addrp, len as _);
// TODO: Find a better way to split this address string
let full_str = addr.to_string();
let full_vec = full_str.split(":");
let lvec: Vec<&str> = full_vec.collect();
let addr_str = lvec[0];
let port = addr.port();
// TODO: Handle native error code, consider cvt?
// This is a false-positive by the linter
// See: https://github.com/rust-lang/rust/issues/78691
#[allow(temporary_cstring_as_ptr)]
zts_bind(
*socket.as_inner(),
CString::new(addr_str).unwrap().as_ptr(),
port,
);
}
Ok(UdpSocketImpl { inner: socket })
}
pub fn socket(&self) -> &Socket {
&self.inner
}
pub fn into_socket(self) -> Socket {
self.inner
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
sockname(|buf, len| unsafe { zts_bsd_getpeername(*self.inner.as_inner(), buf, len) })
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
sockname(|buf, len| unsafe { zts_bsd_getsockname(*self.inner.as_inner(), buf, len) })
}
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.inner.recv_from(buf)
}
pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.inner.peek_from(buf)
}
pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> {
/*
let len = cmp::min(buf.len(), <size_t>::MAX as usize) as size_t;
let (dstp, dstlen) = dst.into_inner();
let ret = cvt(unsafe {
zts_bsd_sendto(
*self.inner.as_inner(),
buf.as_ptr() as *const c_void,
len,
ZTS_MSG_NOSIGNAL,
dstp,
dstlen,
)
})?;
Ok(ret as usize)
*/
Ok(0)
}
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
self.inner.set_timeout(dur, ZTS_SO_RCVTIMEO as i32)
}
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
self.inner.set_timeout(dur, ZTS_SO_SNDTIMEO as i32)
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
self.inner.timeout(ZTS_SO_RCVTIMEO as i32)
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
self.inner.timeout(ZTS_SO_SNDTIMEO as i32)
}
pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
setsockopt(
&self.inner,
ZTS_SOL_SOCKET as i32,
ZTS_SO_BROADCAST as i32,
broadcast as c_int,
)
}
pub fn broadcast(&self) -> io::Result<bool> {
let raw: c_int = getsockopt(&self.inner, ZTS_SOL_SOCKET as i32, ZTS_SO_BROADCAST as i32)?;
Ok(raw != 0)
}
/*
pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> {
setsockopt(
&self.inner,
ZTS_IPPROTO_IP,
ZTS_IP_MULTICAST_LOOP,
multicast_loop_v4 as IpV4MultiCastType,
)
}
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
let raw: IpV4MultiCastType = getsockopt(&self.inner, ZTS_IPPROTO_IP, ZTS_IP_MULTICAST_LOOP)?;
Ok(raw != 0)
}
pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> {
setsockopt(
&self.inner,
ZTS_IPPROTO_IP,
ZTS_IP_MULTICAST_TTL,
multicast_ttl_v4 as IpV4MultiCastType,
)
}
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
let raw: IpV4MultiCastType = getsockopt(&self.inner, ZTS_IPPROTO_IP, ZTS_IP_MULTICAST_TTL)?;
Ok(raw as u32)
}
pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> {
setsockopt(&self.inner, ZTS_IPPROTO_IPV6, ZTS_IPV6_MULTICAST_LOOP, multicast_loop_v6 as c_int)
}
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
let raw: c_int = getsockopt(&self.inner, ZTS_IPPROTO_IPV6, ZTS_IPV6_MULTICAST_LOOP)?;
Ok(raw != 0)
}
pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
let mreq = zts_ip_mreq {
imr_multiaddr: multiaddr.into_inner(),
imr_interface: interface.into_inner(),
};
setsockopt(&self.inner, ZTS_IPPROTO_IP, ZTS_IP_ADD_MEMBERSHIP, mreq)
}
pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
let mreq = zts_ipv6_mreq {
ipv6mr_multiaddr: *multiaddr.as_inner(),
ipv6mr_interface: to_ipv6mr_interface(interface),
};
setsockopt(&self.inner, ZTS_IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq)
}
pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
let mreq = zts_ip_mreq {
imr_multiaddr: multiaddr.into_inner(),
imr_interface: interface.into_inner(),
};
setsockopt(&self.inner, ZTS_IPPROTO_IP, ZTS_IP_DROP_MEMBERSHIP, mreq)
}
pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
let mreq = zts_ipv6_mreq {
ipv6mr_multiaddr: *multiaddr.as_inner(),
ipv6mr_interface: to_ipv6mr_interface(interface),
};
setsockopt(&self.inner, ZTS_IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq)
}
*/
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
setsockopt(
&self.inner,
ZTS_IPPROTO_IP as i32,
ZTS_IP_TTL as i32,
ttl as c_int,
)
}
pub fn ttl(&self) -> io::Result<u32> {
let raw: c_int = getsockopt(&self.inner, ZTS_IPPROTO_IP as i32, ZTS_IP_TTL as i32)?;
Ok(raw as u32)
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.inner.take_error()
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
self.inner.set_nonblocking(nonblocking)
}
pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.peek(buf)
}
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
/*
let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
let ret = cvt(unsafe {
zts_bsd_send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, ZTS_MSG_NOSIGNAL)
})?;
Ok(ret as usize)
*/
unsafe {
let raw = zts_bsd_write(
*self.inner.as_inner(),
buf.as_ptr() as *const c_void,
buf.len().try_into().unwrap(),
);
if raw >= 0 {
Ok(raw.try_into().unwrap())
} else {
Err(io::Error::from_raw_os_error(raw as i32))
}
}
}
pub fn connect(&self, addr: io::Result<&SocketAddr>) -> io::Result<()> {
let addr = addr?;
//let (addrp, len) = addr?.into_inner();
unsafe {
let full_str = addr.to_string();
let full_vec = full_str.split(":");
let lvec: Vec<&str> = full_vec.collect();
let addr_str = lvec[0];
let port = addr.port();
let timeout_ms = 0;
// TODO: Handle native error code, consider cvt?
// This is a false-positive by the linter
// See: https://github.com/rust-lang/rust/issues/78691
#[allow(temporary_cstring_as_ptr)]
cvt(zts_connect(
*self.inner.as_inner(),
CString::new(addr_str).unwrap().as_ptr(),
port,
timeout_ms,
))?;
}
Ok(())
}
}
impl FromInner<Socket> for UdpSocketImpl {
fn from_inner(socket: Socket) -> UdpSocketImpl {
UdpSocketImpl { inner: socket }
}
}
/*
impl fmt::Debug for UdpSocketImpl {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut res = f.debug_struct("UdpSocketImpl");
if let Ok(addr) = self.socket_addr() {
res.field("addr", &addr);
}
let name = if cfg!(windows) { "socket" } else { "fd" };
res.field(name, &self.inner.as_inner()).finish()
}
}
*/
//----------------------------------------------------------------------------//
// UdpSocket //
//----------------------------------------------------------------------------//
pub struct UdpSocket(UdpSocketImpl);
impl UdpSocket {
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
each_addr(addr, UdpSocketImpl::bind).map(UdpSocket)
}
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.0.recv_from(buf)
}
pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.0.peek_from(buf)
}
pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A) -> io::Result<usize> {
match addr.to_socket_addrs()?.next() {
Some(addr) => self.0.send_to(buf, &addr),
None => Err(Error::new(
ErrorKind::InvalidInput,
"No address to send data to",
)),
}
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.0.peer_addr()
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.0.socket_addr()
}
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
self.0.set_read_timeout(dur)
}
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
self.0.set_write_timeout(dur)
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
self.0.read_timeout()
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
self.0.write_timeout()
}
pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
self.0.set_broadcast(broadcast)
}
pub fn broadcast(&self) -> io::Result<bool> {
self.0.broadcast()
}
/*
pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> {
self.0.set_multicast_loop_v4(multicast_loop_v4)
}
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
self.0.multicast_loop_v4()
}
pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> {
self.0.set_multicast_ttl_v4(multicast_ttl_v4)
}
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
self.0.multicast_ttl_v4()
}
pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> {
self.0.set_multicast_loop_v6(multicast_loop_v6)
}
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
self.0.multicast_loop_v6()
}
*/
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
self.0.set_ttl(ttl)
}
pub fn ttl(&self) -> io::Result<u32> {
self.0.ttl()
}
/*
pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
self.0.join_multicast_v4(multiaddr, interface)
}
pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
self.0.join_multicast_v6(multiaddr, interface)
}
pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
self.0.leave_multicast_v4(multiaddr, interface)
}
pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
self.0.leave_multicast_v6(multiaddr, interface)
}
*/
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.0.take_error()
}
pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
each_addr(addr, |addr| self.0.connect(addr))
}
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
self.0.send(buf)
}
pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
self.0.recv(buf)
}
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.0.peek(buf)
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
self.0.set_nonblocking(nonblocking)
}
}
impl AsInner<UdpSocketImpl> for UdpSocket {
fn as_inner(&self) -> &UdpSocketImpl {
&self.0
}
}
impl FromInner<UdpSocketImpl> for UdpSocket {
fn from_inner(inner: UdpSocketImpl) -> UdpSocket {
UdpSocket(inner)
}
}
impl IntoInner<UdpSocketImpl> for UdpSocket {
fn into_inner(self) -> UdpSocketImpl {
self.0
}
}
/*
impl fmt::Debug for UdpSocket {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
*/

View File

@@ -0,0 +1,213 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
include!(concat!("./libzt.rs"));
use std::ffi::c_void;
use std::io::{Error, ErrorKind};
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
use std::os::raw::c_int;
use std::{io, mem};
use crate::socket::Socket;
//----------------------------------------------------------------------------//
// Utilities //
//----------------------------------------------------------------------------//
/*
The following utility functions were lifted directly from the Rust standard
library and tweaked to accommodate ZeroTier sockets. See their original
implementations here:
- https://doc.rust-lang.org/src/std/net/tcp.rs.html#95-97
- https://github.com/rust-lang/rust/blob/master/library/std/src/sys_common/net.rs
- https://github.com/rust-lang/rust/blob/db492ecd5ba6bd82205612cebb9034710653f0c2/library/std/src/net/mod.rs
*/
pub trait IsMinusOne {
fn is_minus_one(&self) -> bool;
}
macro_rules! impl_is_minus_one {
($($t:ident)*) => ($(impl IsMinusOne for $t {
fn is_minus_one(&self) -> bool {
*self == -1
}
})*)
}
impl_is_minus_one! { i8 i16 i32 i64 isize }
pub fn cvt<T: IsMinusOne>(t: T) -> std::io::Result<T> {
if t.is_minus_one() {
Err(std::io::Error::last_os_error())
} else {
Ok(t)
}
}
pub fn cvt_r<T, F>(mut f: F) -> std::io::Result<T>
where
T: IsMinusOne,
F: FnMut() -> T,
{
loop {
match cvt(f()) {
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
other => return other,
}
}
}
pub fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int, payload: T) -> io::Result<()> {
unsafe {
let payload = &payload as *const T as *const c_void;
cvt(zts_bsd_setsockopt(
*sock.as_inner(),
opt,
val,
payload,
mem::size_of::<T>() as zts_socklen_t,
))?;
Ok(())
}
}
pub fn getsockopt<T: Copy>(sock: &Socket, opt: c_int, val: c_int) -> io::Result<T> {
unsafe {
let mut slot: T = mem::zeroed();
let mut len = mem::size_of::<T>() as zts_socklen_t;
cvt(zts_bsd_getsockopt(
*sock.as_inner(),
opt,
val,
&mut slot as *mut _ as *mut _,
&mut len,
))?;
Ok(slot)
}
}
pub trait AsInner<Inner: ?Sized> {
fn as_inner(&self) -> &Inner;
}
pub trait AsInnerMut<Inner: ?Sized> {
fn as_inner_mut(&mut self) -> &mut Inner;
}
pub trait IntoInner<Inner> {
fn into_inner(self) -> Inner;
}
pub trait FromInner<Inner> {
fn from_inner(inner: Inner) -> Self;
}
pub fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
where
F: FnMut(io::Result<&SocketAddr>) -> io::Result<T>,
{
let addrs = match addr.to_socket_addrs() {
Ok(addrs) => addrs,
Err(e) => return f(Err(e)),
};
let mut last_err = None;
for addr in addrs {
match f(Ok(&addr)) {
Ok(l) => return Ok(l),
Err(e) => last_err = Some(e),
}
}
// TODO: Should ideally use new_const as is used in std::net to avoid allocations
Err(last_err.unwrap_or_else(|| {
Error::new(
ErrorKind::InvalidInput,
"Could not resolve to any addresses",
)
}))
}
pub const fn ntohs(i: u16) -> u16 {
u16::from_be(i)
}
pub const fn htons(i: u16) -> u16 {
i.to_be()
}
pub fn ipv4_addr(addr: zts_in_addr) -> u32 {
(addr.s_addr as u32).to_be()
}
// Copied from: https://docs.rs/pnet_sys/0.28.0/src/pnet_sys/unix.rs.html#162-201
pub fn sockaddr_to_addr(storage: &zts_sockaddr_storage, len: usize) -> io::Result<SocketAddr> {
// See: https://github.com/rust-lang/rust/issues/76191
match storage.ss_family as c_int {
// ZTS_AF_INET
0x2 => {
assert!(len as usize >= mem::size_of::<zts_sockaddr_in>());
let storage: &zts_sockaddr_in = unsafe { mem::transmute(storage) };
let ip = ipv4_addr(storage.sin_addr);
let a = (ip >> 24) as u8;
let b = (ip >> 16) as u8;
let c = (ip >> 8) as u8;
let d = ip as u8;
let sockaddrv4 = SocketAddrV4::new(Ipv4Addr::new(a, b, c, d), ntohs(storage.sin_port));
Ok(SocketAddr::V4(sockaddrv4))
}
// ZTS_AF_INET6
0xA => {
assert!(len as usize >= mem::size_of::<zts_sockaddr_in6>());
let storage: &zts_sockaddr_in6 = unsafe { mem::transmute(storage) };
let arr: [u16; 8] = unsafe { mem::transmute(storage.sin6_addr.un.u8_addr) };
let a = ntohs(arr[0]);
let b = ntohs(arr[1]);
let c = ntohs(arr[2]);
let d = ntohs(arr[3]);
let e = ntohs(arr[4]);
let f = ntohs(arr[5]);
let g = ntohs(arr[6]);
let h = ntohs(arr[7]);
let ip = Ipv6Addr::new(a, b, c, d, e, f, g, h);
Ok(SocketAddr::V6(SocketAddrV6::new(
ip,
ntohs(storage.sin6_port),
u32::from_be(storage.sin6_flowinfo),
storage.sin6_scope_id,
)))
}
_ => Err(io::Error::new(
io::ErrorKind::InvalidData,
"expected IPv4 or IPv6 socket",
)),
}
}
pub fn sockname<F>(f: F) -> io::Result<SocketAddr>
where
F: FnOnce(*mut zts_sockaddr, *mut zts_socklen_t) -> c_int,
{
unsafe {
let mut storage: zts_sockaddr_storage = mem::zeroed();
let mut len = mem::size_of_val(&storage) as zts_socklen_t;
f(&mut storage as *mut _ as *mut _, &mut len);
sockaddr_to_addr(&storage, len as usize)
}
}

View File

@@ -0,0 +1 @@
#include "../../../include/ZeroTierSockets.h"