Skip to main content

lawn_protocol/protocol/
mod.rs

1#![allow(non_upper_case_globals)]
2/// # Overview
3///
4/// The protocol is relatively simple.  Each request consists of a 32-bit size of the resulting
5/// message, a 32-bit request ID, a 32-bit message type, and an optional per-message CBOR blob
6/// representing message data.  For performance and security reasons, the message size is limited
7/// to 2^24 in size.  The size includes all fields other than the size.
8///
9/// Each response consists of a 32-bit size of the message, the 32-bit request ID, a 32-bit
10/// response code, and an optional per-response code CBOR blob.
11///
12/// The bottom 31 bits of the request ID may be any value; the response will use the same ID.  No
13/// check is made for duplicates, so the requestor should prefer not repeating IDs that are in
14/// flight.  The top bit is clear if the request is client-to-server request and it is set if the
15/// request is a server-to-client request.  This helps eliminate confusion as to whether a message
16/// is a request or a response.
17///
18/// All data is serialized in a little-endian format.
19///
20/// ## Extension Messages
21///
22/// Extension values (message types and response codes) are assigned with
23/// values `0xff000000` and larger.  These can be dynamically allocated using
24/// the `CreateExtensionRange` message, and once allocated, will allow the
25/// extension to use the given codes both as message types and response codes.
26///
27/// Note that an implementation is not obligated to allocate or use extension
28/// codes.  For example, an implementation which offers a new sort of channel may
29/// well choose to use the existing channel codes, or it may choose to use new
30/// message types with existing response codes.
31///
32/// Lawn currently allocates these by allocating a 12-bit range internally, so
33/// the first code of the first extension is `0xff000000`, the first code of the next is
34/// `0xfff001000`,  and so on.  This provides 4096 codes per extension while
35/// allowing 4096 extensions.  However, this algorithm is subject to change at any
36/// time.
37use crate::config::Config;
38use bitflags::bitflags;
39use bytes::{Bytes, BytesMut};
40use num_traits::FromPrimitive;
41use serde::{de::DeserializeOwned, Deserialize, Serialize};
42use serde_cbor::Value;
43use std::collections::{BTreeMap, BTreeSet};
44use std::convert::{TryFrom, TryInto};
45use std::fmt;
46use std::io;
47use std::io::{Seek, SeekFrom};
48
49/// The response codes for the protocol.
50///
51/// The response codes are based around IMAP's response codes, and the top two bytes of the
52/// response indicates the type:
53///
54/// * 00: success
55/// * 01: no (roughly, the request was understood, but not completed)
56/// * 02: bad (roughly, the request was not understood)
57/// * ff: extension message (dynamically allocated)
58#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
59pub enum ResponseCode {
60    /// The request was successful.  The response contains the requested data.
61    Success = 0x00000000,
62    /// The request is incomplete, but is so far successful.  The request should continue,
63    /// referencing the ID of the last request.
64    Continuation = 0x00000001,
65
66    /// The request requires authentication.
67    ///
68    /// The semantics for this message are equivalent to an HTTP 401 response.
69    NeedsAuthentication = 0x00010000,
70    /// The message was not allowed.
71    ///
72    /// The semantics for this message are equivalent to an HTTP 403 response.
73    Forbidden = 0x00010001,
74    /// The server is shutting down.
75    Closing = 0x00010002,
76    /// The message failed for a system error reason.
77    ///
78    /// This is generally only useful for certain types of channels.
79    Errno = 0x00010003,
80    AuthenticationFailed = 0x00010004,
81    /// The other end of the channel has disappeared.
82    Gone = 0x00010005,
83    NotFound = 0x00010006,
84    InternalError = 0x00010007,
85    /// The channel has ceased to produce new data and this operation cannot complete.
86    ChannelDead = 0x00010008,
87    /// The operation was aborted.
88    Aborted = 0x00010009,
89    /// There is no continuation with the specified parameters.
90    ContinuationNotFound = 0x0001000a,
91    /// The result was out of range.
92    ///
93    /// The semantics for this message are equivalent to `ERANGE`.
94    OutOfRange = 0x0001000b,
95    /// There is no more space for the requested item.
96    NoSpace = 0x0001000c,
97    /// The requested operation would conflict with something already existing.
98    ///
99    /// The semantics for this message are equivalent to an HTTP 409 response.
100    Conflict = 0x0001000d,
101    /// The contents of the object cannot be listed or specified by name.
102    ///
103    /// For example, when using a Git-protocol credential helper, it is not possible to enumerate
104    /// all credentials or pick a credential by ID.
105    Unlistable = 0x0001000e,
106
107    /// The message type was not enabled.
108    NotEnabled = 0x00020000,
109    /// The message type or operation was not supported.
110    NotSupported = 0x00020001,
111    /// The parameters were not supported.
112    ParametersNotSupported = 0x00020002,
113    /// The message type was received, but was not valid.
114    Invalid = 0x00020003,
115    /// The message was too large.
116    TooLarge = 0x00020004,
117    /// There are too many pending messages.
118    TooManyMessages = 0x00020005,
119    /// The parameters are supported, but not correct.
120    ///
121    /// For example, if a selector is not valid for a channel, this message may be sent.
122    InvalidParameters = 0x00020006,
123}
124
125impl ResponseCode {
126    fn from_u32(val: u32) -> Self {
127        FromPrimitive::from_u32(val).unwrap_or(Self::Invalid)
128    }
129}
130
131pub struct WrongTypeError(pub Error);
132
133#[derive(Debug, Clone)]
134pub struct Error {
135    pub code: ResponseCode,
136    pub body: Option<ErrorBody>,
137}
138
139impl fmt::Display for Error {
140    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
141        fmt::Debug::fmt(self, f)
142    }
143}
144
145impl std::error::Error for Error {}
146
147impl Error {
148    pub fn from_errno(err: i32) -> Error {
149        io::Error::from_raw_os_error(err).into()
150    }
151}
152
153impl From<io::Error> for Error {
154    fn from(err: io::Error) -> Error {
155        let lerr: lawn_constants::Error = err.into();
156        Error {
157            code: ResponseCode::Errno,
158            body: Some(ErrorBody::Errno(Errno { errno: lerr as u32 })),
159        }
160    }
161}
162
163impl From<ResponseCode> for Error {
164    fn from(code: ResponseCode) -> Error {
165        Error { code, body: None }
166    }
167}
168
169impl TryInto<io::Error> for Error {
170    type Error = WrongTypeError;
171    fn try_into(self) -> Result<io::Error, Self::Error> {
172        if self.code == ResponseCode::Errno {
173            if let Some(ErrorBody::Errno(Errno { errno })) = self.body {
174                if let Some(e) = lawn_constants::Error::from_u32(errno) {
175                    return Ok(e.into());
176                }
177            }
178        }
179        Err(WrongTypeError(self))
180    }
181}
182
183#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
184pub struct Empty {}
185
186#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
187pub struct Errno {
188    errno: u32,
189}
190
191#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
192#[serde(untagged)]
193pub enum ErrorBody {
194    Errno(Errno),
195    Exit(i32),
196}
197
198#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
199pub enum MessageKind {
200    /// Requests that the other side provide a list of supported versions and capabilities.
201    Capability = 0x00000000,
202    /// Requests a specific version and capabilities.
203    ///
204    /// This request aborts all other in-flight requests by this sender.  Consequently, it should
205    /// be sent at the beginning of the connection right after a successful `Capability` message.
206    ///
207    /// Authentication is not required for this message.
208    Version = 0x00000001,
209    /// Indicates a no-op request which should always be successful.
210    ///
211    /// Authentication is not required for this message.
212    Ping = 0x00000002,
213    /// Requests authentication.
214    ///
215    /// This request aborts all other in-flight requests by this sender.  Consequently, it should
216    /// be sent at the beginning of the connection right after a successful `Capability` message.
217    ///
218    /// Authentication is not required for this message (obviously).
219    Authenticate = 0x00000003,
220    /// Continue an in-progress request.
221    ///
222    /// This request can be used to continue an operation when the `Continuation` response is
223    /// provided.
224    Continue = 0x00000004,
225    /// Abort an in-progress request.
226    ///
227    /// This request can be used to abort an operation when the `Continuation` response is
228    /// provided.
229    Abort = 0x00000005,
230
231    /// Indicates a graceful shutdown.
232    ///
233    /// Authentication is not required for this message.
234    CloseAlert = 0x00001000,
235
236    /// Requests a channel to be created.
237    CreateChannel = 0x00010000,
238    /// Requests a channel to be deleted.
239    ///
240    /// This request is made from the client to the server to terminate the connection.
241    DeleteChannel = 0x00010001,
242    /// Requests a read on the channel.
243    ReadChannel = 0x00010002,
244    /// Requests a write on the channel.
245    WriteChannel = 0x00010003,
246    /// Requests the status of the selectors on the channel.
247    PollChannel = 0x00010004,
248    /// Requests the status of the object on the other end of the channel.
249    ///
250    /// For command channels, this can be used to check if the child has exited.
251    PingChannel = 0x00010005,
252    // Not implemented:
253    // AttachChannelSelector = 0x00010010,
254    DetachChannelSelector = 0x00010011,
255    /// Provides notification of some sort of metadata condition on the channel.
256    ///
257    /// For command channels, this is used by the server to notify the client that the process has
258    /// terminated.
259    ChannelMetadataNotification = 0x00011000,
260
261    /// Allocates a range of IDs for an extension.
262    CreateExtensionRange = 0x00020000,
263
264    /// Deallocates a range of IDs for an extension.
265    DeleteExtensionRange = 0x00020001,
266
267    /// Lists all allocated ranges of IDs for extensions.
268    ListExtensionRanges = 0x00020002,
269
270    /// Open a store and associate an ID with it.
271    OpenStore = 0x00030000,
272
273    /// Close a store and associate an ID with it.
274    CloseStore = 0x00030001,
275
276    /// Lists all elements of a given type in the given store.
277    ListStoreElements = 0x00030002,
278
279    /// Acquire a handle to an element in the given store.
280    AcquireStoreElement = 0x00030003,
281
282    /// Release the handle of a store element.
283    CloseStoreElement = 0x00030004,
284
285    /// Authenticate to a store element if that's required to open it.
286    AuthenticateStoreElement = 0x00030005,
287
288    /// Create a store element.
289    CreateStoreElement = 0x00030006,
290
291    /// Delete a store element.
292    DeleteStoreElement = 0x00030007,
293
294    /// Update a store element.
295    UpdateStoreElement = 0x00030008,
296
297    /// Read a store element.
298    ReadStoreElement = 0x00030009,
299
300    /// Rename a store element.
301    RenameStoreElement = 0x0003000a,
302
303    /// Copy a store element.
304    CopyStoreElement = 0x0003000b,
305
306    /// Search store elements.
307    SearchStoreElements = 0x0003000c,
308
309    /// Read a server context.
310    ReadServerContext = 0x00040000,
311
312    /// Write a server context.
313    WriteServerContext = 0x00040001,
314}
315
316#[derive(Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
317pub enum Capability {
318    AuthExternal,
319    AuthKeyboardInteractive,
320    AuthPlain,
321    ChannelCommand,
322    ChannelCommandTTY,
323    Channel9P,
324    ChannelSFTP,
325    ChannelClipboard,
326    ChannelBlockingIO,
327    ExtensionAllocate,
328    StoreCredential,
329    ContextTemplate,
330    Other(Bytes, Option<Bytes>),
331}
332
333impl Capability {
334    #[allow(clippy::mutable_key_type)]
335    pub fn implemented() -> BTreeSet<Capability> {
336        [
337            Self::AuthExternal,
338            Self::AuthKeyboardInteractive,
339            Self::AuthPlain,
340            Self::ChannelCommand,
341            Self::ChannelClipboard,
342            Self::Channel9P,
343            Self::ChannelSFTP,
344            Self::ChannelBlockingIO,
345            Self::ChannelCommandTTY,
346            Self::ExtensionAllocate,
347            Self::StoreCredential,
348            Self::ContextTemplate,
349        ]
350        .iter()
351        .cloned()
352        .collect()
353    }
354
355    pub fn is_implemented(&self) -> bool {
356        matches!(
357            self,
358            Self::AuthExternal
359                | Self::AuthKeyboardInteractive
360                | Self::AuthPlain
361                | Self::ChannelCommand
362                | Self::ChannelClipboard
363                | Self::Channel9P
364                | Self::ChannelSFTP
365                | Self::ChannelBlockingIO
366                | Self::ChannelCommandTTY
367                | Self::ExtensionAllocate
368                | Self::StoreCredential
369                | Self::ContextTemplate
370        )
371    }
372}
373
374impl From<Capability> for (Bytes, Option<Bytes>) {
375    fn from(capa: Capability) -> (Bytes, Option<Bytes>) {
376        match capa {
377            Capability::AuthExternal => (
378                (b"auth" as &[u8]).into(),
379                Some((b"EXTERNAL" as &[u8]).into()),
380            ),
381            Capability::AuthKeyboardInteractive => (
382                (b"auth" as &[u8]).into(),
383                Some((b"keyboard-interactive" as &[u8]).into()),
384            ),
385            Capability::AuthPlain => ((b"auth" as &[u8]).into(), Some((b"PLAIN" as &[u8]).into())),
386            Capability::ChannelCommand => (
387                (b"channel" as &[u8]).into(),
388                Some((b"command" as &[u8]).into()),
389            ),
390            Capability::ChannelCommandTTY => (
391                (b"channel" as &[u8]).into(),
392                Some((b"command/tty" as &[u8]).into()),
393            ),
394            Capability::Channel9P => ((b"channel" as &[u8]).into(), Some((b"9p" as &[u8]).into())),
395            Capability::ChannelSFTP => (
396                (b"channel" as &[u8]).into(),
397                Some((b"sftp" as &[u8]).into()),
398            ),
399            Capability::ChannelClipboard => (
400                (b"channel" as &[u8]).into(),
401                Some((b"clipboard" as &[u8]).into()),
402            ),
403            Capability::ChannelBlockingIO => (
404                (b"channel" as &[u8]).into(),
405                Some((b"blocking-io" as &[u8]).into()),
406            ),
407            Capability::StoreCredential => (
408                (b"store" as &[u8]).into(),
409                Some((b"credential" as &[u8]).into()),
410            ),
411            Capability::ExtensionAllocate => (
412                (b"extension" as &[u8]).into(),
413                Some((b"allocate" as &[u8]).into()),
414            ),
415            Capability::ContextTemplate => (
416                (b"context" as &[u8]).into(),
417                Some((b"template" as &[u8]).into()),
418            ),
419            Capability::Other(name, subtype) => (name, subtype),
420        }
421    }
422}
423
424impl From<(&[u8], Option<&[u8]>)> for Capability {
425    fn from(data: (&[u8], Option<&[u8]>)) -> Capability {
426        match data {
427            (b"auth", Some(b"EXTERNAL")) => Capability::AuthExternal,
428            (b"auth", Some(b"PLAIN")) => Capability::AuthPlain,
429            (b"auth", Some(b"keyboard-interactive")) => Capability::AuthKeyboardInteractive,
430            (b"channel", Some(b"command")) => Capability::ChannelCommand,
431            (b"channel", Some(b"command/tty")) => Capability::ChannelCommandTTY,
432            (b"channel", Some(b"9p")) => Capability::Channel9P,
433            (b"channel", Some(b"sftp")) => Capability::ChannelSFTP,
434            (b"channel", Some(b"clipboard")) => Capability::ChannelClipboard,
435            (b"channel", Some(b"blocking-io")) => Capability::ChannelBlockingIO,
436            (b"store", Some(b"credential")) => Capability::StoreCredential,
437            (b"extension", Some(b"allocate")) => Capability::ExtensionAllocate,
438            (b"context", Some(b"template")) => Capability::ContextTemplate,
439            (name, subtype) => {
440                Capability::Other(name.to_vec().into(), subtype.map(|s| s.to_vec().into()))
441            }
442        }
443    }
444}
445
446impl From<(Bytes, Option<Bytes>)> for Capability {
447    fn from(data: (Bytes, Option<Bytes>)) -> Capability {
448        match data {
449            (a, Some(b)) => (&a as &[u8], Some(&b as &[u8])).into(),
450            (a, None) => (&a as &[u8], None).into(),
451        }
452    }
453}
454
455#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
456#[serde(rename_all = "kebab-case")]
457pub struct CapabilityResponse {
458    pub version: Vec<u32>,
459    pub capabilities: Vec<(Bytes, Option<Bytes>)>,
460    pub user_agent: Option<String>,
461}
462
463#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
464#[serde(rename_all = "kebab-case")]
465pub struct VersionRequest {
466    pub version: u32,
467    pub enable: Vec<(Bytes, Option<Bytes>)>,
468    pub id: Option<Bytes>,
469    pub user_agent: Option<String>,
470}
471
472#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
473#[serde(rename_all = "kebab-case")]
474pub struct AuthenticateRequest {
475    pub last_id: Option<u32>,
476    // All uppercase methods are SASL methods as defined by IANA.  Other methods are defined
477    // internally.
478    pub method: Bytes,
479    pub message: Option<Bytes>,
480}
481
482#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
483#[serde(rename_all = "kebab-case")]
484pub struct AuthenticateResponse {
485    // All uppercase methods are SASL methods as defined by IANA.  Other methods are defined
486    // internally.
487    pub method: Bytes,
488    pub message: Option<Bytes>,
489}
490
491#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
492#[serde(rename_all = "kebab-case")]
493pub struct PartialContinueRequest {
494    pub id: u32,
495    pub kind: u32,
496}
497
498#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
499#[serde(rename_all = "kebab-case")]
500pub struct ContinueRequest<T> {
501    pub id: u32,
502    pub kind: u32,
503    pub message: Option<T>,
504}
505
506#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
507#[serde(rename_all = "kebab-case")]
508pub struct AbortRequest {
509    pub id: u32,
510    pub kind: u32,
511}
512
513#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
514#[serde(transparent)]
515pub struct ChannelID(pub u32);
516
517impl fmt::Display for ChannelID {
518    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
519        write!(f, "{}", self.0)
520    }
521}
522
523#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
524#[serde(transparent)]
525pub struct ChannelSelectorID(pub u32);
526
527/// A message to create a channel.
528///
529/// The following channel types are known:
530///
531/// * `command`: Invoke a command on the remote side.  `args` is the command-line arguments and
532///   `env` is the environment.
533/// * `9p`: Create a channel implementing the 9p2000.L protocol.  `args[0]` is the desired mount
534///   point as specified by the server.
535///
536/// Custom channel types can be created with an at sign and domain name representing the custom
537/// extension.
538#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
539#[serde(rename_all = "kebab-case")]
540pub struct CreateChannelRequest {
541    pub kind: Bytes,
542    pub kind_args: Option<Vec<Bytes>>,
543    pub args: Option<Vec<Bytes>>,
544    pub env: Option<BTreeMap<Bytes, Bytes>>,
545    pub meta: Option<BTreeMap<Bytes, Value>>,
546    pub selectors: Vec<u32>,
547}
548
549#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
550#[serde(rename_all = "kebab-case")]
551pub struct CreateChannelResponse {
552    pub id: ChannelID,
553}
554
555#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
556#[serde(rename_all = "kebab-case")]
557pub struct ChannelCommandTTYMetadata {
558    pub tty: bool,
559    pub tty_selectors: Vec<u32>,
560    pub term: Bytes,
561    pub modes: BTreeMap<u32, Value>,
562    #[serde(flatten)]
563    pub size: ChannelCommandTTYSizeMetadata,
564}
565
566#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
567#[serde(rename_all = "kebab-case")]
568pub struct ChannelCommandTTYSizeMetadata {
569    pub height_cells: u32,
570    pub width_cells: u32,
571    pub height_pixels: u32,
572    pub width_pixels: u32,
573}
574
575#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
576#[serde(rename_all = "kebab-case")]
577pub struct DeleteChannelRequest {
578    pub id: ChannelID,
579    pub termination: Option<u32>,
580}
581
582#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
583#[serde(rename_all = "kebab-case")]
584pub struct ReadChannelRequest {
585    pub id: ChannelID,
586    pub selector: u32,
587    pub count: u64,
588    #[serde(default)]
589    pub stream_sync: Option<u64>,
590    #[serde(default)]
591    pub blocking: Option<bool>,
592    #[serde(default)]
593    pub complete: bool,
594}
595
596#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
597#[serde(rename_all = "kebab-case")]
598pub struct ReadChannelResponse {
599    pub bytes: Bytes,
600    #[serde(default)]
601    pub offset: Option<u64>,
602}
603
604#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
605#[serde(rename_all = "kebab-case")]
606pub struct WriteChannelRequest {
607    pub id: ChannelID,
608    pub selector: u32,
609    pub bytes: Bytes,
610    #[serde(default)]
611    pub stream_sync: Option<u64>,
612    #[serde(default)]
613    pub blocking: Option<bool>,
614}
615
616#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
617#[serde(rename_all = "kebab-case")]
618pub struct WriteChannelResponse {
619    pub count: u64,
620    #[serde(default)]
621    pub offset: Option<u64>,
622}
623
624#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
625#[serde(rename_all = "kebab-case")]
626pub struct DetachChannelSelectorRequest {
627    pub id: ChannelID,
628    pub selector: u32,
629}
630
631bitflags! {
632    #[derive(Default)]
633    pub struct PollChannelFlags: u64 {
634        const Input   = 0x00000001;
635        const Output  = 0x00000002;
636        const Error   = 0x00000004;
637        const Hangup  = 0x00000008;
638        const Invalid = 0x00000010;
639        const Gone    = 0x00000020;
640    }
641}
642
643#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
644#[serde(rename_all = "kebab-case")]
645pub struct CreateExtensionRangeRequest {
646    pub extension: (Bytes, Option<Bytes>),
647    pub count: u32,
648}
649
650#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
651#[serde(rename_all = "kebab-case")]
652pub struct CreateExtensionRangeResponse {
653    pub range: (u32, u32),
654}
655
656#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
657#[serde(rename_all = "kebab-case")]
658pub struct DeleteExtensionRangeRequest {
659    pub extension: (Bytes, Option<Bytes>),
660    pub range: (u32, u32),
661}
662
663#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
664#[serde(rename_all = "kebab-case")]
665pub struct ListExtensionRangesResponse {
666    pub ranges: Vec<ExtensionRange>,
667}
668
669impl IntoIterator for ListExtensionRangesResponse {
670    type Item = ExtensionRange;
671    type IntoIter = std::vec::IntoIter<ExtensionRange>;
672
673    fn into_iter(self) -> Self::IntoIter {
674        self.ranges.into_iter()
675    }
676}
677
678impl<'a> IntoIterator for &'a ListExtensionRangesResponse {
679    type Item = &'a ExtensionRange;
680    type IntoIter = std::slice::Iter<'a, ExtensionRange>;
681
682    fn into_iter(self) -> Self::IntoIter {
683        self.ranges.iter()
684    }
685}
686
687impl<'a> IntoIterator for &'a mut ListExtensionRangesResponse {
688    type Item = &'a mut ExtensionRange;
689    type IntoIter = std::slice::IterMut<'a, ExtensionRange>;
690
691    fn into_iter(self) -> Self::IntoIter {
692        self.ranges.iter_mut()
693    }
694}
695
696#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
697#[serde(rename_all = "kebab-case")]
698pub struct ExtensionRange {
699    pub extension: (Bytes, Option<Bytes>),
700    pub range: (u32, u32),
701}
702
703#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
704pub enum ChannelMetadataNotificationKind {
705    WaitStatus = 0,
706    TerminalWindowChange = 1,
707}
708
709#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
710pub enum ChannelMetadataStatusKind {
711    Exited = 0,
712    Signalled = 1,
713    SignalledWithCore = 2,
714    Stopped = 3,
715    Unknown = 0x7fffffff,
716}
717
718#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
719#[serde(rename_all = "kebab-case")]
720pub struct PingChannelRequest {
721    pub id: ChannelID,
722}
723
724#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
725#[serde(rename_all = "kebab-case")]
726pub struct PollChannelRequest {
727    pub id: ChannelID,
728    pub selectors: Vec<u32>,
729    pub milliseconds: Option<u32>,
730    pub wanted: Option<Vec<u64>>,
731}
732
733#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
734#[serde(rename_all = "kebab-case")]
735pub struct PollChannelResponse {
736    pub id: ChannelID,
737    pub selectors: BTreeMap<u32, u64>,
738}
739
740#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
741#[serde(rename_all = "kebab-case")]
742pub struct ChannelMetadataNotification {
743    pub id: ChannelID,
744    pub kind: u32,
745    pub status: Option<u32>,
746    pub status_kind: Option<u32>,
747    pub meta: Option<BTreeMap<Bytes, Value>>,
748}
749
750#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
751#[serde(rename_all = "kebab-case")]
752pub struct ChannelMetadataNotificationTyped<T> {
753    pub id: ChannelID,
754    pub kind: u32,
755    pub status: Option<u32>,
756    pub status_kind: Option<u32>,
757    pub meta: Option<T>,
758}
759
760#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
761pub enum ClipboardChannelTarget {
762    Primary,
763    Clipboard,
764}
765
766#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
767pub enum ClipboardChannelOperation {
768    Copy,
769    Paste,
770}
771
772#[derive(Serialize, Deserialize, Hash, Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
773#[serde(transparent)]
774pub struct StoreID(pub u32);
775
776#[derive(Serialize, Deserialize, Hash, Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
777#[serde(transparent)]
778pub struct StoreSelectorID(pub u32);
779
780#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
781#[serde(rename_all = "kebab-case")]
782pub enum StoreSelector {
783    Path(Bytes),
784    #[serde(rename = "id")]
785    ID(StoreSelectorID),
786}
787
788#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
789#[serde(rename_all = "kebab-case")]
790pub struct OpenStoreRequest {
791    pub kind: Bytes,
792    pub path: Option<Bytes>,
793    pub meta: Option<BTreeMap<Bytes, Value>>,
794}
795
796#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
797#[serde(rename_all = "kebab-case")]
798pub struct OpenStoreResponse {
799    pub id: StoreID,
800}
801
802#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
803#[serde(rename_all = "kebab-case")]
804pub struct CloseStoreRequest {
805    pub id: StoreID,
806}
807
808#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
809#[serde(rename_all = "kebab-case")]
810pub struct ListStoreElementsRequest {
811    pub id: StoreID,
812    pub selector: StoreSelector,
813}
814
815#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
816#[serde(rename_all = "kebab-case")]
817pub struct ListStoreElementsResponse {
818    pub elements: Vec<StoreElement>,
819}
820
821impl IntoIterator for ListStoreElementsResponse {
822    type Item = StoreElement;
823    type IntoIter = std::vec::IntoIter<StoreElement>;
824
825    fn into_iter(self) -> Self::IntoIter {
826        self.elements.into_iter()
827    }
828}
829
830impl<'a> IntoIterator for &'a ListStoreElementsResponse {
831    type Item = &'a StoreElement;
832    type IntoIter = std::slice::Iter<'a, StoreElement>;
833
834    fn into_iter(self) -> Self::IntoIter {
835        self.elements.iter()
836    }
837}
838
839impl<'a> IntoIterator for &'a mut ListStoreElementsResponse {
840    type Item = &'a mut StoreElement;
841    type IntoIter = std::slice::IterMut<'a, StoreElement>;
842
843    fn into_iter(self) -> Self::IntoIter {
844        self.elements.iter_mut()
845    }
846}
847
848#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
849#[serde(rename_all = "kebab-case")]
850pub struct AcquireStoreElementRequest {
851    pub id: StoreID,
852    pub selector: Bytes,
853}
854
855#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
856#[serde(rename_all = "kebab-case")]
857pub struct AcquireStoreElementResponse {
858    pub selector: StoreSelectorID,
859}
860
861#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
862#[serde(rename_all = "kebab-case")]
863pub struct CloseStoreElementRequest {
864    pub id: StoreID,
865    pub selector: StoreSelectorID,
866}
867
868#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
869#[serde(rename_all = "kebab-case")]
870pub struct AuthenticateStoreElementRequest {
871    pub id: StoreID,
872    pub selector: StoreSelectorID,
873    pub method: Bytes,
874    pub message: Option<Bytes>,
875}
876
877#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
878#[serde(rename_all = "kebab-case")]
879pub struct AuthenticateStoreElementResponse {
880    pub method: Bytes,
881    pub message: Option<Bytes>,
882}
883
884#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
885#[serde(rename_all = "kebab-case")]
886pub struct StoreElementBareRequest {
887    pub id: StoreID,
888    pub selector: StoreSelector,
889    pub kind: String,
890    pub needs_authentication: Option<bool>,
891    pub authentication_methods: Option<Vec<Bytes>>,
892    pub meta: Option<BTreeMap<Bytes, Value>>,
893}
894
895#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
896#[serde(rename_all = "kebab-case")]
897pub struct CreateStoreElementRequest<T> {
898    pub id: StoreID,
899    pub selector: StoreSelector,
900    pub kind: String,
901    pub needs_authentication: Option<bool>,
902    pub authentication_methods: Option<Vec<Bytes>>,
903    pub meta: Option<BTreeMap<Bytes, Value>>,
904    pub body: T,
905}
906
907#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
908#[serde(rename_all = "kebab-case")]
909pub struct DeleteStoreElementRequest {
910    pub id: StoreID,
911    pub selector: StoreSelector,
912}
913
914#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
915#[serde(rename_all = "kebab-case")]
916pub struct UpdateStoreElementRequest<T> {
917    pub id: StoreID,
918    pub selector: StoreSelector,
919    pub kind: String,
920    pub needs_authentication: Option<bool>,
921    pub authentication_methods: Option<Vec<Bytes>>,
922    pub meta: Option<BTreeMap<Bytes, Value>>,
923    pub body: T,
924}
925
926#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
927#[serde(rename_all = "kebab-case")]
928pub struct ReadStoreElementRequest {
929    pub id: StoreID,
930    pub selector: StoreSelector,
931}
932
933#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
934#[serde(rename_all = "kebab-case")]
935pub struct ReadStoreElementResponse<T> {
936    pub kind: String,
937    pub needs_authentication: Option<bool>,
938    pub authentication_methods: Option<Vec<Bytes>>,
939    pub meta: Option<BTreeMap<Bytes, Value>>,
940    pub body: T,
941}
942
943#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
944#[serde(rename_all = "kebab-case")]
945pub enum StoreSearchRecursionLevel {
946    Boolean(bool),
947    Levels(u32),
948}
949
950#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
951#[serde(rename_all = "kebab-case")]
952pub struct SearchStoreElementsBareRequest {
953    pub id: StoreID,
954    pub selector: StoreSelector,
955    pub recurse: StoreSearchRecursionLevel,
956    pub kind: Option<String>,
957}
958
959#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
960#[serde(rename_all = "kebab-case")]
961pub struct SearchStoreElementsRequest<T> {
962    pub id: StoreID,
963    pub selector: StoreSelector,
964    pub recurse: StoreSearchRecursionLevel,
965    pub kind: Option<String>,
966    pub body: Option<T>,
967}
968
969#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
970#[serde(rename_all = "kebab-case")]
971pub struct SearchStoreElementsResponse<T> {
972    pub elements: Vec<StoreElementWithBody<T>>,
973}
974
975impl<T> IntoIterator for SearchStoreElementsResponse<T> {
976    type Item = StoreElementWithBody<T>;
977    type IntoIter = std::vec::IntoIter<StoreElementWithBody<T>>;
978
979    fn into_iter(self) -> Self::IntoIter {
980        self.elements.into_iter()
981    }
982}
983
984impl<'a, T> IntoIterator for &'a SearchStoreElementsResponse<T> {
985    type Item = &'a StoreElementWithBody<T>;
986    type IntoIter = std::slice::Iter<'a, StoreElementWithBody<T>>;
987
988    fn into_iter(self) -> Self::IntoIter {
989        self.elements.iter()
990    }
991}
992
993impl<'a, T> IntoIterator for &'a mut SearchStoreElementsResponse<T> {
994    type Item = &'a mut StoreElementWithBody<T>;
995    type IntoIter = std::slice::IterMut<'a, StoreElementWithBody<T>>;
996
997    fn into_iter(self) -> Self::IntoIter {
998        self.elements.iter_mut()
999    }
1000}
1001
1002#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1003#[serde(rename_all = "kebab-case")]
1004pub struct StoreElement {
1005    pub path: Bytes,
1006    pub id: Option<StoreSelectorID>,
1007    pub kind: String,
1008    pub needs_authentication: Option<bool>,
1009    pub authentication_methods: Option<Vec<Bytes>>,
1010    pub meta: Option<BTreeMap<Bytes, Value>>,
1011}
1012
1013#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1014#[serde(rename_all = "kebab-case")]
1015pub struct StoreElementWithBody<T> {
1016    pub path: Bytes,
1017    pub id: Option<StoreSelectorID>,
1018    pub kind: String,
1019    pub needs_authentication: Option<bool>,
1020    pub authentication_methods: Option<Vec<Bytes>>,
1021    pub meta: Option<BTreeMap<Bytes, Value>>,
1022    pub body: T,
1023}
1024
1025impl<T> StoreElementWithBody<T> {
1026    pub fn new(elem: StoreElement, body: T) -> Self {
1027        Self {
1028            path: elem.path,
1029            id: elem.id,
1030            kind: elem.kind,
1031            needs_authentication: elem.needs_authentication,
1032            authentication_methods: elem.authentication_methods,
1033            meta: elem.meta,
1034            body,
1035        }
1036    }
1037}
1038
1039#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1040#[serde(rename_all = "kebab-case")]
1041pub enum SearchStoreElementType {
1042    Literal(Value),
1043    Set(BTreeSet<SearchStoreElementType>),
1044    Sequence(Vec<SearchStoreElementType>),
1045    // The unit value here exists to keep the same form across all serializations.
1046    Any(()),
1047    None(()),
1048}
1049
1050#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone, Debug)]
1051#[serde(rename_all = "kebab-case")]
1052pub struct CredentialStoreSearchElement {
1053    pub username: SearchStoreElementType,
1054    pub secret: SearchStoreElementType,
1055    pub authtype: SearchStoreElementType,
1056    pub kind: SearchStoreElementType,
1057    pub protocol: SearchStoreElementType,
1058    pub host: SearchStoreElementType,
1059    pub title: SearchStoreElementType,
1060    pub description: SearchStoreElementType,
1061    pub path: SearchStoreElementType,
1062    pub service: SearchStoreElementType,
1063    pub extra: BTreeMap<String, SearchStoreElementType>,
1064    pub id: SearchStoreElementType,
1065}
1066
1067#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1068#[serde(rename_all = "kebab-case")]
1069pub struct CredentialStoreLocation {
1070    pub protocol: Option<String>,
1071    pub host: Option<String>,
1072    pub port: Option<u16>,
1073    pub path: Option<String>,
1074}
1075
1076#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1077#[serde(rename_all = "kebab-case")]
1078pub struct CredentialStoreElement {
1079    pub username: Option<Bytes>,
1080    pub secret: Option<Bytes>,
1081    pub authtype: Option<String>,
1082    #[serde(rename = "type")]
1083    pub kind: String,
1084    pub title: Option<String>,
1085    pub description: Option<String>,
1086    pub location: Vec<CredentialStoreLocation>,
1087    pub service: Option<String>,
1088    pub extra: BTreeMap<String, Value>,
1089    pub id: Bytes,
1090}
1091
1092#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1093pub struct KeyboardInteractiveAuthenticationPrompt {
1094    pub prompt: String,
1095    pub echo: bool,
1096}
1097
1098#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1099pub struct KeyboardInteractiveAuthenticationRequest {
1100    pub name: String,
1101    pub instruction: String,
1102    pub prompts: Vec<KeyboardInteractiveAuthenticationPrompt>,
1103}
1104
1105#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1106pub struct KeyboardInteractiveAuthenticationResponse {
1107    pub responses: Vec<String>,
1108}
1109
1110#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1111#[serde(rename_all = "kebab-case")]
1112pub struct ReadServerContextRequest {
1113    pub kind: String,
1114    pub id: Option<Bytes>,
1115    pub meta: Option<BTreeMap<Bytes, Value>>,
1116}
1117
1118#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1119#[serde(rename_all = "kebab-case")]
1120pub struct ReadServerContextResponse {
1121    pub id: Option<Bytes>,
1122    pub meta: Option<BTreeMap<Bytes, Value>>,
1123}
1124
1125#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1126#[serde(rename_all = "kebab-case")]
1127pub struct ReadServerContextResponseWithBody<T> {
1128    pub id: Option<Bytes>,
1129    pub meta: Option<BTreeMap<Bytes, Value>>,
1130    pub body: Option<T>,
1131}
1132
1133#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1134#[serde(rename_all = "kebab-case")]
1135pub struct WriteServerContextRequest {
1136    pub kind: String,
1137    pub id: Option<Bytes>,
1138    pub meta: Option<BTreeMap<Bytes, Value>>,
1139}
1140
1141#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1142#[serde(rename_all = "kebab-case")]
1143pub struct WriteServerContextRequestWithBody<T> {
1144    pub kind: String,
1145    pub id: Option<Bytes>,
1146    pub meta: Option<BTreeMap<Bytes, Value>>,
1147    pub body: Option<T>,
1148}
1149
1150#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1151#[serde(rename_all = "kebab-case")]
1152pub struct WriteServerContextResponse {
1153    pub id: Option<Bytes>,
1154    pub meta: Option<BTreeMap<Bytes, Value>>,
1155}
1156
1157#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1158#[serde(rename_all = "kebab-case")]
1159pub struct TemplateServerContextBody {
1160    pub senv: Option<BTreeMap<Bytes, Bytes>>,
1161    pub cenv: Option<BTreeMap<Bytes, Bytes>>,
1162    pub ctxsenv: Option<BTreeMap<Bytes, Bytes>>,
1163    pub args: Option<Vec<Bytes>>,
1164}
1165
1166#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1167#[serde(rename_all = "kebab-case")]
1168pub struct TemplateServerContextBodyWithBody<T> {
1169    pub senv: Option<BTreeMap<Bytes, Bytes>>,
1170    pub cenv: Option<BTreeMap<Bytes, Bytes>>,
1171    pub ctxsenv: Option<BTreeMap<Bytes, Bytes>>,
1172    pub args: Option<Vec<Bytes>>,
1173    pub body: Option<T>,
1174}
1175
1176#[derive(Hash, Debug, FromPrimitive, Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
1177#[allow(non_camel_case_types)]
1178pub enum TerminalMode {
1179    VINTR = 1,
1180    VQUIT = 2,
1181    VERASE = 3,
1182    VKILL = 4,
1183    VEOF = 5,
1184    VEOL = 6,
1185    VEOL2 = 7,
1186    VSTART = 8,
1187    VSTOP = 9,
1188    VSUSP = 10,
1189    VDSUSP = 11,
1190    VREPRINT = 12,
1191    VWERASE = 13,
1192    VLNEXT = 14,
1193    VFLUSH = 15,
1194    VSWTCH = 16,
1195    VSTATUS = 17,
1196    VDISCARD = 18,
1197    IGNPAR = 30,
1198    PARMRK = 31,
1199    INPCK = 32,
1200    ISTRIP = 33,
1201    INLCR = 34,
1202    IGNCR = 35,
1203    ICRNL = 36,
1204    IUCLC = 37,
1205    IXON = 38,
1206    IXANY = 39,
1207    IXOFF = 40,
1208    IMAXBEL = 41,
1209    IUTF8 = 42,
1210    ISIG = 50,
1211    ICANON = 51,
1212    XCASE = 52,
1213    ECHO = 53,
1214    ECHOE = 54,
1215    ECHOK = 55,
1216    ECHONL = 56,
1217    NOFLSH = 57,
1218    TOSTOP = 58,
1219    IEXTEN = 59,
1220    ECHOCTL = 60,
1221    ECHOKE = 61,
1222    PENDIN = 62,
1223    OPOST = 70,
1224    OLCUC = 71,
1225    ONLCR = 72,
1226    OCRNL = 73,
1227    ONOCR = 74,
1228    ONLRET = 75,
1229    CS7 = 90,
1230    CS8 = 91,
1231    PARENB = 92,
1232    PARODD = 93,
1233    TTY_OP_ISPEED = 128,
1234    TTY_OP_OSPEED = 129,
1235    VMIN = 0x00010000,
1236    VTIME = 0x00010001,
1237}
1238
1239/// A message for the protocol.
1240#[derive(Clone, Debug)]
1241pub struct Message {
1242    pub id: u32,
1243    pub kind: u32,
1244    pub message: Option<Bytes>,
1245}
1246
1247#[derive(Clone, Debug)]
1248pub struct Response {
1249    pub id: u32,
1250    pub code: u32,
1251    pub message: Option<Bytes>,
1252}
1253
1254#[derive(Default)]
1255pub struct ProtocolSerializer {}
1256
1257pub enum Data {
1258    Message(Message),
1259    Response(Response),
1260}
1261
1262#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
1263pub enum ResponseValue<T: DeserializeOwned, U: DeserializeOwned> {
1264    Success(T),
1265    Continuation((u32, U)),
1266}
1267
1268impl ProtocolSerializer {
1269    const MAX_MESSAGE_SIZE: u32 = 0x00ffffff;
1270
1271    pub fn new() -> ProtocolSerializer {
1272        Self {}
1273    }
1274
1275    pub fn is_valid_size(&self, size: u32) -> bool {
1276        (8..=Self::MAX_MESSAGE_SIZE).contains(&size)
1277    }
1278
1279    pub fn serialize_header(&self, id: u32, next: u32, data_len: usize) -> Option<Bytes> {
1280        let size = data_len as u64 + 8;
1281        if size > Self::MAX_MESSAGE_SIZE as u64 {
1282            return None;
1283        }
1284        let mut b = BytesMut::with_capacity(size as usize);
1285        let size = size as u32;
1286        b.extend(&size.to_le_bytes());
1287        b.extend(&id.to_le_bytes());
1288        b.extend(&next.to_le_bytes());
1289        Some(b.into())
1290    }
1291
1292    pub fn serialize_message_simple(&self, msg: &Message) -> Option<Bytes> {
1293        let size = 8 + match &msg.message {
1294            Some(m) => m.len(),
1295            None => 0,
1296        };
1297        if size > Self::MAX_MESSAGE_SIZE as usize {
1298            return None;
1299        }
1300        let mut b = BytesMut::with_capacity(size);
1301        let size = size as u32;
1302        b.extend(&size.to_le_bytes());
1303        b.extend(&msg.id.to_le_bytes());
1304        b.extend(&msg.kind.to_le_bytes());
1305        if let Some(m) = &msg.message {
1306            b.extend(m);
1307        }
1308        Some(b.into())
1309    }
1310
1311    pub fn serialize_message_typed<S: Serialize>(&self, msg: &Message, obj: &S) -> Option<Bytes> {
1312        let mut v: Vec<u8> = Vec::with_capacity(12);
1313        // Write a dummy size that we'll then fill in later.
1314        v.extend(&0u32.to_le_bytes());
1315        v.extend(&msg.id.to_le_bytes());
1316        v.extend(&msg.kind.to_le_bytes());
1317        let mut cursor = std::io::Cursor::new(&mut v);
1318        let _ = cursor.seek(SeekFrom::End(0));
1319        if serde_cbor::to_writer(&mut cursor, obj).is_err() {
1320            return None;
1321        }
1322        let size = match u32::try_from(v.len()) {
1323            Ok(sz) if (4..=Self::MAX_MESSAGE_SIZE).contains(&sz) => sz - 4,
1324            _ => return None,
1325        };
1326        v[0..4].copy_from_slice(&size.to_le_bytes());
1327        Some(v.into())
1328    }
1329
1330    pub fn serialize_body<S: Serialize>(&self, obj: &S) -> Option<Bytes> {
1331        match serde_cbor::to_vec(obj) {
1332            Ok(m) => Some(m.into()),
1333            Err(_) => None,
1334        }
1335    }
1336
1337    pub fn serialize_response_simple(&self, resp: &Response) -> Option<Bytes> {
1338        let size = 8 + match &resp.message {
1339            Some(m) => m.len(),
1340            None => 0,
1341        };
1342        if size > Self::MAX_MESSAGE_SIZE as usize {
1343            return None;
1344        }
1345        let mut b = BytesMut::with_capacity(size);
1346        let size = size as u32;
1347        b.extend(&size.to_le_bytes());
1348        b.extend(&resp.id.to_le_bytes());
1349        b.extend(&resp.code.to_le_bytes());
1350        if let Some(m) = &resp.message {
1351            b.extend(m);
1352        }
1353        Some(b.into())
1354    }
1355
1356    pub fn serialize_response_typed<S: Serialize>(&self, msg: &Response, obj: &S) -> Option<Bytes> {
1357        let mut v: Vec<u8> = Vec::with_capacity(12);
1358        // Write a dummy size that we'll then fill in later.
1359        v.extend(&0u32.to_le_bytes());
1360        v.extend(&msg.id.to_le_bytes());
1361        v.extend(&msg.code.to_le_bytes());
1362        let mut cursor = std::io::Cursor::new(&mut v);
1363        let _ = cursor.seek(SeekFrom::End(0));
1364        if serde_cbor::to_writer(&mut cursor, obj).is_err() {
1365            return None;
1366        }
1367        let size = match u32::try_from(v.len()) {
1368            Ok(sz) if (4..=Self::MAX_MESSAGE_SIZE).contains(&sz) => sz - 4,
1369            _ => return None,
1370        };
1371        v[0..4].copy_from_slice(&size.to_le_bytes());
1372        Some(v.into())
1373    }
1374
1375    pub fn deserialize_data(
1376        &self,
1377        config: &Config,
1378        header: &[u8],
1379        body: Bytes,
1380    ) -> Result<Data, Error> {
1381        fn is_sender(config: &Config, id: u32) -> bool {
1382            let sender_mask = if config.is_server() { 0x80000000 } else { 0 };
1383            (id & 0x80000000) == sender_mask
1384        }
1385        let _size: u32 = u32::from_le_bytes(header[0..4].try_into().unwrap());
1386        let id: u32 = u32::from_le_bytes(header[4..8].try_into().unwrap());
1387        let arg: u32 = u32::from_le_bytes(header[8..12].try_into().unwrap());
1388        if is_sender(config, id) {
1389            Ok(Data::Response(Response {
1390                id,
1391                code: arg,
1392                message: if body.is_empty() { None } else { Some(body) },
1393            }))
1394        } else {
1395            Ok(Data::Message(Message {
1396                id,
1397                kind: arg,
1398                message: if body.is_empty() { None } else { Some(body) },
1399            }))
1400        }
1401    }
1402
1403    pub fn deserialize_message_typed<'a, D: Deserialize<'a>>(
1404        &self,
1405        msg: &'a Message,
1406    ) -> Result<Option<D>, Error> {
1407        match &msg.message {
1408            Some(body) => match serde_cbor::from_slice(body) {
1409                Ok(decoded) => Ok(Some(decoded)),
1410                Err(_) => Err(Error {
1411                    code: ResponseCode::Invalid,
1412                    body: None,
1413                }),
1414            },
1415            None => Ok(None),
1416        }
1417    }
1418
1419    pub fn deserialize_response_typed<D1: DeserializeOwned, D2: DeserializeOwned>(
1420        &self,
1421        resp: &Response,
1422    ) -> Result<Option<ResponseValue<D1, D2>>, Error> {
1423        if resp.code == ResponseCode::Success as u32 {
1424            match &resp.message {
1425                Some(body) => match serde_cbor::from_slice(body) {
1426                    Ok(decoded) => Ok(Some(ResponseValue::Success(decoded))),
1427                    Err(_) => Err(Error {
1428                        code: ResponseCode::Invalid,
1429                        body: None,
1430                    }),
1431                },
1432                None => Ok(None),
1433            }
1434        } else if resp.code == ResponseCode::Continuation as u32 {
1435            match &resp.message {
1436                Some(body) => match serde_cbor::from_slice(body) {
1437                    Ok(decoded) => Ok(Some(ResponseValue::Continuation((resp.id, decoded)))),
1438                    Err(_) => Err(Error {
1439                        code: ResponseCode::Invalid,
1440                        body: None,
1441                    }),
1442                },
1443                None => Ok(None),
1444            }
1445        } else {
1446            match &resp.message {
1447                Some(body) => match serde_cbor::from_slice(body) {
1448                    Ok(decoded) => Err(Error {
1449                        code: ResponseCode::from_u32(resp.code),
1450                        body: Some(decoded),
1451                    }),
1452                    Err(_) => Err(Error {
1453                        code: ResponseCode::from_u32(resp.code),
1454                        body: None,
1455                    }),
1456                },
1457                None => Err(Error {
1458                    code: ResponseCode::from_u32(resp.code),
1459                    body: None,
1460                }),
1461            }
1462        }
1463    }
1464}
1465
1466#[cfg(test)]
1467mod tests {
1468    use super::{
1469        ChannelID, Empty, Message, ProtocolSerializer, Response, ResponseValue,
1470        SearchStoreElementType, StoreID, StoreSelector, StoreSelectorID,
1471    };
1472    use bytes::Bytes;
1473    use serde::{de::DeserializeOwned, Deserialize, Serialize};
1474    use serde_cbor::Value;
1475    use std::convert::TryFrom;
1476    use std::fmt::Debug;
1477
1478    #[test]
1479    fn serialize_header() {
1480        let cases: &[(u32, u32, usize, Option<&[u8]>)] = &[
1481            (
1482                0x01234567,
1483                0xffeeddcc,
1484                0x00000000,
1485                Some(b"\x08\x00\x00\x00\x67\x45\x23\x01\xcc\xdd\xee\xff"),
1486            ),
1487            (
1488                0x87654321,
1489                0x00000000,
1490                0x00000099,
1491                Some(b"\xa1\x00\x00\x00\x21\x43\x65\x87\x00\x00\x00\x00"),
1492            ),
1493            (
1494                0x87654321,
1495                0x00000000,
1496                0x00fffff7,
1497                Some(b"\xff\xff\xff\x00\x21\x43\x65\x87\x00\x00\x00\x00"),
1498            ),
1499            (0x87654321, 0x00000000, 0x00fffff8, None),
1500        ];
1501        let ser = ProtocolSerializer::new();
1502        for (id, next, data_len, response) in cases {
1503            assert_eq!(
1504                ser.serialize_header(*id, *next, *data_len).as_deref(),
1505                *response
1506            );
1507        }
1508    }
1509
1510    fn assert_encode<'a, S: Serialize + Deserialize<'a> + Debug + Clone + PartialEq>(
1511        desc: &str,
1512        s: &S,
1513        seq: &[u8],
1514    ) {
1515        let id = 0x01234567u32;
1516        let next = 0xffeeddccu32;
1517        let mut header = [0u8; 12];
1518
1519        header[0..4].copy_from_slice(&u32::try_from(seq.len() + 8).unwrap().to_le_bytes());
1520        header[4..8].copy_from_slice(&id.to_le_bytes());
1521        header[8..12].copy_from_slice(&next.to_le_bytes());
1522
1523        let ser = ProtocolSerializer::new();
1524        let msg = Message {
1525            id,
1526            kind: next,
1527            message: Some(Bytes::copy_from_slice(seq)),
1528        };
1529
1530        let res = ser.serialize_header(id, next, seq.len()).unwrap();
1531        assert_eq!(&res, &header as &[u8], "header: {}", desc);
1532
1533        let res = ser.serialize_message_simple(&msg).unwrap();
1534        assert_eq!(res[0..12], header, "simple header: {}", desc);
1535        assert_eq!(res[12..], *seq, "simple body: {}", desc);
1536
1537        let res = ser.serialize_body(s).unwrap();
1538        assert_eq!(res, *seq, "body: {}", desc);
1539
1540        let msg = Message {
1541            id,
1542            kind: next,
1543            message: None,
1544        };
1545        let res = ser.serialize_message_typed(&msg, s).unwrap();
1546        assert_eq!(res[0..12], header, "typed header: {}", desc);
1547        assert_eq!(res[12..], *seq, "typed body: {}", desc);
1548    }
1549
1550    fn assert_round_trip<S: Serialize + DeserializeOwned + Debug + Clone + PartialEq>(
1551        desc: &str,
1552        s: &S,
1553        seq: &[u8],
1554    ) {
1555        assert_encode(desc, s, seq);
1556        assert_decode(desc, s, seq);
1557    }
1558
1559    fn assert_decode<S: Serialize + DeserializeOwned + Debug + Clone + PartialEq>(
1560        desc: &str,
1561        s: &S,
1562        seq: &[u8],
1563    ) {
1564        let id = 0x01234567u32;
1565        let next = 0u32;
1566        let mut header = [0u8; 12];
1567
1568        header[0..4].copy_from_slice(&u32::try_from(seq.len() + 8).unwrap().to_le_bytes());
1569        header[4..8].copy_from_slice(&id.to_le_bytes());
1570        header[8..12].copy_from_slice(&next.to_le_bytes());
1571
1572        let body = Bytes::copy_from_slice(seq);
1573
1574        let ser = ProtocolSerializer::new();
1575        let resp = Response {
1576            id,
1577            code: next,
1578            message: Some(body.clone()),
1579        };
1580
1581        let mut full_msg: Vec<u8> = header.into();
1582        full_msg.extend(seq);
1583
1584        let res = ser.deserialize_response_typed::<S, Empty>(&resp);
1585        assert_eq!(
1586            res.unwrap().unwrap(),
1587            ResponseValue::Success(s.clone()),
1588            "deserialize typed response: {}",
1589            desc
1590        );
1591    }
1592
1593    #[test]
1594    fn serialize_basic_types() {
1595        assert_round_trip("0u32", &0u32, b"\x00");
1596        assert_round_trip("all ones u32", &0xfedcba98u32, b"\x1a\xfe\xdc\xba\x98");
1597        assert_round_trip(
1598            "simple Bytes",
1599            &Bytes::from(b"Hello, world!\n" as &'static [u8]),
1600            b"\x4eHello, world!\n",
1601        );
1602        assert_encode("simple &str", &"Hello, world!\n", b"\x6eHello, world!\n");
1603        assert_round_trip(
1604            "simple String",
1605            &String::from("Hello, world!\n"),
1606            b"\x6eHello, world!\n",
1607        );
1608    }
1609
1610    #[test]
1611    fn serialize_encoded_types() {
1612        assert_round_trip("ChannelID 0", &ChannelID(0), b"\x00");
1613        assert_round_trip(
1614            "ChannelID all ones u32",
1615            &ChannelID(0xfedcba98u32),
1616            b"\x1a\xfe\xdc\xba\x98",
1617        );
1618        assert_round_trip("StoreID 0", &StoreID(0), b"\x00");
1619        assert_round_trip(
1620            "StoreID pattern",
1621            &StoreID(0xfedcba98u32),
1622            b"\x1a\xfe\xdc\xba\x98",
1623        );
1624        assert_round_trip("StoreSelectorID 0", &StoreSelectorID(0), b"\x00");
1625        assert_round_trip(
1626            "StoreSelectorID pattern",
1627            &StoreSelectorID(0xfedcba98u32),
1628            b"\x1a\xfe\xdc\xba\x98",
1629        );
1630        assert_round_trip(
1631            "StoreSelector path",
1632            &StoreSelector::Path(Bytes::from(b"/dev/null" as &[u8])),
1633            b"\xa1\x64path\x49/dev/null",
1634        );
1635        assert_round_trip(
1636            "StoreSelector ID",
1637            &StoreSelector::ID(StoreSelectorID(0xfedcba98u32)),
1638            b"\xa1\x62id\x1a\xfe\xdc\xba\x98",
1639        );
1640        assert_round_trip(
1641            "SearchStoreElementType literal text",
1642            &SearchStoreElementType::Literal(Value::Text(String::from("abc123"))),
1643            b"\xa1\x67literal\x66abc123",
1644        );
1645        assert_round_trip(
1646            "SearchStoreElementType literal bytes",
1647            &SearchStoreElementType::Literal(Value::Bytes("abc123".into())),
1648            b"\xa1\x67literal\x46abc123",
1649        );
1650        assert_round_trip(
1651            "SearchStoreElementType literal null",
1652            &SearchStoreElementType::Literal(Value::Null),
1653            b"\xa1\x67literal\xf6",
1654        );
1655        assert_round_trip(
1656            "SearchStoreElementType any",
1657            &SearchStoreElementType::Any(()),
1658            b"\xa1\x63any\xf6",
1659        );
1660        assert_round_trip(
1661            "SearchStoreElementType none",
1662            &SearchStoreElementType::None(()),
1663            b"\xa1\x64none\xf6",
1664        );
1665    }
1666
1667    #[test]
1668    fn serialize_requests() {
1669        assert_round_trip(
1670            "CreateExtensionRangeRequest with no second part",
1671            &super::CreateExtensionRangeRequest {
1672                extension: (
1673                    Bytes::from(b"foobar@test.ns.crustytoothpaste.net" as &[u8]),
1674                    None,
1675                ),
1676                count: 5,
1677            },
1678            b"\xa2\x69extension\x82\x58\x23foobar@test.ns.crustytoothpaste.net\xf6\x65count\x05",
1679        );
1680        assert_round_trip(
1681            "CreateExtensionRangeRequest with second part",
1682            &super::CreateExtensionRangeRequest {
1683                extension: (
1684                    Bytes::from(b"foobar@test.ns.crustytoothpaste.net" as &[u8]),
1685                    Some(Bytes::from(b"v1" as &[u8])),
1686                ),
1687                count: 5,
1688            },
1689            b"\xa2\x69extension\x82\x58\x23foobar@test.ns.crustytoothpaste.net\x42v1\x65count\x05",
1690        );
1691    }
1692
1693    #[test]
1694    fn deserialize_requests() {
1695        assert_decode(
1696            "CreateExtensionRangeRequest with extension field",
1697            &super::CreateExtensionRangeRequest {
1698                extension: (
1699                    Bytes::from(b"foobar@test.ns.crustytoothpaste.net" as &[u8]),
1700                    None,
1701                ),
1702                count: 5,
1703            },
1704            b"\xa3\x69extension\x82\x58\x23foobar@test.ns.crustytoothpaste.net\xf6\x58\x26extension@test.ns.crustytoothpaste.net\xf5\x65count\x05",
1705        );
1706    }
1707
1708    #[test]
1709    fn deserialize_requests_rw_compatible() {
1710        #[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
1711        #[serde(rename_all = "kebab-case")]
1712        struct ReadChannelLegacyRequest {
1713            pub id: ChannelID,
1714            pub selector: u32,
1715            pub count: u64,
1716        }
1717
1718        let cases: &[(&[u8], &str)] = &[
1719            (b"\xa3\x62id\x00\x68selector\x02\x65count\x1a\xfe\xdc\xba\x98", "legacy"),
1720            (b"\xa6\x62id\x00\x68selector\x02\x65count\x1a\xfe\xdc\xba\x98\x6bstream-sync\xf6\x68blocking\xf6\x68complete\xf4", "modern"),
1721        ];
1722        for (b, desc) in cases {
1723            assert_decode(
1724                &format!("ReadChannelRequest without blocking I/O: {}", desc),
1725                &super::ReadChannelRequest {
1726                    id: ChannelID(0),
1727                    selector: 2,
1728                    count: 0xfedcba98,
1729                    stream_sync: None,
1730                    blocking: None,
1731                    complete: false,
1732                },
1733                b,
1734            );
1735            assert_decode(
1736                &format!("ReadChannelRequest (legacy): {}", desc),
1737                &ReadChannelLegacyRequest {
1738                    id: ChannelID(0),
1739                    selector: 2,
1740                    count: 0xfedcba98,
1741                },
1742                b,
1743            );
1744        }
1745
1746        #[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
1747        #[serde(rename_all = "kebab-case")]
1748        struct WriteChannelLegacyRequest {
1749            pub id: ChannelID,
1750            pub selector: u32,
1751            pub bytes: Bytes,
1752        }
1753
1754        let cases: &[(&[u8], &str)] = &[
1755            (b"\xa3\x62id\x00\x68selector\x02\x65bytes\x44\xff\xfe\xc2\xa9", "legacy"),
1756            (b"\xa5\x62id\x00\x68selector\x02\x65bytes\x44\xff\xfe\xc2\xa9\x6bstream-sync\xf6\x68blocking\xf6", "modern"),
1757        ];
1758        for (b, desc) in cases {
1759            assert_decode(
1760                &format!("WriteChannelRequest without blocking I/O: {}", desc),
1761                &super::WriteChannelRequest {
1762                    id: ChannelID(0),
1763                    selector: 2,
1764                    bytes: vec![0xffu8, 0xfe, 0xc2, 0xa9].into(),
1765                    stream_sync: None,
1766                    blocking: None,
1767                },
1768                b,
1769            );
1770            assert_decode(
1771                &format!("WriteChannelRequest (legacy): {}", desc),
1772                &WriteChannelLegacyRequest {
1773                    id: ChannelID(0),
1774                    selector: 2,
1775                    bytes: vec![0xffu8, 0xfe, 0xc2, 0xa9].into(),
1776                },
1777                b,
1778            );
1779        }
1780    }
1781}