1#include <fc/network/ntp.hpp>
5#include <fc/thread/thread.hpp>
16 using boost::fibers::future;
23 std::vector< std::pair< std::string, uint16_t> >
_ntp_hosts;
44 _ntp_hosts.push_back( std::make_pair(
"pool.ntp.org",123 ) );
59 uint64_t ntp_timestamp_host = bswap_64(ntp_timestamp_net_order);
60 uint32_t fractional_seconds = ntp_timestamp_host & 0xffffffff;
62 uint32_t seconds_since_1900 = ntp_timestamp_host >> 32;
63 uint32_t seconds_since_epoch = seconds_since_1900 - 2208988800;
70 uint32_t seconds_since_epoch = (
uint32_t)(microseconds_since_epoch / 1000000);
71 uint32_t seconds_since_1900 = seconds_since_epoch + 2208988800;
74 uint64_t ntp_timestamp_net_order = ((
uint64_t)seconds_since_1900 << 32) + fractional_seconds;
75 return bswap_64(ntp_timestamp_net_order);
85 wlog(
"resolving... ${r}", (
"r", item) );
86 auto eps =
resolve( item.first, item.second );
89 wlog(
"sending request to ${ep}", (
"ep",ep) );
90 std::shared_ptr<char> send_buffer(
new char[48], [](
char*
p){
delete[]
p; });
91 std::array<unsigned char, 48> packet_to_send { {010,0,0,0,0,0,0,0,0} };
92 memcpy(send_buffer.get(), packet_to_send.data(), packet_to_send.size());
99 catch (
const fc::canceled_exception&)
103 catch (
const std::bad_alloc& )
107 catch (
const boost::interprocess::bad_alloc& )
116 catch (
const std::exception& e )
142 std::shared_ptr<char> receive_buffer(
new char[receive_buffer_size], [](
char*
p){
delete[]
p; });
155 _sock.receive_from( receive_buffer, receive_buffer_size, from );
165 (server_transmit_time - receive_time)).
count() / 2);
167 (server_transmit_time - server_receive_time));
175 wlog(
"received stale ntp reply requested at ${request_time}, send a new time request", (
"request_time", origin_time));
186 wlog(
"ntp_delta_time updated to ${delta_time} us", (
"delta_time",ntp_delta_time) );
189 elog(
"NTP time and local time vary by more than a day! ntp:${ntp_time} local:${local}",
193 wlog(
"exiting ntp read_loop");
214 :my( new
detail::ntp_impl() )
216 my->start_read_loop();
221 ilog(
"shutting down ntp" );
222 my->_ntp_thread.async([=](){
224 if( my->_scheduled_request_time ) {
225 ilog(
"wait cancel scheduled request " );
226 my->_scheduled_request_time->cancel();
227 my->_scheduled_request_time->get_future().wait();
228 my->_scheduled_request_time.reset();
230 ilog(
"wait request time task " );
231 my->_request_time_task_done.wait();
232 ilog(
"wait read loop " );
233 my->_read_loop_done.wait();
235 my->_ntp_thread.quit();
236 ilog(
"joining ntp" );
237 my->_ntp_thread.join();
241 void ntp::add_server(
const std::string& hostname,
uint16_t port)
243 my->_ntp_thread.async( [=](){ my->_ntp_hosts.push_back( std::make_pair(hostname,port) ); }).
wait();
246 void ntp::set_request_interval(
uint32_t interval_sec )
248 my->_request_interval_sec = interval_sec;
249 my->_retry_failed_request_interval_sec = std::min(my->_retry_failed_request_interval_sec, interval_sec);
253 void ntp::request_now()
255 my->_ntp_thread.async( [=](){ my->request_now(); } ).get();
258 std::optional<time_point> ntp::get_time()
const
260 if( my->_last_ntp_delta_initialized )
262 return std::optional<time_point>();
uint32_t _request_interval_sec
std::atomic< int64_t > _last_ntp_delta_microseconds
future< void > _request_time_task_done
fc::time_point ntp_timestamp_to_fc_time_point(uint64_t ntp_timestamp_net_order)
std::vector< std::pair< std::string, uint16_t > > _ntp_hosts
fc::time_point _last_valid_ntp_reply_received_time
std::atomic_bool _last_ntp_delta_initialized
future< void > _read_loop_done
uint32_t _retry_failed_request_interval_sec
uint64_t fc_time_point_to_ntp_timestamp(const fc::time_point &fc_timestamp)
std::shared_ptr< scheduled_task_impl< void > > _scheduled_request_time
Used to generate a useful error report when an exception is thrown.
std::string to_detail_string(log_level ll=log_level::all) const
const char * what() const noexcept override
constexpr int64_t count() const
constexpr const microseconds & time_since_epoch() const
void send_to(const char *b, size_t l, boost::asio::ip::udp::endpoint &to)
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
#define FC_RETHROW_EXCEPTIONS(LOG_LEVEL, FORMAT,...)
Catchs all exception's, std::exceptions, and ... and rethrows them after appending the provided log m...
constexpr microseconds seconds(int64_t s)
std::vector< boost::asio::ip::udp::endpoint > resolve(boost::asio::io_service &io_service, const std::string &host, uint16_t port)
unsigned __int64 uint64_t
memcpy((char *) pInfo->slotDescription, s, l)