Пример #1
0
// 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;
}
Пример #2
0
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);
}
Пример #3
0
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);
  }
}