From acfabd815f1be870ea01120248384c663832e2b2 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Tue, 23 Jan 2018 08:57:43 +0100 Subject: Handle download failure in TAI bulletin download and replace boost regex with std --- m4/ax_boost_regex.m4 | 111 ---------------------------------------- src/ClockTAI.cpp | 112 ++++++++++++++++++++++------------------- src/ClockTAI.h | 7 ++- src/Makefile.am | 2 +- src/dabOutput/dabOutputUdp.cpp | 9 ++-- 5 files changed, 72 insertions(+), 169 deletions(-) delete mode 100644 m4/ax_boost_regex.m4 diff --git a/m4/ax_boost_regex.m4 b/m4/ax_boost_regex.m4 deleted file mode 100644 index e2413c2..0000000 --- a/m4/ax_boost_regex.m4 +++ /dev/null @@ -1,111 +0,0 @@ -# =========================================================================== -# https://www.gnu.org/software/autoconf-archive/ax_boost_regex.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_BOOST_REGEX -# -# DESCRIPTION -# -# Test for Regex library from the Boost C++ libraries. The macro requires -# a preceding call to AX_BOOST_BASE. Further documentation is available at -# . -# -# This macro calls: -# -# AC_SUBST(BOOST_REGEX_LIB) -# -# And sets: -# -# HAVE_BOOST_REGEX -# -# LICENSE -# -# Copyright (c) 2008 Thomas Porschberg -# Copyright (c) 2008 Michael Tindal -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 23 - -AC_DEFUN([AX_BOOST_REGEX], -[ - AC_ARG_WITH([boost-regex], - AS_HELP_STRING([--with-boost-regex@<:@=special-lib@:>@], - [use the Regex library from boost - it is possible to specify a certain library for the linker - e.g. --with-boost-regex=boost_regex-gcc-mt-d-1_33_1 ]), - [ - if test "$withval" = "no"; then - want_boost="no" - elif test "$withval" = "yes"; then - want_boost="yes" - ax_boost_user_regex_lib="" - else - want_boost="yes" - ax_boost_user_regex_lib="$withval" - fi - ], - [want_boost="yes"] - ) - - if test "x$want_boost" = "xyes"; then - AC_REQUIRE([AC_PROG_CC]) - CPPFLAGS_SAVED="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" - export CPPFLAGS - - LDFLAGS_SAVED="$LDFLAGS" - LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" - export LDFLAGS - - AC_CACHE_CHECK(whether the Boost::Regex library is available, - ax_cv_boost_regex, - [AC_LANG_PUSH([C++]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include - ]], - [[boost::regex r(); return 0;]])], - ax_cv_boost_regex=yes, ax_cv_boost_regex=no) - AC_LANG_POP([C++]) - ]) - if test "x$ax_cv_boost_regex" = "xyes"; then - AC_DEFINE(HAVE_BOOST_REGEX,,[define if the Boost::Regex library is available]) - BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` - if test "x$ax_boost_user_regex_lib" = "x"; then - for libextension in `ls $BOOSTLIBDIR/libboost_regex*.so* $BOOSTLIBDIR/libboost_regex*.dylib* $BOOSTLIBDIR/libboost_regex*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_regex.*\)\.so.*$;\1;' -e 's;^lib\(boost_regex.*\)\.dylib.*;\1;' -e 's;^lib\(boost_regex.*\)\.a.*$;\1;'` ; do - ax_lib=${libextension} - AC_CHECK_LIB($ax_lib, exit, - [BOOST_REGEX_LIB="-l$ax_lib"; AC_SUBST(BOOST_REGEX_LIB) link_regex="yes"; break], - [link_regex="no"]) - done - if test "x$link_regex" != "xyes"; then - for libextension in `ls $BOOSTLIBDIR/boost_regex*.dll* $BOOSTLIBDIR/boost_regex*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_regex.*\)\.dll.*$;\1;' -e 's;^\(boost_regex.*\)\.a.*$;\1;'` ; do - ax_lib=${libextension} - AC_CHECK_LIB($ax_lib, exit, - [BOOST_REGEX_LIB="-l$ax_lib"; AC_SUBST(BOOST_REGEX_LIB) link_regex="yes"; break], - [link_regex="no"]) - done - fi - - else - for ax_lib in $ax_boost_user_regex_lib boost_regex-$ax_boost_user_regex_lib; do - AC_CHECK_LIB($ax_lib, main, - [BOOST_REGEX_LIB="-l$ax_lib"; AC_SUBST(BOOST_REGEX_LIB) link_regex="yes"; break], - [link_regex="no"]) - done - fi - if test "x$ax_lib" = "x"; then - AC_MSG_ERROR(Could not find a version of the Boost::Regex library!) - fi - if test "x$link_regex" != "xyes"; then - AC_MSG_ERROR(Could not link against $ax_lib !) - fi - fi - - CPPFLAGS="$CPPFLAGS_SAVED" - LDFLAGS="$LDFLAGS_SAVED" - fi -]) diff --git a/src/ClockTAI.cpp b/src/ClockTAI.cpp index b2a3e87..8c01127 100644 --- a/src/ClockTAI.cpp +++ b/src/ClockTAI.cpp @@ -3,7 +3,7 @@ 2011, 2012 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2017 + Copyright (C) 2018 Matthias P. Braendli, matthias.braendli@mpb.li http://www.opendigitalradio.org @@ -29,7 +29,7 @@ * so that correct time can be communicated in EDI timestamps. * * This file contains self-test code that can be executed by running - * g++ -g -Wall -DTEST -DHAVE_CURL -std=c++11 -lcurl -lboost_regex -pthread \ + * g++ -g -Wall -DTEST -DHAVE_CURL -std=c++11 -lcurl -pthread \ * ClockTAI.cpp Log.cpp -o taitest && ./taitest */ @@ -53,12 +53,16 @@ #include #include #include -#include +#include + +using namespace std; #ifdef TEST static bool wait_longer = true; #endif +constexpr int download_retry_interval_hours = 1; + // Offset between NTP time and POSIX time: // timestamp_unix = timestamp_ntp - ntp_unix_offset const int64_t ntp_unix_offset = 2208988800L; @@ -109,7 +113,7 @@ int ClockTAI::get_valid_offset() offset_valid = true; } } - catch (std::runtime_error& e) { + catch (const runtime_error& e) { etiLog.level(warn) << "TAI-UTC offset could not be retrieved from " << url << " : " << e.what(); @@ -127,25 +131,26 @@ int ClockTAI::get_valid_offset() // With the current evolution of the offset, we're probably going // to reach 500 long after DAB gets replaced by another standard. if (offset < 0 or offset > 500) { - std::stringstream ss; + stringstream ss; ss << "TAI offset " << offset << " out of range"; - throw std::range_error(ss.str()); + throw range_error(ss.str()); } return offset; } else { - // Try again in 1 hour - m_bulletin_download_time += std::chrono::hours(1); + // Try again later + m_bulletin_download_time += chrono::hours(download_retry_interval_hours); - throw std::runtime_error("Could not fetch TAI-UTC offset"); + throw download_failed(); } } int ClockTAI::get_offset() { - auto time_now = std::chrono::system_clock::now(); + using namespace std::chrono; + auto time_now = system_clock::now(); if (not m_offset_valid) { #ifdef TEST @@ -153,41 +158,46 @@ int ClockTAI::get_offset() m_offset_valid = true; // Simulate requiring a new download - m_bulletin_download_time = std::chrono::system_clock::now() - - std::chrono::hours(24 * 40); + m_bulletin_download_time = system_clock::now() - hours(24 * 40); #else // First time we run we must block until we know // the offset m_offset = get_valid_offset(); m_offset_valid = true; - m_bulletin_download_time = std::chrono::system_clock::now(); + m_bulletin_download_time = system_clock::now(); #endif etiLog.level(info) << "Initialised TAI-UTC offset to " << m_offset << "s."; } - if (time_now - m_bulletin_download_time > - std::chrono::seconds(3600 * 24 * 31)) { + if (time_now - m_bulletin_download_time > hours(24 * 31)) { // Refresh if it's older than one month. Leap seconds are // announced several months in advance if (m_offset_future.valid()) { - auto state = m_offset_future.wait_for(std::chrono::seconds(0)); + auto state = m_offset_future.wait_for(seconds(0)); switch (state) { - case std::future_status::ready: - m_offset = m_offset_future.get(); - m_offset_valid = true; - m_bulletin_download_time = std::chrono::system_clock::now(); - - etiLog.level(info) << - "Updated TAI-UTC offset to " << m_offset << "s."; + case future_status::ready: + try { + m_offset = m_offset_future.get(); + m_offset_valid = true; + m_bulletin_download_time = system_clock::now(); + + etiLog.level(info) << + "Updated TAI-UTC offset to " << m_offset << "s."; + } + catch (const download_failed&) { + etiLog.level(warn) << + "TAI-UTC download failed, will retry in " + + to_string(download_retry_interval_hours) + " hour(s)"; + } #ifdef TEST wait_longer = false; #endif break; - case std::future_status::deferred: - case std::future_status::timeout: + case future_status::deferred: + case future_status::timeout: // Not ready yet #ifdef TEST etiLog.level(debug) << " async not ready yet"; @@ -199,7 +209,7 @@ int ClockTAI::get_offset() #ifdef TEST etiLog.level(debug) << " Launch async"; #endif - m_offset_future = std::async(std::launch::async, + m_offset_future = async(launch::async, &ClockTAI::get_valid_offset, this); } } @@ -230,12 +240,12 @@ int ClockTAI::parse_ietf_bulletin() // Example Line: // 3692217600 37 # 1 Jan 2017 // - // NTP timestamp leap seconds # some comment + // NTP timestampleap seconds# some comment // The NTP timestamp starts at epoch 1.1.1900. // The difference between NTP timestamps and unix epoch is 70 // years i.e. 2208988800 seconds - boost::regex regex_bulletin(R"(([0-9]+)\s+([0-9]+)\s+#.*)"); + std::regex regex_bulletin(R"(([0-9]+)\s+([0-9]+)\s+#.*)"); time_t now = time(nullptr); @@ -252,18 +262,18 @@ int ClockTAI::parse_ietf_bulletin() * So we need to look at the current date, and compare it * with the date of the leap second. */ - for (std::string line; std::getline(m_bulletin, line); ) { + for (string line; getline(m_bulletin, line); ) { - boost::smatch bulletin_entry; + std::smatch bulletin_entry; - bool is_match = boost::regex_search(line, bulletin_entry, regex_bulletin); + bool is_match = std::regex_search(line, bulletin_entry, regex_bulletin); if (is_match) { if (bulletin_entry.size() != 3) { - throw std::runtime_error( + throw runtime_error( "Incorrect number of matched TAI IETF bulletin entries"); } - const std::string bulletin_ntp_timestamp(bulletin_entry[1]); - const std::string bulletin_offset(bulletin_entry[2]); + const string bulletin_ntp_timestamp(bulletin_entry[1]); + const string bulletin_offset(bulletin_entry[2]); const int64_t timestamp_unix = std::atol(bulletin_ntp_timestamp.c_str()) - ntp_unix_offset; @@ -276,16 +286,16 @@ int ClockTAI::parse_ietf_bulletin() } #if TEST else { - std::cerr << "IETF Ignoring offset " << bulletin_offset << + cerr << "IETF Ignoring offset " << bulletin_offset << " at TS " << bulletin_ntp_timestamp << - " in the future" << std::endl; + " in the future" << endl; } #endif } } if (not tai_utc_offset_valid) { - throw std::runtime_error("No data in TAI bulletin"); + throw runtime_error("No data in TAI bulletin"); } return tai_utc_offset; @@ -312,7 +322,7 @@ void ClockTAI::load_bulletin_from_file(const char* cache_filename) m_bulletin.str(""); m_bulletin.clear(); - std::ifstream f(cache_filename); + ifstream f(cache_filename); if (not f.good()) { return; } @@ -323,9 +333,9 @@ void ClockTAI::load_bulletin_from_file(const char* cache_filename) void ClockTAI::update_cache(const char* cache_filename) { - std::ofstream f(cache_filename); + ofstream f(cache_filename); if (not f.good()) { - throw std::runtime_error("TAI-UTC bulletin open cache for writing"); + throw runtime_error("TAI-UTC bulletin open cache for writing"); } m_bulletin.clear(); @@ -350,23 +360,23 @@ bool ClockTAI::bulletin_is_valid() // The entry looks like this: //#@ 3707596800 - boost::regex regex_expiration(R"(#@\s+([0-9]+))"); + std::regex regex_expiration(R"(#@\s+([0-9]+))"); time_t now = time(nullptr); m_bulletin.clear(); m_bulletin.seekg(0); - for (std::string line; std::getline(m_bulletin, line); ) { - boost::smatch bulletin_entry; + for (string line; getline(m_bulletin, line); ) { + std::smatch bulletin_entry; - bool is_match = boost::regex_search(line, bulletin_entry, regex_expiration); + bool is_match = std::regex_search(line, bulletin_entry, regex_expiration); if (is_match) { if (bulletin_entry.size() != 2) { - throw std::runtime_error( + throw runtime_error( "Incorrect number of matched TAI IETF bulletin expiration"); } - const std::string expiry_data_str(bulletin_entry[1]); + const string expiry_data_str(bulletin_entry[1]); const int64_t expiry_unix = std::atol(expiry_data_str.c_str()) - ntp_unix_offset; @@ -399,12 +409,12 @@ void ClockTAI::download_tai_utc_bulletin(const char* url) curl_easy_cleanup(curl); if (res != CURLE_OK) { - throw std::runtime_error( "TAI-UTC bulletin download failed: " + - std::string(curl_easy_strerror(res))); + throw runtime_error( "TAI-UTC bulletin download failed: " + + string(curl_easy_strerror(res))); } } #else - throw std::runtime_error("Cannot download TAI Clock information without cURL"); + throw runtime_error("Cannot download TAI Clock information without cURL"); #endif // HAVE_CURL } @@ -453,12 +463,12 @@ int main(int argc, char **argv) etiLog.level(info) << "Offset is " << tai.get_offset(); } - catch (std::exception &e) { + catch (const exception &e) { etiLog.level(error) << "Exception " << e.what(); } - std::this_thread::sleep_for(std::chrono::seconds(2)); + this_thread::sleep_for(chrono::seconds(2)); } return 0; diff --git a/src/ClockTAI.h b/src/ClockTAI.h index 99827ba..4ee4072 100644 --- a/src/ClockTAI.h +++ b/src/ClockTAI.h @@ -3,7 +3,7 @@ 2011, 2012 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2017 + Copyright (C) 2018 Matthias P. Braendli, matthias.braendli@mpb.li http://www.opendigitalradio.org @@ -59,9 +59,12 @@ class ClockTAI { #endif private: + class download_failed {}; + // Either retrieve the bulletin from the cache or if necessarly // download it, and calculate the TAI-UTC offset. - // Returns the offset. + // Returns the offset or throws download_failed or a range_error + // if the offset is out of bounds. int get_valid_offset(void); // Download of new bulletin is done asynchronously diff --git a/src/Makefile.am b/src/Makefile.am index cc9b032..1087588 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -42,7 +42,7 @@ endif odr_dabmux_CFLAGS =-Wall -I$(FARSYNC_DIR) $(GITVERSION_FLAGS) odr_dabmux_CXXFLAGS =-Wall -std=c++11 -I$(FARSYNC_DIR) $(GITVERSION_FLAGS) $(BOOST_CPPFLAGS) $(ZMQ_CPPFLAGS) odr_dabmux_LDADD =$(ZMQ_LIBS) $(CURL_LIBS) $(BOOST_LDFLAGS) \ - -lpthread $(BOOST_SYSTEM_LIB) $(BOOST_THREAD_LIB) $(BOOST_REGEX_LIB) $(BOOST_ASIO_LIB) + -lpthread $(BOOST_SYSTEM_LIB) $(BOOST_THREAD_LIB) $(BOOST_ASIO_LIB) odr_dabmux_SOURCES =DabMux.cpp DabMux.h \ DabMultiplexer.cpp DabMultiplexer.h \ diff --git a/src/dabOutput/dabOutputUdp.cpp b/src/dabOutput/dabOutputUdp.cpp index 20e0c40..c129569 100644 --- a/src/dabOutput/dabOutputUdp.cpp +++ b/src/dabOutput/dabOutputUdp.cpp @@ -33,7 +33,7 @@ #include #include -#include +#include #include #include #include @@ -54,14 +54,14 @@ int DabOutputUdp::Open(const char* name) { using namespace std; - using namespace boost; const string uri_without_proto(name); regex re_url("([^:]+):([0-9]+)(.*)"); regex re_query("[?](?:src=([^&,]+))(?:[&,]ttl=([0-9]+))?"); smatch what; - if (regex_match(uri_without_proto, what, re_url, match_default)) { + if (regex_match(uri_without_proto, what, re_url, + regex_constants::match_default)) { string address = what[1]; if (this->packet_->getAddress().setAddress(address.c_str()) == -1) { @@ -83,7 +83,8 @@ int DabOutputUdp::Open(const char* name) string query_params = what[3]; smatch query_what; - if (regex_match(query_params, query_what, re_query, match_default)) { + if (regex_match(query_params, query_what, re_query, + regex_constants::match_default)) { string src = query_what[1]; int err = socket_->setMulticastSource(src.c_str()); -- cgit v1.2.3