1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#![forbid(unsafe_code)]

use core::marker::PhantomData;
use serde::{
    de::{Deserializer, EnumAccess, Error, VariantAccess, Visitor},
    Deserialize,
};
use std::fmt;

use super::constants;

/// **WARNING: Response can only be used with ssh_mux_format, which treats
/// tuple and struct as the same.**
#[derive(Clone, Debug)]
pub enum Response {
    Hello { version: u32 },

    Alive { response_id: u32, server_pid: u32 },

    Ok { response_id: u32 },
    Failure { response_id: u32, reason: Box<str> },

    PermissionDenied { response_id: u32, reason: Box<str> },

    SessionOpened { response_id: u32, session_id: u32 },
    ExitMessage { session_id: u32, exit_value: u32 },
    TtyAllocFail { session_id: u32 },

    RemotePort { response_id: u32, remote_port: u32 },
}
impl<'de> Deserialize<'de> for Response {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        deserializer.deserialize_enum(
            "Response",
            &[
                "Hello",
                "Alive",
                "Ok",
                "Failure",
                "PermissionDenied",
                "SessionOpened",
                "ExitMessage",
                "TtyAllocFail",
                "RemotePort",
            ],
            ResponseVisitor,
        )
    }
}

struct ResponseVisitor;
impl<'de> Visitor<'de> for ResponseVisitor {
    type Value = Response;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "expecting Response")
    }

    fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
    where
        A: EnumAccess<'de>,
    {
        use constants::*;

        let result: (u32, _) = data.variant()?;
        let (index, accessor) = result;

        match index {
            MUX_MSG_HELLO => {
                let version: u32 = accessor.newtype_variant_seed(PhantomData)?;
                Ok(Response::Hello { version })
            }
            MUX_S_ALIVE => {
                let tup: (u32, u32) = accessor.newtype_variant_seed(PhantomData)?;
                Ok(Response::Alive {
                    response_id: tup.0,
                    server_pid: tup.1,
                })
            }
            MUX_S_OK => {
                let response_id: u32 = accessor.newtype_variant_seed(PhantomData)?;
                Ok(Response::Ok { response_id })
            }
            MUX_S_FAILURE => {
                let tup: (u32, Box<str>) = accessor.newtype_variant_seed(PhantomData)?;
                Ok(Response::Failure {
                    response_id: tup.0,
                    reason: tup.1,
                })
            }
            MUX_S_PERMISSION_DENIED => {
                let tup: (u32, Box<str>) = accessor.newtype_variant_seed(PhantomData)?;
                Ok(Response::PermissionDenied {
                    response_id: tup.0,
                    reason: tup.1,
                })
            }
            MUX_S_SESSION_OPENED => {
                let tup: (u32, u32) = accessor.newtype_variant_seed(PhantomData)?;
                Ok(Response::SessionOpened {
                    response_id: tup.0,
                    session_id: tup.1,
                })
            }
            MUX_S_EXIT_MESSAGE => {
                let tup: (u32, u32) = accessor.newtype_variant_seed(PhantomData)?;
                Ok(Response::ExitMessage {
                    session_id: tup.0,
                    exit_value: tup.1,
                })
            }
            MUX_S_TTY_ALLOC_FAIL => {
                let session_id: u32 = accessor.newtype_variant_seed(PhantomData)?;
                Ok(Response::TtyAllocFail { session_id })
            }
            MUX_S_REMOTE_PORT => {
                let tup: (u32, u32) = accessor.newtype_variant_seed(PhantomData)?;
                Ok(Response::RemotePort {
                    response_id: tup.0,
                    remote_port: tup.1,
                })
            }
            _ => Err(A::Error::custom("Unexpected packet type")),
        }
    }
}