• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_sender.h"
6 
7 #include <memory>
8 #include <vector>
9 
10 #include "discovery/mdns/mdns_records.h"
11 #include "gmock/gmock.h"
12 #include "gtest/gtest.h"
13 #include "platform/test/fake_udp_socket.h"
14 #include "platform/test/mock_udp_socket.h"
15 
16 namespace openscreen {
17 namespace discovery {
18 
19 using testing::_;
20 using testing::Args;
21 using testing::Return;
22 using testing::StrictMock;
23 using testing::WithArgs;
24 
25 namespace {
26 
ACTION_P(VoidPointerMatchesBytes,expected_data)27 ACTION_P(VoidPointerMatchesBytes, expected_data) {
28   const uint8_t* actual_data = static_cast<const uint8_t*>(arg0);
29   for (size_t i = 0; i < expected_data.size(); ++i) {
30     EXPECT_EQ(actual_data[i], expected_data[i]);
31   }
32 }
33 
34 }  // namespace
35 
36 class MdnsSenderTest : public testing::Test {
37  public:
MdnsSenderTest()38   MdnsSenderTest()
39       : a_question_(DomainName{"testing", "local"},
40                     DnsType::kA,
41                     DnsClass::kIN,
42                     ResponseType::kMulticast),
43         a_record_(DomainName{"testing", "local"},
44                   DnsType::kA,
45                   DnsClass::kIN,
46                   RecordType::kShared,
47                   std::chrono::seconds(120),
48                   ARecordRdata(IPAddress{172, 0, 0, 1})),
49         query_message_(1, MessageType::Query),
50         response_message_(1, MessageType::Response),
51         ipv4_multicast_endpoint_{
52             .address = IPAddress(kDefaultMulticastGroupIPv4),
53             .port = kDefaultMulticastPort},
54         ipv6_multicast_endpoint_{
55             .address = IPAddress(kDefaultMulticastGroupIPv6),
56             .port = kDefaultMulticastPort} {
57     query_message_.AddQuestion(a_question_);
58     response_message_.AddAnswer(a_record_);
59   }
60 
61  protected:
62   // clang-format off
63   const std::vector<uint8_t> kQueryBytes = {
64       0x00, 0x01,  // ID = 1
65       0x00, 0x00,  // FLAGS = None
66       0x00, 0x01,  // Question count
67       0x00, 0x00,  // Answer count
68       0x00, 0x00,  // Authority count
69       0x00, 0x00,  // Additional count
70       // Question
71       0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
72       0x05, 'l', 'o', 'c', 'a', 'l',
73       0x00,
74       0x00, 0x01,  // TYPE = A (1)
75       0x00, 0x01,  // CLASS = IN (1)
76   };
77 
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   // clang-format on
96 
97   MdnsQuestion a_question_;
98   MdnsRecord a_record_;
99   MdnsMessage query_message_;
100   MdnsMessage response_message_;
101   IPEndpoint ipv4_multicast_endpoint_;
102   IPEndpoint ipv6_multicast_endpoint_;
103 };
104 
TEST_F(MdnsSenderTest,SendMulticast)105 TEST_F(MdnsSenderTest, SendMulticast) {
106   StrictMock<MockUdpSocket> socket;
107   EXPECT_CALL(socket, IsIPv4()).WillRepeatedly(Return(true));
108   EXPECT_CALL(socket, IsIPv6()).WillRepeatedly(Return(true));
109   MdnsSender sender(&socket);
110   EXPECT_CALL(socket, SendMessage(_, kQueryBytes.size(), _))
111       .WillOnce(WithArgs<0>(VoidPointerMatchesBytes(kQueryBytes)));
112   EXPECT_EQ(sender.SendMulticast(query_message_), Error::Code::kNone);
113 }
114 
TEST_F(MdnsSenderTest,SendUnicastIPv4)115 TEST_F(MdnsSenderTest, SendUnicastIPv4) {
116   IPEndpoint endpoint{.address = IPAddress{192, 168, 1, 1}, .port = 31337};
117 
118   StrictMock<MockUdpSocket> socket;
119   MdnsSender sender(&socket);
120   EXPECT_CALL(socket, SendMessage(_, kResponseBytes.size(), _))
121       .WillOnce(WithArgs<0>(VoidPointerMatchesBytes(kResponseBytes)));
122   EXPECT_EQ(sender.SendMessage(response_message_, endpoint),
123             Error::Code::kNone);
124 }
125 
TEST_F(MdnsSenderTest,SendUnicastIPv6)126 TEST_F(MdnsSenderTest, SendUnicastIPv6) {
127   constexpr uint16_t kIPv6AddressHextets[] = {
128       0xfe80, 0x0000, 0x0000, 0x0000, 0x0202, 0xb3ff, 0xfe1e, 0x8329,
129   };
130   IPEndpoint endpoint{.address = IPAddress(kIPv6AddressHextets), .port = 31337};
131 
132   StrictMock<MockUdpSocket> socket;
133   MdnsSender sender(&socket);
134   EXPECT_CALL(socket, SendMessage(_, kResponseBytes.size(), _))
135       .WillOnce(WithArgs<0>(VoidPointerMatchesBytes(kResponseBytes)));
136   EXPECT_EQ(sender.SendMessage(response_message_, endpoint),
137             Error::Code::kNone);
138 }
139 
TEST_F(MdnsSenderTest,MessageTooBig)140 TEST_F(MdnsSenderTest, MessageTooBig) {
141   MdnsMessage big_message_(1, MessageType::Query);
142   for (size_t i = 0; i < 100; ++i) {
143     big_message_.AddQuestion(a_question_);
144     big_message_.AddAnswer(a_record_);
145   }
146 
147   StrictMock<MockUdpSocket> socket;
148   EXPECT_CALL(socket, IsIPv4()).WillRepeatedly(Return(true));
149   EXPECT_CALL(socket, IsIPv6()).WillRepeatedly(Return(true));
150   MdnsSender sender(&socket);
151   EXPECT_EQ(sender.SendMulticast(big_message_),
152             Error::Code::kInsufficientBuffer);
153 }
154 
TEST_F(MdnsSenderTest,ReturnsErrorOnSocketFailure)155 TEST_F(MdnsSenderTest, ReturnsErrorOnSocketFailure) {
156   FakeUdpSocket::MockClient socket_client;
157   FakeUdpSocket socket(nullptr, &socket_client);
158   MdnsSender sender(&socket);
159   Error error = Error(Error::Code::kConnectionFailed, "error message");
160   socket.EnqueueSendResult(error);
161   EXPECT_CALL(socket_client, OnSendError(_, error)).Times(1);
162   EXPECT_EQ(sender.SendMulticast(query_message_), Error::Code::kNone);
163   EXPECT_EQ(socket.send_queue_size(), size_t{0});
164 }
165 
166 }  // namespace discovery
167 }  // namespace openscreen
168