mirror of
https://github.com/espressif/openthread.git
synced 2026-07-30 07:37:46 +00:00
[sntp] initial implementation of sntp client (#3237)
This commit is contained in:
committed by
Jonathan Hui
parent
8f25db11cc
commit
4a89cc63b6
+5
-4
@@ -75,6 +75,7 @@ python --version || die
|
||||
--enable-radio-only \
|
||||
--enable-raw-link-api \
|
||||
--enable-service \
|
||||
--enable-sntp-client \
|
||||
--enable-udp-proxy \
|
||||
--with-examples=posix || die
|
||||
|
||||
@@ -118,7 +119,7 @@ python --version || die
|
||||
git checkout -- . || die
|
||||
git clean -xfd || die
|
||||
./bootstrap || die
|
||||
BORDER_ROUTER=1 COAP=1 COMMISSIONER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 ECDSA=1 FULL_LOGS=1 JOINER=1 LINK_RAW=1 MAC_FILTER=1 MTD_NETDIAG=1 SERVICE=1 UDP_PROXY=1 make -f examples/Makefile-nrf52840 || die
|
||||
BORDER_ROUTER=1 COAP=1 COMMISSIONER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 ECDSA=1 FULL_LOGS=1 JOINER=1 LINK_RAW=1 MAC_FILTER=1 MTD_NETDIAG=1 SERVICE=1 SNTP_CLIENT=1 UDP_PROXY=1 make -f examples/Makefile-nrf52840 || die
|
||||
arm-none-eabi-size output/nrf52840/bin/ot-cli-ftd || die
|
||||
arm-none-eabi-size output/nrf52840/bin/ot-cli-mtd || die
|
||||
arm-none-eabi-size output/nrf52840/bin/ot-ncp-ftd || die
|
||||
@@ -196,7 +197,7 @@ python --version || die
|
||||
git checkout -- . || die
|
||||
git clean -xfd || die
|
||||
./bootstrap || die
|
||||
BORDER_ROUTER=1 COAP=1 COMMISSIONER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 ECDSA=1 FULL_LOGS=1 JOINER=1 MAC_FILTER=1 MTD_NETDIAG=1 SERVICE=1 UDP_PROXY=1 make -f examples/Makefile-nrf52840 || die
|
||||
BORDER_ROUTER=1 COAP=1 COMMISSIONER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 ECDSA=1 FULL_LOGS=1 JOINER=1 MAC_FILTER=1 MTD_NETDIAG=1 SERVICE=1 SNTP_CLIENT=1 UDP_PROXY=1 make -f examples/Makefile-nrf52840 || die
|
||||
arm-none-eabi-size output/nrf52840/bin/ot-cli-ftd || die
|
||||
arm-none-eabi-size output/nrf52840/bin/ot-cli-mtd || die
|
||||
arm-none-eabi-size output/nrf52840/bin/ot-ncp-ftd || die
|
||||
@@ -274,7 +275,7 @@ python --version || die
|
||||
git checkout -- . || die
|
||||
git clean -xfd || die
|
||||
./bootstrap || die
|
||||
BORDER_ROUTER=1 COAP=1 COMMISSIONER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 ECDSA=1 FULL_LOGS=1 JOINER=1 MAC_FILTER=1 MTD_NETDIAG=1 SERVICE=1 UDP_PROXY=1 make -f examples/Makefile-nrf52840 || die
|
||||
BORDER_ROUTER=1 COAP=1 COMMISSIONER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 ECDSA=1 FULL_LOGS=1 JOINER=1 MAC_FILTER=1 MTD_NETDIAG=1 SERVICE=1 SNTP_CLIENT=1 UDP_PROXY=1 make -f examples/Makefile-nrf52840 || die
|
||||
arm-none-eabi-size output/nrf52840/bin/ot-cli-ftd || die
|
||||
arm-none-eabi-size output/nrf52840/bin/ot-cli-mtd || die
|
||||
arm-none-eabi-size output/nrf52840/bin/ot-ncp-ftd || die
|
||||
@@ -363,7 +364,7 @@ python --version || die
|
||||
git checkout -- . || die
|
||||
git clean -xfd || die
|
||||
./bootstrap || die
|
||||
BORDER_ROUTER=1 COAP=1 COMMISSIONER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 FULL_LOGS=1 JOINER=1 MAC_FILTER=1 MTD_NETDIAG=1 SERVICE=1 UDP_PROXY=1 make -f examples/Makefile-nrf52840 || die
|
||||
BORDER_ROUTER=1 COAP=1 COMMISSIONER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 FULL_LOGS=1 JOINER=1 MAC_FILTER=1 MTD_NETDIAG=1 SERVICE=1 SNTP_CLIENT=1 UDP_PROXY=1 make -f examples/Makefile-nrf52840 || die
|
||||
arm-none-eabi-size output/nrf52840/bin/ot-cli-ftd || die
|
||||
arm-none-eabi-size output/nrf52840/bin/ot-cli-mtd || die
|
||||
arm-none-eabi-size output/nrf52840/bin/ot-ncp-ftd || die
|
||||
|
||||
@@ -1336,6 +1336,36 @@ AC_SUBST(OPENTHREAD_ENABLE_DNS_CLIENT)
|
||||
AM_CONDITIONAL([OPENTHREAD_ENABLE_DNS_CLIENT], [test "${enable_dns_client}" = "yes"])
|
||||
AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_DNS_CLIENT],[${OPENTHREAD_ENABLE_DNS_CLIENT}],[Define to 1 if you want to enable DNS Client])
|
||||
|
||||
#
|
||||
# SNTP Client
|
||||
#
|
||||
|
||||
AC_ARG_ENABLE(sntp_client,
|
||||
[AS_HELP_STRING([--enable-sntp-client],[Enable SNTP client support @<:@default=no@:>@.])],
|
||||
[
|
||||
case "${enableval}" in
|
||||
|
||||
no|yes)
|
||||
enable_sntp_client=${enableval}
|
||||
;;
|
||||
|
||||
*)
|
||||
AC_MSG_ERROR([Invalid value ${enable_sntp_client} for --enable-sntp-client])
|
||||
;;
|
||||
esac
|
||||
],
|
||||
[enable_sntp_client=no])
|
||||
|
||||
if test "$enable_sntp_client" = "yes"; then
|
||||
OPENTHREAD_ENABLE_SNTP_CLIENT=1
|
||||
else
|
||||
OPENTHREAD_ENABLE_SNTP_CLIENT=0
|
||||
fi
|
||||
|
||||
AC_SUBST(OPENTHREAD_ENABLE_SNTP_CLIENT)
|
||||
AM_CONDITIONAL([OPENTHREAD_ENABLE_SNTP_CLIENT], [test "${enable_sntp_client}" = "yes"])
|
||||
AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_SNTP_CLIENT],[${OPENTHREAD_ENABLE_SNTP_CLIENT}],[Define to 1 if you want to enable SNTP Client])
|
||||
|
||||
#
|
||||
# Application CoAP
|
||||
#
|
||||
@@ -1915,6 +1945,7 @@ AC_MSG_NOTICE([
|
||||
OpenThread DHCPv6 Server support : ${enable_dhcp6_server}
|
||||
OpenThread DHCPv6 Client support : ${enable_dhcp6_client}
|
||||
OpenThread DNS Client support : ${enable_dns_client}
|
||||
OpenThread SNTP Client support : ${enable_sntp_client}
|
||||
OpenThread Application CoAP support : ${enable_application_coap}
|
||||
OpenThread Application CoAP Secure support: ${enable_application_coap_secure}
|
||||
OpenThread Raw Link-Layer support : ${enable_raw_link_api}
|
||||
|
||||
@@ -119,6 +119,10 @@ ifeq ($(SERVICE),1)
|
||||
configure_OPTIONS += --enable-service
|
||||
endif
|
||||
|
||||
ifeq ($(SNTP_CLIENT),1)
|
||||
configure_OPTIONS += --enable-sntp-client
|
||||
endif
|
||||
|
||||
ifeq ($(UDP_PROXY),1)
|
||||
configure_OPTIONS += --enable-udp-proxy
|
||||
endif
|
||||
|
||||
@@ -78,6 +78,7 @@ openthread_headers = \
|
||||
netdata.h \
|
||||
network_time.h \
|
||||
server.h \
|
||||
sntp.h \
|
||||
tasklet.h \
|
||||
thread.h \
|
||||
thread_ftd.h \
|
||||
|
||||
@@ -314,7 +314,7 @@ typedef enum otError
|
||||
OT_ERROR_NOT_CAPABLE = 27,
|
||||
|
||||
/**
|
||||
* Coap response or acknowledgment or DNS response not received.
|
||||
* Coap response or acknowledgment or DNS, SNTP response not received.
|
||||
*/
|
||||
OT_ERROR_RESPONSE_TIMEOUT = 28,
|
||||
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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 top-level sntp functions for the OpenThread library.
|
||||
*/
|
||||
|
||||
#ifndef OPENTHREAD_SNTP_H_
|
||||
#define OPENTHREAD_SNTP_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <openthread/ip6.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup api-sntp
|
||||
*
|
||||
* @brief
|
||||
* This module includes functions that control SNTP communication.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
#define OT_SNTP_DEFAULT_SERVER_IP "2001:4860:4806:8::" ///< Defines default SNTP Server address - Google NTP Server.
|
||||
#define OT_SNTP_DEFAULT_SERVER_PORT 123 ///< Defines default SNTP Server port.
|
||||
|
||||
/**
|
||||
* This structure implements SNTP Query parameters.
|
||||
*
|
||||
*/
|
||||
typedef struct otSntpQuery
|
||||
{
|
||||
const otMessageInfo *mMessageInfo; ///< A reference to the message info related with SNTP Server.
|
||||
} otSntpQuery;
|
||||
|
||||
/**
|
||||
* This function pointer is called when a SNTP response is received.
|
||||
*
|
||||
* @param[in] aContext A pointer to application-specific context.
|
||||
* @param[in] aTime Specifies the at the server when the response left for the client, in NTP timestamp format.
|
||||
* @param[in] aResult A result of the SNTP transaction.
|
||||
*
|
||||
* @retval OT_ERROR_NONE A response was received successfully and time is provided
|
||||
* in @p aTime.
|
||||
* @retval OT_ERROR_ABORT A SNTP transaction was aborted by stack.
|
||||
* @retval OT_ERROR_BUSY The Kiss-o'-death packet has been received.
|
||||
* @retval OT_ERROR_RESPONSE_TIMEOUT No SNTP response has been received within timeout.
|
||||
* @retval OT_ERROR_FAILED A response was received but contains incorrect data.
|
||||
*
|
||||
*/
|
||||
typedef void (*otSntpResponseHandler)(void *aContext, uint64_t aTime, otError aResult);
|
||||
|
||||
/**
|
||||
* This function sends a SNTP query.
|
||||
*
|
||||
* This function is available only if feature `OPENTHREAD_ENABLE_SNTP_CLIENT` is enabled.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aQuery A pointer to specify SNTP query parameters.
|
||||
* @param[in] aHandler A function pointer that shall be called on response reception or time-out.
|
||||
* @param[in] aContext A pointer to arbitrary context information.
|
||||
*
|
||||
*/
|
||||
otError otSntpClientQuery(otInstance * aInstance,
|
||||
const otSntpQuery * aQuery,
|
||||
otSntpResponseHandler aHandler,
|
||||
void * aContext);
|
||||
|
||||
/**
|
||||
* This function sets the unix era number.
|
||||
*
|
||||
* The default value of unix era is set to 0. The subsequent eras start after year 2106.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aUnixEra Unix era number.
|
||||
*
|
||||
*/
|
||||
void otSntpClientSetUnixEra(otInstance *aInstance, uint32_t aUnixEra);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_SNTP_H_
|
||||
@@ -67,6 +67,7 @@ OpenThread test scripts use the CLI to execute test cases.
|
||||
* [routerupgradethreshold](#routerupgradethreshold)
|
||||
* [scan](#scan)
|
||||
* [singleton](#singleton)
|
||||
* [sntp](#sntp-query-sntp-server-ip-sntp-server-port)
|
||||
* [state](#state)
|
||||
* [thread](#thread-start)
|
||||
* [txpower](#txpower)
|
||||
@@ -1735,6 +1736,24 @@ true or false
|
||||
Done
|
||||
```
|
||||
|
||||
### sntp query \[SNTP server IP\] \[SNTP server port\]
|
||||
|
||||
Send SNTP Query to obtain current unix epoch time (from 1st January 1970).
|
||||
The latter two parameters have following default values:
|
||||
* NTP server IP: 2001:4860:4806:8:: (Google IPv6 NTP Server)
|
||||
* NTP server port: 123
|
||||
|
||||
```bash
|
||||
> sntp query
|
||||
> SNTP response - Unix time: 1540894725 (era: 0)
|
||||
```
|
||||
|
||||
You can use NAT64 of OpenThread Border Router to reach e.g. Google IPv4 NTP Server:
|
||||
```bash
|
||||
> sntp query 64:ff9b::d8ef:2308
|
||||
> SNTP response - Unix time: 1540898611 (era: 0)
|
||||
```
|
||||
|
||||
### state
|
||||
Return state of current state.
|
||||
|
||||
|
||||
@@ -226,6 +226,9 @@ const struct Command Interpreter::sCommands[] = {
|
||||
{"service", &Interpreter::ProcessService},
|
||||
#endif
|
||||
{"singleton", &Interpreter::ProcessSingleton},
|
||||
#if OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
{"sntp", &Interpreter::ProcessSntp},
|
||||
#endif
|
||||
{"state", &Interpreter::ProcessState},
|
||||
{"thread", &Interpreter::ProcessThread},
|
||||
#ifndef OTDLL
|
||||
@@ -2706,6 +2709,80 @@ void Interpreter::ProcessSingleton(int argc, char *argv[])
|
||||
AppendResult(error);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
void Interpreter::ProcessSntp(int argc, char *argv[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
long port = OT_SNTP_DEFAULT_SERVER_PORT;
|
||||
Ip6::MessageInfo messageInfo;
|
||||
otSntpQuery query;
|
||||
|
||||
VerifyOrExit(argc > 0, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
if (strcmp(argv[0], "query") == 0)
|
||||
{
|
||||
VerifyOrExit(!mSntpQueryingInProgress, error = OT_ERROR_BUSY);
|
||||
|
||||
messageInfo.mInterfaceId = OT_NETIF_INTERFACE_ID_THREAD;
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
SuccessOrExit(error = messageInfo.GetPeerAddr().FromString(argv[1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use IPv6 address of default SNTP server.
|
||||
SuccessOrExit(error = messageInfo.GetPeerAddr().FromString(OT_SNTP_DEFAULT_SERVER_IP));
|
||||
}
|
||||
|
||||
if (argc > 2)
|
||||
{
|
||||
SuccessOrExit(error = ParseLong(argv[2], port));
|
||||
}
|
||||
|
||||
messageInfo.SetPeerPort(static_cast<uint16_t>(port));
|
||||
|
||||
query.mMessageInfo = static_cast<const otMessageInfo *>(&messageInfo);
|
||||
|
||||
SuccessOrExit(error = otSntpClientQuery(mInstance, &query, &Interpreter::s_HandleSntpResponse, this));
|
||||
|
||||
mSntpQueryingInProgress = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitNow(error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
AppendResult(error);
|
||||
}
|
||||
}
|
||||
|
||||
void Interpreter::s_HandleSntpResponse(void *aContext, uint64_t aTime, otError aResult)
|
||||
{
|
||||
static_cast<Interpreter *>(aContext)->HandleSntpResponse(aTime, aResult);
|
||||
}
|
||||
|
||||
void Interpreter::HandleSntpResponse(uint64_t aTime, otError aResult)
|
||||
{
|
||||
if (aResult == OT_ERROR_NONE)
|
||||
{
|
||||
// Some Embedded C libraries do not support printing of 64-bit unsigned integers.
|
||||
// To simplify, unix epoch time and era number are printed separately.
|
||||
mServer->OutputFormat("SNTP response - Unix time: %ld (era: %ld)\r\n",
|
||||
static_cast<uint32_t>(aTime & UINT32_MAX), static_cast<uint32_t>(aTime >> 32));
|
||||
}
|
||||
else
|
||||
{
|
||||
mServer->OutputFormat("SNTP error - %s\r\n", otThreadErrorToString(aResult));
|
||||
}
|
||||
|
||||
mSntpQueryingInProgress = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Interpreter::ProcessState(int argc, char *argv[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
+15
-2
@@ -61,6 +61,7 @@
|
||||
#ifndef OTDLL
|
||||
#include <openthread/dhcp6_client.h>
|
||||
#include <openthread/dns.h>
|
||||
#include <openthread/sntp.h>
|
||||
#include "common/timer.hpp"
|
||||
#include "net/icmp6.hpp"
|
||||
#endif
|
||||
@@ -312,6 +313,9 @@ private:
|
||||
void ProcessRloc16(int argc, char *argv[]);
|
||||
void ProcessScan(int argc, char *argv[]);
|
||||
void ProcessSingleton(int argc, char *argv[]);
|
||||
#if OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
void ProcessSntp(int argc, char *argv[]);
|
||||
#endif
|
||||
void ProcessState(int argc, char *argv[]);
|
||||
void ProcessThread(int argc, char *argv[]);
|
||||
#ifndef OTDLL
|
||||
@@ -366,6 +370,10 @@ private:
|
||||
otError aResult);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
static void s_HandleSntpResponse(void *aContext, uint64_t aTime, otError aResult);
|
||||
#endif
|
||||
|
||||
#ifndef OTDLL
|
||||
void HandleIcmpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo, const otIcmp6Header &aIcmpHeader);
|
||||
void HandlePingTimer();
|
||||
@@ -386,11 +394,12 @@ private:
|
||||
void HandleDiagnosticGetResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
#endif
|
||||
void HandleJoinerCallback(otError aError);
|
||||
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
void HandleDnsResponse(const char *aHostname, Ip6::Address &aAddress, uint32_t aTtl, otError aResult);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
void HandleSntpResponse(uint64_t aTime, otError aResult);
|
||||
#endif
|
||||
static Interpreter &GetOwner(OwnerLocator &aOwnerLocator);
|
||||
|
||||
static const struct Command sCommands[];
|
||||
@@ -434,6 +443,10 @@ private:
|
||||
char mResolvingHostname[OT_DNS_MAX_HOSTNAME_LENGTH];
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
bool mSntpQueryingInProgress;
|
||||
#endif
|
||||
|
||||
UdpExample mUdp;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -126,6 +126,7 @@ SOURCES_COMMON = \
|
||||
api/netdata_api.cpp \
|
||||
api/network_time_api.cpp \
|
||||
api/server_api.cpp \
|
||||
api/sntp_api.cpp \
|
||||
api/tasklet_api.cpp \
|
||||
api/thread_api.cpp \
|
||||
api/thread_ftd_api.cpp \
|
||||
@@ -184,6 +185,7 @@ SOURCES_COMMON = \
|
||||
net/ip6_mpl.cpp \
|
||||
net/ip6_routes.cpp \
|
||||
net/netif.cpp \
|
||||
net/sntp_client.cpp \
|
||||
net/udp6.cpp \
|
||||
thread/address_resolver.cpp \
|
||||
thread/announce_begin_server.cpp \
|
||||
@@ -344,6 +346,7 @@ HEADERS_COMMON = \
|
||||
net/ip6_mpl.hpp \
|
||||
net/ip6_routes.hpp \
|
||||
net/netif.hpp \
|
||||
net/sntp_client.hpp \
|
||||
net/socket.hpp \
|
||||
net/tcp.hpp \
|
||||
net/udp6.hpp \
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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
|
||||
* This file implements the OpenThread SNTP API.
|
||||
*/
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include <openthread/sntp.h>
|
||||
|
||||
#include "common/instance.hpp"
|
||||
|
||||
using namespace ot;
|
||||
|
||||
#if OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
otError otSntpClientQuery(otInstance * aInstance,
|
||||
const otSntpQuery * aQuery,
|
||||
otSntpResponseHandler aHandler,
|
||||
void * aContext)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.GetThreadNetif().GetSntpClient().Query(aQuery, aHandler, aContext);
|
||||
}
|
||||
|
||||
void otSntpClientSetUnixEra(otInstance *aInstance, uint32_t aUnixEra)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.GetThreadNetif().GetSntpClient().SetUnixEra(aUnixEra);
|
||||
}
|
||||
#endif
|
||||
@@ -648,6 +648,13 @@ template <> inline Utils::JamDetector &Instance::Get(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
template <> inline Sntp::Client &Instance::Get(void)
|
||||
{
|
||||
return GetThreadNetif().GetSntpClient();
|
||||
}
|
||||
#endif
|
||||
|
||||
template <> inline Utils::ChildSupervisor &Instance::Get(void)
|
||||
{
|
||||
return GetThreadNetif().GetChildSupervisor();
|
||||
|
||||
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*/
|
||||
|
||||
#include "sntp_client.hpp"
|
||||
|
||||
#include "utils/wrap_string.h"
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/debug.hpp"
|
||||
#include "common/instance.hpp"
|
||||
#include "common/logging.hpp"
|
||||
#include "common/owner-locator.hpp"
|
||||
#include "net/udp6.hpp"
|
||||
#include "thread/thread_netif.hpp"
|
||||
|
||||
#if OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements the SNTP client.
|
||||
*/
|
||||
|
||||
using ot::Encoding::BigEndian::HostSwap16;
|
||||
|
||||
namespace ot {
|
||||
namespace Sntp {
|
||||
|
||||
otError Client::Start(void)
|
||||
{
|
||||
otError error;
|
||||
Ip6::SockAddr addr;
|
||||
|
||||
SuccessOrExit(error = mSocket.Open(&Client::HandleUdpReceive, this));
|
||||
SuccessOrExit(error = mSocket.Bind(addr));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Client::Stop(void)
|
||||
{
|
||||
Message * message = mPendingQueries.GetHead();
|
||||
Message * messageToRemove;
|
||||
QueryMetadata queryMetadata;
|
||||
|
||||
// Remove all pending queries.
|
||||
while (message != NULL)
|
||||
{
|
||||
messageToRemove = message;
|
||||
message = message->GetNext();
|
||||
|
||||
queryMetadata.ReadFrom(*messageToRemove);
|
||||
FinalizeSntpTransaction(*messageToRemove, queryMetadata, 0, OT_ERROR_ABORT);
|
||||
}
|
||||
|
||||
return mSocket.Close();
|
||||
}
|
||||
|
||||
otError Client::Query(const otSntpQuery *aQuery, otSntpResponseHandler aHandler, void *aContext)
|
||||
{
|
||||
otError error;
|
||||
QueryMetadata queryMetadata(aHandler, aContext);
|
||||
Message * message = NULL;
|
||||
Message * messageCopy = NULL;
|
||||
Header header;
|
||||
const Ip6::MessageInfo *messageInfo;
|
||||
|
||||
VerifyOrExit(aQuery->mMessageInfo != NULL, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
// Originate timestamp is used only as a unique token.
|
||||
header.SetTransmitTimestampSeconds(TimerMilli::GetNow() / 1000 + kTimeAt1970);
|
||||
|
||||
VerifyOrExit((message = NewMessage(header)) != NULL, error = OT_ERROR_NO_BUFS);
|
||||
|
||||
messageInfo = static_cast<const Ip6::MessageInfo *>(aQuery->mMessageInfo);
|
||||
|
||||
queryMetadata.mTransmitTimestamp = header.GetTransmitTimestampSeconds();
|
||||
queryMetadata.mTransmissionTime = TimerMilli::GetNow() + kResponseTimeout;
|
||||
queryMetadata.mSourceAddress = messageInfo->GetSockAddr();
|
||||
queryMetadata.mDestinationPort = messageInfo->GetPeerPort();
|
||||
queryMetadata.mDestinationAddress = messageInfo->GetPeerAddr();
|
||||
queryMetadata.mRetransmissionCount = 0;
|
||||
|
||||
VerifyOrExit((messageCopy = CopyAndEnqueueMessage(*message, queryMetadata)) != NULL, error = OT_ERROR_NO_BUFS);
|
||||
SuccessOrExit(error = SendMessage(*message, *messageInfo));
|
||||
|
||||
exit:
|
||||
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
if (message)
|
||||
{
|
||||
message->Free();
|
||||
}
|
||||
|
||||
if (messageCopy)
|
||||
{
|
||||
DequeueMessage(*messageCopy);
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
Message *Client::NewMessage(const Header &aHeader)
|
||||
{
|
||||
Message *message = NULL;
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(sizeof(aHeader))) != NULL);
|
||||
message->Prepend(&aHeader, sizeof(aHeader));
|
||||
message->SetOffset(0);
|
||||
|
||||
exit:
|
||||
return message;
|
||||
}
|
||||
|
||||
Message *Client::CopyAndEnqueueMessage(const Message &aMessage, const QueryMetadata &aQueryMetadata)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint32_t now = TimerMilli::GetNow();
|
||||
Message *messageCopy = NULL;
|
||||
uint32_t nextTransmissionTime;
|
||||
|
||||
// Create a message copy for further retransmissions.
|
||||
VerifyOrExit((messageCopy = aMessage.Clone()) != NULL, error = OT_ERROR_NO_BUFS);
|
||||
|
||||
// Append the copy with retransmission data and add it to the queue.
|
||||
SuccessOrExit(error = aQueryMetadata.AppendTo(*messageCopy));
|
||||
mPendingQueries.Enqueue(*messageCopy);
|
||||
|
||||
// Setup the timer.
|
||||
if (mRetransmissionTimer.IsRunning())
|
||||
{
|
||||
// If timer is already running, check if it should be restarted with earlier fire time.
|
||||
nextTransmissionTime = mRetransmissionTimer.GetFireTime();
|
||||
|
||||
if (aQueryMetadata.IsEarlier(nextTransmissionTime))
|
||||
{
|
||||
mRetransmissionTimer.Start(aQueryMetadata.mTransmissionTime - now);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mRetransmissionTimer.Start(aQueryMetadata.mTransmissionTime - now);
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
if (error != OT_ERROR_NONE && messageCopy != NULL)
|
||||
{
|
||||
messageCopy->Free();
|
||||
messageCopy = NULL;
|
||||
}
|
||||
|
||||
return messageCopy;
|
||||
}
|
||||
|
||||
void Client::DequeueMessage(Message &aMessage)
|
||||
{
|
||||
mPendingQueries.Dequeue(aMessage);
|
||||
|
||||
if (mRetransmissionTimer.IsRunning() && (mPendingQueries.GetHead() == NULL))
|
||||
{
|
||||
// No more requests pending, stop the timer.
|
||||
mRetransmissionTimer.Stop();
|
||||
}
|
||||
|
||||
// Free the message memory.
|
||||
aMessage.Free();
|
||||
}
|
||||
|
||||
otError Client::SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
return mSocket.SendTo(aMessage, aMessageInfo);
|
||||
}
|
||||
|
||||
otError Client::SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
otError error;
|
||||
Message *messageCopy = NULL;
|
||||
|
||||
// Create a message copy for lower layers.
|
||||
VerifyOrExit((messageCopy = aMessage.Clone(aMessage.GetLength() - sizeof(QueryMetadata))) != NULL,
|
||||
error = OT_ERROR_NO_BUFS);
|
||||
|
||||
// Send the copy.
|
||||
SuccessOrExit(error = SendMessage(*messageCopy, aMessageInfo));
|
||||
|
||||
exit:
|
||||
|
||||
if (error != OT_ERROR_NONE && messageCopy != NULL)
|
||||
{
|
||||
messageCopy->Free();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
Message *Client::FindRelatedQuery(const Header &aResponseHeader, QueryMetadata &aQueryMetadata)
|
||||
{
|
||||
Header header;
|
||||
Message *message = mPendingQueries.GetHead();
|
||||
|
||||
while (message != NULL)
|
||||
{
|
||||
// Read originate timestamp.
|
||||
uint16_t count = aQueryMetadata.ReadFrom(*message);
|
||||
assert(count == sizeof(aQueryMetadata));
|
||||
|
||||
if (aQueryMetadata.mTransmitTimestamp == aResponseHeader.GetOriginateTimestampSeconds())
|
||||
{
|
||||
aQueryMetadata.ReadFrom(*message);
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
message = message->GetNext();
|
||||
}
|
||||
|
||||
exit:
|
||||
return message;
|
||||
}
|
||||
|
||||
void Client::FinalizeSntpTransaction(Message & aQuery,
|
||||
const QueryMetadata &aQueryMetadata,
|
||||
uint64_t aTime,
|
||||
otError aResult)
|
||||
{
|
||||
DequeueMessage(aQuery);
|
||||
|
||||
if (aQueryMetadata.mResponseHandler != NULL)
|
||||
{
|
||||
aQueryMetadata.mResponseHandler(aQueryMetadata.mResponseContext, aTime, aResult);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::HandleRetransmissionTimer(Timer &aTimer)
|
||||
{
|
||||
aTimer.GetOwner<Client>().HandleRetransmissionTimer();
|
||||
}
|
||||
|
||||
void Client::HandleRetransmissionTimer(void)
|
||||
{
|
||||
uint32_t now = TimerMilli::GetNow();
|
||||
uint32_t nextDelta = 0xffffffff;
|
||||
QueryMetadata queryMetadata;
|
||||
Message * message = mPendingQueries.GetHead();
|
||||
Message * nextMessage = NULL;
|
||||
Ip6::MessageInfo messageInfo;
|
||||
|
||||
while (message != NULL)
|
||||
{
|
||||
nextMessage = message->GetNext();
|
||||
queryMetadata.ReadFrom(*message);
|
||||
|
||||
if (queryMetadata.IsLater(now))
|
||||
{
|
||||
// Calculate the next delay and choose the lowest.
|
||||
if (queryMetadata.mTransmissionTime - now < nextDelta)
|
||||
{
|
||||
nextDelta = queryMetadata.mTransmissionTime - now;
|
||||
}
|
||||
}
|
||||
else if (queryMetadata.mRetransmissionCount < kMaxRetransmit)
|
||||
{
|
||||
// Increment retransmission counter and timer.
|
||||
queryMetadata.mRetransmissionCount++;
|
||||
queryMetadata.mTransmissionTime = now + kResponseTimeout;
|
||||
queryMetadata.UpdateIn(*message);
|
||||
|
||||
// Check if retransmission time is lower than current lowest.
|
||||
if (queryMetadata.mTransmissionTime - now < nextDelta)
|
||||
{
|
||||
nextDelta = queryMetadata.mTransmissionTime - now;
|
||||
}
|
||||
|
||||
// Retransmit
|
||||
messageInfo.SetPeerAddr(queryMetadata.mDestinationAddress);
|
||||
messageInfo.SetPeerPort(queryMetadata.mDestinationPort);
|
||||
messageInfo.SetSockAddr(queryMetadata.mSourceAddress);
|
||||
|
||||
SendCopy(*message, messageInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No expected response.
|
||||
FinalizeSntpTransaction(*message, queryMetadata, 0, OT_ERROR_RESPONSE_TIMEOUT);
|
||||
}
|
||||
|
||||
message = nextMessage;
|
||||
}
|
||||
|
||||
if (nextDelta != 0xffffffff)
|
||||
{
|
||||
mRetransmissionTimer.Start(nextDelta);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
|
||||
{
|
||||
static_cast<Client *>(aContext)->HandleUdpReceive(*static_cast<Message *>(aMessage),
|
||||
*static_cast<const Ip6::MessageInfo *>(aMessageInfo));
|
||||
}
|
||||
|
||||
void Client::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Header responseHeader;
|
||||
QueryMetadata queryMetadata;
|
||||
Message * message = NULL;
|
||||
uint64_t unixTime = 0;
|
||||
|
||||
OT_UNUSED_VARIABLE(aMessageInfo);
|
||||
|
||||
VerifyOrExit(aMessage.Read(aMessage.GetOffset(), sizeof(responseHeader), &responseHeader) ==
|
||||
sizeof(responseHeader));
|
||||
|
||||
VerifyOrExit((message = FindRelatedQuery(responseHeader, queryMetadata)) != NULL);
|
||||
|
||||
// Check if response came from the server.
|
||||
VerifyOrExit(responseHeader.GetMode() == Header::kModeServer, error = OT_ERROR_FAILED);
|
||||
|
||||
// Check the Kiss-o'-death packet.
|
||||
if (!responseHeader.GetStratum())
|
||||
{
|
||||
char kissCode[Header::GetKissCodeLength() + 1];
|
||||
|
||||
memcpy(kissCode, responseHeader.GetKissCode(), Header::GetKissCodeLength());
|
||||
kissCode[Header::GetKissCodeLength()] = 0;
|
||||
|
||||
otLogInfoIp6("SNTP response contains the Kiss-o'-death packet with %s code", kissCode);
|
||||
ExitNow(error = OT_ERROR_BUSY);
|
||||
}
|
||||
|
||||
// Check if timestamp has been set.
|
||||
VerifyOrExit(responseHeader.GetTransmitTimestampSeconds() != 0 &&
|
||||
responseHeader.GetTransmitTimestampFraction() != 0,
|
||||
error = OT_ERROR_FAILED);
|
||||
|
||||
// The NTP time starts at 1900 while the unix epoch starts at 1970.
|
||||
// Due to NTP protocol limitation, this module stops working correctly after around year 2106, if
|
||||
// unix era is not updated. This seems to be a reasonable limitation for now. Era number cannot be
|
||||
// obtained using NTP protocol, and client of this module is responsible to set it properly.
|
||||
unixTime = GetUnixEra() * (UINT32_MAX + 1);
|
||||
|
||||
if (responseHeader.GetTransmitTimestampSeconds() > kTimeAt1970)
|
||||
{
|
||||
unixTime += static_cast<uint64_t>(responseHeader.GetTransmitTimestampSeconds()) - kTimeAt1970;
|
||||
}
|
||||
else
|
||||
{
|
||||
unixTime +=
|
||||
static_cast<uint64_t>(responseHeader.GetTransmitTimestampSeconds()) + (UINT32_MAX + 1) - kTimeAt1970;
|
||||
}
|
||||
|
||||
// Return the time since 1970.
|
||||
FinalizeSntpTransaction(*message, queryMetadata, unixTime, OT_ERROR_NONE);
|
||||
|
||||
exit:
|
||||
|
||||
if (message != NULL && error != OT_ERROR_NONE)
|
||||
{
|
||||
FinalizeSntpTransaction(*message, queryMetadata, 0, error);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace Sntp
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
@@ -0,0 +1,629 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*/
|
||||
|
||||
#ifndef SNTP_CLIENT_HPP_
|
||||
#define SNTP_CLIENT_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include <openthread/sntp.h>
|
||||
|
||||
#include "common/message.hpp"
|
||||
#include "common/timer.hpp"
|
||||
#include "net/ip6.hpp"
|
||||
#include "net/netif.hpp"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes definitions for the SNTP client.
|
||||
*/
|
||||
|
||||
namespace ot {
|
||||
namespace Sntp {
|
||||
|
||||
/**
|
||||
* This class implements SNTP header generation and parsing.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class Header
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Default constructor for SNTP Header.
|
||||
*
|
||||
*/
|
||||
Header(void)
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
|
||||
// Set default value of flags field.
|
||||
SetFlags(kNtpVersion << kVersionOffset | kModeClient << kModeOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines supported SNTP modes.
|
||||
*
|
||||
*/
|
||||
enum Mode
|
||||
{
|
||||
kModeClient = 3,
|
||||
kModeServer = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* This method returns the flags field value.
|
||||
*
|
||||
* @returns Value of the flags field (LI, VN and Mode).
|
||||
*
|
||||
*/
|
||||
uint8_t GetFlags(void) const { return mFlags; }
|
||||
|
||||
/**
|
||||
* This method sets the flags field.
|
||||
*
|
||||
* @param[in] aFlags The value of the flags field.
|
||||
*
|
||||
*/
|
||||
void SetFlags(uint8_t aFlags) { mFlags = aFlags; }
|
||||
|
||||
/**
|
||||
* This method returns the SNTP operational mode.
|
||||
*
|
||||
* @returns SNTP operational mode.
|
||||
*
|
||||
*/
|
||||
Mode GetMode(void) const { return static_cast<Mode>((mFlags & kModeMask) >> kModeOffset); }
|
||||
|
||||
/**
|
||||
* This method returns the packet stratum field value.
|
||||
*
|
||||
* @returns Value of the packet stratum.
|
||||
*
|
||||
*/
|
||||
uint8_t GetStratum(void) const { return mStratum; }
|
||||
|
||||
/**
|
||||
* This method sets the packet stratum field value.
|
||||
*
|
||||
* @param[in] aStratum The value of the packet stratum field.
|
||||
*
|
||||
*/
|
||||
void SetStratum(uint8_t aStratum) { mStratum = aStratum; }
|
||||
|
||||
/**
|
||||
* This method returns the poll field value.
|
||||
*
|
||||
* @returns Value of the poll field.
|
||||
*
|
||||
*/
|
||||
uint8_t GetPoll(void) const { return mPoll; }
|
||||
|
||||
/**
|
||||
* This method sets the poll field.
|
||||
*
|
||||
* @param[in] aPoll The value of the poll field.
|
||||
*
|
||||
*/
|
||||
void SetPoll(uint8_t aPoll) { mPoll = aPoll; }
|
||||
|
||||
/**
|
||||
* This method returns the precision field value.
|
||||
*
|
||||
* @returns Value of the precision field.
|
||||
*
|
||||
*/
|
||||
uint8_t GetPrecision(void) const { return mPrecision; }
|
||||
|
||||
/**
|
||||
* This method sets the precision field.
|
||||
*
|
||||
* @param[in] aPrecision The value of the precision field.
|
||||
*
|
||||
*/
|
||||
void SetPrecision(uint8_t aPrecision) { mPrecision = aPrecision; }
|
||||
|
||||
/**
|
||||
* This method returns the root delay field value.
|
||||
*
|
||||
* @returns Value of the the root delay field.
|
||||
*
|
||||
*/
|
||||
uint32_t GetRootDelay(void) const { return HostSwap32(mRootDelay); }
|
||||
|
||||
/**
|
||||
* This method sets the the root delay field.
|
||||
*
|
||||
* @param[in] aRootDelay The value of the the root delay field.
|
||||
*
|
||||
*/
|
||||
void SetRootDelay(uint32_t aRootDelay) { mRootDelay = HostSwap32(aRootDelay); }
|
||||
|
||||
/**
|
||||
* This method returns the root dispersion field value.
|
||||
*
|
||||
* @returns Value of the the root dispersion field.
|
||||
*
|
||||
*/
|
||||
uint32_t GetRootDispersion(void) const { return HostSwap32(mRootDispersion); }
|
||||
|
||||
/**
|
||||
* This method sets the the root dispersion field.
|
||||
*
|
||||
* @param[in] aRootDispersion The value of the the root dispersion field.
|
||||
*
|
||||
*/
|
||||
void SetRootDispersion(uint32_t aRootDispersion) { mRootDispersion = HostSwap32(aRootDispersion); }
|
||||
|
||||
/**
|
||||
* This method returns the reference identifier field value.
|
||||
*
|
||||
* @returns Value of the the reference identifier field.
|
||||
*
|
||||
*/
|
||||
uint32_t GetReferenceId(void) const { return HostSwap32(mReferenceId); }
|
||||
|
||||
/**
|
||||
* This method sets the the reference identifier field.
|
||||
*
|
||||
* @param[in] aReferenceId The value of the the reference identifier field.
|
||||
*
|
||||
*/
|
||||
void SetReferenceId(uint32_t aReferenceId) { mReferenceId = HostSwap32(aReferenceId); }
|
||||
|
||||
/**
|
||||
* This method returns the kiss code in ASCII format.
|
||||
*
|
||||
* @returns Value of the the reference identifier field in ASCII format.
|
||||
*
|
||||
*/
|
||||
char *GetKissCode(void) { return reinterpret_cast<char *>(&mReferenceId); }
|
||||
|
||||
/**
|
||||
* This method returns the length of the kiss code in ASCII format.
|
||||
*
|
||||
* @returns The length of the kiss code in ASCII format.
|
||||
*
|
||||
*/
|
||||
static uint16_t GetKissCodeLength(void) { return sizeof(uint32_t); };
|
||||
|
||||
/**
|
||||
* This method returns the reference timestamp seconds field.
|
||||
*
|
||||
* @returns Value of the reference timestamp seconds field.
|
||||
*
|
||||
*/
|
||||
uint32_t GetReferenceTimestampSeconds(void) const { return HostSwap32(mReferenceTimestampSeconds); }
|
||||
|
||||
/**
|
||||
* This method sets the reference timestamp seconds field.
|
||||
*
|
||||
* @param[in] aReferenceTimestampSeconds Value of the reference timestamp seconds field.
|
||||
*
|
||||
*/
|
||||
void SetReferenceTimestampSeconds(uint32_t aReferenceTimestampSeconds)
|
||||
{
|
||||
mReferenceTimestampSeconds = HostSwap32(aReferenceTimestampSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the reference timestamp fraction field.
|
||||
*
|
||||
* @returns Value of the reference timestamp fraction field.
|
||||
*
|
||||
*/
|
||||
uint32_t GetReferenceTimestampFraction(void) const { return HostSwap32(mReferenceTimestampFraction); }
|
||||
|
||||
/**
|
||||
* This method sets the reference timestamp fraction field.
|
||||
*
|
||||
* @param[in] aReferenceTimestampFraction Value of the reference timestamp fraction field.
|
||||
*
|
||||
*/
|
||||
void SetReferenceTimestampFraction(uint32_t aReferenceTimestampFraction)
|
||||
{
|
||||
mReferenceTimestampFraction = HostSwap32(aReferenceTimestampFraction);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the originate timestamp seconds field.
|
||||
*
|
||||
* @returns Value of the originate timestamp seconds field.
|
||||
*
|
||||
*/
|
||||
uint32_t GetOriginateTimestampSeconds(void) const { return HostSwap32(mOriginateTimestampSeconds); }
|
||||
|
||||
/**
|
||||
* This method sets the originate timestamp seconds field.
|
||||
*
|
||||
* @param[in] aOriginateTimestampSeconds Value of the originate timestamp seconds field.
|
||||
*
|
||||
*/
|
||||
void SetOriginateTimestampSeconds(uint32_t aOriginateTimestampSeconds)
|
||||
{
|
||||
mOriginateTimestampSeconds = HostSwap32(aOriginateTimestampSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the originate timestamp fraction field.
|
||||
*
|
||||
* @returns Value of the originate timestamp fraction field.
|
||||
*
|
||||
*/
|
||||
uint32_t GetOriginateTimestampFraction(void) const { return HostSwap32(mOriginateTimestampFraction); }
|
||||
|
||||
/**
|
||||
* This method sets the originate timestamp fraction field.
|
||||
*
|
||||
* @param[in] aOriginateTimestampFraction Value of the originate timestamp fraction field.
|
||||
*
|
||||
*/
|
||||
void SetOriginateTimestampFraction(uint32_t aOriginateTimestampFraction)
|
||||
{
|
||||
mOriginateTimestampFraction = HostSwap32(aOriginateTimestampFraction);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the receive timestamp seconds field.
|
||||
*
|
||||
* @returns Value of the receive timestamp seconds field.
|
||||
*
|
||||
*/
|
||||
uint32_t GetReceiveTimestampSeconds(void) const { return HostSwap32(mReceiveTimestampSeconds); }
|
||||
|
||||
/**
|
||||
* This method sets the receive timestamp seconds field.
|
||||
*
|
||||
* @param[in] aReceiveTimestampSeconds Value of the receive timestamp seconds field.
|
||||
*
|
||||
*/
|
||||
void SetReceiveTimestampSeconds(uint32_t aReceiveTimestampSeconds)
|
||||
{
|
||||
mReceiveTimestampSeconds = HostSwap32(aReceiveTimestampSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the receive timestamp fraction field.
|
||||
*
|
||||
* @returns Value of the receive timestamp fraction field.
|
||||
*
|
||||
*/
|
||||
uint32_t GetReceiveTimestampFraction(void) const { return HostSwap32(mReceiveTimestampFraction); }
|
||||
|
||||
/**
|
||||
* This method sets the receive timestamp fraction field.
|
||||
*
|
||||
* @param[in] aReceiveTimestampFraction Value of the receive timestamp fraction field.
|
||||
*
|
||||
*/
|
||||
void SetReceiveTimestampFraction(uint32_t aReceiveTimestampFraction)
|
||||
{
|
||||
mReceiveTimestampFraction = HostSwap32(aReceiveTimestampFraction);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the transmit timestamp seconds field.
|
||||
*
|
||||
* @returns Value of the transmit timestamp seconds field.
|
||||
*
|
||||
*/
|
||||
uint32_t GetTransmitTimestampSeconds(void) const { return HostSwap32(mTransmitTimestampSeconds); }
|
||||
|
||||
/**
|
||||
* This method sets the transmit timestamp seconds field.
|
||||
*
|
||||
* @param[in] aTransmitTimestampSeconds Value of the transmit timestamp seconds field.
|
||||
*
|
||||
*/
|
||||
void SetTransmitTimestampSeconds(uint32_t aTransmitTimestampSeconds)
|
||||
{
|
||||
mTransmitTimestampSeconds = HostSwap32(aTransmitTimestampSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the transmit timestamp fraction field.
|
||||
*
|
||||
* @returns Value of the transmit timestamp fraction field.
|
||||
*
|
||||
*/
|
||||
uint32_t GetTransmitTimestampFraction(void) const { return HostSwap32(mTransmitTimestampFraction); }
|
||||
|
||||
/**
|
||||
* This method sets the transmit timestamp fraction field.
|
||||
*
|
||||
* @param[in] aTransmitTimestampFraction Value of the transmit timestamp fraction field.
|
||||
*
|
||||
*/
|
||||
void SetTransmitTimestampFraction(uint32_t aTransmitTimestampFraction)
|
||||
{
|
||||
mTransmitTimestampFraction = HostSwap32(aTransmitTimestampFraction);
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Protocol Constants (RFC 5905).
|
||||
*
|
||||
*/
|
||||
enum
|
||||
{
|
||||
/**
|
||||
* Current NTP version.
|
||||
*
|
||||
*/
|
||||
kNtpVersion = 4,
|
||||
|
||||
/**
|
||||
* Flags offsets and masks.
|
||||
*
|
||||
*/
|
||||
kLeapOffset = 6, ///< Leap Indicator field offset.
|
||||
kLeapMask = 0x03 << kLeapOffset, ///< Leap Indicator field mask.
|
||||
kVersionOffset = 3, ///< Version field offset.
|
||||
kVersionMask = 0x07 << kVersionOffset, ///< Version field mask.
|
||||
kModeOffset = 0, ///< Mode field offset.
|
||||
kModeMask = 0x07 << kModeOffset, ///< Mode filed mask.
|
||||
};
|
||||
|
||||
/**
|
||||
* SNTP Header fields.
|
||||
*
|
||||
*/
|
||||
uint8_t mFlags; ///< SNTP flags: LI Leap Indicator, VN Version Number and Mode.
|
||||
uint8_t mStratum; ///< Packet Stratum.
|
||||
uint8_t mPoll; ///< Maximum interval between successive messages, in log2 seconds.
|
||||
uint8_t mPrecision; ///< The precision of the system clock, in log2 seconds.
|
||||
uint32_t mRootDelay; ///< Total round-trip delay to the reference clock, in NTP short format.
|
||||
uint32_t mRootDispersion; ///< Total dispersion to the reference clock.
|
||||
uint32_t mReferenceId; ///< ID identifying the particular server or reference clock.
|
||||
uint32_t mReferenceTimestampSeconds; ///< Time when the system clock was last set or corrected, in NTP
|
||||
///< timestamp format.
|
||||
uint32_t mReferenceTimestampFraction; ///< Fraction part of above value.
|
||||
uint32_t mOriginateTimestampSeconds; ///< Time at the client when the request departed for the server, in NTP
|
||||
///< timestamp format.
|
||||
uint32_t mOriginateTimestampFraction; ///< Fraction part of above value.
|
||||
uint32_t mReceiveTimestampSeconds; ///< Time at the server when the request arrived from the client, in NTP
|
||||
///< timestamp format.
|
||||
uint32_t mReceiveTimestampFraction; ///< Fraction part of above value.
|
||||
uint32_t mTransmitTimestampSeconds; ///< Time at the server when the response left for the client, in NTP
|
||||
///< timestamp format.
|
||||
uint32_t mTransmitTimestampFraction; ///< Fraction part of above value.
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements metadata required for SNTP retransmission.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class QueryMetadata
|
||||
{
|
||||
friend class Client;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Default constructor for the object.
|
||||
*
|
||||
*/
|
||||
QueryMetadata(void) { memset(this, 0, sizeof(*this)); };
|
||||
|
||||
/**
|
||||
* This constructor initializes the object with specific values.
|
||||
*
|
||||
* @param[in] aHandler Pointer to a handler function for the response.
|
||||
* @param[in] aContext Context for the handler function.
|
||||
*
|
||||
*/
|
||||
QueryMetadata(otSntpResponseHandler aHandler, void *aContext)
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
mResponseHandler = aHandler;
|
||||
mResponseContext = aContext;
|
||||
};
|
||||
|
||||
/**
|
||||
* This method appends request data to the message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully appended the bytes.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient available buffers to grow the message.
|
||||
*
|
||||
*/
|
||||
otError AppendTo(Message &aMessage) const { return aMessage.Append(this, sizeof(*this)); };
|
||||
|
||||
/**
|
||||
* This method reads request data from the message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
*
|
||||
* @returns The number of bytes read.
|
||||
*
|
||||
*/
|
||||
uint16_t ReadFrom(const Message &aMessage)
|
||||
{
|
||||
return aMessage.Read(aMessage.GetLength() - sizeof(*this), sizeof(*this), this);
|
||||
};
|
||||
|
||||
/**
|
||||
* This method updates request data in the message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
*
|
||||
* @returns The number of bytes updated.
|
||||
*
|
||||
*/
|
||||
int UpdateIn(Message &aMessage) const
|
||||
{
|
||||
return aMessage.Write(aMessage.GetLength() - sizeof(*this), sizeof(*this), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks if the message shall be sent before the given time.
|
||||
*
|
||||
* @param[in] aTime A time to compare.
|
||||
*
|
||||
* @retval TRUE If the message shall be sent before the given time.
|
||||
* @retval FALSE Otherwise.
|
||||
*/
|
||||
bool IsEarlier(uint32_t aTime) const { return (static_cast<int32_t>(aTime - mTransmissionTime) > 0); };
|
||||
|
||||
/**
|
||||
* This method checks if the message shall be sent after the given time.
|
||||
*
|
||||
* @param[in] aTime A time to compare.
|
||||
*
|
||||
* @retval TRUE If the message shall be sent after the given time.
|
||||
* @retval FALSE Otherwise.
|
||||
*/
|
||||
bool IsLater(uint32_t aTime) const { return (static_cast<int32_t>(aTime - mTransmissionTime) < 0); };
|
||||
|
||||
private:
|
||||
uint32_t mTransmitTimestamp; ///< Time at the client when the request departed for the server.
|
||||
otSntpResponseHandler mResponseHandler; ///< A function pointer that is called on response reception.
|
||||
void * mResponseContext; ///< A pointer to arbitrary context information.
|
||||
uint32_t mTransmissionTime; ///< Time when the timer should shoot for this message.
|
||||
Ip6::Address mSourceAddress; ///< IPv6 address of the message source.
|
||||
Ip6::Address mDestinationAddress; ///< IPv6 address of the message destination.
|
||||
uint16_t mDestinationPort; ///< UDP port of the message destination.
|
||||
uint8_t mRetransmissionCount; ///< Number of retransmissions.
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements Sntp client.
|
||||
*
|
||||
*/
|
||||
class Client
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This constructor initializes the object.
|
||||
*
|
||||
* @param[in] aNetif A reference to the network interface that SNTP client should be assigned to.
|
||||
*
|
||||
*/
|
||||
Client(Ip6::Netif &aNetif)
|
||||
: mSocket(aNetif.GetIp6().GetUdp())
|
||||
, mRetransmissionTimer(aNetif.GetInstance(), &Client::HandleRetransmissionTimer, this)
|
||||
, mUnixEra(0){};
|
||||
|
||||
/**
|
||||
* This method starts the SNTP client.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully started the SNTP client.
|
||||
* @retval OT_ERROR_ALREADY The socket is already open.
|
||||
*/
|
||||
otError Start(void);
|
||||
|
||||
/**
|
||||
* This method stops the SNTP client.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully stopped the SNTP client.
|
||||
*
|
||||
*/
|
||||
otError Stop(void);
|
||||
|
||||
/**
|
||||
* This method returns the unix era number.
|
||||
*
|
||||
* @returns The unix era number.
|
||||
*
|
||||
*/
|
||||
uint32_t GetUnixEra(void) const { return mUnixEra; }
|
||||
|
||||
/**
|
||||
* This method sets the unix era number.
|
||||
*
|
||||
* @param[in] aUnixEra The unix era number.
|
||||
*
|
||||
*/
|
||||
void SetUnixEra(uint32_t aUnixEra) { mUnixEra = aUnixEra; }
|
||||
|
||||
/**
|
||||
* This method sends an SNTP query.
|
||||
*
|
||||
* @param[in] aQuery A pointer to specify SNTP query parameters.
|
||||
* @param[in] aHandler A function pointer that shall be called on response reception or time-out.
|
||||
* @param[in] aContext A pointer to arbitrary context information.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully sent SNTP query.
|
||||
* @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data.
|
||||
* @retval OT_ERROR_INVALID_ARGS Invalid arguments supplied.
|
||||
*
|
||||
*/
|
||||
otError Query(const otSntpQuery *aQuery, otSntpResponseHandler aHandler, void *aContext);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Protocol Constants (RFC 5905).
|
||||
*
|
||||
*/
|
||||
enum
|
||||
{
|
||||
/**
|
||||
* Number of seconds between 1st January 1900 and 1st January 1970.
|
||||
*
|
||||
*/
|
||||
kTimeAt1970 = 2208988800UL,
|
||||
};
|
||||
|
||||
/**
|
||||
* Retransmission parameters.
|
||||
*
|
||||
*/
|
||||
enum
|
||||
{
|
||||
kResponseTimeout = OPENTHREAD_CONFIG_SNTP_RESPONSE_TIMEOUT,
|
||||
kMaxRetransmit = OPENTHREAD_CONFIG_SNTP_MAX_RETRANSMIT,
|
||||
};
|
||||
|
||||
Message *NewMessage(const Header &aHeader);
|
||||
Message *CopyAndEnqueueMessage(const Message &aMessage, const QueryMetadata &aQueryMetadata);
|
||||
void DequeueMessage(Message &aMessage);
|
||||
otError SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
otError SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
|
||||
Message *FindRelatedQuery(const Header &aResponseHeader, QueryMetadata &aQueryMetadata);
|
||||
void FinalizeSntpTransaction(Message &aQuery, const QueryMetadata &aQueryMetadata, uint64_t aTime, otError aResult);
|
||||
|
||||
static void HandleRetransmissionTimer(Timer &aTimer);
|
||||
void HandleRetransmissionTimer(void);
|
||||
|
||||
static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
|
||||
void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
|
||||
Ip6::UdpSocket mSocket;
|
||||
|
||||
MessageQueue mPendingQueries;
|
||||
TimerMilli mRetransmissionTimer;
|
||||
|
||||
uint32_t mUnixEra;
|
||||
};
|
||||
|
||||
} // namespace Sntp
|
||||
} // namespace ot
|
||||
|
||||
#endif // SNTP_CLIENT_HPP_
|
||||
@@ -543,6 +543,26 @@
|
||||
#define OPENTHREAD_CONFIG_DNS_MAX_RETRANSMIT 2
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_SNTP_RESPONSE_TIMEOUT
|
||||
*
|
||||
* Maximum time that SNTP Client waits for response in milliseconds.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_SNTP_RESPONSE_TIMEOUT
|
||||
#define OPENTHREAD_CONFIG_SNTP_RESPONSE_TIMEOUT 3000
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_SNTP_MAX_RETRANSMIT
|
||||
*
|
||||
* Maximum number of retransmissions for SNTP client.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_SNTP_MAX_RETRANSMIT
|
||||
#define OPENTHREAD_CONFIG_SNTP_MAX_RETRANSMIT 2
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_JOIN_BEACON_VERSION
|
||||
*
|
||||
|
||||
@@ -61,6 +61,9 @@ ThreadNetif::ThreadNetif(Instance &aInstance)
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
, mDnsClient(aInstance.GetThreadNetif())
|
||||
#endif // OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
#if OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
, mSntpClient(aInstance.GetThreadNetif())
|
||||
#endif // OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
, mActiveDataset(aInstance)
|
||||
, mPendingDataset(aInstance)
|
||||
, mKeyManager(aInstance)
|
||||
@@ -121,6 +124,9 @@ otError ThreadNetif::Up(void)
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
mDnsClient.Start();
|
||||
#endif
|
||||
#if OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
mSntpClient.Start();
|
||||
#endif
|
||||
#if OPENTHREAD_ENABLE_CHANNEL_MONITOR
|
||||
GetInstance().GetChannelMonitor().Start();
|
||||
#endif
|
||||
@@ -137,6 +143,9 @@ otError ThreadNetif::Down(void)
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
mDnsClient.Stop();
|
||||
#endif
|
||||
#if OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
mSntpClient.Stop();
|
||||
#endif
|
||||
#if OPENTHREAD_ENABLE_CHANNEL_MONITOR
|
||||
GetInstance().GetChannelMonitor().Stop();
|
||||
#endif
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
#include "net/dns_client.hpp"
|
||||
#include "net/ip6_filter.hpp"
|
||||
#include "net/netif.hpp"
|
||||
#include "net/sntp_client.hpp"
|
||||
#include "thread/address_resolver.hpp"
|
||||
#include "thread/announce_begin_server.hpp"
|
||||
#include "thread/energy_scan_server.hpp"
|
||||
@@ -419,6 +420,16 @@ public:
|
||||
TimeSync &GetTimeSync(void) { return mTimeSync; }
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
/**
|
||||
* This method returns a reference to the SNTP client object.
|
||||
*
|
||||
* @returns A reference to the SNTP client object.
|
||||
*
|
||||
*/
|
||||
Sntp::Client &GetSntpClient(void) { return mSntpClient; }
|
||||
#endif // OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
|
||||
/**
|
||||
* This method returns whether Thread Management Framework Addressing Rules are met.
|
||||
*
|
||||
@@ -441,6 +452,9 @@ private:
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
Dns::Client mDnsClient;
|
||||
#endif // OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
#if OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
Sntp::Client mSntpClient;
|
||||
#endif // OPENTHREAD_ENABLE_SNTP_CLIENT
|
||||
MeshCoP::ActiveDataset mActiveDataset;
|
||||
MeshCoP::PendingDataset mPendingDataset;
|
||||
Ip6::Filter mIp6Filter;
|
||||
|
||||
Reference in New Issue
Block a user