openssh_mux_client/
response.rs

1#![forbid(unsafe_code)]
2
3use serde::{
4    de::{Deserializer, EnumAccess, Error, VariantAccess, Visitor},
5    Deserialize,
6};
7use std::{fmt, marker::PhantomData};
8
9use super::constants;
10
11/// **WARNING: Response can only be used with ssh_mux_format, which treats
12/// tuple and struct as the same.**
13#[derive(Clone, Debug)]
14pub enum Response {
15    Hello { version: u32 },
16
17    Alive { response_id: u32, server_pid: u32 },
18
19    Ok { response_id: u32 },
20    Failure { response_id: u32, reason: Box<str> },
21
22    PermissionDenied { response_id: u32, reason: Box<str> },
23
24    SessionOpened { response_id: u32, session_id: u32 },
25    ExitMessage { session_id: u32, exit_value: u32 },
26    TtyAllocFail { session_id: u32 },
27
28    RemotePort { response_id: u32, remote_port: u32 },
29}
30impl<'de> Deserialize<'de> for Response {
31    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
32        deserializer.deserialize_enum(
33            "Response",
34            &[
35                "Hello",
36                "Alive",
37                "Ok",
38                "Failure",
39                "PermissionDenied",
40                "SessionOpened",
41                "ExitMessage",
42                "TtyAllocFail",
43                "RemotePort",
44            ],
45            ResponseVisitor,
46        )
47    }
48}
49
50struct ResponseVisitor;
51impl<'de> Visitor<'de> for ResponseVisitor {
52    type Value = Response;
53
54    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
55        write!(formatter, "expecting Response")
56    }
57
58    fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
59    where
60        A: EnumAccess<'de>,
61    {
62        use constants::*;
63
64        let result: (u32, _) = data.variant()?;
65        let (index, accessor) = result;
66
67        match index {
68            MUX_MSG_HELLO => {
69                let version: u32 = accessor.newtype_variant_seed(PhantomData)?;
70                Ok(Response::Hello { version })
71            }
72            MUX_S_ALIVE => {
73                let tup: (u32, u32) = accessor.newtype_variant_seed(PhantomData)?;
74                Ok(Response::Alive {
75                    response_id: tup.0,
76                    server_pid: tup.1,
77                })
78            }
79            MUX_S_OK => {
80                let response_id: u32 = accessor.newtype_variant_seed(PhantomData)?;
81                Ok(Response::Ok { response_id })
82            }
83            MUX_S_FAILURE => {
84                let tup: (u32, Box<str>) = accessor.newtype_variant_seed(PhantomData)?;
85                Ok(Response::Failure {
86                    response_id: tup.0,
87                    reason: tup.1,
88                })
89            }
90            MUX_S_PERMISSION_DENIED => {
91                let tup: (u32, Box<str>) = accessor.newtype_variant_seed(PhantomData)?;
92                Ok(Response::PermissionDenied {
93                    response_id: tup.0,
94                    reason: tup.1,
95                })
96            }
97            MUX_S_SESSION_OPENED => {
98                let tup: (u32, u32) = accessor.newtype_variant_seed(PhantomData)?;
99                Ok(Response::SessionOpened {
100                    response_id: tup.0,
101                    session_id: tup.1,
102                })
103            }
104            MUX_S_EXIT_MESSAGE => {
105                let tup: (u32, u32) = accessor.newtype_variant_seed(PhantomData)?;
106                Ok(Response::ExitMessage {
107                    session_id: tup.0,
108                    exit_value: tup.1,
109                })
110            }
111            MUX_S_TTY_ALLOC_FAIL => {
112                let session_id: u32 = accessor.newtype_variant_seed(PhantomData)?;
113                Ok(Response::TtyAllocFail { session_id })
114            }
115            MUX_S_REMOTE_PORT => {
116                let tup: (u32, u32) = accessor.newtype_variant_seed(PhantomData)?;
117                Ok(Response::RemotePort {
118                    response_id: tup.0,
119                    remote_port: tup.1,
120                })
121            }
122            _ => Err(A::Error::custom("Unexpected packet type")),
123        }
124    }
125}