/*
 *  Copyright (c) 2020, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the copyright holder nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file
 * @brief
 *  This file defines the OpenThread SRP (Service Registration Protocol) client APIs.
 */

#ifndef OPENTHREAD_SRP_CLIENT_H_
#define OPENTHREAD_SRP_CLIENT_H_

#include <stdbool.h>
#include <stdint.h>

#include <openthread/dns.h>
#include <openthread/error.h>
#include <openthread/instance.h>
#include <openthread/ip6.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @addtogroup api-srp
 *
 * @brief
 *   This module includes functions that control SRP client behavior.
 *
 * @{
 */

/**
 * Specifies an SRP client item (service or host info) state.
 */
typedef enum
{
    OT_SRP_CLIENT_ITEM_STATE_TO_ADD,     ///< Item to be added/registered.
    OT_SRP_CLIENT_ITEM_STATE_ADDING,     ///< Item is being added/registered.
    OT_SRP_CLIENT_ITEM_STATE_TO_REFRESH, ///< Item to be refreshed (re-register to renew lease).
    OT_SRP_CLIENT_ITEM_STATE_REFRESHING, ///< Item is being refreshed.
    OT_SRP_CLIENT_ITEM_STATE_TO_REMOVE,  ///< Item to be removed.
    OT_SRP_CLIENT_ITEM_STATE_REMOVING,   ///< Item is being removed.
    OT_SRP_CLIENT_ITEM_STATE_REGISTERED, ///< Item is registered with server.
    OT_SRP_CLIENT_ITEM_STATE_REMOVED,    ///< Item is removed.
} otSrpClientItemState;

/**
 * Represents an SRP client host info.
 */
typedef struct otSrpClientHostInfo
{
    const char          *mName;         ///< Host name (label) string (NULL if not yet set).
    const otIp6Address  *mAddresses;    ///< Array of host IPv6 addresses (NULL if not set or auto address is enabled).
    uint8_t              mNumAddresses; ///< Number of IPv6 addresses in `mAddresses` array.
    bool                 mAutoAddress;  ///< Indicates whether auto address mode is enabled or not.
    otSrpClientItemState mState;        ///< Host info state.
} otSrpClientHostInfo;

/**
 * Represents an SRP client service.
 *
 * The values in this structure, including the string buffers for the names and the TXT record entries, MUST persist
 * and stay constant after an instance of this structure is passed to OpenThread from `otSrpClientAddService()` or
 * `otSrpClientRemoveService()`.
 *
 * The `mState`, `mData`, `mNext` fields are used/managed by OT core only. Their value is ignored when an instance of
 * `otSrpClientService` is passed in `otSrpClientAddService()` or `otSrpClientRemoveService()` or other functions. The
 * caller does not need to set these fields.
 *
 * The `mLease` and `mKeyLease` fields specify the desired lease and key lease intervals for this service. Zero value
 * indicates that the interval is unspecified and then the default lease or key lease intervals from
 * `otSrpClientGetLeaseInterval()` and `otSrpClientGetKeyLeaseInterval()` are used for this service. If the key lease
 * interval (whether set explicitly or determined from the default) is shorter than the lease interval for a service,
 * SRP client will re-use the lease interval value for key lease interval as well. For example, if in service `mLease`
 * is explicitly set to 2 days and `mKeyLease` is set to zero and default key lease is set to 1 day, then when
 * registering this service, the requested key lease for this service is also set to 2 days.
 */
typedef struct otSrpClientService
{
    const char                *mName;          ///< The service labels (e.g., "_mt._udp", not the full domain name).
    const char                *mInstanceName;  ///< The service instance name label (not the full name).
    const char *const         *mSubTypeLabels; ///< Array of sub-type labels (must end with `NULL` or can be `NULL`).
    const otDnsTxtEntry       *mTxtEntries;    ///< Array of TXT entries (`mNumTxtEntries` gives num of entries).
    uint16_t                   mPort;          ///< The service port number.
    uint16_t                   mPriority;      ///< The service priority.
    uint16_t                   mWeight;        ///< The service weight.
    uint8_t                    mNumTxtEntries; ///< Number of entries in the `mTxtEntries` array.
    otSrpClientItemState       mState;         ///< Service state (managed by OT core).
    uint32_t                   mData;          ///< Internal data (used by OT core).
    struct otSrpClientService *mNext;          ///< Pointer to next entry in a linked-list (managed by OT core).
    uint32_t                   mLease;         ///< Desired lease interval in sec - zero to use default.
    uint32_t                   mKeyLease;      ///< Desired key lease interval in sec - zero to use default.
} otSrpClientService;

/**
 * Pointer type defines the callback used by SRP client to notify user of changes/events/errors.
 *
 * This callback is invoked on a successful registration of an update (i.e., add/remove of host-info and/or some
 * service(s)) with the SRP server, or if there is a failure or error (e.g., server rejects a update request or client
 * times out waiting for response, etc).
 *
 * In case of a successful reregistration of an update, `aError` parameter would be `OT_ERROR_NONE` and the host info
 * and the full list of services is provided as input parameters to the callback. Note that host info and services each
 * track its own state in the corresponding `mState` member variable of the related data structure (the state
 * indicating whether the host-info/service is registered or removed or still being added/removed, etc).
 *
 * The list of removed services is passed as its own linked-list `aRemovedServices` in the callback. Note that when the
 * callback is invoked, the SRP client (OpenThread implementation) is done with the removed service instances listed in
 * `aRemovedServices` and no longer tracks/stores them (i.e., if from the callback we call `otSrpClientGetServices()`
 * the removed services will not be present in the returned list). Providing a separate list of removed services in
 * the callback helps indicate to user which items are now removed and allow user to re-claim/reuse the instances.
 *
 * If the server rejects an SRP update request, the DNS response code (RFC 2136) is mapped to the following errors:
 *
 *  - (0)  NOERROR   Success (no error condition)                    -> OT_ERROR_NONE
 *  - (1)  FORMERR   Server unable to interpret due to format error  -> OT_ERROR_PARSE
 *  - (2)  SERVFAIL  Server encountered an internal failure          -> OT_ERROR_FAILED
 *  - (3)  NXDOMAIN  Name that ought to exist, does not exist        -> OT_ERROR_NOT_FOUND
 *  - (4)  NOTIMP    Server does not support the query type (OpCode) -> OT_ERROR_NOT_IMPLEMENTED
 *  - (5)  REFUSED   Server refused for policy/security reasons      -> OT_ERROR_SECURITY
 *  - (6)  YXDOMAIN  Some name that ought not to exist, does exist   -> OT_ERROR_DUPLICATED
 *  - (7)  YXRRSET   Some RRset that ought not to exist, does exist  -> OT_ERROR_DUPLICATED
 *  - (8)  NXRRSET   Some RRset that ought to exist, does not exist  -> OT_ERROR_NOT_FOUND
 *  - (9)  NOTAUTH   Service is not authoritative for zone           -> OT_ERROR_SECURITY
 *  - (10) NOTZONE   A name is not in the zone                       -> OT_ERROR_PARSE
 *  - (20) BADNAME   Bad name                                        -> OT_ERROR_PARSE
 *  - (21) BADALG    Bad algorithm                                   -> OT_ERROR_SECURITY
 *  - (22) BADTRUN   Bad truncation                                  -> OT_ERROR_PARSE
 *  - Other response codes                                           -> OT_ERROR_FAILED
 *
 * The following errors are also possible:
 *
 *  - OT_ERROR_RESPONSE_TIMEOUT : Timed out waiting for response from server (client would continue to retry).
 *  - OT_ERROR_INVALID_ARGS     : The provided service structure is invalid (e.g., bad service name or `otDnsTxtEntry`).
 *  - OT_ERROR_NO_BUFS          : Insufficient buffer to prepare or send the update message.
 *
 * Note that in case of any failure, the client continues the operation, i.e. it prepares and (re)transmits the SRP
 * update message to the server, after some wait interval. The retry wait interval starts from the minimum value and
 * is increased by the growth factor every failure up to the max value (please see configuration parameter
 * `OPENTHREAD_CONFIG_SRP_CLIENT_MIN_RETRY_WAIT_INTERVAL` and the related ones for more details).
 *
 * @param[in] aError            The error (see above).
 * @param[in] aHostInfo         A pointer to host info.
 * @param[in] aServices         The head of linked-list containing all services (excluding the ones removed). NULL if
 *                              the list is empty.
 * @param[in] aRemovedServices  The head of linked-list containing all removed services. NULL if the list is empty.
 * @param[in] aContext          A pointer to an arbitrary context (provided when callback was registered).
 */
typedef void (*otSrpClientCallback)(otError                    aError,
                                    const otSrpClientHostInfo *aHostInfo,
                                    const otSrpClientService  *aServices,
                                    const otSrpClientService  *aRemovedServices,
                                    void                      *aContext);

/**
 * Pointer type defines the callback used by SRP client to notify user when it is auto-started or stopped.
 *
 * This is only used when auto-start feature `OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE` is enabled.
 *
 * This callback is invoked when auto-start mode is enabled and the SRP client is either automatically started or
 * stopped.
 *
 * @param[in] aServerSockAddr   A non-NULL pointer indicates SRP server was started and pointer will give the
 *                              selected server socket address. A NULL pointer indicates SRP server was stopped.
 * @param[in] aContext          A pointer to an arbitrary context (provided when callback was registered).
 */
typedef void (*otSrpClientAutoStartCallback)(const otSockAddr *aServerSockAddr, void *aContext);

/**
 * Starts the SRP client operation.
 *
 * SRP client will prepare and send "SRP Update" message to the SRP server once all the following conditions are met:
 *
 *  - The SRP client is started - `otSrpClientStart()` is called.
 *  - Host name is set - `otSrpClientSetHostName()` is called.
 *  - At least one host IPv6 address is set - `otSrpClientSetHostAddresses()` is called.
 *  - At least one service is added - `otSrpClientAddService()` is called.
 *
 * It does not matter in which order these functions are called. When all conditions are met, the SRP client will
 * wait for a short delay before preparing an "SRP Update" message and sending it to server. This delay allows for user
 * to add multiple services and/or IPv6 addresses before the first SRP Update message is sent (ensuring a single SRP
 * Update is sent containing all the info). The config `OPENTHREAD_CONFIG_SRP_CLIENT_UPDATE_TX_DELAY` specifies the
 * delay interval.
 *
 * @param[in] aInstance        A pointer to the OpenThread instance.
 * @param[in] aServerSockAddr  The socket address (IPv6 address and port number) of the SRP server.
 *
 * @retval OT_ERROR_NONE       SRP client operation started successfully or it is already running with same server
 *                             socket address and callback.
 * @retval OT_ERROR_BUSY       SRP client is busy running with a different socket address.
 * @retval OT_ERROR_FAILED     Failed to open/connect the client's UDP socket.
 */
otError otSrpClientStart(otInstance *aInstance, const otSockAddr *aServerSockAddr);

/**
 * Stops the SRP client operation.
 *
 * Stops any further interactions with the SRP server. Note that it does not remove or clear host info
 * and/or list of services. It marks all services to be added/removed again once the client is (re)started.
 *
 * @param[in] aInstance       A pointer to the OpenThread instance.
 */
void otSrpClientStop(otInstance *aInstance);

/**
 * Indicates whether the SRP client is running or not.
 *
 * @param[in] aInstance       A pointer to the OpenThread instance.
 *
 * @returns TRUE if the SRP client is running, FALSE otherwise.
 */
bool otSrpClientIsRunning(otInstance *aInstance);

/**
 * Gets the socket address (IPv6 address and port number) of the SRP server which is being used by SRP
 * client.
 *
 * If the client is not running, the address is unspecified (all zero) with zero port number.
 *
 * @param[in] aInstance       A pointer to the OpenThread instance.
 *
 * @returns A pointer to the SRP server's socket address (is always non-NULL).
 */
const otSockAddr *otSrpClientGetServerAddress(otInstance *aInstance);

/**
 * Sets the callback to notify caller of events/changes from SRP client.
 *
 * The SRP client allows a single callback to be registered. So consecutive calls to this function will overwrite any
 * previously set callback functions.
 *
 * @param[in] aInstance   A pointer to the OpenThread instance.
 * @param[in] aCallback   The callback to notify of events and changes. Can be NULL if not needed.
 * @param[in] aContext    An arbitrary context used with @p aCallback.
 */
void otSrpClientSetCallback(otInstance *aInstance, otSrpClientCallback aCallback, void *aContext);

/**
 * Enables the auto-start mode.
 *
 * This is only available when auto-start feature `OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE` is enabled.
 *
 * Config option `OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE` specifies the default auto-start mode (whether
 * it is enabled or disabled at the start of OT stack).
 *
 * When auto-start is enabled, the SRP client will monitor the Thread Network Data to discover SRP servers and select
 * the preferred server and automatically start and stop the client when an SRP server is detected.
 *
 * There are three categories of Network Data entries indicating presence of SRP sever. They are preferred in the
 * following order:
 *
 *   1) Preferred unicast entries where server address is included in the service data. If there are multiple options,
 *      the one with numerically lowest IPv6 address is preferred.
 *
 *   2) Anycast entries each having a seq number. A larger sequence number in the sense specified by Serial Number
 *      Arithmetic logic in RFC-1982 is considered more recent and therefore preferred. The largest seq number using
 *      serial number arithmetic is preferred if it is well-defined (i.e., the seq number is larger than all other
 *      seq numbers). If it is not well-defined, then the numerically largest seq number is preferred.
 *
 *   3) Unicast entries where the server address info is included in server data. If there are multiple options, the
 *      one with numerically lowest IPv6 address is preferred.
 *
 * When there is a change in the Network Data entries, client will check that the currently selected server is still
 * present in the Network Data and is still the preferred one. Otherwise the client will switch to the new preferred
 * server or stop if there is none.
 *
 * When the SRP client is explicitly started through a successful call to `otSrpClientStart()`, the given SRP server
 * address in `otSrpClientStart()` will continue to be used regardless of the state of auto-start mode and whether the
 * same SRP server address is discovered or not in the Thread Network Data. In this case, only an explicit
 * `otSrpClientStop()` call will stop the client.
 *
 * @param[in] aInstance   A pointer to the OpenThread instance.
 * @param[in] aCallback   A callback to notify when client is auto-started/stopped. Can be NULL if not needed.
 * @param[in] aContext    A context to be passed when invoking @p aCallback.
 */
void otSrpClientEnableAutoStartMode(otInstance *aInstance, otSrpClientAutoStartCallback aCallback, void *aContext);

/**
 * Disables the auto-start mode.
 *
 * This is only available when auto-start feature `OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE` is enabled.
 *
 * Disabling the auto-start mode will not stop the client if it is already running but the client stops monitoring
 * the Thread Network Data to verify that the selected SRP server is still present in it.
 *
 * Note that a call to `otSrpClientStop()` will also disable the auto-start mode.
 *
 * @param[in] aInstance   A pointer to the OpenThread instance.
 */
void otSrpClientDisableAutoStartMode(otInstance *aInstance);

/**
 * Indicates the current state of auto-start mode (enabled or disabled).
 *
 * This is only available when auto-start feature `OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE` is enabled.
 *
 * @param[in] aInstance   A pointer to the OpenThread instance.
 *
 * @returns TRUE if the auto-start mode is enabled, FALSE otherwise.
 */
bool otSrpClientIsAutoStartModeEnabled(otInstance *aInstance);

/**
 * Gets the TTL value in every record included in SRP update requests.
 *
 * Note that this is the TTL requested by the SRP client. The server may choose to accept a different TTL.
 *
 * By default, the TTL will equal the lease interval. Passing 0 or a value larger than the lease interval via
 * `otSrpClientSetTtl()` will also cause the TTL to equal the lease interval.
 *
 * @param[in] aInstance  A pointer to the OpenThread instance.
 *
 * @returns The TTL (in seconds).
 */
uint32_t otSrpClientGetTtl(otInstance *aInstance);

/**
 * Sets the TTL value in every record included in SRP update requests.
 *
 * Changing the TTL does not impact the TTL of already registered services/host-info.
 * It only affects future SRP update messages (i.e., adding new services and/or refreshes of the existing services).
 *
 * @param[in] aInstance   A pointer to the OpenThread instance.
 * @param[in] aTtl        The TTL (in seconds). If value is zero or greater than lease interval, the TTL is set to the
 *                        lease interval.
 */
void otSrpClientSetTtl(otInstance *aInstance, uint32_t aTtl);

/**
 * Gets the default lease interval used in SRP update requests.
 *
 * The default interval is used only for `otSrpClientService` instances with `mLease` set to zero.
 *
 * Note that this is the lease duration requested by the SRP client. The server may choose to accept a different lease
 * interval.
 *
 * @param[in] aInstance        A pointer to the OpenThread instance.
 *
 * @returns The lease interval (in seconds).
 */
uint32_t otSrpClientGetLeaseInterval(otInstance *aInstance);

/**
 * Sets the default lease interval used in SRP update requests.
 *
 * The default interval is used only for `otSrpClientService` instances with `mLease` set to zero.
 *
 * Changing the lease interval does not impact the accepted lease interval of already registered services/host-info.
 * It only affects any future SRP update messages (i.e., adding new services and/or refreshes of the existing services).
 *
 * @param[in] aInstance   A pointer to the OpenThread instance.
 * @param[in] aInterval   The lease interval (in seconds). If zero, the default value specified by
 *                        `OPENTHREAD_CONFIG_SRP_CLIENT_DEFAULT_LEASE` would be used.
 */
void otSrpClientSetLeaseInterval(otInstance *aInstance, uint32_t aInterval);

/**
 * Gets the default key lease interval used in SRP update requests.
 *
 * The default interval is used only for `otSrpClientService` instances with `mKeyLease` set to zero.
 *
 * Note that this is the lease duration requested by the SRP client. The server may choose to accept a different lease
 * interval.
 *
 * @param[in] aInstance        A pointer to the OpenThread instance.
 *
 * @returns The key lease interval (in seconds).
 */
uint32_t otSrpClientGetKeyLeaseInterval(otInstance *aInstance);

/**
 * Sets the default key lease interval used in SRP update requests.
 *
 * The default interval is used only for `otSrpClientService` instances with `mKeyLease` set to zero.
 *
 * Changing the lease interval does not impact the accepted lease interval of already registered services/host-info.
 * It only affects any future SRP update messages (i.e., adding new services and/or refreshes of existing services).
 *
 * @param[in] aInstance    A pointer to the OpenThread instance.
 * @param[in] aInterval    The key lease interval (in seconds). If zero, the default value specified by
 *                         `OPENTHREAD_CONFIG_SRP_CLIENT_DEFAULT_KEY_LEASE` would be used.
 */
void otSrpClientSetKeyLeaseInterval(otInstance *aInstance, uint32_t aInterval);

/**
 * Gets the host info.
 *
 * @param[in] aInstance        A pointer to the OpenThread instance.
 *
 * @returns A pointer to host info structure.
 */
const otSrpClientHostInfo *otSrpClientGetHostInfo(otInstance *aInstance);

/**
 * Sets the host name label.
 *
 * After a successful call to this function, `otSrpClientCallback` will be called to report the status of host info
 * registration with SRP server.
 *
 * The name string buffer pointed to by @p aName MUST persist and stay unchanged after returning from this function.
 * OpenThread will keep the pointer to the string.
 *
 * The host name can be set before client is started or after start but before host info is registered with server
 * (host info should be in either `STATE_TO_ADD` or `STATE_REMOVED`).
 *
 * @param[in] aInstance   A pointer to the OpenThread instance.
 * @param[in] aName       A pointer to host name label string (MUST NOT be NULL). Pointer to the string buffer MUST
 *                        persist and remain valid and constant after return from this function.
 *
 * @retval OT_ERROR_NONE            The host name label was set successfully.
 * @retval OT_ERROR_INVALID_ARGS    The @p aName is NULL.
 * @retval OT_ERROR_INVALID_STATE   The host name is already set and registered with the server.
 */
otError otSrpClientSetHostName(otInstance *aInstance, const char *aName);

/**
 * Enables auto host address mode.
 *
 * When enabled host IPv6 addresses are automatically set by SRP client using all the preferred unicast addresses on
 * Thread netif excluding all link-local and mesh-local addresses. If there is no preferred address, then Mesh Local
 * EID address is added. The SRP client will automatically re-register when/if addresses on Thread netif are updated
 * (new addresses are added or existing addresses are removed or marked as non-preferred).
 *
 * The auto host address mode can be enabled before start or during operation of SRP client except when the host info
 * is being removed (client is busy handling a remove request from an call to `otSrpClientRemoveHostAndServices()` and
 * host info still being in  either `STATE_TO_REMOVE` or `STATE_REMOVING` states).
 *
 * After auto host address mode is enabled, it can be disabled by a call to `otSrpClientSetHostAddresses()` which
 * then explicitly sets the host addresses.
 *
 * @retval OT_ERROR_NONE            Successfully enabled auto host address mode.
 * @retval OT_ERROR_INVALID_STATE   Host is being removed and therefore cannot enable auto host address mode.
 */
otError otSrpClientEnableAutoHostAddress(otInstance *aInstance);

/**
 * Sets/updates the list of host IPv6 address.
 *
 * Host IPv6 addresses can be set/changed before start or during operation of SRP client (e.g. to add/remove or change
 * a previously registered host address), except when the host info is being removed (client is busy handling a remove
 * request from an earlier call to `otSrpClientRemoveHostAndServices()` and host info still being in  either
 * `STATE_TO_REMOVE` or `STATE_REMOVING` states).
 *
 * The host IPv6 address array pointed to by @p aIp6Addresses MUST persist and remain unchanged after returning from
 * this function (with `OT_ERROR_NONE`). OpenThread will save the pointer to the array.
 *
 * After a successful call to this function, `otSrpClientCallback` will be called to report the status of the address
 * registration with SRP server.
 *
 * Calling this function disables auto host address mode if it was previously enabled from a successful call to
 * `otSrpClientEnableAutoHostAddress()`.
 *
 * @param[in] aInstance           A pointer to the OpenThread instance.
 * @param[in] aIp6Addresses       A pointer to the an array containing the host IPv6 addresses.
 * @param[in] aNumAddresses       The number of addresses in the @p aIp6Addresses array.
 *
 * @retval OT_ERROR_NONE            The host IPv6 address list change started successfully. The `otSrpClientCallback`
 *                                  will be called to report the status of registering addresses with server.
 * @retval OT_ERROR_INVALID_ARGS    The address list is invalid (e.g., must contain at least one address).
 * @retval OT_ERROR_INVALID_STATE   Host is being removed and therefore cannot change host address.
 */
otError otSrpClientSetHostAddresses(otInstance *aInstance, const otIp6Address *aIp6Addresses, uint8_t aNumAddresses);

/**
 * Adds a service to be registered with server.
 *
 * After a successful call to this function, `otSrpClientCallback` will be called to report the status of the service
 * addition/registration with SRP server.
 *
 * The `otSrpClientService` instance being pointed to by @p aService MUST persist and remain unchanged after returning
 * from this function (with `OT_ERROR_NONE`). OpenThread will save the pointer to the service instance.
 *
 * The `otSrpClientService` instance is not longer tracked by OpenThread and can be reclaimed only when
 *
 *  -  It is removed explicitly by a call to `otSrpClientRemoveService()` or removed along with other services by a
 *     call to `otSrpClientRemoveHostAndServices() and only after the `otSrpClientCallback` is called indicating the
 *     service was removed. Or,
 *  -  A call to `otSrpClientClearHostAndServices()` which removes the host and all related services immediately.
 *
 * @param[in] aInstance        A pointer to the OpenThread instance.
 * @param[in] aService         A pointer to a `otSrpClientService` instance to add.

 * @retval OT_ERROR_NONE          The addition of service started successfully. The `otSrpClientCallback` will be
 *                                called to report the status.
 * @retval OT_ERROR_ALREADY       A service with the same service and instance names is already in the list.
 * @retval OT_ERROR_INVALID_ARGS  The service structure is invalid (e.g., bad service name or `otDnsTxtEntry`).
 */
otError otSrpClientAddService(otInstance *aInstance, otSrpClientService *aService);

/**
 * Requests a service to be unregistered with server.
 *
 * After a successful call to this function, `otSrpClientCallback` will be called to report the status of remove
 * request with SRP server.

 * The `otSrpClientService` instance being pointed to by @p aService MUST persist and remain unchanged after returning
 * from this function (with `OT_ERROR_NONE`). OpenThread will keep the service instance during the remove process.
 * Only after the `otSrpClientCallback` is called indicating the service instance is removed from SRP client
 * service list and can be be freed/reused.
 *
 * @param[in] aInstance        A pointer to the OpenThread instance.
 * @param[in] aService         A pointer to a `otSrpClientService` instance to remove.
 *
 * @retval OT_ERROR_NONE       The removal of service started successfully. The `otSrpClientCallback` will be called to
 *                             report the status.
 * @retval OT_ERROR_NOT_FOUND  The service could not be found in the list.
 */
otError otSrpClientRemoveService(otInstance *aInstance, otSrpClientService *aService);

/**
 * Clears a service, immediately removing it from the client service list.
 *
 * Unlike `otSrpClientRemoveService()` which sends an update message to the server to remove the service, this function
 * clears the service from the client's service list without any interaction with the server. On a successful call to
 * this function, the `otSrpClientCallback` will NOT be called and the @p aService entry can be reclaimed and re-used
 * by the caller immediately.
 *
 * Can be used along with a subsequent call to `otSrpClientAddService()` (potentially reusing the same @p
 * aService entry with the same service and instance names) to update some of the parameters in an existing service.
 *
 * @param[in] aInstance        A pointer to the OpenThread instance.
 * @param[in] aService         A pointer to a `otSrpClientService` instance to delete.
 *
 * @retval OT_ERROR_NONE       The @p aService is deleted successfully. It can be reclaimed and re-used immediately.
 * @retval OT_ERROR_NOT_FOUND  The service could not be found in the list.
 */
otError otSrpClientClearService(otInstance *aInstance, otSrpClientService *aService);

/**
 * Gets the list of services being managed by client.
 *
 * @param[in] aInstance        A pointer to the OpenThread instance.
 *
 * @returns A pointer to the head of linked-list of all services or NULL if the list is empty.
 */
const otSrpClientService *otSrpClientGetServices(otInstance *aInstance);

/**
 * Starts the remove process of the host info and all services.
 *
 * After returning from this function, `otSrpClientCallback` will be called to report the status of remove request with
 * SRP server.
 *
 * If the host info is to be permanently removed from server, @p aRemoveKeyLease should be set to `true` which removes
 * the key lease associated with host on server. Otherwise, the key lease record is kept as before, which ensures
 * that the server holds the host name in reserve for when the client is once again able to provide and register its
 * service(s).
 *
 * The @p aSendUnregToServer determines the behavior when the host info is not yet registered with the server. If
 * @p aSendUnregToServer is set to `false` (which is the default/expected value) then the SRP client will immediately
 * remove the host info and services without sending an update message to server (no need to update the server if
 * nothing is yet registered with it). If @p aSendUnregToServer is set to `true` then the SRP client will send an
 * update message to the server. Note that if the host info is registered then the value of @p aSendUnregToServer does
 * not matter and the SRP client will always send an update message to server requesting removal of all info.
 *
 * One situation where @p aSendUnregToServer can be useful is on a device reset/reboot, caller may want to remove any
 * previously registered services with the server. In this case, caller can `otSrpClientSetHostName()` and then request
 * `otSrpClientRemoveHostAndServices()` with `aSendUnregToServer` as `true`.
 *
 * @param[in] aInstance          A pointer to the OpenThread instance.
 * @param[in] aRemoveKeyLease    A boolean indicating whether or not the host key lease should also be removed.
 * @param[in] aSendUnregToServer A boolean indicating whether to send update to server when host info is not registered.
 *
 * @retval OT_ERROR_NONE       The removal of host info and services started successfully. The `otSrpClientCallback`
 *                             will be called to report the status.
 * @retval OT_ERROR_ALREADY    The host info is already removed.
 */
otError otSrpClientRemoveHostAndServices(otInstance *aInstance, bool aRemoveKeyLease, bool aSendUnregToServer);

/**
 * Clears all host info and all the services.
 *
 * Unlike `otSrpClientRemoveHostAndServices()` which sends an update message to the server to remove all the info, this
 * function clears all the info immediately without any interaction with the server.
 *
 * @param[in] aInstance        A pointer to the OpenThread instance.
 */
void otSrpClientClearHostAndServices(otInstance *aInstance);

/**
 * Gets the domain name being used by SRP client.
 *
 * Requires `OPENTHREAD_CONFIG_SRP_CLIENT_DOMAIN_NAME_API_ENABLE` to be enabled.
 *
 * If domain name is not set, "default.service.arpa" will be used.
 *
 * @param[in] aInstance        A pointer to the OpenThread instance.
 *
 * @returns The domain name string.
 */
const char *otSrpClientGetDomainName(otInstance *aInstance);

/**
 * Sets the domain name to be used by SRP client.
 *
 * Requires `OPENTHREAD_CONFIG_SRP_CLIENT_DOMAIN_NAME_API_ENABLE` to be enabled.
 *
 * If not set "default.service.arpa" will be used.
 *
 * The name string buffer pointed to by @p aName MUST persist and stay unchanged after returning from this function.
 * OpenThread will keep the pointer to the string.
 *
 * The domain name can be set before client is started or after start but before host info is registered with server
 * (host info should be in either `STATE_TO_ADD` or `STATE_TO_REMOVE`).
 *
 * @param[in] aInstance     A pointer to the OpenThread instance.
 * @param[in] aName         A pointer to the domain name string. If NULL sets it to default "default.service.arpa".
 *
 * @retval OT_ERROR_NONE            The domain name label was set successfully.
 * @retval OT_ERROR_INVALID_STATE   The host info is already registered with server.
 */
otError otSrpClientSetDomainName(otInstance *aInstance, const char *aName);

/**
 * Converts a `otSrpClientItemState` to a string.
 *
 * @param[in] aItemState  An item state.
 *
 * @returns A string representation of @p aItemState.
 */
const char *otSrpClientItemStateToString(otSrpClientItemState aItemState);

/**
 * Enables/disables "service key record inclusion" mode.
 *
 * When enabled, SRP client will include KEY record in Service Description Instructions in the SRP update messages
 * that it sends.
 *
 * Is available when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` configuration is enabled.
 *
 * @note KEY record is optional in Service Description Instruction (it is required and always included in the Host
 * Description Instruction). The default behavior of SRP client is to not include it. This function is intended to
 * override the default behavior for testing only.
 *
 * @param[in] aInstance  A pointer to the OpenThread instance.
 * @param[in] aEnabled   TRUE to enable, FALSE to disable the "service key record inclusion" mode.
 */
void otSrpClientSetServiceKeyRecordEnabled(otInstance *aInstance, bool aEnabled);

/**
 * Indicates whether the "service key record inclusion" mode is enabled or disabled.
 *
 * Is available when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` configuration is enabled.
 *
 * @param[in] aInstance     A pointer to the OpenThread instance.
 *
 * @returns TRUE if "service key record inclusion" mode is enabled, FALSE otherwise.
 */
bool otSrpClientIsServiceKeyRecordEnabled(otInstance *aInstance);

/**
 * @}
 */

#ifdef __cplusplus
} // extern "C"
#endif

#endif // OPENTHREAD_SRP_CLIENT_H_
