1 /*
2 * Copyright (c) 2017 Linaro Limited
3 * Copyright (c) 2019 Intel Corporation
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_REGISTER(net_sntp_client_sample, LOG_LEVEL_DBG);
10
11 #include <zephyr/net/socket.h>
12 #include <zephyr/net/socket_service.h>
13 #include <zephyr/net/sntp.h>
14 #include <arpa/inet.h>
15 #include <netdb.h>
16
17 #include "net_sample_common.h"
18
19 static K_SEM_DEFINE(sntp_async_received, 0, 1);
20 static void sntp_service_handler(struct net_socket_service_event *pev);
21
22 NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(service_sntp_async, sntp_service_handler, 1);
23
dns_query(const char * host,uint16_t port,int family,int socktype,struct sockaddr * addr,socklen_t * addrlen)24 int dns_query(const char *host, uint16_t port, int family, int socktype, struct sockaddr *addr,
25 socklen_t *addrlen)
26 {
27 struct addrinfo hints = {
28 .ai_family = family,
29 .ai_socktype = socktype,
30 };
31 struct addrinfo *res = NULL;
32 char addr_str[INET6_ADDRSTRLEN] = {0};
33 int rv;
34
35 /* Perform DNS query */
36 rv = getaddrinfo(host, NULL, &hints, &res);
37 if (rv < 0) {
38 LOG_ERR("getaddrinfo failed (%d, errno %d)", rv, errno);
39 return rv;
40 }
41 /* Store the first result */
42 *addr = *res->ai_addr;
43 *addrlen = res->ai_addrlen;
44 /* Free the allocated memory */
45 freeaddrinfo(res);
46 /* Store the port */
47 net_sin(addr)->sin_port = htons(port);
48 /* Print the found address */
49 inet_ntop(addr->sa_family, &net_sin(addr)->sin_addr, addr_str, sizeof(addr_str));
50 LOG_INF("%s -> %s", host, addr_str);
51 return 0;
52 }
53
sntp_service_handler(struct net_socket_service_event * pev)54 static void sntp_service_handler(struct net_socket_service_event *pev)
55 {
56 struct sntp_time s_time;
57 int rc;
58
59 /* Read the response from the socket */
60 rc = sntp_read_async(pev, &s_time);
61 if (rc != 0) {
62 LOG_ERR("Failed to read SNTP response (%d)", rc);
63 return;
64 }
65
66 /* Close the service */
67 sntp_close_async(&service_sntp_async);
68
69 LOG_INF("SNTP Time: %llu (async)", s_time.seconds);
70
71 /* Notify test thread */
72 k_sem_give(&sntp_async_received);
73 }
74
do_sntp(int family)75 static void do_sntp(int family)
76 {
77 char *family_str = family == AF_INET ? "IPv4" : "IPv6";
78 struct sntp_time s_time;
79 struct sntp_ctx ctx;
80 struct sockaddr addr;
81 socklen_t addrlen;
82 int rv;
83
84 /* Get SNTP server */
85 rv = dns_query(CONFIG_NET_SAMPLE_SNTP_SERVER_ADDRESS, CONFIG_NET_SAMPLE_SNTP_SERVER_PORT,
86 family, SOCK_DGRAM, &addr, &addrlen);
87 if (rv != 0) {
88 LOG_ERR("Failed to lookup %s SNTP server (%d)", family_str, rv);
89 return;
90 }
91
92 rv = sntp_init(&ctx, &addr, addrlen);
93 if (rv < 0) {
94 LOG_ERR("Failed to init SNTP %s ctx: %d", family_str, rv);
95 goto end;
96 }
97
98 LOG_INF("Sending SNTP %s request...", family_str);
99 rv = sntp_query(&ctx, 4 * MSEC_PER_SEC, &s_time);
100 if (rv < 0) {
101 LOG_ERR("SNTP %s request failed: %d", family_str, rv);
102 goto end;
103 }
104
105 LOG_INF("SNTP Time: %llu", s_time.seconds);
106
107 sntp_close(&ctx);
108
109 rv = sntp_init_async(&ctx, &addr, addrlen, &service_sntp_async);
110 if (rv < 0) {
111 LOG_ERR("Failed to initialise SNTP context (%d)", rv);
112 goto end;
113 }
114
115 rv = sntp_send_async(&ctx);
116 if (rv < 0) {
117 LOG_ERR("Failed to send SNTP query (%d)", rv);
118 goto end;
119 }
120
121 /* Wait for the response to be received asynchronously */
122 rv = k_sem_take(&sntp_async_received, K_MSEC(CONFIG_NET_SAMPLE_SNTP_SERVER_TIMEOUT_MS));
123 if (rv < 0) {
124 LOG_INF("SNTP response timed out (%d)", rv);
125 }
126
127 end:
128 sntp_close(&ctx);
129 }
130
main(void)131 int main(void)
132 {
133 wait_for_network();
134
135 do_sntp(AF_INET);
136
137 #if defined(CONFIG_NET_IPV6)
138 do_sntp(AF_INET6);
139 #endif
140
141 return 0;
142 }
143