Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2025 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 : #pragma once
19 :
20 : #include <minmdns/MinMdnsConfig.h>
21 :
22 : #include <inet/IPAddress.h>
23 : #include <inet/InetInterface.h>
24 : #include <inet/UDPEndPoint.h>
25 : #include <lib/core/CHIPError.h>
26 : #include <lib/support/PoolWrapper.h>
27 :
28 : #include <lib/dnssd/minimal_mdns/ListenIterator.h>
29 : #include <lib/dnssd/minimal_mdns/core/BytesRange.h>
30 :
31 : namespace mdns {
32 : namespace Minimal {
33 :
34 : namespace BroadcastIpAddresses {
35 :
36 : // Get standard mDNS Broadcast addresses
37 : chip::Inet::IPAddress Get(chip::Inet::IPAddressType addressType);
38 :
39 : } // namespace BroadcastIpAddresses
40 :
41 : /// Handles mDNS Server Callbacks
42 : class ServerDelegate
43 : {
44 : public:
45 97 : virtual ~ServerDelegate() {}
46 :
47 : // Callback of when a query is received
48 : virtual void OnQuery(const BytesRange & data, const chip::Inet::IPPacketInfo * info) = 0;
49 :
50 : // Callback of when a response is received
51 : virtual void OnResponse(const BytesRange & data, const chip::Inet::IPPacketInfo * info) = 0;
52 : };
53 :
54 : // Defines an mDNS server that listens on one or more interfaces.
55 : //
56 : // I can send and receive mDNS packets (requests/replies)
57 : class ServerBase
58 : {
59 : public:
60 : class EndpointInfo
61 : {
62 : public:
63 : #if CHIP_MINMDNS_USE_EPHEMERAL_UNICAST_PORT
64 34 : EndpointInfo(chip::Inet::InterfaceId interfaceId, chip::Inet::IPAddressType addressType,
65 34 : chip::Inet::UDPEndPointHandle && listenUdp, chip::Inet::UDPEndPointHandle && unicastQueryUdp) :
66 34 : mInterfaceId(interfaceId),
67 34 : mAddressType(addressType), mListenUdp(listenUdp), mUnicastQueryUdp(unicastQueryUdp)
68 34 : {}
69 : #else
70 : EndpointInfo(chip::Inet::InterfaceId interfaceId, chip::Inet::IPAddressType addressType,
71 : chip::Inet::UDPEndPointHandle && listenUdp) :
72 : mInterfaceId(interfaceId),
73 : mAddressType(addressType), mListenUdp(listenUdp)
74 : {}
75 : #endif
76 :
77 : const chip::Inet::InterfaceId mInterfaceId;
78 : const chip::Inet::IPAddressType mAddressType;
79 : chip::Inet::UDPEndPointHandle mListenUdp;
80 : #if CHIP_MINMDNS_USE_EPHEMERAL_UNICAST_PORT
81 : chip::Inet::UDPEndPointHandle mUnicastQueryUdp;
82 : #endif
83 : };
84 :
85 : /**
86 : * Helps implement a generic broadcast implementation:
87 : * - provides the ability to determine what udp endpoint to use to broadcast
88 : * a packet for the given endpoint info
89 : */
90 : class BroadcastSendDelegate
91 : {
92 : public:
93 156 : virtual ~BroadcastSendDelegate() = default;
94 :
95 : /**
96 : * Returns non-null UDPEndpoint IFF a broadcast should be performed for the given EndpointInfo
97 : */
98 : virtual chip::Inet::UDPEndPointHandle Accept(ServerBase::EndpointInfo * info) = 0;
99 : };
100 :
101 : #if CHIP_MINMDNS_USE_EPHEMERAL_UNICAST_PORT
102 : using EndpointInfoPoolType = chip::PoolInterface<EndpointInfo, chip::Inet::InterfaceId, chip::Inet::IPAddressType,
103 : chip::Inet::UDPEndPointHandle, chip::Inet::UDPEndPointHandle>;
104 : #else
105 : using EndpointInfoPoolType =
106 : chip::PoolInterface<EndpointInfo, chip::Inet::InterfaceId, chip::Inet::IPAddressType, chip::Inet::UDPEndPointHandle>;
107 : #endif
108 :
109 109 : ServerBase(EndpointInfoPoolType & pool) : mEndpoints(pool)
110 : {
111 109 : mIpv6BroadcastAddress = BroadcastIpAddresses::Get(chip::Inet::IPAddressType::kIPv6);
112 : #if INET_CONFIG_ENABLE_IPV4
113 109 : mIpv4BroadcastAddress = BroadcastIpAddresses::Get(chip::Inet::IPAddressType::kIPv4);
114 : #endif
115 109 : }
116 : virtual ~ServerBase();
117 :
118 : /// Closes all currently open endpoints and resets the 'initialized' flag
119 : void Shutdown();
120 :
121 : void ShutdownEndpoints();
122 : void ShutdownEndpoint(EndpointInfo & aEndpoint);
123 :
124 : /// Listen on the given interfaces/address types.
125 : ///
126 : /// Since mDNS uses link-local addresses, one generally wants to listen on all
127 : /// non-loopback interfaces.
128 : CHIP_ERROR Listen(chip::Inet::EndPointManager<chip::Inet::UDPEndPoint> * udpEndPointManager, ListenIterator * it,
129 : uint16_t port);
130 :
131 : /// Send the specified packet to a destination IP address over the specified address
132 : virtual CHIP_ERROR DirectSend(chip::System::PacketBufferHandle && data, const chip::Inet::IPAddress & addr, uint16_t port,
133 : chip::Inet::InterfaceId interface);
134 :
135 : /// Send out a broadcast query, may use an ephemeral port to receive replies.
136 : /// Ephemeral ports will make replies be marked as 'LEGACY' and replies will include a query secion.
137 : virtual CHIP_ERROR BroadcastUnicastQuery(chip::System::PacketBufferHandle && data, uint16_t port);
138 :
139 : /// Send a specific packet broadcast to a specific interface using a specific address type
140 : /// May use an ephemeral port to receive replies.
141 : /// Ephemeral ports will make replies be marked as 'LEGACY' and replies will include a query secion.
142 : virtual CHIP_ERROR BroadcastUnicastQuery(chip::System::PacketBufferHandle && data, uint16_t port,
143 : chip::Inet::InterfaceId interface, chip::Inet::IPAddressType addressType);
144 :
145 : /// Send a specific packet broadcast to all interfaces
146 : virtual CHIP_ERROR BroadcastSend(chip::System::PacketBufferHandle && data, uint16_t port);
147 :
148 : /// Send a specific packet broadcast to a specific interface using a specific address type
149 : virtual CHIP_ERROR BroadcastSend(chip::System::PacketBufferHandle && data, uint16_t port, chip::Inet::InterfaceId interface,
150 : chip::Inet::IPAddressType addressType);
151 :
152 97 : ServerBase & SetDelegate(ServerDelegate * d)
153 : {
154 97 : mDelegate = d;
155 97 : return *this;
156 : }
157 :
158 : /// A server is considered listening if any UDP endpoint is active.
159 : ///
160 : /// This is expected to return false after any Shutdown() and will
161 : /// return true IFF lListen was called and the listen iterator successfully
162 : /// found a valid listening interface.
163 : bool IsListening() const;
164 :
165 : private:
166 : CHIP_ERROR BroadcastImpl(chip::System::PacketBufferHandle && data, uint16_t port, BroadcastSendDelegate * delegate);
167 :
168 : static void OnUdpPacketReceived(chip::Inet::UDPEndPoint * endPoint, chip::System::PacketBufferHandle && buffer,
169 : const chip::Inet::IPPacketInfo * info);
170 :
171 : EndpointInfoPoolType & mEndpoints; // possible endpoints, to listen on multiple interfaces
172 : ServerDelegate * mDelegate = nullptr;
173 :
174 : // Broadcast IP addresses are cached to not require a string parse every time
175 : // Ideally we should be able to constexpr these
176 : chip::Inet::IPAddress mIpv6BroadcastAddress;
177 : #if INET_CONFIG_ENABLE_IPV4
178 : chip::Inet::IPAddress mIpv4BroadcastAddress;
179 : #endif
180 : bool mIsInitialized = false;
181 : };
182 :
183 : // The PoolImpl impl is used as a base class because its destructor must be called after ServerBase's destructor.
184 : template <size_t kCount>
185 : class Server : private chip::PoolImpl<ServerBase::EndpointInfo, kCount, chip::ObjectPoolMem::kInline,
186 : ServerBase::EndpointInfoPoolType::Interface>,
187 : public ServerBase
188 : {
189 : public:
190 97 : Server() : ServerBase(*static_cast<ServerBase::EndpointInfoPoolType *>(this)) {}
191 97 : ~Server() override {}
192 : };
193 :
194 : } // namespace Minimal
195 : } // namespace mdns
|