netidx_netproto/
resolver.rs

1use crate::glob::GlobSet;
2use arcstr::ArcStr;
3use bytes::{Buf, BufMut, Bytes};
4use netidx_core::{
5    pack::{
6        len_wrapped_decode, len_wrapped_encode, len_wrapped_len, Pack, PackError, Z64,
7    },
8    path::Path,
9};
10use netidx_derive::Pack;
11use poolshark::global::GPooled;
12use smallvec::SmallVec;
13use std::{
14    cmp::{Eq, PartialEq},
15    hash::{Hash, Hasher},
16    net::SocketAddr,
17    result,
18};
19
20type Error = PackError;
21pub type Result<T> = result::Result<T, Error>;
22
23#[derive(Clone, Debug, Copy, PartialEq, Eq, Pack)]
24pub enum HashMethod {
25    Sha3_512,
26}
27
28#[derive(Clone, Debug, Copy, PartialEq, Pack)]
29pub struct AuthChallenge {
30    pub hash_method: HashMethod,
31    pub challenge: u128,
32}
33
34#[derive(Clone, Debug, PartialEq, Eq, Pack)]
35pub enum AuthRead {
36    Anonymous,
37    Krb5,
38    Local,
39    Tls,
40}
41
42#[derive(Clone, Debug, PartialEq, Eq, Pack)]
43pub enum AuthWrite {
44    Anonymous,
45    Reuse,
46    Krb5 { spn: ArcStr },
47    Local,
48    Tls { name: ArcStr },
49}
50
51#[derive(Clone, Debug, PartialEq, Eq, Pack)]
52pub struct ClientHelloWrite {
53    pub write_addr: SocketAddr,
54    pub auth: AuthWrite,
55    #[pack(default)]
56    pub priority: PublisherPriority,
57}
58
59#[derive(Clone, Debug, PartialEq, Eq, Pack)]
60pub enum ClientHello {
61    /// Instruct the resolver server that this connection will not
62    /// publish paths.
63    ReadOnly(AuthRead),
64    /// Instruct the resolver server that this connection will
65    /// only publish paths. All published paths will use the
66    /// specified address `write_addr`, and the publisher must
67    /// send a heartbeat at least every `ttl` seconds or the
68    /// resolver server will purge all paths published by
69    /// `write_addr`.
70    WriteOnly(ClientHelloWrite),
71}
72
73#[derive(Clone, Debug, PartialEq, Eq, Pack)]
74pub struct ServerHelloWrite {
75    pub ttl: u64,
76    pub ttl_expired: bool,
77    pub auth: AuthWrite,
78    pub resolver_id: SocketAddr,
79}
80
81#[derive(Clone, Debug, PartialEq, Eq, Pack)]
82pub struct Secret(pub u128);
83
84#[derive(Clone, Debug, PartialEq, Eq)]
85pub struct ReadyForOwnershipCheck;
86
87impl Pack for ReadyForOwnershipCheck {
88    fn encoded_len(&self) -> usize {
89        len_wrapped_len(1)
90    }
91
92    fn encode(&self, buf: &mut impl BufMut) -> Result<()> {
93        len_wrapped_encode(buf, self, |buf| Ok(buf.put_u8(0)))
94    }
95
96    fn decode(buf: &mut impl Buf) -> Result<Self> {
97        len_wrapped_decode(buf, |buf| match <u8 as Pack>::decode(buf)? {
98            0 => Ok(ReadyForOwnershipCheck),
99            _ => Err(PackError::UnknownTag),
100        })
101    }
102}
103
104#[derive(Clone, Debug, PartialEq, Eq, Pack)]
105pub enum ToRead {
106    /// Resolve path to addresses/ports
107    Resolve(Path),
108    /// List the paths published under the specified root path
109    List(Path),
110    /// Describe the table rooted at the specified path
111    Table(Path),
112    /// List paths matching the specified glob set.
113    ListMatching(GlobSet),
114    /// Get the change nr for the specified path
115    GetChangeNr(Path),
116}
117
118#[derive(Clone, Debug, PartialEq, Eq, Pack)]
119pub enum Auth {
120    Anonymous,
121    Local { path: ArcStr },
122    Krb5 { spn: ArcStr },
123    Tls { name: ArcStr },
124}
125
126atomic_id!(PublisherId);
127
128#[derive(Clone, Debug, PartialEq, Eq, Pack)]
129pub enum TargetAuth {
130    Anonymous,
131    Local,
132    Krb5 { spn: ArcStr },
133    Tls { name: ArcStr },
134}
135
136impl TargetAuth {
137    pub fn is_anonymous(&self) -> bool {
138        match self {
139            Self::Anonymous => true,
140            Self::Krb5 { .. } | Self::Local | Self::Tls { .. } => false,
141        }
142    }
143}
144
145impl TryFrom<AuthWrite> for TargetAuth {
146    type Error = anyhow::Error;
147
148    fn try_from(v: AuthWrite) -> result::Result<Self, Self::Error> {
149        match v {
150            AuthWrite::Anonymous => Ok(Self::Anonymous),
151            AuthWrite::Local => Ok(Self::Local),
152            AuthWrite::Krb5 { spn } => Ok(Self::Krb5 { spn }),
153            AuthWrite::Reuse => bail!("no session to reuse"),
154            AuthWrite::Tls { name } => Ok(Self::Tls { name }),
155        }
156    }
157}
158
159#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Pack)]
160pub struct UserInfo {
161    pub name: ArcStr,
162    pub primary_group: ArcStr,
163    pub groups: SmallVec<[ArcStr; 16]>,
164    pub resolver: SocketAddr,
165    pub token: Bytes,
166}
167
168#[derive(Clone, Copy, Debug, PartialEq, Eq, Pack)]
169pub enum PublisherPriority {
170    High,
171    Normal,
172    Low,
173}
174
175impl Default for PublisherPriority {
176    fn default() -> Self {
177        PublisherPriority::Normal
178    }
179}
180
181#[derive(Clone, Debug, PartialEq, Eq, Pack)]
182pub struct Publisher {
183    pub resolver: SocketAddr,
184    pub id: PublisherId,
185    pub addr: SocketAddr,
186    pub hash_method: HashMethod,
187    pub target_auth: TargetAuth,
188    #[pack(default)]
189    pub user_info: Option<UserInfo>,
190    #[pack(default)]
191    pub priority: PublisherPriority,
192}
193
194#[derive(Clone, Debug, PartialEq, Eq, Pack)]
195pub struct PublisherRef {
196    pub id: PublisherId,
197    pub token: Bytes,
198}
199
200/// The result of resolving a path
201#[derive(Clone, Debug, PartialEq, Eq, Pack)]
202pub struct Resolved {
203    pub resolver: SocketAddr,
204    pub publishers: GPooled<Vec<PublisherRef>>,
205    pub timestamp: u64,
206    pub flags: u32,
207    pub permissions: u32,
208}
209
210#[derive(Clone, Debug, Pack)]
211pub struct Referral {
212    pub path: Path,
213    pub ttl: Option<u16>,
214    pub addrs: GPooled<Vec<(SocketAddr, Auth)>>,
215}
216
217impl Hash for Referral {
218    fn hash<H: Hasher>(&self, state: &mut H) {
219        for (addr, _) in &*self.addrs {
220            Hash::hash(&addr, state)
221        }
222    }
223}
224
225impl PartialEq for Referral {
226    fn eq(&self, other: &Referral) -> bool {
227        self.addrs.iter().zip(other.addrs.iter()).all(|(l, r)| l == r)
228    }
229}
230
231impl Eq for Referral {}
232
233/// An inferred table
234#[derive(Clone, Debug, PartialEq, Eq, Pack)]
235pub struct Table {
236    pub rows: GPooled<Vec<Path>>,
237    pub cols: GPooled<Vec<(Path, Z64)>>,
238}
239
240#[derive(Clone, Debug, PartialEq, Eq, Pack)]
241pub struct ListMatching {
242    pub matched: GPooled<Vec<GPooled<Vec<Path>>>>,
243    pub referrals: GPooled<Vec<Referral>>,
244}
245
246#[derive(Clone, Debug, PartialEq, Eq, Pack)]
247pub struct GetChangeNr {
248    pub change_number: Z64,
249    pub resolver: SocketAddr,
250    pub referrals: GPooled<Vec<Referral>>,
251}
252
253#[derive(Clone, Debug, PartialEq, Eq, Pack)]
254pub enum FromRead {
255    Publisher(Publisher),
256    Resolved(Resolved),
257    List(GPooled<Vec<Path>>),
258    Table(Table),
259    Referral(Referral),
260    Denied,
261    Error(ArcStr),
262    ListMatching(ListMatching),
263    GetChangeNr(GetChangeNr),
264}
265
266#[derive(Clone, Debug, PartialEq, Eq, Hash, Pack)]
267pub enum ToWrite {
268    /// Publish the path
269    Publish(Path),
270    /// Add a default publisher to path
271    PublishDefault(Path),
272    /// Stop publishing the path
273    Unpublish(Path),
274    /// Clear all values you've published
275    Clear,
276    /// Tell the resolver that we are still alive
277    Heartbeat,
278    /// Publish the path and set associated flags
279    PublishWithFlags(Path, u32),
280    /// Add a default publisher to path and set associated flags
281    PublishDefaultWithFlags(Path, u32),
282    /// Unpublish a default publisher
283    UnpublishDefault(Path),
284}
285
286#[derive(Clone, Debug, PartialEq, Eq, Hash, Pack)]
287pub enum FromWrite {
288    Published,
289    Unpublished,
290    Referral(Referral),
291    Denied,
292    Error(ArcStr),
293}