SNTP module enhancements (#1243)
* Provide an error code to SNTP error callback. * Switch SNTP to use ephemeral port. In case we're being hit by ISP-level thou-shall-not-run-NTP silliness.
This commit is contained in:
parent
a33f586855
commit
f428897810
|
@ -58,6 +58,14 @@
|
||||||
# define sntp_dbg(...)
|
# define sntp_dbg(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NTP_NO_ERR = 0,
|
||||||
|
NTP_DNS_ERR,
|
||||||
|
NTP_MEM_ERR,
|
||||||
|
NTP_SEND_ERR,
|
||||||
|
NTP_TIMEOUT_ERR
|
||||||
|
} ntp_err_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint32_t sec;
|
uint32_t sec;
|
||||||
|
@ -107,14 +115,15 @@ static void cleanup (lua_State *L)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void handle_error (lua_State *L)
|
static void handle_error (lua_State *L, ntp_err_t err)
|
||||||
{
|
{
|
||||||
sntp_dbg("sntp: handle_error\n");
|
sntp_dbg("sntp: handle_error\n");
|
||||||
if (state->err_cb_ref != LUA_NOREF)
|
if (state->err_cb_ref != LUA_NOREF)
|
||||||
{
|
{
|
||||||
lua_rawgeti (L, LUA_REGISTRYINDEX, state->err_cb_ref);
|
lua_rawgeti (L, LUA_REGISTRYINDEX, state->err_cb_ref);
|
||||||
|
lua_pushinteger (L, err);
|
||||||
cleanup (L);
|
cleanup (L);
|
||||||
lua_call (L, 0, 0);
|
lua_call (L, 1, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
cleanup (L);
|
cleanup (L);
|
||||||
|
@ -135,7 +144,7 @@ static void sntp_dosend (lua_State *L)
|
||||||
|
|
||||||
struct pbuf *p = pbuf_alloc (PBUF_TRANSPORT, sizeof (ntp_frame_t), PBUF_RAM);
|
struct pbuf *p = pbuf_alloc (PBUF_TRANSPORT, sizeof (ntp_frame_t), PBUF_RAM);
|
||||||
if (!p)
|
if (!p)
|
||||||
handle_error (L);
|
handle_error (L, NTP_MEM_ERR);
|
||||||
|
|
||||||
ntp_frame_t req;
|
ntp_frame_t req;
|
||||||
os_memset (&req, 0, sizeof (req));
|
os_memset (&req, 0, sizeof (req));
|
||||||
|
@ -156,7 +165,7 @@ static void sntp_dosend (lua_State *L)
|
||||||
sntp_dbg("sntp: send: %d\n", ret);
|
sntp_dbg("sntp: send: %d\n", ret);
|
||||||
pbuf_free (p);
|
pbuf_free (p);
|
||||||
if (ret != ERR_OK)
|
if (ret != ERR_OK)
|
||||||
handle_error (L);
|
handle_error (L, NTP_SEND_ERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -167,8 +176,8 @@ static void sntp_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
|
||||||
lua_State *L = lua_getstate ();
|
lua_State *L = lua_getstate ();
|
||||||
if (ipaddr == NULL)
|
if (ipaddr == NULL)
|
||||||
{
|
{
|
||||||
NODE_ERR("DNS Fail!\n");
|
sntp_dbg("DNS Fail!\n");
|
||||||
handle_error(L);
|
handle_error(L, NTP_DNS_ERR);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -184,7 +193,7 @@ static void on_timeout (void *arg)
|
||||||
sntp_dbg("sntp: timer\n");
|
sntp_dbg("sntp: timer\n");
|
||||||
lua_State *L = lua_getstate ();
|
lua_State *L = lua_getstate ();
|
||||||
if (state->attempts >= MAX_ATTEMPTS)
|
if (state->attempts >= MAX_ATTEMPTS)
|
||||||
handle_error (L);
|
handle_error (L, NTP_TIMEOUT_ERR);
|
||||||
else
|
else
|
||||||
sntp_dosend (L);
|
sntp_dosend (L);
|
||||||
}
|
}
|
||||||
|
@ -332,8 +341,8 @@ static int sntp_sync (lua_State *L)
|
||||||
if (!state->pcb)
|
if (!state->pcb)
|
||||||
sync_err ("out of memory");
|
sync_err ("out of memory");
|
||||||
|
|
||||||
if (udp_bind (state->pcb, IP_ADDR_ANY, NTP_PORT) != ERR_OK)
|
if (udp_bind (state->pcb, IP_ADDR_ANY, 0) != ERR_OK)
|
||||||
sync_err ("ntp port in use");
|
sync_err ("no port available");
|
||||||
|
|
||||||
udp_recv (state->pcb, on_recv, L);
|
udp_recv (state->pcb, on_recv, L);
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,11 @@ Attempts to obtain time synchronization.
|
||||||
#### Parameters
|
#### Parameters
|
||||||
- `server_ip` if non-`nil`, that server is used. If `nil`, then the last contacted server is used. This ties in with the NTP anycast mode, where the first responding server is remembered for future synchronization requests. The easiest way to use anycast is to always pass nil for the server argument.
|
- `server_ip` if non-`nil`, that server is used. If `nil`, then the last contacted server is used. This ties in with the NTP anycast mode, where the first responding server is remembered for future synchronization requests. The easiest way to use anycast is to always pass nil for the server argument.
|
||||||
- `callback` Iif provided it will be invoked on a successful synchronization, with three parameters: seconds, microseconds, and server. Note that when the [rtctime](rtctime.md) module is available, there is no need to explicitly call [`rtctime.set()`](rtctime.md#rtctimeset) - this module takes care of doing so internally automatically, for best accuracy.
|
- `callback` Iif provided it will be invoked on a successful synchronization, with three parameters: seconds, microseconds, and server. Note that when the [rtctime](rtctime.md) module is available, there is no need to explicitly call [`rtctime.set()`](rtctime.md#rtctimeset) - this module takes care of doing so internally automatically, for best accuracy.
|
||||||
- `errcallback` failure callback with no parameters. The module automatically performs a number of retries before giving up and reporting the error.
|
- `errcallback` failure callback with a single integer parameter describing the type of error. The module automatically performs a number of retries before giving up and reporting the error. Error codes:
|
||||||
|
- 1: DNS lookup failed
|
||||||
|
- 2: Memory allocation failure
|
||||||
|
- 3: UDP send failed
|
||||||
|
- 4: Timeout, no NTP response received
|
||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
`nil`
|
`nil`
|
||||||
|
|
Loading…
Reference in New Issue