mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-26 08:57:26 +02:00
150 lines
5 KiB
Rust
150 lines
5 KiB
Rust
/*
|
|
* 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::CString;
|
|
use std::mem::MaybeUninit;
|
|
use std::os::raw::{c_char, c_uint};
|
|
|
|
use num_derive::{FromPrimitive, ToPrimitive};
|
|
use num_traits::FromPrimitive;
|
|
|
|
use crate::*;
|
|
use crate::capi as ztcore;
|
|
|
|
#[derive(FromPrimitive, ToPrimitive, PartialEq, Eq)]
|
|
pub enum EndpointType {
|
|
Nil = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_NIL as isize,
|
|
ZeroTier = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_ZEROTIER as isize,
|
|
Ethernet = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_ETHERNET as isize,
|
|
WifiDirect = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_WIFI_DIRECT as isize,
|
|
Bluetooth = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_BLUETOOTH as isize,
|
|
Ip = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_IP as isize,
|
|
IpUdp = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_IP_UDP as isize,
|
|
IpTcp = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_IP_TCP as isize,
|
|
IpTcpWs = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_IP_TCP_WS as isize,
|
|
}
|
|
|
|
pub struct Endpoint {
|
|
pub type_: EndpointType,
|
|
pub(crate) capi: ztcore::ZT_Endpoint
|
|
}
|
|
|
|
impl Endpoint {
|
|
pub(crate) fn new_from_capi(ep: &ztcore::ZT_Endpoint) -> Endpoint {
|
|
return Endpoint{
|
|
type_: EndpointType::from_i32(ep.type_ as i32).unwrap(),
|
|
capi: *ep
|
|
};
|
|
}
|
|
|
|
pub fn new_from_bytes(bytes: &[u8]) -> Result<Endpoint, ResultCode> {
|
|
unsafe {
|
|
let mut cep: MaybeUninit<ztcore::ZT_Endpoint> = MaybeUninit::uninit();
|
|
let ec = ztcore::ZT_Endpoint_fromBytes(cep.as_mut_ptr(), bytes.as_ptr().cast(), bytes.len() as c_uint);
|
|
if ec == 0 {
|
|
let epi = cep.assume_init();
|
|
return Ok(Endpoint{
|
|
type_: EndpointType::from_i32(epi.type_ as i32).unwrap(),
|
|
capi: epi
|
|
});
|
|
}
|
|
return Err(ResultCode::from_i32(ec).unwrap());
|
|
}
|
|
}
|
|
|
|
pub fn new_from_string(s: &str) -> Result<Endpoint, ResultCode> {
|
|
let cs = CString::new(s);
|
|
if cs.is_err() {
|
|
return Err(ResultCode::ErrorBadParameter);
|
|
}
|
|
let cs = cs.unwrap();
|
|
unsafe {
|
|
let mut cep: MaybeUninit<ztcore::ZT_Endpoint> = MaybeUninit::uninit();
|
|
let ec = ztcore::ZT_Endpoint_fromString(cep.as_mut_ptr(), cs.as_ptr()) as i32;
|
|
if ec == 0 {
|
|
let epi = cep.assume_init();
|
|
return Ok(Endpoint{
|
|
type_: EndpointType::from_i32(epi.type_ as i32).unwrap(),
|
|
capi: epi
|
|
});
|
|
}
|
|
return Err(ResultCode::from_i32(ec).unwrap());
|
|
}
|
|
}
|
|
|
|
/// Get a reference to the InetAddress in this endpoint or None if this is not of a relevant type.
|
|
pub fn as_inetaddress(&self) -> Option<&InetAddress> {
|
|
match self.type_ {
|
|
EndpointType::Ip | EndpointType::IpUdp | EndpointType::IpTcp | EndpointType::IpTcpWs => {
|
|
unsafe {
|
|
Some(InetAddress::transmute_capi(&self.capi.value.ia))
|
|
}
|
|
},
|
|
_ => None
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ToString for Endpoint {
|
|
fn to_string(&self) -> String {
|
|
unsafe {
|
|
let mut buf: MaybeUninit<[c_char; 1024]> = MaybeUninit::uninit();
|
|
if ztcore::ZT_Endpoint_toString(&(self.capi) as *const ztcore::ZT_Endpoint, (*buf.as_mut_ptr()).as_mut_ptr(), 1024).is_null() {
|
|
return String::from("(invalid)");
|
|
}
|
|
return cstr_to_string((*buf.as_ptr()).as_ptr(), 1024);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PartialEq for Endpoint {
|
|
fn eq(&self, other: &Endpoint) -> bool {
|
|
if self.type_ == other.type_ {
|
|
self.to_string() == other.to_string()
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Eq for Endpoint {}
|
|
|
|
impl serde::Serialize for Endpoint {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
|
serializer.serialize_str(self.to_string().as_str())
|
|
}
|
|
}
|
|
|
|
struct EndpointVisitor;
|
|
|
|
impl<'de> serde::de::Visitor<'de> for EndpointVisitor {
|
|
type Value = Endpoint;
|
|
|
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
formatter.write_str("Endpoint value in string form")
|
|
}
|
|
|
|
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error {
|
|
let id = Endpoint::new_from_string(s);
|
|
if id.is_err() {
|
|
return Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self));
|
|
}
|
|
return Ok(id.ok().unwrap() as Self::Value);
|
|
}
|
|
}
|
|
|
|
impl<'de> serde::Deserialize<'de> for Endpoint {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
|
|
deserializer.deserialize_str(EndpointVisitor)
|
|
}
|
|
}
|