awdl_frame_parser/tlvs/dns_sd/service_response_tlv/
mod.rs1pub mod dns_record;
2
3use crate::{
4 common::{AWDLDnsName, AWDLStr, ReadLabelIterator},
5 tlvs::{AWDLTLVType, AwdlTlv},
6};
7
8use dns_record::AWDLDnsRecord;
9
10use scroll::{
11 ctx::{MeasureWith, TryFromCtx, TryIntoCtx},
12 Endian, Pread, Pwrite,
13};
14
15#[derive(Clone, Copy, Debug, Hash)]
16pub struct ServiceResponseTLV<'a, I> {
18 pub name: AWDLDnsName<I>,
20
21 pub record: AWDLDnsRecord<'a, I>,
23}
24impl<I> AwdlTlv for ServiceResponseTLV<'_, I> {
25 const TLV_TYPE: AWDLTLVType = AWDLTLVType::ServiceResponse;
26}
27impl<'a, I: IntoIterator<Item = AWDLStr<'a>> + Clone> Eq for ServiceResponseTLV<'a, I> {}
28impl<'a, LhsIterator, RhsIterator> PartialEq<ServiceResponseTLV<'a, RhsIterator>>
29 for ServiceResponseTLV<'a, LhsIterator>
30where
31 LhsIterator: IntoIterator<Item = AWDLStr<'a>> + Clone,
32 RhsIterator: IntoIterator<Item = AWDLStr<'a>> + Clone,
33{
34 fn eq(&self, other: &ServiceResponseTLV<'a, RhsIterator>) -> bool {
35 self.name == other.name && self.record == other.record
36 }
37}
38impl<'a, I> MeasureWith<()> for ServiceResponseTLV<'a, I>
39where
40 I: IntoIterator<Item = AWDLStr<'a>> + Clone,
41{
42 fn measure_with(&self, ctx: &()) -> usize {
43 6 + self.name.measure_with(ctx) + self.record.measure_with(ctx)
44 }
45}
46impl<'a> TryFromCtx<'a> for ServiceResponseTLV<'a, ReadLabelIterator<'a>> {
47 type Error = scroll::Error;
48 fn try_from_ctx(from: &'a [u8], _ctx: ()) -> Result<(Self, usize), Self::Error> {
49 let mut offset = 0;
50
51 let length = from.gread_with::<u16>(&mut offset, Endian::Little)? as usize;
52 let name = from
53 .gread_with::<&'a [u8]>(&mut offset, length - 1)?
54 .pread(0)?;
55 let record = from.gread(&mut offset)?;
56 Ok((Self { name, record }, offset))
57 }
58}
59impl<'a, I> TryIntoCtx for ServiceResponseTLV<'a, I>
60where
61 I: IntoIterator<Item = AWDLStr<'a>> + Clone,
62{
63 type Error = scroll::Error;
64 fn try_into_ctx(self, buf: &mut [u8], _ctx: ()) -> Result<usize, Self::Error> {
65 let mut offset = 0;
66 buf.gwrite_with::<u16>(
67 self.name.measure_with(&()) as u16 + 1,
68 &mut offset,
69 Endian::Little,
70 )?;
71 buf.gwrite(self.name, &mut offset)?;
72 buf.gwrite(self.record, &mut offset)?;
73 Ok(offset)
74 }
75}
76
77pub type DefaultServiceResponseTLV<'a> = ServiceResponseTLV<'a, ReadLabelIterator<'a>>;
79
80#[cfg(test)]
81mod service_response_tests {
82 use alloc::vec;
83 use scroll::{ctx::MeasureWith, Pread, Pwrite};
84
85 use crate::{
86 common::{AWDLDnsCompression, AWDLDnsName, ReadLabelIterator},
87 tlvs::dns_sd::{dns_record::AWDLDnsRecord, ServiceResponseTLV},
88 };
89
90 #[test]
91 fn test_service_response_tlv_ptr() {
92 let bytes = &include_bytes!("../../../../test_bins/service_response_tlv_ptr.bin")[3..];
93
94 let service_response_tlv = bytes
95 .pread::<ServiceResponseTLV<ReadLabelIterator>>(0)
96 .unwrap();
97
98 assert_eq!(
99 service_response_tlv,
100 ServiceResponseTLV {
101 name: AWDLDnsName {
102 labels: vec!["_airplay-p2p".into()],
103 domain: AWDLDnsCompression::TcpLocal,
104 ..Default::default()
105 },
106 record: AWDLDnsRecord::PTR {
107 domain_name: AWDLDnsName {
108 labels: vec!["34FD6A0C9A42@1.021".into()],
109 domain: AWDLDnsCompression::Null,
110 ..Default::default()
111 }
112 }
113 }
114 );
115 let mut buf = vec![0x00; service_response_tlv.measure_with(&())];
116 buf.as_mut_slice().pwrite(service_response_tlv, 0).unwrap();
117 assert_eq!(buf, bytes);
118 }
119 #[test]
120 fn test_service_response_tlv_srv() {
121 let bytes = &include_bytes!("../../../../test_bins/service_response_tlv_srv.bin")[3..];
122
123 let service_response_tlv = bytes
124 .pread::<ServiceResponseTLV<ReadLabelIterator>>(0)
125 .unwrap();
126
127 assert_eq!(
128 service_response_tlv,
129 ServiceResponseTLV {
130 name: AWDLDnsName {
131 labels: vec!["34fd6a0c9a42@1.021".into(), "_airplay-p2p".into()],
132 domain: AWDLDnsCompression::TcpLocal,
133 ..Default::default()
134 },
135 record: AWDLDnsRecord::SRV {
136 priority: 0,
137 weight: 0,
138 port: 7000,
139 target: AWDLDnsName {
140 labels: vec!["dcc83dc2-fae7-4043-8c7a-a8b6bf49eaad".into()],
141 domain: AWDLDnsCompression::Local,
142 ..Default::default()
143 }
144 }
145 }
146 );
147 let mut buf = vec![0x00; service_response_tlv.measure_with(&())];
148 buf.as_mut_slice().pwrite(service_response_tlv, 0).unwrap();
149 assert_eq!(buf, bytes);
150 }
151 #[test]
152 fn test_service_response_tlv_txt() {
153 let bytes = &include_bytes!("../../../../test_bins/service_response_tlv_txt.bin")[3..];
154
155 let service_response_tlv = bytes
156 .pread::<ServiceResponseTLV<ReadLabelIterator>>(0)
157 .unwrap();
158
159 assert_eq!(
160 service_response_tlv,
161 ServiceResponseTLV {
162 name: AWDLDnsName {
163 labels: vec!["6dba48462242".into()],
164 domain: AWDLDnsCompression::AirDropTcpLocal,
165 ..Default::default()
166 },
167 record: AWDLDnsRecord::TXT {
168 txt_record: alloc::vec!["flags=999".into()]
169 }
170 }
171 );
172 let mut buf = vec![0x00; service_response_tlv.measure_with(&())];
173 buf.as_mut_slice().pwrite(service_response_tlv, 0).unwrap();
174 assert_eq!(buf, bytes);
175 }
176}