1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "discovery/mdns/mdns_receiver.h"
6
7 #include <memory>
8 #include <utility>
9 #include <vector>
10
11 #include "discovery/common/config.h"
12 #include "discovery/mdns/mdns_records.h"
13 #include "gmock/gmock.h"
14 #include "gtest/gtest.h"
15 #include "platform/api/time.h"
16 #include "platform/test/fake_udp_socket.h"
17
18 namespace openscreen {
19 namespace discovery {
20
21 using testing::_;
22 using testing::Return;
23
24 class MockMdnsReceiverDelegate : public MdnsReceiver::ResponseClient {
25 public:
26 MOCK_METHOD(void, OnMessageReceived, (const MdnsMessage&));
27 };
28
TEST(MdnsReceiverTest,ReceiveQuery)29 TEST(MdnsReceiverTest, ReceiveQuery) {
30 // clang-format off
31 const std::vector<uint8_t> kQueryBytes = {
32 0x00, 0x01, // ID = 1
33 0x00, 0x00, // FLAGS = None
34 0x00, 0x01, // Question count
35 0x00, 0x00, // Answer count
36 0x00, 0x00, // Authority count
37 0x00, 0x00, // Additional count
38 // Question
39 0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
40 0x05, 'l', 'o', 'c', 'a', 'l',
41 0x00,
42 0x00, 0x01, // TYPE = A (1)
43 0x00, 0x01, // CLASS = IN (1)
44 };
45 // clang-format on
46
47 Config config;
48 FakeUdpSocket socket;
49 MockMdnsReceiverDelegate delegate;
50 MdnsReceiver receiver(config);
51 receiver.SetQueryCallback(
52 [&delegate](const MdnsMessage& message, const IPEndpoint& endpoint) {
53 delegate.OnMessageReceived(message);
54 });
55 receiver.Start();
56
57 MdnsQuestion question(DomainName{"testing", "local"}, DnsType::kA,
58 DnsClass::kIN, ResponseType::kMulticast);
59 MdnsMessage message(1, MessageType::Query);
60 message.AddQuestion(question);
61
62 UdpPacket packet(kQueryBytes.data(), kQueryBytes.data() + kQueryBytes.size());
63 packet.set_source(
64 IPEndpoint{.address = IPAddress(192, 168, 1, 1), .port = 31337});
65 packet.set_destination(
66 IPEndpoint{.address = IPAddress(kDefaultMulticastGroupIPv4),
67 .port = kDefaultMulticastPort});
68
69 // Imitate a call to OnRead from NetworkRunner by calling it manually here
70 EXPECT_CALL(delegate, OnMessageReceived(message)).Times(1);
71 receiver.OnRead(&socket, std::move(packet));
72
73 receiver.Stop();
74 }
75
TEST(MdnsReceiverTest,ReceiveResponse)76 TEST(MdnsReceiverTest, ReceiveResponse) {
77 // clang-format off
78 const std::vector<uint8_t> kResponseBytes = {
79 0x00, 0x01, // ID = 1
80 0x84, 0x00, // FLAGS = AA | RESPONSE
81 0x00, 0x00, // Question count
82 0x00, 0x01, // Answer count
83 0x00, 0x00, // Authority count
84 0x00, 0x00, // Additional count
85 // Answer
86 0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
87 0x05, 'l', 'o', 'c', 'a', 'l',
88 0x00,
89 0x00, 0x01, // TYPE = A (1)
90 0x00, 0x01, // CLASS = IN (1)
91 0x00, 0x00, 0x00, 0x78, // TTL = 120 seconds
92 0x00, 0x04, // RDLENGTH = 4 bytes
93 0xac, 0x00, 0x00, 0x01, // 172.0.0.1
94 };
95
96 constexpr uint16_t kIPv6AddressHextets[] = {
97 0xfe80, 0x0000, 0x0000, 0x0000,
98 0x0202, 0xb3ff, 0xfe1e, 0x8329,
99 };
100 // clang-format on
101
102 Config config;
103 FakeUdpSocket socket;
104 MockMdnsReceiverDelegate delegate;
105 MdnsReceiver receiver(config);
106 receiver.AddResponseCallback(&delegate);
107 receiver.Start();
108
109 MdnsRecord record(DomainName{"testing", "local"}, DnsType::kA, DnsClass::kIN,
110 RecordType::kShared, std::chrono::seconds(120),
111 ARecordRdata(IPAddress{172, 0, 0, 1}));
112 MdnsMessage message(1, MessageType::Response);
113 message.AddAnswer(record);
114
115 UdpPacket packet(kResponseBytes.size());
116 packet.assign(kResponseBytes.data(),
117 kResponseBytes.data() + kResponseBytes.size());
118 packet.set_source(
119 IPEndpoint{.address = IPAddress(kIPv6AddressHextets), .port = 31337});
120 packet.set_destination(
121 IPEndpoint{.address = IPAddress(kDefaultMulticastGroupIPv6),
122 .port = kDefaultMulticastPort});
123
124 // Imitate a call to OnRead from NetworkRunner by calling it manually here
125 EXPECT_CALL(delegate, OnMessageReceived(message)).Times(1);
126 receiver.OnRead(&socket, std::move(packet));
127
128 receiver.Stop();
129 receiver.RemoveResponseCallback(&delegate);
130 }
131
132 } // namespace discovery
133 } // namespace openscreen
134