Skip to content

Commit 72534b8

Browse files
mpenate-ellenbytechmmahadevan108
authored andcommitted
net: lib: sntp_simple: Handle responses from previous iterations
SNTP simple runs request iterations with exponential backoff. If the net interface is a slower connection (ie. CAT M1 modems) then the request will be sent but the response may take time to be received, thus causing a timeout and another request to be sent. Because of the nature of UDP and the fact that the same socket (source IP/port combo) is being used for both requests, a delayed response to the first request can be received as the response to the second request, causing -EINVAL to be returned when the timestamps mismatch (see subsys/net/lib/sntp/sntp.c). The solution provided retries receiving the response when the timestamp is mismatched (without sending an additional request). Signed-off-by: Marcus Penate <[email protected]>
1 parent 4d8acdf commit 72534b8

File tree

3 files changed

+74
-40
lines changed

3 files changed

+74
-40
lines changed

include/zephyr/net/sntp.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,24 @@ int sntp_init(struct sntp_ctx *ctx, struct sockaddr *addr,
7373
*
7474
* @param ctx Address of sntp context.
7575
* @param timeout Timeout of waiting for sntp response (in milliseconds).
76-
* @param time Timestamp including integer and fractional seconds since
76+
* @param ts Timestamp including integer and fractional seconds since
77+
* 1 Jan 1970 (output).
78+
*
79+
* @return 0 if ok, <0 if error (-ETIMEDOUT if timeout).
80+
*/
81+
int sntp_query(struct sntp_ctx *ctx, uint32_t timeout, struct sntp_time *ts);
82+
83+
/**
84+
* @brief Attempt to receive an SNTP response after issuing a query
85+
*
86+
* @param ctx Address of sntp context.
87+
* @param timeout Timeout of waiting for sntp response (in milliseconds).
88+
* @param ts Timestamp including integer and fractional seconds since
7789
* 1 Jan 1970 (output).
7890
*
7991
* @return 0 if ok, <0 if error (-ETIMEDOUT if timeout).
8092
*/
81-
int sntp_query(struct sntp_ctx *ctx, uint32_t timeout,
82-
struct sntp_time *time);
93+
int sntp_recv_response(struct sntp_ctx *ctx, uint32_t timeout, struct sntp_time *ts);
8394

8495
/**
8596
* @brief Release SNTP context

subsys/net/lib/sntp/sntp.c

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ static int32_t parse_response(uint8_t *data, uint16_t len, struct sntp_time *exp
7070
NET_DBG("Mismatch originate timestamp: %d.%09d, expect: %llu.%09u",
7171
ntohl(pkt->orig_tm_s), ntohl(pkt->orig_tm_f), expected_orig_ts->seconds,
7272
expected_orig_ts->fraction);
73-
return -EINVAL;
73+
return -ERANGE;
7474
}
7575

7676
if (pkt->mode != SNTP_MODE_SERVER) {
@@ -151,38 +151,6 @@ static int32_t parse_response(uint8_t *data, uint16_t len, struct sntp_time *exp
151151
return 0;
152152
}
153153

154-
static int sntp_recv_response(struct sntp_ctx *sntp, uint32_t timeout,
155-
struct sntp_time *time)
156-
{
157-
struct sntp_pkt buf = { 0 };
158-
int status;
159-
int rcvd;
160-
161-
status = zsock_poll(sntp->sock.fds, sntp->sock.nfds, timeout);
162-
if (status < 0) {
163-
NET_ERR("Error in poll:%d", errno);
164-
return -errno;
165-
}
166-
167-
if (status == 0) {
168-
return -ETIMEDOUT;
169-
}
170-
171-
rcvd = zsock_recv(sntp->sock.fd, (uint8_t *)&buf, sizeof(buf), 0);
172-
if (rcvd < 0) {
173-
return -errno;
174-
}
175-
176-
if (rcvd != sizeof(struct sntp_pkt)) {
177-
return -EMSGSIZE;
178-
}
179-
180-
status = parse_response((uint8_t *)&buf, sizeof(buf),
181-
&sntp->expected_orig_ts,
182-
time);
183-
return status;
184-
}
185-
186154
int sntp_init(struct sntp_ctx *ctx, struct sockaddr *addr, socklen_t addr_len)
187155
{
188156
int ret;
@@ -213,13 +181,13 @@ int sntp_init(struct sntp_ctx *ctx, struct sockaddr *addr, socklen_t addr_len)
213181
return 0;
214182
}
215183

216-
int sntp_query(struct sntp_ctx *ctx, uint32_t timeout, struct sntp_time *time)
184+
int sntp_query(struct sntp_ctx *ctx, uint32_t timeout, struct sntp_time *ts)
217185
{
218186
struct sntp_pkt tx_pkt = { 0 };
219187
int ret = 0;
220188
int64_t ts_us = 0;
221189

222-
if (!ctx || !time) {
190+
if (!ctx || !ts) {
223191
return -EFAULT;
224192
}
225193

@@ -239,7 +207,39 @@ int sntp_query(struct sntp_ctx *ctx, uint32_t timeout, struct sntp_time *time)
239207
return ret;
240208
}
241209

242-
return sntp_recv_response(ctx, timeout, time);
210+
return sntp_recv_response(ctx, timeout, ts);
211+
}
212+
213+
int sntp_recv_response(struct sntp_ctx *ctx, uint32_t timeout,
214+
struct sntp_time *ts)
215+
{
216+
struct sntp_pkt buf = { 0 };
217+
int status;
218+
int rcvd;
219+
220+
status = zsock_poll(ctx->sock.fds, ctx->sock.nfds, timeout);
221+
if (status < 0) {
222+
NET_ERR("Error in poll:%d", errno);
223+
return -errno;
224+
}
225+
226+
if (status == 0) {
227+
return -ETIMEDOUT;
228+
}
229+
230+
rcvd = zsock_recv(ctx->sock.fd, (uint8_t *)&buf, sizeof(buf), 0);
231+
if (rcvd < 0) {
232+
return -errno;
233+
}
234+
235+
if (rcvd != sizeof(struct sntp_pkt)) {
236+
return -EMSGSIZE;
237+
}
238+
239+
status = parse_response((uint8_t *)&buf, sizeof(buf),
240+
&ctx->expected_orig_ts,
241+
ts);
242+
return status;
243243
}
244244

245245
void sntp_close(struct sntp_ctx *ctx)

subsys/net/lib/sntp/sntp_simple.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66
#include <errno.h>
7+
#include <stdbool.h>
78

89
#include <zephyr/net/sntp.h>
910
#include <zephyr/net/socketutils.h>
@@ -15,6 +16,7 @@ static int sntp_simple_helper(struct sockaddr *addr, socklen_t addr_len, uint32_
1516
struct sntp_ctx sntp_ctx;
1617
uint64_t deadline;
1718
uint32_t iter_timeout;
19+
bool first_iter;
1820

1921
res = sntp_init(&sntp_ctx, addr, addr_len);
2022
if (res < 0) {
@@ -29,18 +31,39 @@ static int sntp_simple_helper(struct sockaddr *addr, socklen_t addr_len, uint32_
2931

3032
/* Timeout for current iteration */
3133
iter_timeout = 100;
34+
first_iter = true;
3235

3336
while (k_uptime_get() < deadline) {
3437
res = sntp_query(&sntp_ctx, iter_timeout, ts);
3538

3639
if (res != -ETIMEDOUT) {
37-
break;
40+
if (false == first_iter && -ERANGE == res) {
41+
while (-ERANGE == res) {
42+
/* Possible out of order packet received.
43+
* Retry recv with current iteration timeout
44+
* until an error or timeout (flushing the socket
45+
* of old iteration responses until we timeout or
46+
* receive our iteration's response)
47+
*/
48+
res = sntp_recv_response(&sntp_ctx, iter_timeout, ts);
49+
}
50+
51+
if (res != ETIMEDOUT) {
52+
break;
53+
}
54+
} else {
55+
break;
56+
}
3857
}
3958

4059
/* Exponential backoff with limit */
4160
if (iter_timeout < 1000) {
4261
iter_timeout *= 2;
4362
}
63+
64+
if (first_iter) {
65+
first_iter = false;
66+
}
4467
}
4568

4669
sntp_close(&sntp_ctx);

0 commit comments

Comments
 (0)