20 #include <ripple/core/impl/SNTPClock.h>
21 #include <ripple/basics/Log.h>
22 #include <ripple/basics/random.h>
23 #include <ripple/beast/core/CurrentThreadName.h>
24 #include <boost/asio.hpp>
25 #include <boost/optional.hpp>
36 { 0x1B, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
38 using namespace std::chrono_literals;
46 #define NTP_SAMPLE_WINDOW 9
55 #define NTP_OFF_INFO 0
56 #define NTP_OFF_ROOTDELAY 1
57 #define NTP_OFF_ROOTDISP 2
58 #define NTP_OFF_REFERENCEID 3
59 #define NTP_OFF_REFTS_INT 4
60 #define NTP_OFF_REFTS_FRAC 5
61 #define NTP_OFF_ORGTS_INT 6
62 #define NTP_OFF_ORGTS_FRAC 7
63 #define NTP_OFF_RECVTS_INT 8
64 #define NTP_OFF_RECVTS_FRAC 9
65 #define NTP_OFF_XMITTS_INT 10
66 #define NTP_OFF_XMITTS_FRAC 11
72 template <
class Duration>
95 boost::asio::io_service::work>
work_;
99 boost::asio::basic_waitable_timer<std::chrono::system_clock>
timer_;
106 boost::asio::ip::udp::endpoint
ep_;
115 , socket_ (io_service_)
116 , timer_ (io_service_)
117 , resolver_ (io_service_)
143 if (it == servers.
end ())
146 "SNTP: no server specified";
152 for (
auto const& item : servers)
154 item, sys_seconds::max());
159 socket_.open (ip::udp::v4 ());
161 socket_.async_receive_from (buffer (buf_, 256),
164 std::placeholders::_1,
165 std::placeholders::_2));
169 std::placeholders::_1));
179 auto const when = time_point_cast<seconds>(clock_type::now());
180 if ((lastUpdate_ == sys_seconds::max()) ||
182 time_point_cast<seconds>(clock_type::now())))
184 return when + offset_;
206 if (ec == error::operation_aborted)
211 "SNTPClock::onTimer: " << ec.message();
219 std::placeholders::_1));
227 if (ec == error::operation_aborted)
239 "SNTP: Packet from " << ep_;
241 auto const query = queries_.
find (ep_);
242 if (query == queries_.
end ())
245 "SNTP: Reply from " << ep_ <<
" found without matching query";
247 else if (query->second.replied)
250 "SNTP: Duplicate response from " << ep_;
254 query->second.replied =
true;
256 if (time_point_cast<seconds>(clock_type::now()) > (query->second.sent + 1s))
259 "SNTP: Late response from " << ep_;
261 else if (bytes_xferd < 48)
264 "SNTP: Short reply from " << ep_ <<
265 " (" << bytes_xferd <<
") " << buf_.
size ();
268 &buf_[0])[NTP_OFF_ORGTS_FRAC] !=
272 "SNTP: Reply from " << ep_ <<
"had wrong nonce";
281 socket_.async_receive_from(buffer(buf_, 256),
283 std::placeholders::_1,
284 std::placeholders::_2));
305 auto best = servers_.
end ();
307 for (
auto iter = servers_.
begin (), end = best;
309 if ((best == end) || (iter->second == sys_seconds::max()) ||
310 (iter->second < best->second))
313 if (best == servers_.
end ())
316 "SNTP: No server to query";
321 auto now = time_point_cast<seconds>(clock_type::now());
323 if ((best->second != sys_seconds::max()) && ((best->second +
NTP_MIN_QUERY) >= now))
326 "SNTP: All servers recently queried";
332 boost::asio::ip::udp::resolver::query query(
333 boost::asio::ip::udp::v4 (), best->first,
"ntp");
334 resolver_.async_resolve (query,
std::bind (
336 std::placeholders::_1,
337 std::placeholders::_2));
339 "SNTPClock: Resolve pending for " << best->first;
344 boost::asio::ip::udp::resolver::iterator it)
347 if (ec == error::operation_aborted)
352 "SNTPClock::resolveComplete: " << ec.message();
356 assert (it != ip::udp::resolver::iterator());
361 while (++it != ip::udp::resolver::iterator())
367 if (sel != ip::udp::resolver::iterator ())
370 Query& query = queries_[*sel];
372 auto now = time_point_cast<seconds>(clock_type::now());
374 if ((query.
sent == now) || ((query.
sent + 1s) == now))
378 "SNTP: Redundant query suppressed";
384 query.
nonce = rand_int<std::uint32_t>();
388 static_cast<std::uint32_t>((time_point_cast<seconds>(clock_type::now()) +
393 std::placeholders::_1,
394 std::placeholders::_2));
400 if (ec == boost::asio::error::operation_aborted)
406 "SNTPClock::onSend: " << ec.message();
414 assert (buf_.
size () >= 48);
417 unsigned info = ntohl (recvBuffer[NTP_OFF_INFO]);
418 auto timev =
seconds{ntohl(recvBuffer[NTP_OFF_RECVTS_INT])};
419 unsigned stratum = (info >> 16) & 0xff;
421 if ((info >> 30) == 3)
424 "SNTP: Alarm condition " << ep_;
428 if ((stratum == 0) || (stratum > 14))
431 "SNTP: Unreasonable stratum (" << stratum <<
") from " << ep_;
436 auto now = time_point_cast<seconds>(clock_type::now());
437 timev -= now.time_since_epoch();
443 if (offsets_.
size () >= NTP_SAMPLE_WINDOW)
449 auto offsetList = offsets_;
450 std::sort(offsetList.begin(), offsetList.end());
451 auto j = offsetList.size ();
452 auto it =
std::next(offsetList.begin (), j/2);
456 offset_ = (offset_ + (*--it)) / 2;
460 if ((offset_ == -1s) || (offset_ == 1s))
463 if (timev != 0s || offset_ != 0s)
465 JLOG(j_.
trace()) <<
"SNTP: Offset is " << timev.count() <<
466 ", new system offset is " << offset_.
count();
476 return std::make_unique<SNTPClientImp>(j);