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