Skip to main content

rtc_dtls/
content.rs

1use std::io::{Read, Write};
2
3use super::alert::*;
4use super::application_data::*;
5use super::change_cipher_spec::*;
6use super::handshake::*;
7use shared::error::*;
8
9/// ## Specifications
10///
11/// * [RFC 4346 §6.2.1]
12///
13/// [RFC 4346 §6.2.1]: https://tools.ietf.org/html/rfc4346#section-6.2.1
14#[derive(Default, Copy, Clone, PartialEq, Eq, Debug)]
15pub enum ContentType {
16    /// `CHANGE_CIPHER_SPEC` (`20`).
17    ChangeCipherSpec = 20,
18    /// `ALERT` (`21`).
19    Alert = 21,
20    /// `HANDSHAKE` (`22`).
21    Handshake = 22,
22    /// `APPLICATION_DATA` (`23`).
23    ApplicationData = 23,
24    #[default]
25    /// A content type this crate does not recognise.
26    Invalid,
27}
28
29impl From<u8> for ContentType {
30    fn from(val: u8) -> Self {
31        match val {
32            20 => ContentType::ChangeCipherSpec,
33            21 => ContentType::Alert,
34            22 => ContentType::Handshake,
35            23 => ContentType::ApplicationData,
36            _ => ContentType::Invalid,
37        }
38    }
39}
40
41#[derive(PartialEq, Debug, Clone)]
42/// The parsed body of a DTLS record.
43pub enum Content {
44    /// A ChangeCipherSpec record.
45    ChangeCipherSpec(ChangeCipherSpec),
46    /// An alert record.
47    Alert(Alert),
48    /// A handshake record.
49    Handshake(Handshake),
50    /// An application data record.
51    ApplicationData(ApplicationData),
52}
53
54impl Content {
55    /// The record content type this message is carried in.
56    pub fn content_type(&self) -> ContentType {
57        match self {
58            Content::ChangeCipherSpec(c) => c.content_type(),
59            Content::Alert(c) => c.content_type(),
60            Content::Handshake(c) => c.content_type(),
61            Content::ApplicationData(c) => c.content_type(),
62        }
63    }
64
65    /// The encoded size of this message in bytes.
66    pub fn size(&self) -> usize {
67        match self {
68            Content::ChangeCipherSpec(c) => c.size(),
69            Content::Alert(c) => c.size(),
70            Content::Handshake(c) => c.size(),
71            Content::ApplicationData(c) => c.size(),
72        }
73    }
74
75    /// Encodes this message to `writer`.
76    ///
77    /// # Errors
78    ///
79    /// Fails on a write error, or if a field exceeds the length its wire format allows.
80    pub fn marshal<W: Write>(&self, writer: &mut W) -> Result<()> {
81        match self {
82            Content::ChangeCipherSpec(c) => c.marshal(writer),
83            Content::Alert(c) => c.marshal(writer),
84            Content::Handshake(c) => c.marshal(writer),
85            Content::ApplicationData(c) => c.marshal(writer),
86        }
87    }
88
89    /// Decodes one of these messages from `reader`.
90    ///
91    /// # Errors
92    ///
93    /// Fails if `reader` is truncated or its contents are not a valid encoding.
94    pub fn unmarshal<R: Read>(content_type: ContentType, reader: &mut R) -> Result<Self> {
95        match content_type {
96            ContentType::ChangeCipherSpec => Ok(Content::ChangeCipherSpec(
97                ChangeCipherSpec::unmarshal(reader)?,
98            )),
99            ContentType::Alert => Ok(Content::Alert(Alert::unmarshal(reader)?)),
100            ContentType::Handshake => Ok(Content::Handshake(Handshake::unmarshal(reader)?)),
101            ContentType::ApplicationData => Ok(Content::ApplicationData(
102                ApplicationData::unmarshal(reader)?,
103            )),
104            _ => Err(Error::ErrInvalidContentType),
105        }
106    }
107}