1use crate::protobuf::{self as p, Field, Value};
9use anyhow::{bail, ensure, Result};
10
11pub const MAX_SIGNALING_BYTES: usize = 1024 * 1024;
13const MAX_FIELDS: usize = 1024;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum CallOperation {
18 Create,
19 Join,
20 Acknowledge,
21 Reject,
22 Cancel,
23 Exit,
24}
25
26impl CallOperation {
27 pub const fn command_id(self) -> u32 {
28 match self {
29 Self::Create => 3066,
30 Self::Join => 3361,
31 Self::Acknowledge => 3007,
32 Self::Reject => 3095,
33 Self::Cancel => 3310,
34 Self::Exit => 3380,
35 }
36 }
37
38 pub const fn path(self) -> &'static str {
39 match self {
40 Self::Create => "/cloudim/cloud-bin/cloudvoipmtcreate",
41 Self::Join => "/cloudim/cloud-bin/cloudvoipmtjoin",
42 Self::Acknowledge => "/cloudim/cloud-bin/cloudvoipmtack",
43 Self::Reject => "/cloudim/cloud-bin/cloudvoipmtreject",
44 Self::Cancel => "/cloudim/cloud-bin/cloudvoipmtcancel",
45 Self::Exit => "/cloudim/cloud-bin/cloudvoipmtexit",
46 }
47 }
48
49 pub fn from_parts(command_id: u32, path: &str) -> Result<Self> {
50 for operation in [
51 Self::Create,
52 Self::Join,
53 Self::Acknowledge,
54 Self::Reject,
55 Self::Cancel,
56 Self::Exit,
57 ] {
58 if command_id == operation.command_id() && path == operation.path() {
59 return Ok(operation);
60 }
61 }
62 bail!("Unsupported call command/path pair")
63 }
64}
65
66#[derive(Default)]
72pub struct CloudRequest {
73 pub task_id: Option<u32>,
74 pub body: Option<Vec<u8>>,
75 pub command_id: Option<u32>,
76 pub path: Option<String>,
77 pub longpolling: Option<bool>,
78 pub longpolling_timeout: Option<u32>,
80 pub unknown_fields: Vec<Field>,
81}
82
83impl CloudRequest {
84 pub fn for_operation(task_id: u32, operation: CallOperation, body: Vec<u8>) -> Self {
85 Self {
86 task_id: Some(task_id),
87 body: Some(body),
88 command_id: Some(operation.command_id()),
89 path: Some(operation.path().to_owned()),
90 ..Self::default()
91 }
92 }
93
94 pub fn operation(&self) -> Result<CallOperation> {
97 CallOperation::from_parts(
98 self.command_id
99 .ok_or_else(|| anyhow::anyhow!("Missing call command"))?,
100 self.path
101 .as_deref()
102 .ok_or_else(|| anyhow::anyhow!("Missing call path"))?,
103 )
104 }
105
106 pub fn encode(&self) -> Result<Vec<u8>> {
107 self.validate()?;
108 let mut fields = Vec::new();
109 append_u32(&mut fields, 1, self.task_id);
110 append_data(&mut fields, 2, self.body.as_deref());
111 append_u32(&mut fields, 3, self.command_id);
112 append_data(&mut fields, 4, self.path.as_deref().map(str::as_bytes));
113 append_u32(&mut fields, 5, self.longpolling.map(u32::from));
114 append_u32(&mut fields, 6, self.longpolling_timeout);
115 finish(fields, &self.unknown_fields, 6)
116 }
117
118 pub fn decode(input: &[u8]) -> Result<Self> {
119 let fields = decode_fields(input)?;
120 let value = Self {
121 task_id: optional_u32(&fields, 1)?,
122 body: p::optional_data(&fields, 2)?.map(Vec::from),
123 command_id: optional_u32(&fields, 3)?,
124 path: p::optional_data(&fields, 4)?
125 .map(|value| String::from_utf8(value.to_vec()))
126 .transpose()?,
127 longpolling: match optional_u32(&fields, 5)? {
128 None => None,
129 Some(0) => Some(false),
130 Some(1) => Some(true),
131 _ => bail!("Invalid call boolean"),
132 },
133 longpolling_timeout: optional_u32(&fields, 6)?,
134 unknown_fields: unknown_fields(fields, 6),
135 };
136 value.validate()?;
137 Ok(value)
138 }
139
140 fn validate(&self) -> Result<()> {
141 if let Some(body) = &self.body {
142 ensure!(body.len() <= MAX_SIGNALING_BYTES, "Call body too large");
143 }
144 if let Some(path) = &self.path {
145 ensure!(
146 path.len() <= 128 && !path.contains('\0'),
147 "Invalid call path"
148 );
149 }
150 if let (Some(command), Some(path)) = (self.command_id, self.path.as_deref()) {
151 CallOperation::from_parts(command, path)?;
152 }
153 Ok(())
154 }
155}
156
157#[derive(Default)]
161pub struct CommonRequest {
162 pub base_request: Option<Vec<u8>>,
163 pub body: Option<Vec<u8>>,
164 pub unknown_fields: Vec<Field>,
165}
166
167impl CommonRequest {
168 pub fn encode(&self) -> Result<Vec<u8>> {
169 if let Some(base) = &self.base_request {
170 validate_base_request(base)?;
171 }
172 encode_common(
173 self.base_request.as_deref(),
174 self.body.as_deref(),
175 &self.unknown_fields,
176 )
177 }
178
179 pub fn decode(input: &[u8]) -> Result<Self> {
180 let (base_request, body, unknown_fields) = decode_common(input)?;
181 if let Some(base) = &base_request {
182 validate_base_request(base)?;
183 }
184 Ok(Self {
185 base_request,
186 body,
187 unknown_fields,
188 })
189 }
190}
191
192#[derive(Default)]
195pub struct CommonResponse {
196 pub base_response: Option<Vec<u8>>,
197 pub body: Option<Vec<u8>>,
198 pub unknown_fields: Vec<Field>,
199}
200
201impl CommonResponse {
202 pub fn encode(&self) -> Result<Vec<u8>> {
203 if let Some(base) = &self.base_response {
204 validate_base_response(base)?;
205 }
206 encode_common(
207 self.base_response.as_deref(),
208 self.body.as_deref(),
209 &self.unknown_fields,
210 )
211 }
212
213 pub fn decode(input: &[u8]) -> Result<Self> {
214 let (base_response, body, unknown_fields) = decode_common(input)?;
215 if let Some(base) = &base_response {
216 validate_base_response(base)?;
217 }
218 Ok(Self {
219 base_response,
220 body,
221 unknown_fields,
222 })
223 }
224
225 pub fn return_code(&self) -> Result<i32> {
227 let base = self
228 .base_response
229 .as_deref()
230 .ok_or_else(|| anyhow::anyhow!("Missing call base response"))?;
231 optional_i32(&decode_fields(base)?, 1)?
232 .ok_or_else(|| anyhow::anyhow!("Missing call return code"))
233 }
234}
235
236fn validate_base_request(input: &[u8]) -> Result<()> {
237 let fields = decode_fields(input)?;
238 p::optional_data(&fields, 1)?;
239 optional_u32(&fields, 2)?;
240 p::optional_data(&fields, 3)?;
241 optional_i32(&fields, 4)?;
242 p::optional_data(&fields, 5)?;
243 optional_u32(&fields, 6)?;
244 Ok(())
245}
246
247fn validate_base_response(input: &[u8]) -> Result<()> {
248 let fields = decode_fields(input)?;
249 optional_i32(&fields, 1)?;
250 if let Some(message) = p::optional_data(&fields, 2)? {
251 let message = decode_fields(message)?;
252 if let Some(text) = p::optional_data(&message, 1)? {
253 std::str::from_utf8(text)?;
254 }
255 }
256 Ok(())
257}
258
259pub(super) fn decode_fields(input: &[u8]) -> Result<Vec<Field>> {
260 ensure!(
261 input.len() <= MAX_SIGNALING_BYTES,
262 "Call envelope too large"
263 );
264 let fields = p::decode(input)?;
265 ensure!(fields.len() <= MAX_FIELDS, "Too many call fields");
266 Ok(fields)
267}
268
269pub(super) fn optional_u32(fields: &[Field], number: u32) -> Result<Option<u32>> {
270 match p::optional(fields, number)? {
271 None => Ok(None),
272 Some(Value::Varint(value)) => Ok(Some(u32::try_from(*value)?)),
273 _ => bail!("Invalid call scalar field {number}"),
274 }
275}
276
277fn optional_i32(fields: &[Field], number: u32) -> Result<Option<i32>> {
278 match p::optional(fields, number)? {
279 None => Ok(None),
280 Some(Value::Varint(value)) => Ok(Some(i32::try_from(*value as i64)?)),
281 _ => bail!("Invalid call signed scalar field {number}"),
282 }
283}
284
285pub(super) fn unknown_fields(fields: Vec<Field>, last_known: u32) -> Vec<Field> {
286 fields
287 .into_iter()
288 .filter(|field| field.number > last_known)
289 .collect()
290}
291
292fn append_u32(output: &mut Vec<Vec<u8>>, number: u32, value: Option<u32>) {
293 if let Some(value) = value {
294 output.push(p::uint(number, u64::from(value)));
295 }
296}
297
298fn append_data(output: &mut Vec<Vec<u8>>, number: u32, value: Option<&[u8]>) {
299 if let Some(value) = value {
300 output.push(p::bytes(number, value));
301 }
302}
303
304fn finish(mut fields: Vec<Vec<u8>>, unknown: &[Field], last_known: u32) -> Result<Vec<u8>> {
305 ensure!(
306 fields.len() + unknown.len() <= MAX_FIELDS,
307 "Too many call fields"
308 );
309 let mut total = fields.iter().try_fold(0usize, |total, field| {
310 total
311 .checked_add(field.len())
312 .ok_or_else(|| anyhow::anyhow!("Call length overflow"))
313 })?;
314 ensure!(total <= MAX_SIGNALING_BYTES, "Call envelope too large");
315 for field in unknown {
316 ensure!(
317 field.number > last_known && field.number < 1 << 29,
318 "Unknown call field collides with a known or invalid field"
319 );
320 let wire = match &field.value {
321 Value::Varint(_) => 0,
322 Value::Fixed64(_) => 1,
323 Value::Bytes(_) => 2,
324 Value::Fixed32(_) => 5,
325 };
326 let mut encoded = p::varint(u64::from(field.number) * 8 + wire);
327 let value_len = match &field.value {
328 Value::Varint(value) => p::varint(*value).len(),
329 Value::Fixed64(_) => 8,
330 Value::Fixed32(_) => 4,
331 Value::Bytes(value) => {
332 ensure!(value.len() <= MAX_SIGNALING_BYTES, "Call field too large");
333 p::varint(value.len() as u64).len() + value.len()
334 }
335 };
336 total = total
337 .checked_add(encoded.len() + value_len)
338 .ok_or_else(|| anyhow::anyhow!("Call length overflow"))?;
339 ensure!(total <= MAX_SIGNALING_BYTES, "Call envelope too large");
340 match &field.value {
341 Value::Varint(value) => encoded.extend(p::varint(*value)),
342 Value::Fixed64(value) => encoded.extend(value),
343 Value::Fixed32(value) => encoded.extend(value),
344 Value::Bytes(value) => {
345 encoded.extend(p::varint(value.len() as u64));
346 encoded.extend(value);
347 }
348 }
349 fields.push(encoded);
350 }
351 p::message(&fields)
352}
353
354fn encode_common(base: Option<&[u8]>, body: Option<&[u8]>, unknown: &[Field]) -> Result<Vec<u8>> {
355 if let Some(body) = body {
356 ensure!(body.len() <= MAX_SIGNALING_BYTES, "Call body too large");
357 }
358 let mut fields = Vec::new();
359 append_data(&mut fields, 1, base);
360 append_data(&mut fields, 2, body);
361 finish(fields, unknown, 2)
362}
363
364type CommonParts = (Option<Vec<u8>>, Option<Vec<u8>>, Vec<Field>);
365fn decode_common(input: &[u8]) -> Result<CommonParts> {
366 let fields = decode_fields(input)?;
367 let base = p::optional_data(&fields, 1)?.map(Vec::from);
368 let body = p::optional_data(&fields, 2)?.map(Vec::from);
369 Ok((base, body, unknown_fields(fields, 2)))
370}
371
372#[cfg(test)]
373mod tests {
374 use super::*;
375
376 #[test]
377 fn callback_has_independent_wire_vector() {
378 let expected = hex::decode(concat!(
380 "08071202080118fa172224",
381 "2f636c6f7564696d2f636c6f75642d62696e2f636c6f7564766f69706d74637265617465",
382 "280030e0d403"
383 ))
384 .unwrap();
385 let request = CloudRequest {
386 longpolling: Some(false),
387 longpolling_timeout: Some(60_000),
388 ..CloudRequest::for_operation(7, CallOperation::Create, vec![8, 1])
389 };
390 assert_eq!(request.encode().unwrap(), expected);
391 let decoded = CloudRequest::decode(&expected).unwrap();
392 assert_eq!(decoded.task_id, Some(7));
393 assert_eq!(decoded.body.as_deref(), Some([8, 1].as_slice()));
394 assert_eq!(decoded.operation().unwrap(), CallOperation::Create);
395 assert_eq!(decoded.longpolling, Some(false));
396 assert_eq!(decoded.longpolling_timeout, Some(60_000));
397 }
398
399 #[test]
400 fn nested_bases_and_duplicate_bodies_are_checked() {
401 for input in [
402 vec![8, 0],
403 vec![10, 0, 10, 0],
404 vec![18, 0, 18, 0],
405 vec![10, 2, 8, 0],
406 vec![10, 2, 18, 0],
407 ] {
408 assert!(CommonRequest::decode(&input).is_err());
409 }
410 for input in [
411 vec![10, 2, 10, 0],
412 vec![10, 2, 16, 0],
413 vec![10, 4, 8, 0, 8, 0],
414 vec![10, 4, 18, 2, 8, 0],
415 ] {
416 assert!(CommonResponse::decode(&input).is_err());
417 }
418 }
419}