s2n_quic_platform/message/cmsg/
encode.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::features;
5use s2n_quic_core::inet::{ExplicitCongestionNotification, SocketAddress};
6
7#[derive(Clone, Copy, Debug)]
8pub struct Error;
9
10pub trait Encoder {
11    /// Encodes the given value as a control message in the cmsg buffer.
12    ///
13    /// The msghdr.msg_control should be zero-initialized and aligned and contain enough
14    /// room for the value to be written.
15    fn encode_cmsg<T: Copy>(
16        &mut self,
17        level: libc::c_int,
18        ty: libc::c_int,
19        value: T,
20    ) -> Result<usize, Error>;
21
22    /// Encodes ECN markings into the cmsg encoder
23    #[inline]
24    fn encode_ecn(
25        &mut self,
26        ecn: ExplicitCongestionNotification,
27        remote_address: &SocketAddress,
28    ) -> Result<usize, Error> {
29        // no need to encode for the default case
30        if ecn == ExplicitCongestionNotification::NotEct {
31            return Ok(0);
32        }
33
34        // the remote address needs to be unmapped in order to set the appropriate cmsg
35        match remote_address.unmap() {
36            SocketAddress::IpV4(_) => {
37                if let (Some(level), Some(ty)) = (features::tos_v4::LEVEL, features::tos_v4::TYPE) {
38                    return self.encode_cmsg(level, ty, ecn as u8 as features::tos_v4::Cmsg);
39                }
40            }
41            SocketAddress::IpV6(_) => {
42                if let (Some(level), Some(ty)) = (features::tos_v6::LEVEL, features::tos_v6::TYPE) {
43                    return self.encode_cmsg(level, ty, ecn as u8 as features::tos_v6::Cmsg);
44                }
45            }
46        }
47
48        Ok(0)
49    }
50
51    /// Encodes GSO segment_size into the cmsg encoder
52    #[inline]
53    fn encode_gso(&mut self, segment_size: u16) -> Result<usize, Error> {
54        if let (Some(level), Some(ty)) = (features::gso::LEVEL, features::gso::TYPE) {
55            let segment_size = segment_size as features::gso::Cmsg;
56            self.encode_cmsg(level, ty, segment_size)
57        } else {
58            panic!("platform does not support GSO");
59        }
60    }
61
62    #[inline]
63    fn encode_local_address(&mut self, address: &SocketAddress) -> Result<usize, Error> {
64        use s2n_quic_core::inet::Unspecified;
65
66        match address {
67            SocketAddress::IpV4(addr) => {
68                use features::pktinfo_v4 as pktinfo;
69                if let (Some(level), Some(ty)) = (pktinfo::LEVEL, pktinfo::TYPE) {
70                    let ip = addr.ip();
71
72                    if ip.is_unspecified() {
73                        return Ok(0);
74                    }
75
76                    let value = pktinfo::encode(ip, None);
77                    return self.encode_cmsg(level, ty, value);
78                }
79            }
80            SocketAddress::IpV6(addr) => {
81                use features::pktinfo_v6 as pktinfo;
82                if let (Some(level), Some(ty)) = (pktinfo::LEVEL, pktinfo::TYPE) {
83                    let ip = addr.ip();
84
85                    if ip.is_unspecified() {
86                        return Ok(0);
87                    }
88
89                    let value = pktinfo::encode(ip, None);
90                    return self.encode_cmsg(level, ty, value);
91                }
92            }
93        }
94
95        Ok(0)
96    }
97}