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