1 /*
2  *  Copyright (c) 2020, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #ifndef SRP_CLIENT_HPP_
30 #define SRP_CLIENT_HPP_
31 
32 #include "openthread-core-config.h"
33 
34 #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
35 
36 #include <openthread/srp_client.h>
37 
38 #include "common/clearable.hpp"
39 #include "common/linked_list.hpp"
40 #include "common/locator.hpp"
41 #include "common/message.hpp"
42 #include "common/non_copyable.hpp"
43 #include "common/notifier.hpp"
44 #include "common/timer.hpp"
45 #include "crypto/ecdsa.hpp"
46 #include "net/dns_types.hpp"
47 #include "net/ip6.hpp"
48 #include "net/udp6.hpp"
49 
50 /**
51  * @file
52  *   This file includes definitions for the SRP (Service Registration Protocol) client.
53  */
54 
55 namespace ot {
56 namespace Srp {
57 
58 #if !OPENTHREAD_CONFIG_ECDSA_ENABLE
59 #error "SRP Client feature requires ECDSA support (OPENTHREAD_CONFIG_ECDSA_ENABLE)."
60 #endif
61 
62 /**
63  * This class implements SRP client.
64  *
65  */
66 class Client : public InstanceLocator, private NonCopyable
67 {
68     friend class ot::Notifier;
69 
70 public:
71     /**
72      * This enumeration types represents an SRP client item (service or host info) state.
73      *
74      */
75     enum ItemState : uint8_t
76     {
77         kToAdd      = OT_SRP_CLIENT_ITEM_STATE_TO_ADD,     ///< Item to be added/registered.
78         kAdding     = OT_SRP_CLIENT_ITEM_STATE_ADDING,     ///< Item is being added/registered.
79         kToRefresh  = OT_SRP_CLIENT_ITEM_STATE_TO_REFRESH, ///< Item to be refreshed (renew lease).
80         kRefreshing = OT_SRP_CLIENT_ITEM_STATE_REFRESHING, ///< Item is being refreshed.
81         kToRemove   = OT_SRP_CLIENT_ITEM_STATE_TO_REMOVE,  ///< Item to be removed.
82         kRemoving   = OT_SRP_CLIENT_ITEM_STATE_REMOVING,   ///< Item is being removed.
83         kRegistered = OT_SRP_CLIENT_ITEM_STATE_REGISTERED, ///< Item is registered with server.
84         kRemoved    = OT_SRP_CLIENT_ITEM_STATE_REMOVED,    ///< Item is removed.
85     };
86 
87     /**
88      * This function pointer type defines the callback used by SRP client to notify user of a changes/events/errors.
89      *
90      * Please see `otSrpClientCallback` for more details.
91      *
92      */
93     typedef otSrpClientCallback Callback;
94 
95     /**
96      * This type represents an SRP client host info.
97      *
98      */
99     class HostInfo : public otSrpClientHostInfo, public Clearable<HostInfo>
100     {
101         friend class Client;
102 
103     public:
104         /**
105          * This method initializes the `HostInfo` object.
106          *
107          */
108         void Init(void);
109 
110         /**
111          * This method clears the `HostInfo` object.
112          *
113          */
114         void Clear(void);
115 
116         /**
117          * This method gets the host name (label) string.
118          *
119          * @returns The host name (label) string, or nullptr if not yet set.
120          *
121          */
GetName(void) const122         const char *GetName(void) const { return mName; }
123 
124         /**
125          * This method gets the number of host IPv6 addresses.
126          *
127          * @returns The number of host IPv6 addresses.
128          *
129          */
GetNumAddresses(void) const130         uint8_t GetNumAddresses(void) const { return mNumAddresses; }
131 
132         /**
133          * This method gets the host IPv6 address at a given index.
134          *
135          * @param[in] aIndex  The index to get (MUST be smaller than `GetNumAddresses()`).
136          *
137          * @returns  The host IPv6 address at index @p aIndex.
138          *
139          */
GetAddress(uint8_t aIndex) const140         const Ip6::Address &GetAddress(uint8_t aIndex) const
141         {
142             return static_cast<const Ip6::Address &>(mAddresses[aIndex]);
143         }
144 
145         /**
146          * This method gets the state of `HostInfo`.
147          *
148          * @returns The `HostInfo` state.
149          *
150          */
GetState(void) const151         ItemState GetState(void) const { return static_cast<ItemState>(mState); }
152 
153     private:
SetName(const char * aName)154         void SetName(const char *aName) { mName = aName; }
155         void SetState(ItemState aState);
156         void SetAddresses(const Ip6::Address *aAddresses, uint8_t aNumAddresses);
157     };
158 
159     /**
160      * This type represents an SRP client service.
161      *
162      */
163     class Service : public otSrpClientService, public LinkedListEntry<Service>
164     {
165         friend class Client;
166         friend class LinkedList<Service>;
167 
168     public:
169         /**
170          * This method initializes and validates the `Service` object and its fields.
171          *
172          * @retval kErrorNone         Successfully initialized and validated the `Service` object.
173          * @retval kErrorInvalidArgs  The info in `Service` object is not valid (e.g. null name or bad `TxtEntry`).
174          *
175          */
176         Error Init(void);
177 
178         /**
179          * This method gets the service name labels string.
180          *
181          * @returns The service name label string (e.g., "_chip._udp", not the full domain name).
182          *
183          */
GetName(void) const184         const char *GetName(void) const { return mName; }
185 
186         /**
187          * This method gets the service instance name label (not the full name).
188          *
189          * @returns The service instance name label string.
190          *
191          */
GetInstanceName(void) const192         const char *GetInstanceName(void) const { return mInstanceName; }
193 
194         /**
195          * This method indicates whether or not the service has any subtypes.
196          *
197          * @retval TRUE   The service has at least one subtype.
198          * @retval FALSE  The service does not have any subtype.
199          *
200          */
HasSubType(void) const201         bool HasSubType(void) const { return (mSubTypeLabels != nullptr); }
202 
203         /**
204          * This method gets the subtype label at a given index.
205          *
206          * This method MUST be used only after `HasSubType()` indicates that service has a subtype.
207          *
208          * @param[in] aIndex  The index into list of subtype labels.
209          *
210          * @returns A pointer to subtype label at @p aIndex, or `nullptr` if there is no label (@p aIndex is after the
211          *          end of the subtype list).
212          *
213          */
GetSubTypeLabelAt(uint16_t aIndex) const214         const char *GetSubTypeLabelAt(uint16_t aIndex) const { return mSubTypeLabels[aIndex]; }
215 
216         /**
217          * This method gets the service port number.
218          *
219          * @returns The service port number.
220          *
221          */
GetPort(void) const222         uint16_t GetPort(void) const { return mPort; }
223 
224         /**
225          * This method gets the service priority.
226          *
227          * @returns The service priority.
228          *
229          */
GetPriority(void) const230         uint16_t GetPriority(void) const { return mPriority; }
231 
232         /**
233          * This method gets the service weight.
234          *
235          * @returns The service weight.
236          *
237          */
GetWeight(void) const238         uint16_t GetWeight(void) const { return mWeight; }
239 
240         /**
241          * This method gets the array of service TXT entries.
242          *
243          * @returns A pointer to an array of service TXT entries.
244          *
245          */
GetTxtEntries(void) const246         const Dns::TxtEntry *GetTxtEntries(void) const { return static_cast<const Dns::TxtEntry *>(mTxtEntries); }
247 
248         /**
249          * This method gets the number of entries in the service TXT entry array.
250          *
251          * @returns The number of entries in the service TXT entry array.
252          *
253          */
GetNumTxtEntries(void) const254         uint8_t GetNumTxtEntries(void) const { return mNumTxtEntries; }
255 
256         /**
257          * This method get the state of service.
258          *
259          * @returns The service state.
260          *
261          */
GetState(void) const262         ItemState GetState(void) const { return static_cast<ItemState>(mState); }
263 
264     private:
265         void      SetState(ItemState aState);
GetLeaseRenewTime(void) const266         TimeMilli GetLeaseRenewTime(void) const { return TimeMilli(mData); }
SetLeaseRenewTime(TimeMilli aTime)267         void      SetLeaseRenewTime(TimeMilli aTime) { mData = aTime.GetValue(); }
268         bool      Matches(const Service &aOther) const;
269     };
270 
271     /**
272      * This constructor initializes the SRP `Client` object.
273      *
274      * @param[in]  aInstance  A reference to the OpenThread instance.
275      *
276      */
277     explicit Client(Instance &aInstance);
278 
279     /**
280      * This method starts the SRP client operation.
281      *
282      * SRP client will prepare and send "SRP Update" message to the SRP server once all the following conditions are
283      * met:
284      *
285      *  - The SRP client is started - `Start()` is called
286      *  - Host name is set - `SetHostName()` is called.
287      *  - At least one host IPv6 address is set - `SetHostAddresses()` is called.
288      *  - At least one service is added - `AddService()` is called.
289      *
290      * It does not matter in which order these methods are called. When all conditions are met, the SRP client will
291      * wait for a short delay before preparing an "SRP Update" message and sending it to server. This delay allows for
292      * user to add multiple services and/or IPv6 addresses before the first SRP Update message is sent (ensuring a
293      * single SRP Update is sent containing all the info).
294      *
295      * @param[in] aServerSockAddr  The socket address (IPv6 address and port number) of the SRP server.
296      *
297      * @retval kErrorNone     SRP client operation started successfully or it is already running with same server
298      *                        socket address and callback.
299      * @retval kErrorBusy     SRP client is busy running with a different socket address.
300      * @retval kErrorFailed   Failed to open/connect the client's UDP socket.
301      *
302      */
Start(const Ip6::SockAddr & aServerSockAddr)303     Error Start(const Ip6::SockAddr &aServerSockAddr) { return Start(aServerSockAddr, kRequesterUser); }
304 
305     /**
306      * This method stops the SRP client operation.
307      *
308      * This method stops any further interactions with the SRP server. Note that it does not remove or clear host info
309      * and/or list of services. It marks all services to be added/removed again once the client is started again.
310      *
311      * If `OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE` (auto-start feature) is enabled, a call to this method
312      * also disables the auto-start mode.
313      *
314      */
Stop(void)315     void Stop(void) { Stop(kRequesterUser, kResetRetryInterval); }
316 
317 #if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
318     /**
319      * This function pointer type defines the callback used by SRP client to notify user when it is auto-started or
320      * stopped.
321      *
322      */
323     typedef otSrpClientAutoStartCallback AutoStartCallback;
324 
325     /**
326      * This method enables the auto-start mode.
327      *
328      * Config option `OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE` specifies the default auto-start mode
329      * (whether it is enabled or disabled at the start of OT stack).
330      *
331      * When auto-start is enabled, the SRP client will monitor the Thread Network Data for SRP Server Service entries
332      * and automatically start and stop the client when an SRP server is detected.
333      *
334      * If multiple SRP servers are found, a random one will be selected. If the selected SRP server is no longer
335      * detected (not longer present in the Thread Network Data), the SRP client will be stopped and then it may switch
336      * to another SRP server (if available).
337      *
338      * When the SRP client is explicitly started through a successful call to `Start()`, the given SRP server address
339      * in `Start()` will continue to be used regardless of the state of auto-start mode and whether the same SRP
340      * server address is discovered or not in the Thread Network Data. In this case, only an explicit `Stop()` call
341      * will stop the client.
342      *
343      * @param[in] aCallback   A callback to notify when client is auto-started/stopped. Can be `nullptr` if not needed.
344      * @param[in] aContext    A context to be passed when invoking @p aCallback.
345      *
346      */
347     void EnableAutoStartMode(AutoStartCallback aCallback, void *aContext);
348 
349     /**
350      * This method disables the auto-start mode.
351      *
352      * Disabling the auto-start mode will not stop the client if it is already running but the client stops monitoring
353      * the Thread Network Data to verify that the selected SRP server is still present in it.
354      *
355      * Note that a call to `Stop()` will also disable the auto-start mode.
356      *
357      */
DisableAutoStartMode(void)358     void DisableAutoStartMode(void) { mAutoStartModeEnabled = false; }
359 
360     /**
361      * This method indicates the current state of auto-start mode (enabled or disabled).
362      *
363      * @returns TRUE if the auto-start mode is enabled, FALSE otherwise.
364      *
365      */
IsAutoStartModeEnabled(void) const366     bool IsAutoStartModeEnabled(void) const { return mAutoStartModeEnabled; }
367 
368     /**
369      * This method indicates whether or not the current SRP server's address is selected by auto-start.
370      *
371      * @returns TRUE if the SRP server's address is selected by auto-start, FALSE otherwise.
372      *
373      */
IsServerSelectedByAutoStart(void) const374     bool IsServerSelectedByAutoStart(void) const { return mAutoStartDidSelectServer; }
375 #endif // OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
376 
377     /**
378      * This method indicates whether the SRP client is running or not.
379      *
380      * @returns TRUE if the SRP client is running, FALSE otherwise.
381      *
382      */
IsRunning(void) const383     bool IsRunning(void) const { return (mState != kStateStopped); }
384 
385     /**
386      * This method gets the socket address (IPv6 address and port number) of the SRP server which is being used by SRP
387      * client.
388      *
389      * If the client is not running, the address is unspecified (all zero) with zero port number.
390      *
391      * @returns The SRP server's socket address.
392      *
393      */
GetServerAddress(void) const394     const Ip6::SockAddr &GetServerAddress(void) const { return mSocket.GetPeerName(); }
395 
396     /**
397      * This method sets the callback used to notify caller of events/changes.
398      *
399      * The SRP client allows a single callback to be registered. So consecutive calls to this method will overwrite any
400      * previously set callback functions.
401      *
402      * @param[in] aCallback        The callback to notify of events and changes. Can be nullptr if not needed.
403      * @param[in] aContext         An arbitrary context used with @p aCallback.
404      *
405      */
406     void SetCallback(Callback aCallback, void *aContext);
407 
408     /**
409      * This method gets the lease interval used in SRP update requests.
410      *
411      * Note that this is lease duration that would be requested by the SRP client. Server may choose to accept a
412      * different lease interval.
413      *
414      * @returns The lease interval (in seconds).
415      *
416      */
GetLeaseInterval(void) const417     uint32_t GetLeaseInterval(void) const { return mLeaseInterval; }
418 
419     /**
420      * This method sets the lease interval used in SRP update requests.
421      *
422      * Changing the lease interval does not impact the accepted lease interval of already registered services/host-info.
423      * It only changes any future SRP update messages (i.e adding new services and/or refreshes of existing services).
424      *
425      * @param[in] The lease interval (in seconds). If zero, the default value `kDefaultLease` would be used.
426      *
427      */
SetLeaseInterval(uint32_t aInterval)428     void SetLeaseInterval(uint32_t aInterval) { mLeaseInterval = GetBoundedLeaseInterval(aInterval, kDefaultLease); }
429 
430     /**
431      * This method gets the key lease interval used in SRP update requests.
432      *
433      * @returns The key lease interval (in seconds).
434      *
435      */
GetKeyLeaseInterval(void) const436     uint32_t GetKeyLeaseInterval(void) const { return mKeyLeaseInterval; }
437 
438     /**
439      * This method sets the key lease interval used in SRP update requests.
440      *
441      * Changing the lease interval does not impact the accepted lease interval of already registered services/host-info.
442      * It only changes any future SRP update messages (i.e adding new services and/or refreshes of existing services).
443      *
444      * @param[in] The key lease interval (in seconds). If zero, the default value `kDefaultKeyLease` would be used.
445      *
446      */
SetKeyLeaseInterval(uint32_t aInterval)447     void SetKeyLeaseInterval(uint32_t aInterval)
448     {
449         mKeyLeaseInterval = GetBoundedLeaseInterval(aInterval, kDefaultKeyLease);
450     }
451 
452     /**
453      * This method gets the host info.
454      *
455      * @returns A reference to host info structure.
456      *
457      */
GetHostInfo(void) const458     const HostInfo &GetHostInfo(void) const { return mHostInfo; }
459 
460     /**
461      * This function sets the host name label.
462      *
463      * After a successful call to this function, `Callback` will be called to report the status of host info
464      *  registration with SRP server.
465      *
466      * The host name can be set before client is started or after start but before host info is registered with server
467      * (host info should be in either `kToAdd` or `kRemoved`).
468      *
469      * @param[in] aName       A pointer to host name label string (MUST NOT be NULL). Pointer the string buffer MUST
470      *                        persist and remain valid and constant after return from this function.
471      *
472      * @retval kErrorNone           The host name label was set successfully.
473      * @retval kErrorInvalidArgs    The @p aName is NULL.
474      * @retval kErrorInvalidState   The host name is already set and registered with the server.
475      *
476      */
477     Error SetHostName(const char *aName);
478 
479     /**
480      * This method sets/updates the list of host IPv6 address.
481      *
482      * Host IPv6 addresses can be set/changed before start or even during operation of SRP client (e.g. to add/remove
483      * or change a previously registered host address), except when the host info is being removed (client is busy
484      * handling a remove request from an earlier call to `RemoveHostAndServices()` and host info still being in either
485      * `kStateToRemove` or `kStateRemoving` states).
486      *
487      * After a successful call to this method, `Callback` will be called to report the status of the address
488      * registration with SRP server.
489      *
490      * @param[in] aAddresses          A pointer to the an array containing the host IPv6 addresses.
491      * @param[in] aNumAddresses       The number of addresses in the @p aAddresses array.
492      *
493      * @retval kErrorNone           The host IPv6 address list change started successfully. The `Callback` will be
494      *                              called to report the status of registering addresses with server.
495      * @retval kErrorInvalidArgs    The address list is invalid (e.g., must contain at least one address).
496      * @retval kErrorInvalidState   Host is being removed and therefore cannot change host address.
497      *
498      */
499     Error SetHostAddresses(const Ip6::Address *aAddresses, uint8_t aNumAddresses);
500 
501     /**
502      * This method adds a service to be registered with server.
503      *
504      * After a successful call to this method, `Callback` will be called to report the status of the service
505      * addition/registration with SRP server.
506      *
507      * @param[in] aService         A `Service` to add (the instance must persist and remain unchanged after
508      *                             successful return from this method).
509      *
510      * @retval kErrorNone          The addition of service started successfully. The `Callback` will be called to
511      *                             report the status.
512      * @retval kErrorAlready       A service with the same service and instance names is already in the list.
513      * @retval kErrorInvalidArgs   The service structure is invalid (e.g., bad service name or `TxEntry`).
514      *
515      */
516     Error AddService(Service &aService);
517 
518     /**
519      * This method removes a service to be unregistered with server.
520      *
521      * @param[in] aService         A `Service` to remove (the instance must persist and remain unchanged after
522      *                             successful return from this method).
523      *
524      * @retval kErrorNone      The removal of service started successfully. The `Callback` will be called to report
525      *                         the status.
526      * @retval kErrorNotFound  The service could not be found in the list.
527      *
528      */
529 
530     Error RemoveService(Service &aService);
531 
532     /**
533      * This method clears a service, immediately removing it from the client service list.
534      *
535      * Unlike `RemoveService()` which sends an update message to the server to remove the service, this method clears
536      * the service from the client's service list without any interaction with the server. On a successful call
537      * to this method, the `Callback` will NOT be called and the @p aService entry can be reclaimed and re-used by the
538      * caller immediately.
539      *
540      * @param[in] aService     A service to delete from the list.
541      *
542      * @retval kErrorNone      The @p aService is cleared successfully. It can be reclaimed and re-used immediately.
543      * @retval kErrorNotFound  The service could not be found in the list.
544      *
545      */
546     Error ClearService(Service &aService);
547 
548     /**
549      * This method gets the list of services being managed by client.
550      *
551      * @returns The list of services.
552      *
553      */
GetServices(void) const554     const LinkedList<Service> &GetServices(void) const { return mServices; }
555 
556     /**
557      * This method starts the remove process of the host info and all services.
558      *
559      * After returning from this method, `Callback` will be called to report the status of remove request with
560      * SRP server.
561      *
562      * If the host info is to be permanently removed from server, @p aRemoveKeyLease should be set to `true` which
563      * removes the key lease associated with host on server. Otherwise, the key lease record is kept as before, which
564      * ensures that the server holds the host name in reserve for when the client once again able to provide and
565      * register its service(s).
566      *
567      * The @p aSendUnregToServer determines the behavior when the host info is not yet registered with the server. If
568      * @p aSendUnregToServer is set to `false` (which is the default/expected value) then the SRP client will
569      * immediately remove the host info and services without sending an update message to server (no need to update the
570      * server if nothing is yet registered with it). If @p aSendUnregToServer is set to `true` then the SRP client will
571      * send an update message to the server. Note that if the host info is registered then the value of
572      * @p aSendUnregToServer does not matter and the SRP client will always send an update message to server requesting
573      * removal of all info.
574      *
575      * One situation where @p aSendUnregToServer can be useful is on a device reset/reboot, caller may want to remove
576      * any previously registered services with the server. In this case, caller can `SetHostName()` and then request
577      * `RemoveHostAndServices()` with `aSendUnregToServer` as `true`.
578      *
579      * @param[in] aRemoveKeyLease     A boolean indicating whether or not the host key lease should also be removed.
580      * @param[in] aSendUnregToServer   A boolean indicating whether to send update to server when host info is not
581      *                                registered.
582      *
583      * @retval kErrorNone      The removal of host and services started successfully. The `Callback` will be called
584      *                         to report the status.
585      * @retval kErrorAlready   The host is already removed.
586      *
587      */
588     Error RemoveHostAndServices(bool aShouldRemoveKeyLease, bool aSendUnregToServer = false);
589 
590     /**
591      * This method clears all host info and all the services.
592      *
593      * Unlike `RemoveHostAndServices()` which sends an update message to the server to remove all the info, this method
594      * clears all the info immediately without any interaction with the server.
595      *
596      */
597     void ClearHostAndServices(void);
598 
599 #if OPENTHREAD_CONFIG_SRP_CLIENT_DOMAIN_NAME_API_ENABLE
600     /**
601      * This method gets the domain name being used by SRP client.
602      *
603      * If domain name is not set, "default.service.arpa" will be used.
604      *
605      * @returns The domain name string.
606      *
607      */
GetDomainName(void) const608     const char *GetDomainName(void) const { return mDomainName; }
609 
610     /**
611      * This method sets the domain name to be used by SRP client.
612      *
613      * This is an optional method. If not set "default.service.arpa" will be used.
614      *
615      * The domain name can be set before client is started or after start but before host info is registered with server
616      * (host info should be in either `kToAdd` or `kToRemove`).
617      *
618      * @param[in] aName      A pointer to the domain name string. If NULL sets it to default "default.service.arpa".
619      *
620      * @retval kErrorNone           The domain name label was set successfully.
621      * @retval kErrorInvalidState   The host info is already registered with server.
622      *
623      */
624     Error SetDomainName(const char *aName);
625 #endif // OPENTHREAD_CONFIG_SRP_CLIENT_DOMAIN_NAME_API_ENABLE
626 
627     /**
628      * This static method converts a `ItemState` to a string.
629      *
630      * @param[in] aState   An `ItemState`.
631      *
632      * @returns A string representation of @p aState.
633      *
634      */
635     static const char *ItemStateToString(ItemState aState);
636 
637 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
638     /**
639      * This method enables/disables "service key record inclusion" mode.
640      *
641      * When enabled, SRP client will include KEY record in Service Description Instructions in the SRP update messages
642      * that it sends.
643      *
644      * @note KEY record is optional in Service Description Instruction (it is required and always included in the Host
645      * Description Instruction). The default behavior of SRP client is to not include it. This method is added under
646      * `REFERENCE_DEVICE` config and is intended to override the default behavior for testing only.
647      *
648      * @param[in] aEnabled   TRUE to enable, FALSE to disable the "service key record inclusion" mode.
649      *
650      */
SetServiceKeyRecordEnabled(bool aEnabled)651     void SetServiceKeyRecordEnabled(bool aEnabled) { mServiceKeyRecordEnabled = aEnabled; }
652 
653     /**
654      * This method indicates whether the "service key record inclusion" mode is enabled or disabled.
655      *
656      * @returns TRUE if "service key record inclusion" mode is enabled, FALSE otherwise.
657      *
658      */
IsServiceKeyRecordEnabled(void) const659     bool IsServiceKeyRecordEnabled(void) const { return mServiceKeyRecordEnabled; }
660 #endif // OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
661 
662 private:
663     // Number of fast data polls after SRP Update tx (11x 188ms = ~2 seconds)
664     static constexpr uint8_t kFastPollsAfterUpdateTx = 11;
665 
666 #if OPENTHREAD_CONFIG_SRP_CLIENT_SWITCH_SERVER_ON_FAILURE
667     static constexpr uint8_t kMaxTimeoutFailuresToSwitchServer =
668         OPENTHREAD_CONFIG_SRP_CLIENT_MAX_TIMEOUT_FAILURES_TO_SWITCH_SERVER;
669 #endif
670 
671     static constexpr uint16_t kUdpPayloadSize = Ip6::Ip6::kMaxDatagramLength - sizeof(Ip6::Udp::Header);
672 
673     // -------------------------------
674     // Lease related constants
675 
676     static constexpr uint32_t kDefaultLease    = OPENTHREAD_CONFIG_SRP_CLIENT_DEFAULT_LEASE;     // in seconds.
677     static constexpr uint32_t kDefaultKeyLease = OPENTHREAD_CONFIG_SRP_CLIENT_DEFAULT_KEY_LEASE; // in seconds.
678 
679     // The guard interval determines how much earlier (relative to
680     // the lease expiration time) the client will send an update
681     // to renew the lease. Value is in seconds.
682     static constexpr uint32_t kLeaseRenewGuardInterval = OPENTHREAD_CONFIG_SRP_CLIENT_LEASE_RENEW_GUARD_INTERVAL;
683 
684     // Max allowed lease time to avoid timer roll-over (~24.8 days).
685     static constexpr uint32_t kMaxLease = (Timer::kMaxDelay / 1000) - 1;
686 
687     // Opportunistic early refresh: When sending an SRP update, the
688     // services that are not yet expired but are close, are allowed
689     // to refresh early and are included in the SRP update. This
690     // helps place more services on the same lease refresh schedule
691     // reducing number of messages sent to the SRP server. The
692     // "early lease renewal interval" is used to determine if a
693     // service can renew early. The interval is calculated by
694     // multiplying the accepted lease interval by the"early lease
695     // renewal factor" which is given as a fraction (numerator and
696     // denominator).
697     //
698     // If the factor is set to zero (numerator=0, denominator=1),
699     // the opportunistic early refresh behavior is disabled. If
700     // denominator is set to zero (the factor is set to infinity),
701     // then all services (including previously registered ones)
702     // are always included in SRP update message.
703 
704     static constexpr uint32_t kEarlyLeaseRenewFactorNumerator =
705         OPENTHREAD_CONFIG_SRP_CLIENT_EARLY_LEASE_RENEW_FACTOR_NUMERATOR;
706     static constexpr uint32_t kEarlyLeaseRenewFactorDenominator =
707         OPENTHREAD_CONFIG_SRP_CLIENT_EARLY_LEASE_RENEW_FACTOR_DENOMINATOR;
708 
709     // -------------------------------
710     // When there is a change (e.g., a new service is added/removed)
711     // that requires an update, the SRP client will wait for a short
712     // delay as specified by `kUpdateTxDelay` before sending an SRP
713     // update to server. This allows the user to provide more change
714     // that are then all sent in same update message.
715     static constexpr uint32_t kUpdateTxDelay = OPENTHREAD_CONFIG_SRP_CLIENT_UPDATE_TX_DELAY; // in msec.
716 
717     // -------------------------------
718     // Retry related constants
719     //
720     // If the preparation or transmission of an SRP update message
721     // fails (e.g., no buffer to allocate the message), SRP client
722     // will retry after a short interval `kTxFailureRetryInterval`
723     // up to `kMaxTxFailureRetries` attempts. After this, the retry
724     // wait interval will be used (which keeps growing on each failure
725     // - please see bellow).
726     //
727     // If the update message is sent successfully but there is no
728     // response from server or if server rejects the update, the
729     // client will retransmit the update message after some wait
730     // interval. The wait interval starts from the minimum value and
731     // is increased by the growth factor on back-to-back failures up
732     // to the max value. The growth factor is given as a fraction
733     // (e.g., for 1.5, we can use 15 as the numerator and 10 as the
734     // denominator). A random jitter is added to the retry interval.
735     // If the current wait interval value is smaller than the jitter
736     // interval, then wait interval value itself is used as the
737     // jitter value. For example, with jitter interval of 2 seconds
738     // if the current retry interval is 800ms, then a random wait
739     // interval in [0,2*800] ms will be used.
740 
741     static constexpr uint32_t kTxFailureRetryInterval = 250; // in ms
742     static constexpr uint32_t kMaxTxFailureRetries    = 8;   // num of quick retries after tx failure
743     static constexpr uint32_t kMinRetryWaitInterval   = OPENTHREAD_CONFIG_SRP_CLIENT_MIN_RETRY_WAIT_INTERVAL; // in ms
744     static constexpr uint32_t kMaxRetryWaitInterval   = OPENTHREAD_CONFIG_SRP_CLIENT_MAX_RETRY_WAIT_INTERVAL; // in ms
745     static constexpr uint32_t kRetryIntervalGrowthFactorNumerator =
746         OPENTHREAD_CONFIG_SRP_CLIENT_RETRY_INTERVAL_GROWTH_FACTOR_NUMERATOR;
747     static constexpr uint32_t kRetryIntervalGrowthFactorDenominator =
748         OPENTHREAD_CONFIG_SRP_CLIENT_RETRY_INTERVAL_GROWTH_FACTOR_DENOMINATOR;
749 
750     static constexpr uint16_t kTxFailureRetryJitter = 10;                                                      // in ms
751     static constexpr uint16_t kRetryIntervalJitter  = OPENTHREAD_CONFIG_SRP_CLIENT_RETRY_WAIT_INTERVAL_JITTER; // in ms
752 
753     static_assert(kDefaultLease <= static_cast<uint32_t>(kMaxLease), "kDefaultLease is larger than max");
754     static_assert(kDefaultKeyLease <= static_cast<uint32_t>(kMaxLease), "kDefaultKeyLease is larger than max");
755 
756     enum State : uint8_t
757     {
758         kStateStopped,  // Client is stopped.
759         kStatePaused,   // Client is paused (due to device being detached).
760         kStateToUpdate, // Waiting to send SRP update
761         kStateUpdating, // SRP update is sent, waiting for response from server.
762         kStateUpdated,  // SRP update response received from server.
763         kStateToRetry,  // SRP update tx failed, waiting to retry.
764     };
765 
766     static constexpr bool kAutoStartDefaultMode = OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE;
767     static constexpr bool kDisallowSwitchOnRegisteredHost =
768         OPENTHREAD_CONFIG_SRP_CLIENT_DISALLOW_SERVER_SWITCH_WITH_REGISTERED_HOST;
769 
770     // Port number to use when server is discovered using "network data anycast service".
771     static constexpr uint16_t kAnycastServerPort = 53;
772 
773     // This enumeration type is used by the private `Start()` and
774     // `Stop()` methods to indicate whether it is being requested by the
775     // user or by the auto-start feature.
776     enum Requester : uint8_t
777     {
778         kRequesterUser,
779 #if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
780         kRequesterAuto,
781 #endif
782     };
783 
784     // This enumeration is used as an input to private `Stop()` to
785     // indicate whether to reset the retry interval or keep it as is.
786     enum StopMode : uint8_t
787     {
788         kResetRetryInterval,
789         kKeepRetryInterval,
790     };
791 
792     struct Info : public Clearable<Info>
793     {
794         static constexpr uint16_t kUnknownOffset = 0; // Unknown offset value (used when offset is not yet set).
795 
796         uint16_t                     mDomainNameOffset; // Offset of domain name serialization
797         uint16_t                     mHostNameOffset;   // Offset of host name serialization.
798         uint16_t                     mRecordCount;      // Number of resource records in Update section.
799         Crypto::Ecdsa::P256::KeyPair mKeyPair;          // The ECDSA key pair.
800     };
801 
802     Error        Start(const Ip6::SockAddr &aServerSockAddr, Requester aRequester);
803     void         Stop(Requester aRequester, StopMode aMode);
804     void         Resume(void);
805     void         Pause(void);
806     void         HandleNotifierEvents(Events aEvents);
807     void         HandleRoleChanged(void);
808     void         UpdateServiceStateToRemove(Service &aService);
GetState(void) const809     State        GetState(void) const { return mState; }
810     void         SetState(State aState);
811     void         ChangeHostAndServiceStates(const ItemState *aNewStates);
812     void         InvokeCallback(Error aError) const;
813     void         InvokeCallback(Error aError, const HostInfo &aHostInfo, const Service *aRemovedServices) const;
814     void         HandleHostInfoOrServiceChange(void);
815     void         SendUpdate(void);
816     Error        PrepareUpdateMessage(Message &aMessage);
817     Error        ReadOrGenerateKey(Crypto::Ecdsa::P256::KeyPair &aKeyPair);
818     Error        AppendServiceInstructions(Service &aService, Message &aMessage, Info &aInfo);
819     Error        AppendHostDescriptionInstruction(Message &aMessage, Info &aInfo) const;
820     Error        AppendKeyRecord(Message &aMessage, Info &aInfo) const;
821     Error        AppendDeleteAllRrsets(Message &aMessage) const;
822     Error        AppendHostName(Message &aMessage, Info &aInfo, bool aDoNotCompress = false) const;
823     Error        AppendUpdateLeaseOptRecord(Message &aMessage) const;
824     Error        AppendSignature(Message &aMessage, Info &aInfo);
825     void         UpdateRecordLengthInMessage(Dns::ResourceRecord &aRecord, uint16_t aOffset, Message &aMessage) const;
826     static void  HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
827     void         ProcessResponse(Message &aMessage);
828     void         HandleUpdateDone(void);
829     void         GetRemovedServices(LinkedList<Service> &aRemovedServices);
830     static Error ReadResourceRecord(const Message &aMessage, uint16_t &aOffset, Dns::ResourceRecord &aRecord);
831     Error        ProcessOptRecord(const Message &aMessage, uint16_t aOffset, const Dns::OptRecord &aOptRecord);
832     void         UpdateState(void);
GetRetryWaitInterval(void) const833     uint32_t     GetRetryWaitInterval(void) const { return mRetryWaitInterval; }
ResetRetryWaitInterval(void)834     void         ResetRetryWaitInterval(void) { mRetryWaitInterval = kMinRetryWaitInterval; }
835     void         GrowRetryWaitInterval(void);
836     uint32_t     GetBoundedLeaseInterval(uint32_t aInterval, uint32_t aDefaultInterval) const;
837     bool         ShouldRenewEarly(const Service &aService) const;
838     static void  HandleTimer(Timer &aTimer);
839     void         HandleTimer(void);
840 #if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
841     void ProcessAutoStart(void);
842 #if OPENTHREAD_CONFIG_SRP_CLIENT_SWITCH_SERVER_ON_FAILURE
843     void SelectNextServer(bool aDisallowSwitchOnRegisteredHost);
844 #endif
845 #endif
846 
847 #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_SRP == 1)
848     static const char *StateToString(State aState);
849     void               LogRetryWaitInterval(void) const;
850 #else
LogRetryWaitInterval(void) const851     void LogRetryWaitInterval(void) const {}
852 #endif
853 
854     static const char kDefaultDomainName[];
855 
856     static_assert(kMaxTxFailureRetries < 16, "kMaxTxFailureRetries exceed the range of mTxFailureRetryCount (4-bit)");
857 
858     State   mState;
859     uint8_t mTxFailureRetryCount : 4;
860     bool    mShouldRemoveKeyLease : 1;
861 #if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
862     bool mAutoStartModeEnabled : 1;
863     bool mAutoStartDidSelectServer : 1;
864     bool mAutoStartIsUsingAnycastAddress : 1;
865 #endif
866 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
867     bool mServiceKeyRecordEnabled : 1;
868 #endif
869 
870     uint16_t mUpdateMessageId;
871     uint32_t mRetryWaitInterval;
872 
873     TimeMilli mLeaseRenewTime;
874     uint32_t  mAcceptedLeaseInterval;
875     uint32_t  mLeaseInterval;
876     uint32_t  mKeyLeaseInterval;
877 
878     Ip6::Udp::Socket mSocket;
879 
880     Callback mCallback;
881     void *   mCallbackContext;
882 
883 #if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
884     AutoStartCallback mAutoStartCallback;
885     void *            mAutoStartContext;
886     uint8_t           mServerSequenceNumber;
887 #if OPENTHREAD_CONFIG_SRP_CLIENT_SWITCH_SERVER_ON_FAILURE
888     uint8_t mTimoutFailureCount;
889 #endif
890 #endif
891 
892     const char *        mDomainName;
893     HostInfo            mHostInfo;
894     LinkedList<Service> mServices;
895     TimerMilli          mTimer;
896 };
897 
898 } // namespace Srp
899 } // namespace ot
900 
901 #endif // OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
902 
903 #endif // SRP_CLIENT_HPP_
904