Skip to main content

microsandbox_protocol/
core.rs

1//! Core protocol message payloads.
2
3use serde::{Deserialize, Serialize};
4
5//--------------------------------------------------------------------------------------------------
6// Types
7//--------------------------------------------------------------------------------------------------
8
9/// Payload for `core.ready` messages.
10///
11/// Sent by the guest agent to signal that it has finished initialization
12/// and is ready to receive commands. Includes timing data for boot
13/// performance measurement.
14#[derive(Debug, Clone, Default, Serialize, Deserialize)]
15pub struct Ready {
16    /// `CLOCK_BOOTTIME` nanoseconds captured at the start of `main()`.
17    ///
18    /// Represents how long the kernel took to boot before userspace started.
19    pub boot_time_ns: u64,
20
21    /// Nanoseconds spent in `init::init()` (mounting filesystems).
22    pub init_time_ns: u64,
23
24    /// `CLOCK_BOOTTIME` nanoseconds captured just before sending this message.
25    ///
26    /// Represents total time from kernel boot to agent readiness.
27    pub ready_time_ns: u64,
28
29    /// The agent's package version (`CARGO_PKG_VERSION`), for diagnostics.
30    ///
31    /// Additive and optional: an older agent that predates this field decodes to
32    /// an empty string, and an older host ignores it. Empty means unknown. This
33    /// is the runtime's self-reported product version; the protocol generation is
34    /// carried separately in the message envelope's `v`.
35    #[serde(default, skip_serializing_if = "String::is_empty")]
36    pub agent_version: String,
37}
38
39/// Payload for `core.clock.sync` messages.
40///
41/// Sent by the host to ask the guest agent to step `CLOCK_REALTIME` to the
42/// host's current wall-clock time.
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct ClockSync {
45    /// Host Unix timestamp in nanoseconds.
46    pub unix_time_nanos: u64,
47}
48
49/// Payload for `core.ping` messages.
50///
51/// Sent by the host to verify that agentd is reachable. A ping is maintenance
52/// traffic and does not refresh the sandbox idle timer.
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct Ping {}
55
56/// Payload for `core.pong` messages.
57///
58/// Sent by agentd in response to `core.ping`.
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct Pong {}
61
62/// Payload for `core.touch` messages.
63///
64/// Sent by the host to explicitly refresh the sandbox idle timer without
65/// starting an exec, filesystem, or TCP session.
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct Touch {}
68
69/// Payload for `core.touched` messages.
70///
71/// Sent by agentd in response to `core.touch`.
72#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct Touched {
74    /// Activity sequence after the explicit touch was recorded.
75    pub activity_seq: u64,
76}
77
78/// Payload for `core.error` messages.
79///
80/// Sent when a peer can identify a recoverable protocol error for a specific
81/// correlation ID. Unrecoverable frame-level errors, such as stream
82/// desynchronization or impossible frame lengths, should close the transport
83/// instead.
84#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct CoreError {
86    /// Machine-readable error kind.
87    pub kind: CoreErrorKind,
88
89    /// Human-readable diagnostic message.
90    pub message: String,
91
92    /// Wire message type involved in the error, when it could be determined.
93    #[serde(default, skip_serializing_if = "Option::is_none")]
94    pub offending_type: Option<String>,
95}
96
97/// Machine-readable `core.error` categories.
98#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
99#[serde(rename_all = "snake_case")]
100pub enum CoreErrorKind {
101    /// The protocol message envelope could not be decoded.
102    MalformedMessage,
103
104    /// The message type is unknown to the peer.
105    UnsupportedMessageType,
106
107    /// The message requires a newer protocol generation than the peer supports.
108    UnsupportedProtocolGeneration,
109
110    /// The frame flags do not match the message type.
111    InvalidFlags,
112
113    /// The message payload could not be decoded or failed validation.
114    InvalidPayload,
115
116    /// The message refers to an unknown, closed, or incompatible session.
117    InvalidSession,
118}
119
120/// Payload for `core.init.resolved` messages.
121///
122/// Sent by agentd after the guest rootfs is ready to resolve init-time facts,
123/// but before user volume mounts are attached. The host uses this to install
124/// early runtime state that depends on guest-resolved values.
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct InitResolved {
127    /// Default guest user for sandbox commands.
128    pub default_user: ResolvedUser,
129}
130
131/// A guest user and group resolved by agentd.
132#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
133pub struct ResolvedUser {
134    /// Effective default guest user id for sandbox commands.
135    pub uid: u32,
136
137    /// Effective default guest group id for sandbox commands.
138    pub gid: u32,
139}
140
141/// Payload for `core.init.ack` messages.
142///
143/// Sent by the host after it has consumed the init context and completed any
144/// dependent setup.
145#[derive(Debug, Clone, Serialize, Deserialize)]
146pub struct InitAck {}
147
148/// Payload for `core.relay.client.disconnected` messages.
149///
150/// Sent by the host relay when one SDK client socket disconnects. The
151/// guest agent uses the assigned correlation ID range to clean up resources
152/// owned by that client, such as open filesystem handles.
153#[derive(Debug, Clone, Serialize, Deserialize)]
154pub struct RelayClientDisconnected {
155    /// First correlation ID assigned to the disconnected client.
156    pub id_start: u32,
157
158    /// Exclusive upper bound of the disconnected client's ID range.
159    pub id_end_exclusive: u32,
160}