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