1use std::future::Future;
17use std::pin::Pin;
18use std::sync::{Arc, Mutex, Weak};
19use std::time::Duration;
20
21use tokio::sync::watch;
22
23use crate::cbor::{self, Value};
24use crate::frame::{self, StreamMode, VerifiedRequest};
25use crate::record::{
26 self, Authorization, ProcedureAdvertisementOptions, Reason, Record, RecordError,
27 TombstoneOptions, Trust,
28};
29
30use super::admission::Verdict;
31use super::framing::MAX_FRAME_BYTES;
32use super::stream::StreamHandler;
33use super::{now_ms, Inner, Link, LinkError};
34
35const CODE_HANDLER_ERROR: &str = "handler_error";
39const CODE_HANDLER_CRASHED: &str = "temporary_relay_failure";
40const CODE_UNKNOWN_PROCEDURE: &str = "unknown_next_peer";
41pub(super) const CODE_REQUEST_COPY: &str = "request_copy";
42const CODE_PAYLOAD_TOO_LARGE: &str = "payload_too_large";
43const CODE_UNSENDABLE: &str = "unknown_error";
44
45const MAX_DETAIL_BYTES: usize = 256;
47
48const MAX_ADVERTISEMENT_TTL: Duration = Duration::from_secs(5 * 60);
50const REFRESH_RETRY: Duration = Duration::from_secs(10);
53
54pub type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send + 'static>>;
56
57pub type Handler = Arc<dyn Fn(Request) -> BoxFuture<Result<Value, String>> + Send + Sync>;
61
62pub fn handler<F, Fut>(f: F) -> Handler
64where
65 F: Fn(Request) -> Fut + Send + Sync + 'static,
66 Fut: Future<Output = Result<Value, String>> + Send + 'static,
67{
68 Arc::new(move |r| Box::pin(f(r)))
69}
70
71#[derive(Debug, Clone, PartialEq)]
75pub struct Request {
76 pub caller: [u8; 32],
77 pub realm: [u8; 32],
78 pub procedure: String,
79 pub payload: Value,
80 pub token: Option<Vec<u8>>,
81 pub proofs: Option<Vec<Vec<u8>>>,
82 pub deadline_ms: u64,
83}
84
85#[derive(Clone)]
90pub struct Offer {
91 pub realm: [u8; 32],
92 pub procedure: String,
93 pub handler: Option<Handler>,
94 pub stream: Option<StreamOffer>,
95 pub realm_key: Option<Vec<u8>>,
96}
97
98impl Offer {
99 pub fn unary(realm: [u8; 32], procedure: &str, handler: Handler) -> Offer {
101 Offer {
102 realm,
103 procedure: procedure.to_string(),
104 handler: Some(handler),
105 stream: None,
106 realm_key: None,
107 }
108 }
109
110 pub fn stream(
112 realm: [u8; 32],
113 procedure: &str,
114 mode: StreamMode,
115 handler: StreamHandler,
116 ) -> Offer {
117 Offer {
118 realm,
119 procedure: procedure.to_string(),
120 handler: None,
121 stream: Some(StreamOffer { mode, handler }),
122 realm_key: None,
123 }
124 }
125}
126
127#[derive(Clone)]
131pub struct StreamOffer {
132 pub mode: StreamMode,
133 pub handler: StreamHandler,
134}
135
136pub(super) type ServedEntry = Arc<ServedInner>;
138
139pub(super) struct ServedInner {
140 link: Weak<Inner>,
141 key: ([u8; 32], String),
142 pub(super) offer: Offer,
143 latest: Mutex<Record>,
144 err: Mutex<Option<LinkError>>,
145 done_tx: watch::Sender<bool>,
146}
147
148#[derive(Clone)]
152pub struct Served {
153 inner: Arc<ServedInner>,
154}
155
156impl Link {
157 pub async fn serve(&self, o: Offer) -> Result<Served, LinkError> {
168 let own = record::in_own_namespace(&o.procedure);
169 if o.handler.is_some() == o.stream.is_some() || (!own && o.realm_key.is_none()) {
170 return Err(LinkError::InvalidOffer);
171 }
172 if !matches!(record::procedure_org(&o.procedure), Ok(Some(_))) {
173 return Err(LinkError::NoOrg);
174 }
175 let (advertisement, wire) = self.advertisement(&o, MAX_ADVERTISEMENT_TTL).await?;
176 let key = (o.realm, o.procedure.clone());
177 let (done_tx, _) = watch::channel(false);
178 let served = Arc::new(ServedInner {
179 link: Arc::downgrade(&self.inner),
180 key: key.clone(),
181 offer: o,
182 latest: Mutex::new(advertisement),
183 err: Mutex::new(None),
184 done_tx,
185 });
186 {
187 let mut state = self.inner.lock();
188 if let Some(e) = &state.ended {
189 return Err(e.clone());
190 }
191 if state.served.contains_key(&key) {
192 return Err(LinkError::AlreadyServed);
193 }
194 state.served.insert(key, served.clone());
195 }
196 if let Err(e) = self.announce(&wire).await {
197 served.end(e.clone());
198 return Err(e);
199 }
200 tokio::spawn(renew(served.clone()));
201 Ok(Served { inner: served })
202 }
203
204 async fn advertisement(
208 &self,
209 o: &Offer,
210 max_ttl: Duration,
211 ) -> Result<(Record, Vec<u8>), LinkError> {
212 let inner = &self.inner;
213 let max_ttl_ms = max_ttl.as_millis() as u64;
214 let opts = if record::in_own_namespace(&o.procedure) {
215 ProcedureAdvertisementOptions {
216 authorization: Authorization::None,
217 ttl_ms: max_ttl_ms,
218 }
219 } else {
220 let org = record::procedure_org(&o.procedure)?.ok_or(LinkError::NoOrg)?;
221 let directory = self
222 .find_record(&record::org_directory_key(&o.realm, org))
223 .await?;
224 let named = record::read_org_directory(directory.record())?;
225 let delegation = self
226 .find_record(&record::procedure_delegation_key(
227 &named.org_key,
228 &inner.self_id,
229 ))
230 .await?;
231 let now = now_ms();
232 let ttl = (max_ttl_ms as i64)
233 .min(directory.record().expires_at as i64 - now)
234 .min(delegation.record().expires_at as i64 - now);
235 if ttl <= 0 {
236 return Err(RecordError::AuthorizationOutlived.into());
237 }
238 ProcedureAdvertisementOptions {
239 authorization: Authorization::Delegation {
240 org_directory: record::encode(directory.record())?,
241 procedure_delegation: record::encode(delegation.record())?,
242 },
243 ttl_ms: ttl as u64,
244 }
245 };
246 let unsigned = record::new_procedure_advertisement(
247 &inner.self_id,
248 &o.realm,
249 &o.procedure,
250 &inner.station.node_id,
251 &opts,
252 )?;
253 let signed = record::sign(&unsigned, &inner.key)?;
256 let wire = record::encode(&signed)?;
257 let now = now_ms();
258 let verified = record::verify(&wire, inner.profile, now)?;
259 record::verify_authorization(
260 &verified,
261 &Trust {
262 profile: inner.profile,
263 realm_key: o.realm_key.clone(),
264 },
265 now,
266 )?;
267 Ok((signed, wire))
268 }
269
270 async fn announce(&self, wire: &[u8]) -> Result<(), LinkError> {
274 self.inner
275 .send_control(&frame::advertise_frame(wire))
276 .await?;
277 self.put_record(wire).await
278 }
279}
280
281impl Served {
282 pub async fn stop(&self) -> Result<(), LinkError> {
287 if self.inner.is_done() {
288 return Ok(());
289 }
290 self.inner.end(LinkError::Stopped);
291 let Some(inner) = self.inner.link.upgrade() else {
292 return Ok(());
293 };
294 let latest = self
295 .inner
296 .latest
297 .lock()
298 .unwrap_or_else(|p| p.into_inner())
299 .clone();
300 let tombstone =
301 record::new_tombstone(&latest, Reason::Shutdown, &TombstoneOptions::default())?;
302 let wire = record::encode(&record::sign(&tombstone, &inner.key)?)?;
303 inner.send_control(&frame::unadvertise_frame(&wire)).await?;
304 Link { inner }.put_record(&wire).await
305 }
306
307 pub async fn done(&self) -> LinkError {
309 let mut done = self.inner.done_tx.subscribe();
310 let _ = done.wait_for(|ended| *ended).await;
311 self.error().unwrap_or(LinkError::Stopped)
312 }
313
314 pub fn error(&self) -> Option<LinkError> {
318 self.inner
319 .err
320 .lock()
321 .unwrap_or_else(|p| p.into_inner())
322 .clone()
323 }
324}
325
326impl ServedInner {
327 fn is_done(&self) -> bool {
328 *self.done_tx.borrow()
329 }
330
331 pub(super) fn end(self: &Arc<Self>, err: LinkError) {
334 {
335 let mut held = self.err.lock().unwrap_or_else(|p| p.into_inner());
336 if held.is_some() {
337 return;
338 }
339 *held = Some(err);
340 }
341 if let Some(inner) = self.link.upgrade() {
342 let mut state = inner.lock();
343 if state
344 .served
345 .get(&self.key)
346 .is_some_and(|s| Arc::ptr_eq(s, self))
347 {
348 state.served.remove(&self.key);
349 }
350 }
351 let _ = self.done_tx.send_replace(true);
352 }
353}
354
355async fn renew(served: Arc<ServedInner>) {
360 let mut current = served
361 .latest
362 .lock()
363 .unwrap_or_else(|p| p.into_inner())
364 .clone();
365 let mut wait = half_life(¤t);
366 let mut last_err: Option<LinkError> = None;
367 let mut stopped = served.done_tx.subscribe();
368 loop {
369 let Some(mut link_done) = served.link.upgrade().map(|l| l.done_rx.clone()) else {
370 return;
371 };
372 tokio::select! {
373 _ = stopped.wait_for(|ended| *ended) => return,
374 _ = link_done.wait_for(|ended| *ended) => {
375 let err = served.link.upgrade().and_then(|l| l.lock().ended.clone()).unwrap_or(LinkError::Closed);
376 served.end(err);
377 return;
378 }
379 _ = tokio::time::sleep(wait) => {}
380 }
381 if now_ms() >= current.expires_at as i64 {
382 served.end(last_err.unwrap_or(LinkError::Stopped));
383 return;
384 }
385 let Some(inner) = served.link.upgrade() else {
386 return;
387 };
388 let link = Link { inner };
389 let renewed = async {
390 let (advertisement, wire) = link
391 .advertisement(&served.offer, MAX_ADVERTISEMENT_TTL)
392 .await?;
393 link.announce(&wire).await?;
394 Ok::<_, LinkError>(advertisement)
395 }
396 .await;
397 match renewed {
398 Ok(advertisement) => {
399 *served.latest.lock().unwrap_or_else(|p| p.into_inner()) = advertisement.clone();
400 wait = half_life(&advertisement);
401 current = advertisement;
402 }
403 Err(e) => {
404 last_err = Some(e);
405 let left = (current.expires_at as i64 - now_ms()).max(0) as u64;
406 wait = REFRESH_RETRY.min(Duration::from_millis(left));
407 }
408 }
409 }
410}
411
412fn half_life(r: &Record) -> Duration {
413 Duration::from_millis(r.expires_at.saturating_sub(r.created_at) / 2)
414}
415
416pub(super) fn called(inner: &Arc<Inner>, v: &Value) {
421 let Ok(request) = frame::verify_request(v, inner.profile) else {
422 inner.count("unverified_call");
423 return;
424 };
425 if request.target != inner.self_id {
426 inner.count("call_for_another_node");
427 return;
428 }
429 let inner = inner.clone();
430 match inner.admission.admit(&request, &inner.share, now_ms()) {
431 Verdict::Refused(code) => {
432 let reply = provider_error(&inner, &request, code, None);
433 tokio::spawn(async move { send_reply(&inner, reply).await });
434 }
435 Verdict::Copy(None) => {
436 let reply = provider_error(&inner, &request, CODE_REQUEST_COPY, None);
437 tokio::spawn(async move { send_reply(&inner, reply).await });
438 }
439 Verdict::Copy(Some(stored)) => {
440 tokio::spawn(async move {
441 let _ = inner.control.write(&stored, MAX_FRAME_BYTES).await;
442 });
443 }
444 Verdict::New => {
445 tokio::spawn(answer(inner, request));
446 }
447 }
448}
449
450async fn answer(inner: Arc<Inner>, request: VerifiedRequest) {
453 let handler = inner
454 .lock()
455 .served
456 .get(&(request.realm, request.procedure.clone()))
457 .and_then(|s| s.offer.handler.clone());
458 let reply = match handler {
459 None => provider_error(&inner, &request, CODE_UNKNOWN_PROCEDURE, None),
460 Some(handler) => handled(&inner, handler, &request).await,
461 };
462 let Ok(encoded) = cbor::encode(&reply) else {
463 inner.count("unencodable_reply");
464 return;
465 };
466 inner.admission.store(&request, encoded.clone());
467 let _ = inner.control.write(&encoded, MAX_FRAME_BYTES).await;
468}
469
470async fn handled(inner: &Inner, handler: Handler, request: &VerifiedRequest) -> Value {
474 let running = tokio::spawn(handler(Request {
475 caller: request.caller,
476 realm: request.realm,
477 procedure: request.procedure.clone(),
478 payload: request.payload.clone(),
479 token: request.token.clone(),
480 proofs: request.proofs.clone(),
481 deadline_ms: request.deadline,
482 }));
483 let abort = running.abort_handle();
484 let left = (request.deadline as i64 - now_ms()).max(0) as u64;
485 let outcome = tokio::time::timeout(Duration::from_millis(left), running).await;
486 match outcome {
487 Err(_) => {
488 abort.abort();
489 provider_error(
490 inner,
491 request,
492 CODE_HANDLER_ERROR,
493 Some("the request's deadline passed"),
494 )
495 }
496 Ok(Err(_panicked)) => provider_error(inner, request, CODE_HANDLER_CRASHED, None),
497 Ok(Ok(Err(refusal))) => provider_error(
498 inner,
499 request,
500 CODE_HANDLER_ERROR,
501 Some(bounded_detail(&refusal)),
502 ),
503 Ok(Ok(Ok(payload))) => match frame::sign_result(request, &payload, None, &inner.key) {
504 Ok(signed) => signed,
505 Err(_) if cbor::encode(&payload).is_ok_and(|e| e.len() > frame::MAX_FRAME_BYTES) => {
506 provider_error(inner, request, CODE_PAYLOAD_TOO_LARGE, None)
507 }
508 Err(_) => provider_error(inner, request, CODE_UNSENDABLE, None),
509 },
510 }
511}
512
513fn provider_error(
517 inner: &Inner,
518 request: &VerifiedRequest,
519 code: &str,
520 detail: Option<&str>,
521) -> Value {
522 frame::sign_provider_error(request, code, detail, None, &inner.key)
523 .unwrap_or_else(|e| panic!("station_link: a provider error that does not sign: {e}"))
524}
525
526async fn send_reply(inner: &Inner, reply: Value) {
527 let _ = inner.write_control(&reply).await;
528}
529
530pub(super) fn bounded_detail(text: &str) -> &str {
532 if text.len() <= MAX_DETAIL_BYTES {
533 return text;
534 }
535 let mut cut = MAX_DETAIL_BYTES;
536 while !text.is_char_boundary(cut) {
537 cut -= 1;
538 }
539 &text[..cut]
540}