// sec, usec = rtctime.get () static int rtctime_get (lua_State *L) { struct rtc_timeval tv; rtctime_gettimeofday (&tv); lua_pushnumber (L, tv.tv_sec); lua_pushnumber (L, tv.tv_usec); return 2; }
static void sntp_dosend (lua_State *L) { if (state->attempts == 0) { os_timer_disarm (&state->timer); os_timer_setfn (&state->timer, on_timeout, NULL); os_timer_arm (&state->timer, 1000, 1); } ++state->attempts; sntp_dbg("sntp: attempt %d\n", state->attempts); struct pbuf *p = pbuf_alloc (PBUF_TRANSPORT, sizeof (ntp_frame_t), PBUF_RAM); if (!p) handle_error (L, NTP_MEM_ERR); ntp_frame_t req; os_memset (&req, 0, sizeof (req)); req.ver = 4; req.mode = 3; // client #ifdef LUA_USE_MODULES_RTCTIME struct rtc_timeval tv; rtctime_gettimeofday (&tv); req.xmit.sec = htonl (tv.tv_sec); req.xmit.frac = htonl (tv.tv_usec); #else req.xmit.frac = htonl (system_get_time ()); #endif state->cookie = req.xmit; os_memcpy (p->payload, &req, sizeof (req)); int ret = udp_sendto (state->pcb, p, &server, NTP_PORT); sntp_dbg("sntp: send: %d\n", ret); pbuf_free (p); if (ret != ERR_OK) handle_error (L, NTP_SEND_ERR); }
static void on_recv (void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, uint16_t port) { (void)port; sntp_dbg("sntp: on_recv\n"); lua_State *L = lua_getstate(); if (!state || state->pcb != pcb) { // "impossible", but don't leak if it did happen somehow... udp_remove (pcb); pbuf_free (p); return; } if (!p) return; if (p->len < sizeof (ntp_frame_t)) { pbuf_free (p); return; // not an ntp frame, ignore } // make sure we have an aligned copy to work from ntp_frame_t ntp; os_memcpy (&ntp, p->payload, sizeof (ntp)); pbuf_free (p); sntp_dbg("sntp: transmit timestamp: %u, %u\n", ntp.xmit.sec, ntp.xmit.frac); // sanity checks before we touch our clocks ip_addr_t anycast; NTP_ANYCAST_ADDR(&anycast); if (server.addr != anycast.addr && server.addr != addr->addr) return; // unknown sender, ignore if (ntp.origin.sec != state->cookie.sec || ntp.origin.frac != state->cookie.frac) return; // unsolicited message, ignore if (ntp.LI == 3) return; // server clock not synchronized (why did it even respond?!) server.addr = addr->addr; ntp.origin.sec = ntohl (ntp.origin.sec); ntp.origin.frac = ntohl (ntp.origin.frac); ntp.recv.sec = ntohl (ntp.recv.sec); ntp.recv.frac = ntohl (ntp.recv.frac); ntp.xmit.sec = ntohl (ntp.xmit.sec); ntp.xmit.frac = ntohl (ntp.xmit.frac); const uint32_t UINT32_MAXI = (uint32_t)-1; const uint64_t MICROSECONDS = 1000000ull; const uint32_t NTP_TO_UNIX_EPOCH = 2208988800ul; bool have_cb = (state->sync_cb_ref != LUA_NOREF); // if we have rtctime, do higher resolution delta calc, else just use // the transmit timestamp #ifdef LUA_USE_MODULES_RTCTIME struct rtc_timeval tv; rtctime_gettimeofday (&tv); ntp_timestamp_t dest; dest.sec = tv.tv_sec; dest.frac = (MICROSECONDS * tv.tv_usec) / UINT32_MAXI; // Compensation as per RFC2030 int64_t delta_s = (((int64_t)ntp.recv.sec - ntp.origin.sec) + ((int64_t)ntp.xmit.sec - dest.sec)) / 2; int64_t delta_f = (((int64_t)ntp.recv.frac - ntp.origin.frac) + ((int64_t)ntp.xmit.frac - dest.frac)) / 2; dest.sec += delta_s; if (delta_f + dest.frac < 0) { delta_f += UINT32_MAXI; --dest.sec; } else if (delta_f + dest.frac > UINT32_MAXI) { delta_f -= UINT32_MAXI; ++dest.sec; } dest.frac += delta_f; tv.tv_sec = dest.sec - NTP_TO_UNIX_EPOCH; tv.tv_usec = (MICROSECONDS * dest.frac) / UINT32_MAXI; rtctime_settimeofday (&tv); if (have_cb) { lua_rawgeti (L, LUA_REGISTRYINDEX, state->sync_cb_ref); lua_pushnumber (L, tv.tv_sec); lua_pushnumber (L, tv.tv_usec); } #else if (have_cb) { lua_rawgeti (L, LUA_REGISTRYINDEX, state->sync_cb_ref); lua_pushnumber (L, ntp.xmit.sec - NTP_TO_UNIX_EPOCH); lua_pushnumber (L, (MICROSECONDS * ntp.xmit.frac) / UINT32_MAXI); } #endif cleanup (L); if (have_cb) { lua_pushstring (L, ipaddr_ntoa (&server)); lua_call (L, 3, 0); } }