1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

sntp: initial import

This commit is contained in:
Luminita 2016-10-29 16:59:00 +02:00
parent ac94d38657
commit cf3f02c2e1
9 changed files with 388 additions and 4 deletions

View File

@ -19,6 +19,11 @@ ifneq (,$(filter nhdp,$(USEMODULE)))
USEMODULE += oonf_rfc5444
endif
ifneq (,$(filter sntp,$(USEMODULE)))
USEMODULE += gnrc_sock_udp
USEMODULE += xtimer
endif
ifneq (,$(filter gnrc_netdev_default,$(USEMODULE)))
USEMODULE += gnrc_netif
USEMODULE += gnrc_netdev2

View File

@ -89,6 +89,10 @@ ifneq (,$(filter gnrc_uhcpc,$(USEMODULE)))
DIRS += net/gnrc/application_layer/uhcpc
endif
ifneq (,$(filter sntp,$(USEMODULE)))
DIRS += net/application_layer/sntp
endif
ifneq (,$(filter netopt,$(USEMODULE)))
DIRS += net/crosslayer/netopt
endif

View File

@ -0,0 +1,167 @@
/*
* Copyright (C) 2016 Luminița Lăzărescu <cluminita.lazarescu@gmail.com>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup net_ntp_packet NTP Packet
* @ingroup net
* @brief The NTP packet module provides functionality to manipulate the NTP header
* @{
*
* @file
* @brief NTP packet definitions
*
* @author Luminița Lăzărescu <cluminita.lazarescu@gmail.com>
* @author Martine Lenders <m.lenders@fu-berlin.de>
*/
#ifndef NTP_PACKET_H_
#define NTP_PACKET_H_
#include <stdint.h>
#include "byteorder.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @{
* @brief Bit positions and masks for ntp_packet_t::li_vn_mode
*/
/**
* @brief Leap indicator position
*/
#define NTP_PACKET_LI_POS (6U)
#define NTP_PACKET_LI_MASK (0xc0) /**< leap indicator mask */
#define NTP_PACKET_VN_POS (3U) /**< version position */
#define NTP_PACKET_VN_MASK (0x38) /**< version mask */
#define NTP_PACKET_MODE_MASK (0x07) /**< mode mask */
/** @} */
#define NTP_VERSION (4U) /**< NTP version */
#define NTP_PORT (123U) /**< NTP port number */
/**
* @brief NTP modes
*/
typedef enum {
NTP_MODE_RESERVED = 0, /**< reserved */
NTP_MODE_SYM_ACTIVE, /**< symmetric active */
NTP_MODE_SYM_PASSIVE, /**< symmetric passive */
NTP_MODE_CLIENT, /**< client */
NTP_MODE_SERVER, /**< server */
NTP_MODE_BROADCAST, /**< broadcast */
NTP_MODE_PRIV /**< reserved for private use */
} ntp_mode_t;
/**
* @brief NTP timestamp
*
* @see [RFC 5905, Section 6](https://tools.ietf.org/html/rfc5905#section-6)
*/
typedef struct __attribute__((packed)) {
network_uint32_t seconds; /**< seconds since 1 January 1900 00:00 UTC */
network_uint32_t fraction; /**< fraction of seconds in 232 picoseconds */
} ntp_timestamp_t;
/**
* @brief NTP packet
*
* @see [RFC 5905, Section 7.3](https://tools.ietf.org/html/rfc5905#section-7.3)
*/
typedef struct __attribute__((packed)) {
uint8_t li_vn_mode; /**< leap indicator, version and mode */
uint8_t stratum; /**< stratum */
uint8_t poll; /**< poll in log2 seconds */
uint8_t precision; /**< precision in log2 seconds */
network_uint32_t root_delay; /**< root delay in NTP short format */
network_uint32_t root_dispersion; /**< root dispersion in NTP short format */
network_uint32_t reference_id; /**< reference ID */
ntp_timestamp_t reference; /**< reference timestamp */
ntp_timestamp_t origin; /**< origin timesptamp */
ntp_timestamp_t receive; /**< receive timestamp */
ntp_timestamp_t transmit; /**< transmit timestamp */
} ntp_packet_t;
/**
* @brief Set leap indicator in a NTP packet
*
* @param[in] packet The NTP packet
* @param[in] li Leap indicator
*/
static inline void ntp_packet_set_li(ntp_packet_t *packet, uint8_t li)
{
packet->li_vn_mode &= ~NTP_PACKET_LI_MASK;
packet->li_vn_mode |= li << NTP_PACKET_LI_POS;
}
/**
* @brief Set version in a NTP packet
*
* @param[in] packet The NTP packet
*/
static inline void ntp_packet_set_vn(ntp_packet_t *packet)
{
packet->li_vn_mode &= ~NTP_PACKET_VN_MASK;
packet->li_vn_mode |= (NTP_VERSION << NTP_PACKET_VN_POS) & NTP_PACKET_VN_MASK;
}
/**
* @brief Set mode in a NTP packet
*
* @param[in] packet The NTP packet
* @param[in] mode Mode
*/
static inline void ntp_packet_set_mode(ntp_packet_t *packet, ntp_mode_t mode)
{
packet->li_vn_mode &= ~NTP_PACKET_MODE_MASK;
packet->li_vn_mode |= mode & NTP_PACKET_MODE_MASK;
}
/**
* @brief Get leap indicator from a NTP packet
*
* @param[in] packet The NTP packet
*
* @return The leap indicator of @p packet
*/
static inline uint8_t ntp_packet_get_li(ntp_packet_t *packet)
{
return (packet->li_vn_mode & NTP_PACKET_LI_MASK) >> NTP_PACKET_LI_POS;
}
/**
* @brief Get version from a NTP packet
*
* @param[in] packet The NTP packet
*
* @return The version of @p packet
*/
static inline uint8_t ntp_packet_get_vn(ntp_packet_t *packet)
{
return (packet->li_vn_mode & NTP_PACKET_VN_MASK) >> NTP_PACKET_VN_POS;
}
/**
* @brief Get mode from a NTP packet
*
* @param[in] packet The NTP packet
*
* @return The version of @p packet
*/
static inline ntp_mode_t ntp_packet_get_mode(ntp_packet_t *packet)
{
return (packet->li_vn_mode & NTP_PACKET_MODE_MASK);
}
#ifdef __cplusplus
}
#endif
#endif /* NTP_PACKET_H_ */
/** @} */

55
sys/include/net/sntp.h Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2016 Luminița Lăzărescu <cluminita.lazarescu@gmail.com>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup net_sntp Simple Network Time Protocol
* @ingroup net
* @brief Simple Network Time Protocol (SNTP) implementation
* @{
*
* @file
* @brief SNTP definitions
*
* @author Luminița Lăzărescu <cluminita.lazarescu@gmail.com>
* @author Martine Lenders <m.lenders@fu-berlin.de>
*/
#ifndef SNTP_H_
#define SNTP_H_
#include <stdint.h>
#include "net/sock/udp.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Synchronize with time server
*
* @param[in] server The time server
* @param[in] timeout Timeout for the server response
*
* @return 0 on success
* @return Negative number on error
*/
int sntp_sync(sock_udp_ep_t *server, uint32_t timeout);
/**
* @brief Get real time offset from system time as returned by @ref xtimer_now64()
*
* @return Real time offset in microseconds relative to 1900-01-01 00:00 UTC
*/
int64_t sntp_get_offset(void);
#ifdef __cplusplus
}
#endif
#endif /* SNTP_H_ */
/** @} */

View File

@ -0,0 +1,2 @@
MODULE = sntp
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,89 @@
/*
* Copyright (C) 2016 Luminița Lăzărescu <cluminita.lazarescu@gmail.com>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
*
* @file
* @brief SNTP implementation
*
* @author Luminița Lăzărescu <cluminita.lazarescu@gmail.com>
* @author Martine Lenders <m.lenders@fu-berlin.de>
*
* @}
*/
#include <string.h>
#include "net/sntp.h"
#include "net/ntp_packet.h"
#include "net/sock/udp.h"
#include "xtimer.h"
#include "mutex.h"
#include "byteorder.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static sock_udp_t _sntp_sock;
static int64_t _sntp_offset = 0;
static mutex_t _sntp_mutex = MUTEX_INIT;
static ntp_packet_t _sntp_packet;
int sntp_sync(sock_udp_ep_t *server, uint32_t timeout)
{
int result;
mutex_lock(&_sntp_mutex);
if ((result = sock_udp_create(&_sntp_sock,
NULL,
server,
0)) < 0) {
DEBUG("Error creating UDP sock\n");
mutex_unlock(&_sntp_mutex);
return result;
}
memset(&_sntp_packet, 0, sizeof(_sntp_packet));
ntp_packet_set_vn(&_sntp_packet);
ntp_packet_set_mode(&_sntp_packet, NTP_MODE_CLIENT);
if ((result = (int)sock_udp_send(&_sntp_sock,
&_sntp_packet,
sizeof(_sntp_packet),
NULL)) < 0) {
DEBUG("Error sending message\n");
sock_udp_close(&_sntp_sock);
mutex_unlock(&_sntp_mutex);
return result;
}
if ((result = (int)sock_udp_recv(&_sntp_sock,
&_sntp_packet,
sizeof(_sntp_packet),
timeout,
NULL)) < 0) {
DEBUG("Error receiving message\n");
sock_udp_close(&_sntp_sock);
mutex_unlock(&_sntp_mutex);
return result;
}
sock_udp_close(&_sntp_sock);
_sntp_offset = (byteorder_ntohl(_sntp_packet.transmit.seconds) * SEC_IN_USEC) +
((byteorder_ntohl(_sntp_packet.transmit.fraction) * 232)
/ 1000000) - xtimer_now64();
mutex_unlock(&_sntp_mutex);
return 0;
}
int64_t sntp_get_offset(void)
{
int64_t result;
mutex_lock(&_sntp_mutex);
result = _sntp_offset;
mutex_unlock(&_sntp_mutex);
return result;
}

View File

@ -66,6 +66,9 @@ endif
ifneq (,$(filter ccn-lite-utils,$(USEMODULE)))
SRC += sc_ccnl.c
endif
ifneq (,$(filter sntp,$(USEMODULE)))
SRC += sc_sntp.c
endif
# TODO
# Conditional building not possible at the moment due to

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2016 Luminița Lăzărescu <cluminita.lazarescu@gmail.com>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_shell_commands
* @{
*
* @file
* @brief Prints the real time offset from the system time
*
* @author Luminița Lăzărescu <cluminita.lazarescu@gmail.com>
*/
#include "net/sntp.h"
#include "net/ntp_packet.h"
#include "net/af.h"
#include "net/ipv6/addr.h"
#define _DEFAULT_TIMEOUT (5000U);
static void _usage(char *cmd)
{
printf("Usage: %s <server addr> [<timeout>]\n", cmd);
puts("default: timeout = 5000");
}
int _ntpdate(int argc, char **argv)
{
uint32_t timeout = _DEFAULT_TIMEOUT;
if (argc < 2) {
_usage(argv[0]);
return 1;
}
sock_udp_ep_t server = { .port = NTP_PORT, .family = AF_INET6 };
ipv6_addr_from_str((ipv6_addr_t *)&server.addr, argv[1]);
if (argc > 2) {
timeout = atoi(argv[2]);
}
if (sntp_sync(&server, timeout) < 0) {
puts("Error in synchronization");
return 1;
}
printf("Offset: %i\n", (int)sntp_get_offset());
return 0;
}

View File

@ -129,6 +129,10 @@ extern int _ccnl_interest(int argc, char **argv);
extern int _ccnl_fib(int argc, char **argv);
#endif
#ifdef MODULE_SNTP
extern int _ntpdate(int argc, char **argv);
#endif
const shell_command_t _shell_command_list[] = {
{"reboot", "Reboot the node", _reboot_handler},
#ifdef MODULE_CONFIG
@ -209,10 +213,13 @@ const shell_command_t _shell_command_list[] = {
{"saul", "interact with sensors and actuators using SAUL", _saul },
#endif
#ifdef MODULE_CCN_LITE_UTILS
{ "ccnl_open", "opens an interface or socket", _ccnl_open},
{ "ccnl_int", "sends an interest", _ccnl_interest},
{ "ccnl_cont", "create content and populated it", _ccnl_content},
{ "ccnl_fib", "shows or modifies the CCN-Lite FIB", _ccnl_fib},
{ "ccnl_open", "opens an interface or socket", _ccnl_open },
{ "ccnl_int", "sends an interest", _ccnl_interest },
{ "ccnl_cont", "create content and populated it", _ccnl_content },
{ "ccnl_fib", "shows or modifies the CCN-Lite FIB", _ccnl_fib },
#endif
#ifdef MODULE_SNTP
{ "ntpdate", "synchronizes with a remote time server", _ntpdate },
#endif
{NULL, NULL, NULL}
};