Skip to main content

nym_ip_packet_requests/v8/
response.rs

1use nym_bin_common::build_information::BinaryBuildInformationOwned;
2use serde::{Deserialize, Serialize};
3
4use crate::{IpPair, make_bincode_serializer};
5
6use super::VERSION;
7
8#[derive(Clone, Debug, Serialize, Deserialize)]
9pub struct IpPacketResponse {
10    pub version: u8,
11    pub data: IpPacketResponseData,
12}
13
14#[derive(Clone, Debug, Serialize, Deserialize)]
15pub enum IpPacketResponseData {
16    Data(DataResponse),
17    Control(Box<ControlResponse>),
18}
19
20#[derive(Clone, Debug, Serialize, Deserialize)]
21pub struct DataResponse {
22    pub ip_packet: bytes::Bytes,
23}
24
25#[derive(Clone, Debug, Serialize, Deserialize)]
26pub enum ControlResponse {
27    // Response for a connect request
28    Connect(ConnectResponse),
29
30    // Response for a disconnect initiqated by the client
31    Disconnect(DisconnectResponse),
32
33    // Message from the server that the client got disconnected without the client initiating it
34    UnrequestedDisconnect(UnrequestedDisconnect),
35
36    // Response to ping request
37    Pong(PongResponse),
38
39    // Response for a health request
40    Health(Box<HealthResponse>),
41
42    // Info response. This can be anything from informative messages to errors
43    Info(InfoResponse),
44}
45
46#[derive(Clone, Debug, Serialize, Deserialize)]
47pub struct ConnectResponse {
48    pub request_id: u64,
49    pub reply: ConnectResponseReply,
50}
51
52#[derive(Clone, Debug, Serialize, Deserialize)]
53pub enum ConnectResponseReply {
54    Success(ConnectSuccess),
55    Failure(ConnectFailureReason),
56}
57
58#[derive(Clone, Debug, Serialize, Deserialize)]
59pub struct ConnectSuccess {
60    pub ips: IpPair,
61}
62
63#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)]
64pub enum ConnectFailureReason {
65    #[error("client is already connected")]
66    ClientAlreadyConnected,
67
68    #[error("no available ip address")]
69    NoAvailableIp,
70
71    #[error("{0}")]
72    Other(String),
73}
74
75#[derive(Clone, Debug, Serialize, Deserialize)]
76pub struct DisconnectResponse {
77    pub request_id: u64,
78    pub reply: DisconnectResponseReply,
79}
80
81#[derive(Clone, Debug, Serialize, Deserialize)]
82pub enum DisconnectResponseReply {
83    Success,
84    Failure(DisconnectFailureReason),
85}
86
87#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)]
88pub enum DisconnectFailureReason {
89    #[error("client is not connected")]
90    ClientNotConnected,
91
92    #[error("{0}")]
93    Other(String),
94}
95
96#[derive(Clone, Debug, Serialize, Deserialize)]
97pub struct UnrequestedDisconnect {
98    pub reason: UnrequestedDisconnectReason,
99}
100
101#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)]
102pub enum UnrequestedDisconnectReason {
103    #[error("client mixnet traffic timeout")]
104    ClientMixnetTrafficTimeout,
105
106    #[error("client tun traffic timeout")]
107    ClientTunTrafficTimeout,
108
109    #[error("{0}")]
110    Other(String),
111}
112
113#[derive(Clone, Debug, Serialize, Deserialize)]
114pub struct PongResponse {
115    pub request_id: u64,
116}
117
118#[derive(Clone, Debug, Serialize, Deserialize)]
119pub struct HealthResponse {
120    pub request_id: u64,
121    pub reply: HealthResponseReply,
122}
123
124#[derive(Clone, Debug, Serialize, Deserialize)]
125pub struct HealthResponseReply {
126    // Return the binary build information of the IPR
127    pub build_info: BinaryBuildInformationOwned,
128
129    // Return if the IPR has performed a successful routing test.
130    pub routable: Option<bool>,
131}
132
133#[derive(Clone, Debug, Serialize, Deserialize)]
134pub struct InfoResponse {
135    pub request_id: u64,
136    pub reply: InfoResponseReply,
137    pub level: InfoLevel,
138}
139
140#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)]
141pub enum InfoResponseReply {
142    #[error("{msg}")]
143    Generic { msg: String },
144
145    #[error("version mismatch: response is v{request_version} and response is v{response_version}")]
146    VersionMismatch {
147        request_version: u8,
148        response_version: u8,
149    },
150
151    #[error("destination failed exit policy filter check: {dst}")]
152    ExitPolicyFilterCheckFailed { dst: String },
153}
154
155#[derive(Clone, Debug, Serialize, Deserialize)]
156pub enum InfoLevel {
157    Info,
158    Warn,
159    Error,
160}
161
162impl IpPacketResponse {
163    pub fn new_ip_packet(ip_packet: bytes::Bytes) -> Self {
164        Self {
165            version: VERSION,
166            data: IpPacketResponseData::Data(DataResponse { ip_packet }),
167        }
168    }
169
170    pub fn id(&self) -> Option<u64> {
171        match &self.data {
172            IpPacketResponseData::Data(_) => None,
173            IpPacketResponseData::Control(response) => response.id(),
174        }
175    }
176
177    pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
178        use bincode::Options;
179        make_bincode_serializer().serialize(self)
180    }
181
182    pub fn from_bytes(data: &[u8]) -> Result<Self, bincode::Error> {
183        use bincode::Options;
184        make_bincode_serializer().deserialize(data)
185    }
186
187    pub fn from_reconstructed_message(
188        message: &nym_sphinx::receiver::ReconstructedMessage,
189    ) -> Result<Self, bincode::Error> {
190        Self::from_bytes(&message.message)
191    }
192}
193
194impl IpPacketResponseData {
195    pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
196        use bincode::Options;
197        make_bincode_serializer().serialize(self)
198    }
199}
200
201impl ControlResponse {
202    fn id(&self) -> Option<u64> {
203        match self {
204            ControlResponse::Connect(response) => Some(response.request_id),
205            ControlResponse::Disconnect(response) => Some(response.request_id),
206            ControlResponse::UnrequestedDisconnect(_) => None,
207            ControlResponse::Pong(response) => Some(response.request_id),
208            ControlResponse::Health(response) => Some(response.request_id),
209            ControlResponse::Info(response) => Some(response.request_id),
210        }
211    }
212}
213
214impl ConnectResponseReply {
215    pub fn is_success(&self) -> bool {
216        match self {
217            ConnectResponseReply::Success(_) => true,
218            ConnectResponseReply::Failure(_) => false,
219        }
220    }
221}