microsandbox_control_client/
protocol.rs1use std::sync::Arc;
4
5use microsandbox_protocol::{
6 codec::{self, RawFrame},
7 control::{
8 CONTROL_GENERATION, ControlError, ControlHello, ControlWelcome, DEFAULT_MAX_IN_FLIGHT,
9 DEFAULT_REQUEST_TIMEOUT, DEFAULT_SETUP_TIMEOUT, MAX_HANDSHAKE_FRAME_SIZE,
10 },
11 wire::Envelope,
12};
13use microsandbox_protocol_client::{
14 BoxFuture, BoxTransport, CborEnvelopeCodec, Client, ClientError, ClientResult, ConnectOptions,
15 ErrorKind, Established, IdRange, Protocol, SendMetadata,
16};
17use tokio::io::AsyncReadExt;
18
19pub type ControlClient = Client<ControlProtocol>;
25
26pub struct ControlProtocol;
28
29#[derive(Debug, Clone)]
31pub struct ControlReady {
32 pub welcome: ControlWelcome,
34 pub frame: RawFrame,
36}
37
38impl Protocol for ControlProtocol {
43 type Ready = ControlReady;
44
45 fn establish(
46 mut stream: BoxTransport,
47 options: ConnectOptions,
48 ) -> BoxFuture<'static, ClientResult<Established<Self::Ready>>> {
49 Box::pin(async move {
50 let hello = ControlHello {
51 max_frame_size: options.limits.max_frame_size,
52 max_in_flight: options
53 .limits
54 .max_in_flight
55 .min(DEFAULT_MAX_IN_FLIGHT as usize) as u32,
56 ..Default::default()
57 };
58 hello
59 .validate()
60 .map_err(|_| ClientError::new(ErrorKind::InvalidOptions))?;
61 let opening =
62 Envelope::new(CONTROL_GENERATION, "control.hello", &hello)?.frame(0, 0)?;
63 codec::write_raw_frame(&mut stream, &opening)
64 .await
65 .map_err(|error| match error {
66 microsandbox_protocol::ProtocolError::Io(error) => ClientError::from(error),
67 _ => ClientError::new(ErrorKind::InvalidData),
68 })?;
69 let length = stream.read_u32().await?;
72 if !(5..=MAX_HANDSHAKE_FRAME_SIZE).contains(&length) {
73 return Err(ClientError::new(ErrorKind::InvalidData));
74 }
75 let id = stream.read_u32().await?;
76 let flags = stream.read_u8().await?;
77 let mut body = vec![0; length as usize - 5];
78 stream.read_exact(&mut body).await?;
79 let frame = RawFrame { id, flags, body };
80 let envelope = Envelope::decode(&frame.body)?;
81 if frame.id != 0 || frame.flags != 1 || envelope.v != CONTROL_GENERATION {
82 return Err(ClientError::new(ErrorKind::InvalidData));
83 }
84 if envelope.t == "control.error" {
85 let refusal: ControlError = envelope.payload()?;
86 let kind = if refusal.code == "unsupported_generation" {
87 ErrorKind::UnsupportedOperation
88 } else {
89 ErrorKind::InvalidData
90 };
91 return Err(ClientError::new(kind));
92 }
93 if envelope.t != "control.welcome" {
94 return Err(ClientError::new(ErrorKind::InvalidData));
95 }
96 let welcome: ControlWelcome = envelope.payload()?;
97 welcome
98 .validate_for(&hello)
99 .map_err(|_| ClientError::new(ErrorKind::InvalidData))?;
100 let mut limits = options.limits;
101 limits.max_frame_size = welcome.max_frame_size;
102 limits.max_in_flight = welcome.max_in_flight as usize;
103 limits
104 .incomplete_frame_timeout
105 .get_or_insert(DEFAULT_SETUP_TIMEOUT);
106 limits
107 .request_timeout
108 .get_or_insert(DEFAULT_REQUEST_TIMEOUT);
109 Ok(Established {
110 transport: stream,
111 codec: Arc::new(CborEnvelopeCodec),
112 ids: IdRange {
113 start: 1,
114 end_exclusive: 1u64 << 32,
115 },
116 ready: ControlReady { welcome, frame },
117 limits,
118 })
119 })
120 }
121
122 fn prepare(ready: &Self::Ready, wire_name: &str) -> ClientResult<SendMetadata> {
123 if matches!(wire_name, "control.hello" | "control.welcome") {
126 return Err(ClientError::new(ErrorKind::UnsupportedOperation));
127 }
128 Ok(SendMetadata {
129 generation: ready.welcome.generation,
130 flags: 0,
131 })
132 }
133}