summaryrefslogtreecommitdiff
path: root/src/protocol/udp.rs
blob: d5302ebd7b199a8f82718a458d9771138e2a7785 (plain)
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
use crate::protocol::codec::Decode;
use nom::number;
use nom::IResult;

/******************************************************************************
 * Struct
 ******************************************************************************/

/*
 * User Datagram Header Format
 *
 *   0                   1                   2                   3
 *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *  |          Source Port          |       Destination Port        |
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *  |           Length              |         Checksum              |
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *  |                             Data                              |
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 */

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct UdpHeader {
    pub source_port: u16,
    pub dest_port: u16,
    pub length: u16,
    pub checksum: u16,
}

/******************************************************************************
 * API
 ******************************************************************************/

impl Decode<UdpHeader> for UdpHeader {
    fn decode(input: &[u8]) -> IResult<&[u8], UdpHeader> {
        let (input, source_port) = number::streaming::be_u16(input)?;
        let (input, dest_port) = number::streaming::be_u16(input)?;
        let (input, length) = number::streaming::be_u16(input)?;
        let (input, checksum) = number::streaming::be_u16(input)?;

        Ok((
            input,
            UdpHeader {
                source_port,
                dest_port,
                length,
                checksum,
            },
        ))
    }
}

/******************************************************************************
 * TEST
 ******************************************************************************/

#[cfg(test)]
mod tests {
    use super::UdpHeader;
    use crate::protocol::codec::Decode;

    const LAST_SLICE: &'static [u8] = &[0xff];

    #[test]
    fn udp_header_decode() {
        /*
         * User Datagram Protocol, Src Port: 9993, Dst Port: 9993
         *     Source Port: 9993
         *     Destination Port: 9993
         *     Length: 145
         *     Checksum: 0x57d3 [correct]
         *         [Calculated Checksum: 0x57d3]
         *     [Checksum Status: Good]
         *     [Stream index: 3]
         *     [Timestamps]
         *         [Time since first frame: 0.000000000 seconds]
         *         [Time since previous frame: 0.000000000 seconds]
         *     UDP payload (137 bytes)
         * Data (137 bytes)
         */

        let bytes = [
            0x27, 0x09, /* Source Port */
            0x27, 0x09, /* Destination Port */
            0x00, 0x91, /* Length */
            0x57, 0xd3, /* Checksum */
            0xff, /* Payload */
        ];

        let expectation = UdpHeader {
            source_port: 9993,
            dest_port: 9993,
            length: 145,
            checksum: 0x57d3,
        };

        assert_eq!(UdpHeader::decode(&bytes), Ok((LAST_SLICE, expectation)));

        // example
        let result = UdpHeader::decode(&bytes);
        if let Ok((payload, header)) = result {
            println!("return: {:?}, payload: {}", header, payload.len());
        } else {
            println!("return: Incomplete data");
        }
    }
}