3 * Copyright (c) 2020 Project CHIP Authors
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include <mdns/minimal/core/DnsHeader.h>
32 ShutdownOnError(ServerBase * s) : mServer(s) {}
35 if (mServer != nullptr)
41 CHIP_ERROR ReturnSuccess()
53 namespace BroadcastIpAddresses {
55 // Get standard mDNS Broadcast addresses
57 void GetIpv6Into(chip::Inet::IPAddress & dest)
59 if (!chip::Inet::IPAddress::FromString("FF02::FB", dest))
61 ChipLogError(Discovery, "Failed to parse standard IPv6 broadcast address");
65 void GetIpv4Into(chip::Inet::IPAddress & dest)
67 if (!chip::Inet::IPAddress::FromString("224.0.0.251", dest))
69 ChipLogError(Discovery, "Failed to parse standard IPv4 broadcast address");
73 } // namespace BroadcastIpAddresses
77 CHIP_ERROR JoinMulticastGroup(chip::Inet::InterfaceId interfaceId, chip::Inet::UDPEndPoint * endpoint,
78 chip::Inet::IPAddressType addressType)
81 chip::Inet::IPAddress address;
83 if (addressType == chip::Inet::IPAddressType::kIPAddressType_IPv6)
85 BroadcastIpAddresses::GetIpv6Into(address);
86 #if INET_CONFIG_ENABLE_IPV4
88 else if (addressType == chip::Inet::IPAddressType::kIPAddressType_IPv4)
90 BroadcastIpAddresses::GetIpv4Into(address);
91 #endif // INET_CONFIG_ENABLE_IPV4
95 return CHIP_ERROR_INVALID_ARGUMENT;
98 return endpoint->JoinMulticastGroup(interfaceId, address);
101 const char * AddressTypeStr(chip::Inet::IPAddressType addressType)
105 case chip::Inet::IPAddressType::kIPAddressType_IPv6:
107 #if INET_CONFIG_ENABLE_IPV4
108 case chip::Inet::IPAddressType::kIPAddressType_IPv4:
110 #endif // INET_CONFIG_ENABLE_IPV4
118 ServerBase::~ServerBase()
123 void ServerBase::Shutdown()
125 for (size_t i = 0; i < mEndpointCount; i++)
127 if (mEndpoints[i].udp != nullptr)
129 mEndpoints[i].udp->Free();
130 mEndpoints[i].udp = nullptr;
135 CHIP_ERROR ServerBase::Listen(chip::Inet::InetLayer * inetLayer, ListenIterator * it, uint16_t port)
137 Shutdown(); // ensure everything starts fresh
139 size_t endpointIndex = 0;
140 chip::Inet::InterfaceId interfaceId = INET_NULL_INTERFACEID;
141 chip::Inet::IPAddressType addressType;
143 ShutdownOnError autoShutdown(this);
145 while (it->Next(&interfaceId, &addressType))
147 ReturnErrorCodeIf(endpointIndex >= mEndpointCount, CHIP_ERROR_NO_MEMORY);
149 EndpointInfo * info = &mEndpoints[endpointIndex];
150 info->addressType = addressType;
151 info->interfaceId = interfaceId;
153 ReturnErrorOnFailure(inetLayer->NewUDPEndPoint(&info->udp));
155 ReturnErrorOnFailure(info->udp->Bind(addressType, chip::Inet::IPAddress::Any, port, interfaceId));
157 info->udp->AppState = static_cast<void *>(this);
158 info->udp->OnMessageReceived = OnUdpPacketReceived;
160 ReturnErrorOnFailure(info->udp->Listen());
162 CHIP_ERROR err = JoinMulticastGroup(interfaceId, info->udp, addressType);
163 if (err != CHIP_NO_ERROR)
165 char interfaceName[chip::Inet::InterfaceIterator::kMaxIfNameLength];
166 chip::Inet::GetInterfaceName(interfaceId, interfaceName, sizeof(interfaceName));
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));
176 return autoShutdown.ReturnSuccess();
179 CHIP_ERROR ServerBase::DirectSend(chip::System::PacketBufferHandle && data, const chip::Inet::IPAddress & addr, uint16_t port,
180 chip::Inet::InterfaceId interface)
182 for (size_t i = 0; i < mEndpointCount; i++)
184 EndpointInfo * info = &mEndpoints[i];
185 if (info->udp == nullptr)
190 if (info->addressType != addr.Type())
195 chip::Inet::InterfaceId boundIf = info->udp->GetBoundInterface();
197 if ((boundIf != INET_NULL_INTERFACEID) && (boundIf != interface))
202 return info->udp->SendTo(addr, port, std::move(data));
205 return CHIP_ERROR_NOT_CONNECTED;
208 CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle data, uint16_t port, chip::Inet::InterfaceId interface)
210 for (size_t i = 0; i < mEndpointCount; i++)
212 EndpointInfo * info = &mEndpoints[i];
214 if (info->udp == nullptr)
219 if ((info->udp->GetBoundInterface() != interface) && (info->udp->GetBoundInterface() != INET_NULL_INTERFACEID))
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();
231 if (info->addressType == chip::Inet::kIPAddressType_IPv6)
233 err = info->udp->SendTo(mIpv6BroadcastAddress, port, info->udp->GetBoundInterface(), std::move(copy));
235 #if INET_CONFIG_ENABLE_IPV4
236 else if (info->addressType == chip::Inet::kIPAddressType_IPv4)
238 err = info->udp->SendTo(mIpv4BroadcastAddress, port, info->udp->GetBoundInterface(), std::move(copy));
243 return CHIP_ERROR_INCORRECT_STATE;
246 if (err != CHIP_NO_ERROR)
252 return CHIP_NO_ERROR;
255 CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle data, uint16_t port)
257 for (size_t i = 0; i < mEndpointCount; i++)
259 EndpointInfo * info = &mEndpoints[i];
261 if (info->udp == nullptr)
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();
273 if (info->addressType == chip::Inet::kIPAddressType_IPv6)
275 err = info->udp->SendTo(mIpv6BroadcastAddress, port, info->udp->GetBoundInterface(), std::move(copy));
277 #if INET_CONFIG_ENABLE_IPV4
278 else if (info->addressType == chip::Inet::kIPAddressType_IPv4)
280 err = info->udp->SendTo(mIpv4BroadcastAddress, port, info->udp->GetBoundInterface(), std::move(copy));
285 return CHIP_ERROR_INCORRECT_STATE;
288 if (err == chip::System::MapErrorPOSIX(ENETUNREACH))
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.");
295 else if (err != CHIP_NO_ERROR)
301 return CHIP_NO_ERROR;
304 void ServerBase::OnUdpPacketReceived(chip::Inet::IPEndPointBasis * endPoint, chip::System::PacketBufferHandle buffer,
305 const chip::Inet::IPPacketInfo * info)
307 ServerBase * srv = static_cast<ServerBase *>(endPoint->AppState);
313 mdns::Minimal::BytesRange data(buffer->Start(), buffer->Start() + buffer->DataLength());
314 if (data.Size() < HeaderRef::kSizeBytes)
316 ChipLogError(Discovery, "Packet to small for mDNS data: %d bytes", static_cast<int>(data.Size()));
320 if (HeaderRef(const_cast<uint8_t *>(data.Start())).GetFlags().IsQuery())
322 srv->mDelegate->OnQuery(data, info);
326 srv->mDelegate->OnResponse(data, info);
330 } // namespace Minimal