forked from project-chip/connectedhomeip
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAddressResolve.h
275 lines (240 loc) · 10.8 KB
/
AddressResolve.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
/*
*
* Copyright (c) 2022 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <lib/core/PeerId.h>
#include <lib/support/IntrusiveList.h>
#include <messaging/ReliableMessageProtocolConfig.h>
#include <system/SystemClock.h>
#include <system/SystemLayer.h>
#include <transport/raw/PeerAddress.h>
namespace chip {
namespace AddressResolve {
/// Contains resolve information received from nodes. Contains all information
/// bits that are considered useful but does not contain a full DNSSD data
/// structure since not all DNSSD data is useful during operational processing.
struct ResolveResult
{
Transport::PeerAddress address;
ReliableMessageProtocolConfig mrpRemoteConfig;
bool supportsTcp = false;
bool isICDOperatingAsLIT = false;
ResolveResult() : address(Transport::Type::kUdp), mrpRemoteConfig(GetDefaultMRPConfig()) {}
};
/// Represents an object interested in callbacks for a resolve operation.
class NodeListener
{
public:
NodeListener() = default;
virtual ~NodeListener() = default;
/// Callback executed once only for a lookup, when the final address of a
/// node is considered to be the best choice for reachability.
///
/// The callback is expected to be executed within the CHIP event loop
/// thread.
virtual void OnNodeAddressResolved(const PeerId & peerId, const ResolveResult & result) = 0;
/// Node resolution failure - occurs only once for a lookup, when an address
/// could not be resolved - generally due to a timeout or due to DNSSD
/// infrastructure returning an error.
///
/// The callback is expected to be executed within the CHIP event loop
/// thread.
virtual void OnNodeAddressResolutionFailed(const PeerId & peerId, CHIP_ERROR reason) = 0;
};
/// Represents an active Address resolution lookup.
///
/// Implementations extend this class with implementation-specific data like
/// storing the 'last known good address' and 'scores' or any additional data
/// required to figure out when a resolve is ok.
class NodeLookupHandleBase : public IntrusiveListNodeBase<>
{
public:
NodeLookupHandleBase() {}
virtual ~NodeLookupHandleBase() {}
// While active, resolve handles are maintained in an internal list
// to be processed, so copying their values (i.e. pointers) is not
// allowed.
NodeLookupHandleBase(const NodeLookupHandleBase &) = delete;
NodeLookupHandleBase & operator=(const NodeLookupHandleBase &) = delete;
void SetListener(NodeListener * listener) { mListener = listener; }
NodeListener * GetListener() { return mListener; }
/// Convenience method that is more readable than 'IsInList'
inline bool IsActive() const { return IntrusiveListNodeBase::IsInList(); }
protected:
NodeListener * mListener = nullptr;
};
/// Represents a request to perform a single node lookup
/// Contains all the information that should be looked for as well as
/// extra timeout configurations.
class NodeLookupRequest
{
public:
NodeLookupRequest() {}
NodeLookupRequest(const PeerId & peerId) : mPeerId(peerId) {}
NodeLookupRequest(const NodeLookupRequest &) = default;
NodeLookupRequest & operator=(const NodeLookupRequest &) = default;
const PeerId & GetPeerId() const { return mPeerId; }
System::Clock::Milliseconds32 GetMinLookupTime() const { return mMinLookupTimeMs; }
System::Clock::Milliseconds32 GetMaxLookupTime() const { return mMaxLookupTimeMs; }
/// The minimum lookup time is how much to wait for additional DNSSD
/// queries even if a reply has already been received or to allow for
/// additional heuristics regarding node choice to succeed.
/// Example heuristics and considerations:
/// - ping/ping6 could be used as an indicator of reachability. NOTE that
/// not all devices may respond to ping, so this would only be an
/// additional signal to accept/increase suitability score of an address
/// and should NOT be used as a reject if no ping response
/// - At lookup time, if the source ip of a dns reply is contained in the
/// list of server ips, that is a great indication of routability and
/// this minlookuptime could be bypassed altogether.
///
/// Implementations for DNSSD may choose to return responses one by one
/// for addresses (e.g. Platform mdns does this at the time this was written)
/// or different interfaces will return separate 'done resolving' calls.
///
/// If the min lookup time is set to 0, implementations are expected to call
/// 'OnNodeAddressResolved' as soon as the first DNSSD response is received.
NodeLookupRequest & SetMinLookupTime(System::Clock::Milliseconds32 value)
{
mMinLookupTimeMs = value;
return *this;
}
/// The maximum lookup time is how much to wait until a TIMEOUT error is
/// declared.
///
/// If a DNSSD response is received before this max timeout, then
/// OnNodeAddressResolved will be called on listener objects (immediately)
/// if the first DNSSD reply arrives after MinLookupTimeMs has expired.
NodeLookupRequest & SetMaxLookupTime(System::Clock::Milliseconds32 value)
{
mMaxLookupTimeMs = value;
return *this;
}
private:
static constexpr uint32_t kMinLookupTimeMsDefault = 200;
static constexpr uint32_t kMaxLookupTimeMsDefault = 45000;
PeerId mPeerId;
System::Clock::Milliseconds32 mMinLookupTimeMs{ kMinLookupTimeMsDefault };
System::Clock::Milliseconds32 mMaxLookupTimeMs{ kMaxLookupTimeMsDefault };
};
/// These things are expected to be defined by the implementation header.
namespace Impl {
// The NodeLookup handle is a CONCRETE implementation that
// MUST derive from NodeLookupHandleBase
//
// The underlying reason is that this handle is used to hold memory for
// lookup metadata, so that resolvers do not need to maintain a likely unused
// pool of 'active lookup' metadata.
//
// The side-effect of this is that the Impl::NodeLookupHandle is exposed to
// clients for sizeof() memory purposes.
//
// Clients MUST only use the interface in NodeLookupHandleBase and assume all
// other methods/content is implementation defined.
class NodeLookupHandle;
} // namespace Impl
class Resolver
{
public:
/// Enumeration defining how to handle cancel callbacks during operation
/// cancellation.
enum class FailureCallback
{
Call, // Call the failure callback
Skip // do not call the failure callback (generally silent operation)
};
virtual ~Resolver();
/// Expected to be called at least once before the resolver is ever
/// used.
///
/// Expected to override global setting of DNSSD callback for addres resolution
/// and may use the underlying system layer for timers and other functionality.
///
/// If called multiple times, it is expected that the input systemLayer does
/// not change.
virtual CHIP_ERROR Init(System::Layer * systemLayer) = 0;
/// Initiate a node lookup for a particular node and use the specified
/// Lookup handle to keep track of node resolution
///
/// If this returns CHIP_NO_ERROR, the following is expected:
/// - exactly one of the listener OnNodeAddressResolved
/// or OnNodeAddressResolutionFailed will be called at a later time
/// - handle must NOT be destroyed while the lookup is in progress (it
/// is part of an internal 'lookup list')
/// - handle must NOT be reused (the lookup is done on a per-node basis
/// and maintains lookup data internally while the operation is still
/// in progress)
virtual CHIP_ERROR LookupNode(const NodeLookupRequest & request, Impl::NodeLookupHandle & handle) = 0;
/// Inform the Lookup handle that the previous node lookup was not
/// sufficient for the purpose of the caller (e.g establishing a session
/// fails with the result of the previous lookup), and that more data is
/// needed.
///
/// This method must be called on a handle that is no longer active to
/// succeed.
///
/// If the handle is no longer active and has results that have not been
/// delivered to the listener yet, the listener's OnNodeAddressResolved will
/// be called synchronously before the method returns. Note that depending
/// on the listener implementation this can end up destroying the handle
/// and/or the listener.
///
/// This method will return CHIP_NO_ERROR if and only if it has called
/// OnNodeAddressResolved.
///
/// This method will return CHIP_ERROR_INCORRECT_STATE if the handle is
/// still active.
///
/// This method will return CHIP_ERROR_NOT_FOUND if there are no more
/// results.
///
/// This method may return other errors in some cases.
virtual CHIP_ERROR TryNextResult(Impl::NodeLookupHandle & handle) = 0;
/// Stops an active lookup request.
///
/// Caller controlls weather the `fail` callback of the handle is invoked or not by using
/// the `cancel_method` argument.
///
/// Note that there is no default cancel_method on purpose, so that the caller has to make
/// a clear decision if the callback should or should not be invoked.
virtual CHIP_ERROR CancelLookup(Impl::NodeLookupHandle & handle, FailureCallback cancel_method) = 0;
/// Shut down any active resolves
///
/// Will immediately fail any scheduled resolve calls and will refuse to register
/// any new lookups until re-initialized.
virtual void Shutdown() = 0;
/// Expected to be provided by the implementation.
static Resolver & Instance();
};
} // namespace AddressResolve
} // namespace chip
// Include the required platform header for the actual implementation, if defined.
// Otherwise assume the default implementation is being used.
// Expectations of this include:
// - define the `Impl::NodeLookupHandle` deriving from NodeLookupHandleBase
// - corresponding CPP file should provide a valid Resolver::Instance()
// implementation
#ifdef CHIP_ADDRESS_RESOLVE_IMPL_INCLUDE_HEADER
#include CHIP_ADDRESS_RESOLVE_IMPL_INCLUDE_HEADER
#else
#include <lib/address_resolve/AddressResolve_DefaultImpl.h>
#endif
namespace chip {
namespace AddressResolve {
// Make the code easy to read: do not reach into Impl.
using NodeLookupHandle = Impl::NodeLookupHandle;
} // namespace AddressResolve
} // namespace chip