1#![cfg(feature = "afc")]
4#![cfg_attr(docsrs, doc(cfg(feature = "afc")))]
5
6use core::fmt;
7use std::{
8 fmt::{Debug, Display},
9 sync::{Arc, Mutex},
10};
11
12use anyhow::Context;
13use aranya_daemon_api::{AfcChannelId, AfcLocalChannelId, AfcShmInfo, DaemonApiClient, CS};
14use aranya_fast_channels::{
15 self as afc,
16 shm::{Flag, Mode, ReadState},
17 AfcState, Client as AfcClient,
18};
19use derive_where::derive_where;
20use serde::{Deserialize, Serialize};
21use tracing::debug;
22
23use crate::{
24 client::create_ctx,
25 error::{aranya_error, IpcError},
26 util::ApiConv as _,
27 DeviceId, LabelId, Result, TeamId,
28};
29
30#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq, Ord, PartialOrd)]
44pub struct Seq(afc::Seq);
45
46#[derive(Clone, Debug, Serialize, Deserialize)]
48pub struct CtrlMsg(Box<[u8]>);
49
50impl CtrlMsg {
51 pub fn as_bytes(&self) -> &[u8] {
53 &self.0
54 }
55}
56
57impl From<Box<[u8]>> for CtrlMsg {
58 fn from(value: Box<[u8]>) -> Self {
59 Self(value)
60 }
61}
62
63#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
65#[serde(transparent)]
66pub struct ChannelId {
67 #[doc(hidden)]
68 pub __id: AfcChannelId,
69}
70
71impl Display for ChannelId {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 Display::fmt(&self.__id, f)
74 }
75}
76
77#[derive(Debug, thiserror::Error)]
79pub struct AfcSealError(
80 #[allow(dead_code, reason = "Don't expose internal error type in public API")]
81 aranya_fast_channels::Error,
82);
83
84impl Display for AfcSealError {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 Display::fmt(&self.0, f)
87 }
88}
89
90#[derive(Debug, thiserror::Error)]
92pub struct AfcOpenError(
93 #[allow(dead_code, reason = "Don't expose internal error type in public API")]
94 aranya_fast_channels::Error,
95);
96
97impl Display for AfcOpenError {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 Display::fmt(&self.0, f)
100 }
101}
102
103#[derive(Debug, thiserror::Error)]
105#[non_exhaustive]
106pub enum Error {
107 #[error("unable to seal datagram")]
109 Seal(#[from] AfcSealError),
110
111 #[error("unable to open datagram")]
113 Open(#[from] AfcOpenError),
114
115 #[error("unable to connect to channel keys IPC")]
117 AfcIpc(#[from] anyhow::Error),
118
119 #[error("no channel info found")]
121 NoChannelInfoFound,
122
123 #[error(transparent)]
125 Bug(#[from] buggy::Bug),
126}
127
128pub struct Channels {
130 daemon: DaemonApiClient,
131 keys: Arc<ChannelKeys>,
132}
133
134impl Debug for Channels {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 f.debug_struct("Channels")
138 .field("daemon", &self.daemon)
139 .finish_non_exhaustive()
140 }
141}
142
143impl Channels {
144 pub const OVERHEAD: usize = AfcClient::<ReadState<CS>>::OVERHEAD;
147
148 pub(crate) fn new(daemon: DaemonApiClient, keys: Arc<ChannelKeys>) -> Self {
149 Self { daemon, keys }
150 }
151
152 pub async fn create_channel(
168 &self,
169 team_id: TeamId,
170 peer_id: DeviceId,
171 label_id: LabelId,
172 ) -> Result<(SendChannel, CtrlMsg)> {
173 let info = self
174 .daemon
175 .create_afc_channel(
176 create_ctx(),
177 team_id.into_api(),
178 peer_id.into_api(),
179 label_id.into_api(),
180 )
181 .await
182 .map_err(IpcError::new)?
183 .map_err(aranya_error)?;
184 let seal_ctx = self
185 .keys
186 .0
187 .setup_seal_ctx(info.local_channel_id)
188 .map_err(AfcSealError)
189 .map_err(Error::Seal)?;
190 let chan = SendChannel {
191 daemon: self.daemon.clone(),
192 keys: self.keys.clone(),
193 channel_id: ChannelId {
194 __id: info.channel_id,
195 },
196 local_channel_id: info.local_channel_id,
197 label_id,
198 peer_id,
199 seal_ctx: Box::new(seal_ctx),
200 };
201 Ok((chan, CtrlMsg(info.ctrl)))
202 }
203
204 pub async fn accept_channel(&self, team_id: TeamId, ctrl: CtrlMsg) -> Result<ReceiveChannel> {
206 let info = self
207 .daemon
208 .accept_afc_channel(create_ctx(), team_id.into_api(), ctrl.0)
209 .await
210 .map_err(IpcError::new)?
211 .map_err(aranya_error)?;
212 let open_ctx = self
213 .keys
214 .0
215 .setup_open_ctx(info.local_channel_id)
216 .map_err(AfcSealError)
217 .map_err(Error::Seal)?;
218 Ok(ReceiveChannel {
219 daemon: self.daemon.clone(),
220 keys: self.keys.clone(),
221 channel_id: ChannelId {
222 __id: info.channel_id,
223 },
224 local_channel_id: info.local_channel_id,
225 label_id: LabelId::from_api(info.label_id),
226 peer_id: DeviceId::from_api(info.peer_id),
227 open_ctx: Arc::new(Mutex::new(open_ctx)),
228 })
229 }
230}
231
232#[derive_where(Debug)]
234pub struct SendChannel {
235 daemon: DaemonApiClient,
236 keys: Arc<ChannelKeys>,
237 channel_id: ChannelId,
238 local_channel_id: AfcLocalChannelId,
239 label_id: LabelId,
240 peer_id: DeviceId,
241 #[derive_where(skip(Debug))]
242 seal_ctx: Box<<ReadState<CS> as AfcState>::SealCtx>,
243}
244
245impl SendChannel {
246 pub fn id(&self) -> ChannelId {
248 self.channel_id
249 }
250
251 pub fn label_id(&self) -> LabelId {
253 self.label_id
254 }
255
256 pub fn peer_id(&self) -> DeviceId {
258 self.peer_id
259 }
260
261 pub fn seal(&mut self, dst: &mut [u8], plaintext: &[u8]) -> Result<(), Error> {
273 debug!(?self.local_channel_id, ?self.label_id, "seal");
274 self.keys
275 .0
276 .seal(&mut self.seal_ctx, dst, plaintext)
277 .map_err(AfcSealError)
278 .map_err(Error::Seal)?;
279 Ok(())
280 }
281
282 pub async fn delete(&self) -> Result<(), crate::Error> {
284 self.daemon
285 .delete_afc_channel(create_ctx(), self.local_channel_id)
286 .await
287 .map_err(IpcError::new)?
288 .map_err(aranya_error)?;
289 Ok(())
290 }
291}
292
293#[derive(Clone)]
295#[derive_where(Debug)]
296pub struct ReceiveChannel {
297 daemon: DaemonApiClient,
298 keys: Arc<ChannelKeys>,
299 channel_id: ChannelId,
300 local_channel_id: AfcLocalChannelId,
301 label_id: LabelId,
302 peer_id: DeviceId,
303 #[derive_where(skip(Debug))]
304 open_ctx: Arc<Mutex<<ReadState<CS> as AfcState>::OpenCtx>>,
305}
306
307impl ReceiveChannel {
308 pub fn id(&self) -> ChannelId {
310 self.channel_id
311 }
312
313 pub fn label_id(&self) -> LabelId {
315 self.label_id
316 }
317
318 pub fn peer_id(&self) -> DeviceId {
320 self.peer_id
321 }
322
323 pub fn open(&self, dst: &mut [u8], ciphertext: &[u8]) -> Result<Seq, Error> {
339 debug!(?self.local_channel_id, ?self.label_id, "open");
340 let (label_id, seq) = self
341 .keys
342 .0
343 .open(
344 &mut *self.open_ctx.lock().expect("poisoned"),
345 dst,
346 ciphertext,
347 )
348 .map_err(AfcOpenError)
349 .map_err(Error::Open)?;
350 debug_assert_eq!(label_id.as_base(), self.label_id.into_api().as_base());
351 Ok(Seq(seq))
352 }
353
354 pub async fn delete(&self) -> Result<(), crate::Error> {
356 self.daemon
357 .delete_afc_channel(create_ctx(), self.local_channel_id)
358 .await
359 .map_err(IpcError::new)?
360 .map_err(aranya_error)?;
361 Ok(())
362 }
363}
364
365pub(crate) struct ChannelKeys(AfcClient<ReadState<CS>>);
367
368impl ChannelKeys {
369 pub fn new(afc_shm_info: &AfcShmInfo) -> Result<Self, Error> {
371 debug!(
373 "setting up afc shm read side: {:?}",
374 afc_shm_info.path.clone()
375 );
376 let read = ReadState::open(
377 afc_shm_info.path.clone(),
378 Flag::OpenOnly,
379 Mode::ReadWrite,
380 afc_shm_info.max_chans,
381 )
382 .with_context(|| format!("unable to open `ReadState`: {:?}", afc_shm_info.path))
383 .map_err(Error::AfcIpc)?;
384
385 Ok(Self(AfcClient::new(read)))
386 }
387}
388
389impl Debug for ChannelKeys {
390 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
391 f.debug_struct("ChannelKeys").finish_non_exhaustive()
392 }
393}