Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / lib / mdns / minimal / Server.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *
5  *    Licensed under the Apache License, Version 2.0 (the "License");
6  *    you may not use this file except in compliance with the License.
7  *    You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *    Unless required by applicable law or agreed to in writing, software
12  *    distributed under the License is distributed on an "AS IS" BASIS,
13  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *    See the License for the specific language governing permissions and
15  *    limitations under the License.
16  */
17
18 #include "Server.h"
19
20 #include <errno.h>
21 #include <utility>
22
23 #include <mdns/minimal/core/DnsHeader.h>
24
25 namespace mdns {
26 namespace Minimal {
27 namespace {
28
29 class ShutdownOnError
30 {
31 public:
32     ShutdownOnError(ServerBase * s) : mServer(s) {}
33     ~ShutdownOnError()
34     {
35         if (mServer != nullptr)
36         {
37             mServer->Shutdown();
38         }
39     }
40
41     CHIP_ERROR ReturnSuccess()
42     {
43         mServer = nullptr;
44         return CHIP_NO_ERROR;
45     }
46
47 private:
48     ServerBase * mServer;
49 };
50
51 } // namespace
52
53 namespace BroadcastIpAddresses {
54
55 // Get standard mDNS Broadcast addresses
56
57 void GetIpv6Into(chip::Inet::IPAddress & dest)
58 {
59     if (!chip::Inet::IPAddress::FromString("FF02::FB", dest))
60     {
61         ChipLogError(Discovery, "Failed to parse standard IPv6 broadcast address");
62     }
63 }
64
65 void GetIpv4Into(chip::Inet::IPAddress & dest)
66 {
67     if (!chip::Inet::IPAddress::FromString("224.0.0.251", dest))
68     {
69         ChipLogError(Discovery, "Failed to parse standard IPv4 broadcast address");
70     }
71 }
72
73 } // namespace BroadcastIpAddresses
74
75 namespace {
76
77 CHIP_ERROR JoinMulticastGroup(chip::Inet::InterfaceId interfaceId, chip::Inet::UDPEndPoint * endpoint,
78                               chip::Inet::IPAddressType addressType)
79 {
80
81     chip::Inet::IPAddress address;
82
83     if (addressType == chip::Inet::IPAddressType::kIPAddressType_IPv6)
84     {
85         BroadcastIpAddresses::GetIpv6Into(address);
86 #if INET_CONFIG_ENABLE_IPV4
87     }
88     else if (addressType == chip::Inet::IPAddressType::kIPAddressType_IPv4)
89     {
90         BroadcastIpAddresses::GetIpv4Into(address);
91 #endif // INET_CONFIG_ENABLE_IPV4
92     }
93     else
94     {
95         return CHIP_ERROR_INVALID_ARGUMENT;
96     }
97
98     return endpoint->JoinMulticastGroup(interfaceId, address);
99 }
100
101 const char * AddressTypeStr(chip::Inet::IPAddressType addressType)
102 {
103     switch (addressType)
104     {
105     case chip::Inet::IPAddressType::kIPAddressType_IPv6:
106         return "IPv6";
107 #if INET_CONFIG_ENABLE_IPV4
108     case chip::Inet::IPAddressType::kIPAddressType_IPv4:
109         return "IPv4";
110 #endif // INET_CONFIG_ENABLE_IPV4
111     default:
112         return "UNKNOWN";
113     }
114 }
115
116 } // namespace
117
118 ServerBase::~ServerBase()
119 {
120     Shutdown();
121 }
122
123 void ServerBase::Shutdown()
124 {
125     for (size_t i = 0; i < mEndpointCount; i++)
126     {
127         if (mEndpoints[i].udp != nullptr)
128         {
129             mEndpoints[i].udp->Free();
130             mEndpoints[i].udp = nullptr;
131         }
132     }
133 }
134
135 CHIP_ERROR ServerBase::Listen(chip::Inet::InetLayer * inetLayer, ListenIterator * it, uint16_t port)
136 {
137     Shutdown(); // ensure everything starts fresh
138
139     size_t endpointIndex                = 0;
140     chip::Inet::InterfaceId interfaceId = INET_NULL_INTERFACEID;
141     chip::Inet::IPAddressType addressType;
142
143     ShutdownOnError autoShutdown(this);
144
145     while (it->Next(&interfaceId, &addressType))
146     {
147         ReturnErrorCodeIf(endpointIndex >= mEndpointCount, CHIP_ERROR_NO_MEMORY);
148
149         EndpointInfo * info = &mEndpoints[endpointIndex];
150         info->addressType   = addressType;
151         info->interfaceId   = interfaceId;
152
153         ReturnErrorOnFailure(inetLayer->NewUDPEndPoint(&info->udp));
154
155         ReturnErrorOnFailure(info->udp->Bind(addressType, chip::Inet::IPAddress::Any, port, interfaceId));
156
157         info->udp->AppState          = static_cast<void *>(this);
158         info->udp->OnMessageReceived = OnUdpPacketReceived;
159
160         ReturnErrorOnFailure(info->udp->Listen());
161
162         CHIP_ERROR err = JoinMulticastGroup(interfaceId, info->udp, addressType);
163         if (err != CHIP_NO_ERROR)
164         {
165             char interfaceName[chip::Inet::InterfaceIterator::kMaxIfNameLength];
166             chip::Inet::GetInterfaceName(interfaceId, interfaceName, sizeof(interfaceName));
167
168             // Log only as non-fatal error. Failure to join will mean we reply to unicast queries only.
169             ChipLogError(DeviceLayer, "MDNS failed to join multicast group on %s for address type %s: %s", interfaceName,
170                          AddressTypeStr(addressType), chip::ErrorStr(err));
171         }
172
173         endpointIndex++;
174     }
175
176     return autoShutdown.ReturnSuccess();
177 }
178
179 CHIP_ERROR ServerBase::DirectSend(chip::System::PacketBufferHandle && data, const chip::Inet::IPAddress & addr, uint16_t port,
180                                   chip::Inet::InterfaceId interface)
181 {
182     for (size_t i = 0; i < mEndpointCount; i++)
183     {
184         EndpointInfo * info = &mEndpoints[i];
185         if (info->udp == nullptr)
186         {
187             continue;
188         }
189
190         if (info->addressType != addr.Type())
191         {
192             continue;
193         }
194
195         chip::Inet::InterfaceId boundIf = info->udp->GetBoundInterface();
196
197         if ((boundIf != INET_NULL_INTERFACEID) && (boundIf != interface))
198         {
199             continue;
200         }
201
202         return info->udp->SendTo(addr, port, std::move(data));
203     }
204
205     return CHIP_ERROR_NOT_CONNECTED;
206 }
207
208 CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle data, uint16_t port, chip::Inet::InterfaceId interface)
209 {
210     for (size_t i = 0; i < mEndpointCount; i++)
211     {
212         EndpointInfo * info = &mEndpoints[i];
213
214         if (info->udp == nullptr)
215         {
216             continue;
217         }
218
219         if ((info->udp->GetBoundInterface() != interface) && (info->udp->GetBoundInterface() != INET_NULL_INTERFACEID))
220         {
221             continue;
222         }
223
224         CHIP_ERROR err;
225
226         /// The same packet needs to be sent over potentially multiple interfaces.
227         /// LWIP does not like having a pbuf sent over serparate interfaces, hence we create a copy
228         /// TODO: this wastes one copy of the data and that could be optimized away
229         chip::System::PacketBufferHandle copy = data.CloneData();
230
231         if (info->addressType == chip::Inet::kIPAddressType_IPv6)
232         {
233             err = info->udp->SendTo(mIpv6BroadcastAddress, port, info->udp->GetBoundInterface(), std::move(copy));
234         }
235 #if INET_CONFIG_ENABLE_IPV4
236         else if (info->addressType == chip::Inet::kIPAddressType_IPv4)
237         {
238             err = info->udp->SendTo(mIpv4BroadcastAddress, port, info->udp->GetBoundInterface(), std::move(copy));
239         }
240 #endif
241         else
242         {
243             return CHIP_ERROR_INCORRECT_STATE;
244         }
245
246         if (err != CHIP_NO_ERROR)
247         {
248             return err;
249         }
250     }
251
252     return CHIP_NO_ERROR;
253 }
254
255 CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle data, uint16_t port)
256 {
257     for (size_t i = 0; i < mEndpointCount; i++)
258     {
259         EndpointInfo * info = &mEndpoints[i];
260
261         if (info->udp == nullptr)
262         {
263             continue;
264         }
265
266         CHIP_ERROR err;
267
268         /// The same packet needs to be sent over potentially multiple interfaces.
269         /// LWIP does not like having a pbuf sent over serparate interfaces, hence we create a copy
270         /// TODO: this wastes one copy of the data and that could be optimized away
271         chip::System::PacketBufferHandle copy = data.CloneData();
272
273         if (info->addressType == chip::Inet::kIPAddressType_IPv6)
274         {
275             err = info->udp->SendTo(mIpv6BroadcastAddress, port, info->udp->GetBoundInterface(), std::move(copy));
276         }
277 #if INET_CONFIG_ENABLE_IPV4
278         else if (info->addressType == chip::Inet::kIPAddressType_IPv4)
279         {
280             err = info->udp->SendTo(mIpv4BroadcastAddress, port, info->udp->GetBoundInterface(), std::move(copy));
281         }
282 #endif
283         else
284         {
285             return CHIP_ERROR_INCORRECT_STATE;
286         }
287
288         if (err == chip::System::MapErrorPOSIX(ENETUNREACH))
289         {
290             // Send attempted to an unreachable network. Generally should not happen if
291             // interfaces are configured properly, however such a failure to broadcast
292             // may not be critical either.
293             ChipLogError(Discovery, "Attempt to mDNS broadcast to an unreachable destination.");
294         }
295         else if (err != CHIP_NO_ERROR)
296         {
297             return err;
298         }
299     }
300
301     return CHIP_NO_ERROR;
302 }
303
304 void ServerBase::OnUdpPacketReceived(chip::Inet::IPEndPointBasis * endPoint, chip::System::PacketBufferHandle buffer,
305                                      const chip::Inet::IPPacketInfo * info)
306 {
307     ServerBase * srv = static_cast<ServerBase *>(endPoint->AppState);
308     if (!srv->mDelegate)
309     {
310         return;
311     }
312
313     mdns::Minimal::BytesRange data(buffer->Start(), buffer->Start() + buffer->DataLength());
314     if (data.Size() < HeaderRef::kSizeBytes)
315     {
316         ChipLogError(Discovery, "Packet to small for mDNS data: %d bytes", static_cast<int>(data.Size()));
317         return;
318     }
319
320     if (HeaderRef(const_cast<uint8_t *>(data.Start())).GetFlags().IsQuery())
321     {
322         srv->mDelegate->OnQuery(data, info);
323     }
324     else
325     {
326         srv->mDelegate->OnResponse(data, info);
327     }
328 }
329
330 } // namespace Minimal
331 } // namespace mdns